From c91171d458733018ac43cfe75027f88bfe66c02a Mon Sep 17 00:00:00 2001 From: Vica Teodor Andrei Date: Sat, 23 Nov 2024 12:41:10 +0200 Subject: [PATCH] chapters/data: Add checkers for `memory-security` tasks Done solving the issue 134 : chapters/data/memory-security/drills/tasks: Add solutions and checkers #134 Added the generate_skels.py infrastructure to generate the skeletons from the solutions Added checkers for the tasks which needed one Updated the README.md for every task with useful information on how to generate the skels and run the checker Added solution Updated generate_skels.py to add support for a task that requires uncommenting lines in the Makefile. Fixes #134 Signed-off-by: Vica Teodor Andrei --- .../drills/tasks/aslr/.gitignore | 1 + .../drills/tasks/aslr/Makefile | 10 + .../drills/tasks/aslr/README.md | 18 ++ .../drills/tasks/aslr/generate_skels.py | 159 ++++++++++++++ .../drills/tasks/aslr/solution/src/.gitignore | 1 + .../aslr/{support => solution/src}/Makefile | 3 + .../{support => solution/src}/Makefile.aslr | 0 .../aslr/{support => solution/src}/aslr.c | 0 .../support => aslr/solution}/tests/Makefile | 6 +- .../aslr/solution/tests/graded_test.inc.sh | 40 ++++ .../solution}/tests/run_all_tests.sh | 14 +- .../drills/tasks/aslr/solution/tests/test.sh | 22 ++ .../bypassing-stack-protector/.gitignore | 1 + .../tasks/bypassing-stack-protector/Makefile | 10 + .../tasks/bypassing-stack-protector/README.md | 20 +- .../generate_skels.py | 152 ++++++++++++++ .../solution/src/.gitignore | 1 + .../{support => solution/src}/Makefile | 0 .../src}/stack_protector.c | 8 +- .../solution/tests/Makefile | 34 +++ .../solution}/tests/graded_test.inc.sh | 1 - .../solution/tests/run_all_tests.sh | 21 ++ .../solution/tests/test.sh | 23 ++ .../drills/tasks/exec-shellcode/.gitignore | 1 + .../drills/tasks/exec-shellcode/Makefile | 10 + .../drills/tasks/exec-shellcode/README.md | 3 + .../tasks/exec-shellcode/generate_skels.py | 152 ++++++++++++++ .../exec-shellcode/support/src/.gitignore | 1 - .../tasks/exec-shellcode/support/src/Makefile | 14 -- .../support/src/exec_shellcode.c | 40 ---- .../exec-shellcode/support/tests/.gitignore | 4 - .../exec-shellcode/support/tests/brk.asm | 12 -- .../exec-shellcode/support/tests/getpid.asm | 12 -- .../support/tests/helloworld.asm | 25 --- .../exec-shellcode/support/tests/openfile.asm | 25 --- .../exec-shellcode/support/tests/test_brk.sh | 40 ---- .../support/tests/test_getpid.sh | 40 ---- .../support/tests/test_helloworld.sh | 39 ---- .../support/tests/test_openfile.sh | 53 ----- .../support/utils/log/CPPLINT.cfg | 1 - .../exec-shellcode/support/utils/log/log.c | 197 ------------------ .../exec-shellcode/support/utils/log/log.h | 69 ------ .../support/utils/sock/sock_util.c | 114 ---------- .../support/utils/sock/sock_util.h | 34 --- .../exec-shellcode/support/utils/utils.h | 36 ---- .../tasks/pointer-arithmetic-leak/.gitignore | 1 + .../tasks/pointer-arithmetic-leak/Makefile | 10 + .../tasks/pointer-arithmetic-leak/README.md | 3 + .../pointer-arithmetic-leak/generate_skels.py | 152 ++++++++++++++ .../solution/src/.gitignore | 1 + .../{support => solution/src}/Makefile | 0 .../{support => solution/src}/buff_leak.c | 0 .../drills/tasks/stack-protector/.gitignore | 1 + .../drills/tasks/stack-protector/Makefile | 10 + .../drills/tasks/stack-protector/README.md | 17 ++ .../tasks/stack-protector/generate_skels.py | 159 ++++++++++++++ .../stack-protector/solution/src/.gitignore | 1 + .../{support => solution/src}/Makefile | 3 + .../src}/bo_write_practice.c | 0 .../stack-protector/solution/tests/Makefile | 34 +++ .../solution/tests/graded_test.inc.sh | 40 ++++ .../solution/tests/run_all_tests.sh | 21 ++ .../stack-protector/solution/tests/test.sh | 21 ++ 63 files changed, 1170 insertions(+), 771 deletions(-) create mode 100644 chapters/data/memory-security/drills/tasks/aslr/.gitignore create mode 100644 chapters/data/memory-security/drills/tasks/aslr/Makefile create mode 100644 chapters/data/memory-security/drills/tasks/aslr/generate_skels.py create mode 100644 chapters/data/memory-security/drills/tasks/aslr/solution/src/.gitignore rename chapters/data/memory-security/drills/tasks/aslr/{support => solution/src}/Makefile (88%) rename chapters/data/memory-security/drills/tasks/aslr/{support => solution/src}/Makefile.aslr (100%) rename chapters/data/memory-security/drills/tasks/aslr/{support => solution/src}/aslr.c (100%) rename chapters/data/memory-security/drills/tasks/{exec-shellcode/support => aslr/solution}/tests/Makefile (82%) create mode 100644 chapters/data/memory-security/drills/tasks/aslr/solution/tests/graded_test.inc.sh rename chapters/data/memory-security/drills/tasks/{exec-shellcode/support => aslr/solution}/tests/run_all_tests.sh (73%) create mode 100644 chapters/data/memory-security/drills/tasks/aslr/solution/tests/test.sh create mode 100644 chapters/data/memory-security/drills/tasks/bypassing-stack-protector/.gitignore create mode 100644 chapters/data/memory-security/drills/tasks/bypassing-stack-protector/Makefile create mode 100644 chapters/data/memory-security/drills/tasks/bypassing-stack-protector/generate_skels.py create mode 100644 chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/src/.gitignore rename chapters/data/memory-security/drills/tasks/bypassing-stack-protector/{support => solution/src}/Makefile (100%) rename chapters/data/memory-security/drills/tasks/bypassing-stack-protector/{support => solution/src}/stack_protector.c (72%) create mode 100644 chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/tests/Makefile rename chapters/data/memory-security/drills/tasks/{exec-shellcode/support => bypassing-stack-protector/solution}/tests/graded_test.inc.sh (99%) create mode 100755 chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/tests/run_all_tests.sh create mode 100644 chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/tests/test.sh create mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/.gitignore create mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/Makefile create mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/generate_skels.py delete mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/support/src/.gitignore delete mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/support/src/Makefile delete mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/support/src/exec_shellcode.c delete mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/.gitignore delete mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/brk.asm delete mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/getpid.asm delete mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/helloworld.asm delete mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/openfile.asm delete mode 100755 chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/test_brk.sh delete mode 100755 chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/test_getpid.sh delete mode 100755 chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/test_helloworld.sh delete mode 100755 chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/test_openfile.sh delete mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/log/CPPLINT.cfg delete mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/log/log.c delete mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/log/log.h delete mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/sock/sock_util.c delete mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/sock/sock_util.h delete mode 100644 chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/utils.h create mode 100644 chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/.gitignore create mode 100644 chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/Makefile create mode 100644 chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/generate_skels.py create mode 100644 chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/solution/src/.gitignore rename chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/{support => solution/src}/Makefile (100%) rename chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/{support => solution/src}/buff_leak.c (100%) create mode 100644 chapters/data/memory-security/drills/tasks/stack-protector/.gitignore create mode 100644 chapters/data/memory-security/drills/tasks/stack-protector/Makefile create mode 100644 chapters/data/memory-security/drills/tasks/stack-protector/generate_skels.py create mode 100644 chapters/data/memory-security/drills/tasks/stack-protector/solution/src/.gitignore rename chapters/data/memory-security/drills/tasks/stack-protector/{support => solution/src}/Makefile (85%) rename chapters/data/memory-security/drills/tasks/stack-protector/{support => solution/src}/bo_write_practice.c (100%) create mode 100644 chapters/data/memory-security/drills/tasks/stack-protector/solution/tests/Makefile create mode 100644 chapters/data/memory-security/drills/tasks/stack-protector/solution/tests/graded_test.inc.sh create mode 100755 chapters/data/memory-security/drills/tasks/stack-protector/solution/tests/run_all_tests.sh create mode 100644 chapters/data/memory-security/drills/tasks/stack-protector/solution/tests/test.sh diff --git a/chapters/data/memory-security/drills/tasks/aslr/.gitignore b/chapters/data/memory-security/drills/tasks/aslr/.gitignore new file mode 100644 index 0000000000..54811d5f0f --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/aslr/.gitignore @@ -0,0 +1 @@ +support diff --git a/chapters/data/memory-security/drills/tasks/aslr/Makefile b/chapters/data/memory-security/drills/tasks/aslr/Makefile new file mode 100644 index 0000000000..35ad62412c --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/aslr/Makefile @@ -0,0 +1,10 @@ +PYTHON = python3 +SCRIPT = generate_skels.py + +skels: + mkdir -p support/src + $(PYTHON) $(SCRIPT) --input ./solution/src --output ./support/src + $(PYTHON) $(SCRIPT) --input ./solution/tests --output ./support/tests + +clean: + rm -rf support/ diff --git a/chapters/data/memory-security/drills/tasks/aslr/README.md b/chapters/data/memory-security/drills/tasks/aslr/README.md index f84ca4b48d..d5768bbde3 100644 --- a/chapters/data/memory-security/drills/tasks/aslr/README.md +++ b/chapters/data/memory-security/drills/tasks/aslr/README.md @@ -1,5 +1,9 @@ # ASLR +Navigate to `chapters/data/memory-security/drills/tasks/aslr` and run `make skels` to generate the `support/` folder. +Then navigate to `support/src`. + + Use the `Makefile.aslr` file to compile the `chapters/data/memory-security/drills/tasks/aslr/support/aslr.c` file: ```console @@ -26,3 +30,17 @@ Disable PIC by uncommenting the `-fno-PIC` and `LDFLAGS` lines. We observe that for randomization to work, we need to instruct the OS to randomize the program sections and the compiler to generate code that is position independent. If you're having difficulties solving this exercise, go through [this](../../../reading/memory-security.md) reading material. + +## Checker + +To run the checker, go into the `tests` directory located in `src`, then type `make check`. +A successful output of the checker should look like this : + +```console +student@os:~/.../drills/tasks/aslr/support/src/tests make check +test_aslr ........................ passed ... 100 + +======================================================================== + +Total: 100/100 +``` diff --git a/chapters/data/memory-security/drills/tasks/aslr/generate_skels.py b/chapters/data/memory-security/drills/tasks/aslr/generate_skels.py new file mode 100644 index 0000000000..0067849339 --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/aslr/generate_skels.py @@ -0,0 +1,159 @@ +#!/usr/bin/python3 -u +# SPDX-License-Identifier: BSD-3-Clause + +import sys +import argparse +import os.path +import re + + +def process_file(src, dst, pattern, replace, remove, replace_pairs, end_string=None): + if not pattern or not replace or not remove: + print( + f"ERROR: The script behaviour is not properly specified for {src}", + file=sys.stderr, + ) + sys.exit(1) + + fin = open(src, "r") + os.makedirs(os.path.dirname(dst), exist_ok=True) + fout = open(dst, "w") + + remove_lines = 0 + skip_lines = 0 + uncomment_lines = 0 + end_found = True + makefile_special_handling = "Makefile" in src + + for i, l in enumerate(fin.readlines()): + # Skip generation of file. + if "SKIP_GENERATE" in l: + fout.close() + os.remove(dst) + return + + if end_string and not end_found: + fout.write(l) + if end_string in l: + end_found = True + continue + + if remove_lines > 0: + remove_lines -= 1 + continue + + if skip_lines > 0: + skip_lines -= 1 + m = re.search(pattern, l) + if m: + l = "%s%s\n" % (m.group(1), m.group(3)) + fout.write(l) + continue + + if uncomment_lines > 0: + uncomment_lines -= 1 + for fro, to in replace_pairs: + l = re.sub(fro, to, l) + fout.write(l) + continue + + if makefile_special_handling and "TODO" in l and "Uncomment" in l: + fout.write(l) + next_line = fin.readline() + fout.write("# " + next_line) + continue + + m = re.search(pattern, l) + if m: + if m.group(2): + skip_lines = int(m.group(2)) + else: + skip_lines = 1 + + if end_string and end_string not in l: + end_found = False + + l = "%s%s\n" % (m.group(1), m.group(3)) + + m = re.search(replace, l) + if m: + if m.group(2): + uncomment_lines = int(m.group(2)) + else: + uncomment_lines = 1 + continue + + m = re.search(remove, l) + if m: + if m.group(2): + remove_lines = int(m.group(2)) + else: + remove_lines = 1 + continue + + fout.write(l) + + fout.close() + +def main(): + parser = argparse.ArgumentParser( + description="Generate skeletons sources from reference solution sources" + ) + parser.add_argument( + "--input", help="input directory to process files", required=True + ) + parser.add_argument( + "--output", help="output directory to copy processed files", required=True + ) + args = parser.parse_args() + + for root, dirs, files in os.walk(args.input): + new_root = os.path.join(args.output, os.path.relpath(root, args.input)) + for d in dirs: + os.makedirs(os.path.join(new_root, d), exist_ok=True) + + for src in files: + if ( + re.match("Makefile.*$", src) + or re.match(r".*\.sh$", src) + or re.match(r".*\.[sS]$", src) + or re.match(r".*\.py$", src) + ): + pattern = r"(^\s*#\s*TODO)( [0-9]*)(:.*)" + replace = r"(^\s*#\s*REPLACE)( [0-9]*)" + remove = r"(^\s*#\s*REMOVE)( [0-9]*)" + replace_pairs = [("# ", "")] + end_string = None + elif re.match(r".*\.asm$", src): + pattern = r"(^\s*;\s*TODO)( [0-9]*)(:.*)" + replace = r"(^\s*;\s*REPLACE)( [0-9]*)" + remove = r"(^\s*;\s*REMOVE)( [0-9]*)" + replace_pairs = [("; ", "")] + end_string = None + elif ( + re.match(r".*\.[ch]$", src) + or re.match(r".*\.cpp$", src) + or re.match(r".*\.hpp$", src) + ): + pattern = r"(.*/\*\s*TODO)([ 0-9]*)(:.*)" + replace = r"(.*/\*\s*REPLACE)( [0-9]*)" + remove = r"(.*/\*\s*REMOVE)( [0-9]*)" + replace_pairs = [(r"/\* ", ""), (r" \*/", "")] + end_string = "*/" + elif re.match(r".*\.d$", src): + pattern = r"(.*//\s*TODO)([ 0-9]*)(:.*)" + replace = r"(.*//\s*REPLACE)( [0-9]*)" + remove = r"(.*//\s*REMOVE)( [0-9]*)" + replace_pairs = [(r"// ", "")] + end_string = None + else: + continue + + dst = os.path.join(new_root, src) + src = os.path.join(root, src) + print(dst) + process_file(src, dst, pattern, replace, remove, replace_pairs, end_string) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/chapters/data/memory-security/drills/tasks/aslr/solution/src/.gitignore b/chapters/data/memory-security/drills/tasks/aslr/solution/src/.gitignore new file mode 100644 index 0000000000..14a1844e19 --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/aslr/solution/src/.gitignore @@ -0,0 +1 @@ +/aslr diff --git a/chapters/data/memory-security/drills/tasks/aslr/support/Makefile b/chapters/data/memory-security/drills/tasks/aslr/solution/src/Makefile similarity index 88% rename from chapters/data/memory-security/drills/tasks/aslr/support/Makefile rename to chapters/data/memory-security/drills/tasks/aslr/solution/src/Makefile index 572ce6bfee..6cb218d02b 100644 --- a/chapters/data/memory-security/drills/tasks/aslr/support/Makefile +++ b/chapters/data/memory-security/drills/tasks/aslr/solution/src/Makefile @@ -8,7 +8,10 @@ SRCS = aslr.c OBJS = $(SRCS:.c=.o) # Flags for compiling and linking +# TODO: Uncomment the -fno-PIC line CFLAGS += -fno-stack-protector -fno-PIC + +# TODO: Uncomment the LDFLAGS line LDFLAGS += -no-pie # Output binary diff --git a/chapters/data/memory-security/drills/tasks/aslr/support/Makefile.aslr b/chapters/data/memory-security/drills/tasks/aslr/solution/src/Makefile.aslr similarity index 100% rename from chapters/data/memory-security/drills/tasks/aslr/support/Makefile.aslr rename to chapters/data/memory-security/drills/tasks/aslr/solution/src/Makefile.aslr diff --git a/chapters/data/memory-security/drills/tasks/aslr/support/aslr.c b/chapters/data/memory-security/drills/tasks/aslr/solution/src/aslr.c similarity index 100% rename from chapters/data/memory-security/drills/tasks/aslr/support/aslr.c rename to chapters/data/memory-security/drills/tasks/aslr/solution/src/aslr.c diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/Makefile b/chapters/data/memory-security/drills/tasks/aslr/solution/tests/Makefile similarity index 82% rename from chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/Makefile rename to chapters/data/memory-security/drills/tasks/aslr/solution/tests/Makefile index 8a060a7ecb..96252fe070 100644 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/Makefile +++ b/chapters/data/memory-security/drills/tasks/aslr/solution/tests/Makefile @@ -1,6 +1,6 @@ SRC_PATH ?= ../src -FULL_SRC_PATH = "$(realpath $(SRC_PATH))" -CPPFLAGS = -I. -I$(FULL_SRC_PATH) -I../utils +FULL_SRC_PATH = $(realpath $(SRC_PATH)) +CPPFLAGS = -I. -I$(realpath $(SRC_PATH)) -I../utils CFLAGS = -Wall -Wextra # Remove the line below to disable debugging support. CFLAGS += -g -O0 @@ -22,7 +22,7 @@ check: $(SHELLCODES) make -C $(FULL_SRC_PATH) clean make clean make -i SRC_PATH=$(FULL_SRC_PATH) - ./run_all_tests.sh + sudo bash ./run_all_tests.sh lint: -cd .. && checkpatch.pl -f src/*.c diff --git a/chapters/data/memory-security/drills/tasks/aslr/solution/tests/graded_test.inc.sh b/chapters/data/memory-security/drills/tasks/aslr/solution/tests/graded_test.inc.sh new file mode 100644 index 0000000000..162a3f2f4c --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/aslr/solution/tests/graded_test.inc.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause + +# +# Print test result. Printed message should fit in 72 characters. +# +# Print format is: +# +# description ...................... passed ... NNN +# description ...................... failed ... NNN +# 32 chars 24 chars 6 3 3 +# + +print_test() +{ + func="$1" + result="$2" + points="$3" + + if test "$points" -gt 999; then + points=999 + fi + + printf "%-32s " "${func:0:31}" + printf "........................" + if test "$result" -eq 0; then + printf " passed ... %3d\n" "$points" + else + printf " failed ... 0\n" + fi +} + +run_test() +{ + func="$1" + points="$2" + # Run in subshell. + (eval "$func") + print_test "$func" "$?" "$points" +} diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/run_all_tests.sh b/chapters/data/memory-security/drills/tasks/aslr/solution/tests/run_all_tests.sh similarity index 73% rename from chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/run_all_tests.sh rename to chapters/data/memory-security/drills/tasks/aslr/solution/tests/run_all_tests.sh index 23f26ec56e..e609766333 100755 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/run_all_tests.sh +++ b/chapters/data/memory-security/drills/tasks/aslr/solution/tests/run_all_tests.sh @@ -1,19 +1,17 @@ -#!/bin/bash # SPDX-License-Identifier: BSD-3-Clause +#!/bin/bash if test -z "$SRC_PATH"; then - SRC_PATH=../src + SRC_PATH=../src/ fi export SRC_PATH - +echo "" ( -./test_helloworld.sh -./test_getpid.sh -./test_openfile.sh -./test_brk.sh + bash test.sh ) | tee results.txt - +echo "" +echo "========================================================================" total=$(grep '\( passed \| failed \)' results.txt | rev | cut -d ' ' -f 1 | rev | paste -s -d'+' | bc) echo "" echo -n "Total: " diff --git a/chapters/data/memory-security/drills/tasks/aslr/solution/tests/test.sh b/chapters/data/memory-security/drills/tasks/aslr/solution/tests/test.sh new file mode 100644 index 0000000000..aad2f019b7 --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/aslr/solution/tests/test.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause + +source graded_test.inc.sh + +binary=../src/aslr + +if test -z "$SRC_PATH"; then + SRC_PATH=./../src +fi + +test_aslr() +{ + start_address=$(nm "$binary" | awk '/_start/ {print $1}' | head -n 1) + start_address_decimal=$((0x$start_address)) + if ((start_address_decimal < 0x400000)); then + exit 1 + fi + exit 0 +} + +run_test test_aslr 100 diff --git a/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/.gitignore b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/.gitignore new file mode 100644 index 0000000000..54811d5f0f --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/.gitignore @@ -0,0 +1 @@ +support diff --git a/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/Makefile b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/Makefile new file mode 100644 index 0000000000..35ad62412c --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/Makefile @@ -0,0 +1,10 @@ +PYTHON = python3 +SCRIPT = generate_skels.py + +skels: + mkdir -p support/src + $(PYTHON) $(SCRIPT) --input ./solution/src --output ./support/src + $(PYTHON) $(SCRIPT) --input ./solution/tests --output ./support/tests + +clean: + rm -rf support/ diff --git a/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/README.md b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/README.md index dab1d9b1ff..84f68f7ac3 100644 --- a/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/README.md +++ b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/README.md @@ -1,9 +1,27 @@ # Bypassing the Stack Protector +Navigate to `chapters/data/memory-security/drills/tasks/bypassing-stack-protector` and run `make skels` to generate the `support/` folder. +Then navigate to `support/src`. + + Inspect the `chapters/data/memory-security/drills/tasks/bypassing-stack-protector/support/stack_protector.c` source file. Compile the program and examine the object code. Try to identify the canary value. -Using the `addr` variable, write 2 `scanf` instructions: one that overwrites the canary with the correct value and one that overwrites the return address with the address of function `pawned`. +Using the `addr` variable, write 2 instructions: one that indexes `addr` to overwrite the canary with the correct value and one that indexes `addr` to overwrite the return address with the address of function `pawned()`. In case of a successful exploit a video will be offered as reward. If you're having difficulties solving this exercise, go through [this](../../../reading/memory-security.md) reading material. + +## Checker + +To run the checker, go into the `tests` directory located in `src`, then type `make check`. +A successful output of the checker should look like this : + +```console +student@os:~/.../drills/tasks/aslr/support/src/tests make check +test_bypassing-stackprotector ........................ passed ... 100 + +======================================================================== + +Total: 100/100 +``` diff --git a/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/generate_skels.py b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/generate_skels.py new file mode 100644 index 0000000000..92ac3f0050 --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/generate_skels.py @@ -0,0 +1,152 @@ +#!/usr/bin/python3 -u +# SPDX-License-Identifier: BSD-3-Clause + +import sys +import argparse +import os.path +import re + + +def process_file(src, dst, pattern, replace, remove, replace_pairs, end_string=None): + if not pattern or not replace or not remove: + print( + f"ERROR: The script behaviour is not properly specified for {src}", + file=sys.stderr, + ) + sys.exit(1) + + fin = open(src, "r") + os.makedirs(os.path.dirname(dst), exist_ok=True) + fout = open(dst, "w") + remove_lines = 0 + skip_lines = 0 + uncomment_lines = 0 + end_found = True + + for l in fin.readlines(): + # Skip generation of file. + if "SKIP_GENERATE" in l: + fout.close() + os.remove(dst) + return + + if end_string and end_found == False: + fout.write(l) + if end_string in l: + end_found = True + continue + + if remove_lines > 0: + remove_lines -= 1 + continue + + if skip_lines > 0: + skip_lines -= 1 + m = re.search(pattern, l) + if m: + l = "%s%s\n" % (m.group(1), m.group(3)) + fout.write(l) + continue + + if uncomment_lines > 0: + uncomment_lines -= 1 + for fro, to in replace_pairs: + l = re.sub(fro, to, l) + fout.write(l) + continue + + m = re.search(pattern, l) + if m: + if m.group(2): + skip_lines = int(m.group(2)) + else: + skip_lines = 1 + + if end_string and end_string not in l: + end_found = False + + l = "%s%s\n" % (m.group(1), m.group(3)) + + m = re.search(replace, l) + if m: + if m.group(2): + uncomment_lines = int(m.group(2)) + else: + uncomment_lines = 1 + continue + + m = re.search(remove, l) + if m: + if m.group(2): + remove_lines = int(m.group(2)) + else: + remove_lines = 1 + continue + + fout.write(l) + + fout.close() + + +def main(): + parser = argparse.ArgumentParser( + description="Generate skeletons sources from reference solution sources" + ) + parser.add_argument( + "--input", help="input directory to process files", required=True + ) + parser.add_argument( + "--output", help="output directory to copy processed files", required=True + ) + args = parser.parse_args() + + for root, dirs, files in os.walk(args.input): + new_root = os.path.join(args.output, os.path.relpath(root, args.input)) + for d in dirs: + os.makedirs(os.path.join(new_root, d), exist_ok=True) + + for src in files: + if ( + re.match("Makefile.*$", src) + or re.match(r".*\.sh$", src) + or re.match(r".*\.[sS]$", src) + or re.match(r".*\.py$", src) + ): + pattern = r"(^\s*#\s*TODO)( [0-9]*)(:.*)" + replace = r"(^\s*#\s*REPLACE)( [0-9]*)" + remove = r"(^\s*#\s*REMOVE)( [0-9]*)" + replace_pairs = [("# ", "")] + end_string = None + elif re.match(r".*\.asm$", src): + pattern = r"(^\s*;\s*TODO)( [0-9]*)(:.*)" + replace = r"(^\s*;\s*REPLACE)( [0-9]*)" + remove = r"(^\s*;\s*REMOVE)( [0-9]*)" + replace_pairs = [("; ", "")] + end_string = None + elif ( + re.match(r".*\.[ch]$", src) + or re.match(r".*\.cpp$", src) + or re.match(r".*\.hpp$", src) + ): + pattern = r"(.*/\*\s*TODO)([ 0-9]*)(:.*)" + replace = r"(.*/\*\s*REPLACE)( [0-9]*)" + remove = r"(.*/\*\s*REMOVE)( [0-9]*)" + replace_pairs = [(r"/\* ", ""), (r" \*/", "")] + end_string = "*/" + elif re.match(r".*\.d$", src): + pattern = r"(.*//\s*TODO)([ 0-9]*)(:.*)" + replace = r"(.*//\s*REPLACE)( [0-9]*)" + remove = r"(.*//\s*REMOVE)( [0-9]*)" + replace_pairs = [(r"// ", "")] + end_string = None + else: + continue + + dst = os.path.join(new_root, src) + src = os.path.join(root, src) + print(dst) + process_file(src, dst, pattern, replace, remove, replace_pairs, end_string) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/src/.gitignore b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/src/.gitignore new file mode 100644 index 0000000000..761de0e03e --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/src/.gitignore @@ -0,0 +1 @@ +/stack_protector diff --git a/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/support/Makefile b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/src/Makefile similarity index 100% rename from chapters/data/memory-security/drills/tasks/bypassing-stack-protector/support/Makefile rename to chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/src/Makefile diff --git a/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/support/stack_protector.c b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/src/stack_protector.c similarity index 72% rename from chapters/data/memory-security/drills/tasks/bypassing-stack-protector/support/stack_protector.c rename to chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/src/stack_protector.c index fd7b7eb271..f93b49b25b 100644 --- a/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/support/stack_protector.c +++ b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/src/stack_protector.c @@ -19,16 +19,20 @@ void fun1(char *p) } printf("overwrite canary:\n"); - // TODO(Student): Add code that overwrites the canary + /* TODO 1: Add code that overwrites the canary. */ + addr[6] = 0; printf("overwrite return address:\n"); - // TODO(Student): Add code that overwrites the return address with the addess of pawned + /* TODO 2: Add code that overwrites the return address with the address of pawned. */ + addr[7] = &pawned; (void) p; } int main(void) { + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); char *p = (char *)0x4343434343434343; fun1(p); diff --git a/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/tests/Makefile b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/tests/Makefile new file mode 100644 index 0000000000..96252fe070 --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/tests/Makefile @@ -0,0 +1,34 @@ +SRC_PATH ?= ../src +FULL_SRC_PATH = $(realpath $(SRC_PATH)) +CPPFLAGS = -I. -I$(realpath $(SRC_PATH)) -I../utils +CFLAGS = -Wall -Wextra +# Remove the line below to disable debugging support. +CFLAGS += -g -O0 + +SRCS = $(wildcard *.asm) +SHELLCODES = $(patsubst %.asm,%,$(SRCS)) + +.PHONY: all src check lint clean + +all: $(SHELLCODES) src + +$(SHELLCODES): %:%.asm | src + nasm -o $@ $< + +src: + make -C $(FULL_SRC_PATH) + +check: $(SHELLCODES) + make -C $(FULL_SRC_PATH) clean + make clean + make -i SRC_PATH=$(FULL_SRC_PATH) + sudo bash ./run_all_tests.sh + +lint: + -cd .. && checkpatch.pl -f src/*.c + -cd .. && checkpatch.pl -f tests/*.sh + -cd .. && cpplint --recursive src/ + -cd .. && shellcheck tests/*.sh + +clean: + -rm -f *~ diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/graded_test.inc.sh b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/tests/graded_test.inc.sh similarity index 99% rename from chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/graded_test.inc.sh rename to chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/tests/graded_test.inc.sh index bce1f05bbe..8ff8cdb51f 100644 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/graded_test.inc.sh +++ b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/tests/graded_test.inc.sh @@ -34,7 +34,6 @@ run_test() { func="$1" points="$2" - # Run in subshell. (eval "$func") print_test "$func" "$?" "$points" diff --git a/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/tests/run_all_tests.sh b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/tests/run_all_tests.sh new file mode 100755 index 0000000000..9736b66658 --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/tests/run_all_tests.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause + +if test -z "$SRC_PATH"; then + SRC_PATH=../src/ +fi + +export SRC_PATH +echo "" +( + bash test.sh +) | tee results.txt +echo "" +echo "========================================================================" +total=$(grep '\( passed \| failed \)' results.txt | rev | cut -d ' ' -f 1 | rev | paste -s -d'+' | bc) +echo "" +echo -n "Total: " +echo -n " " +LC_ALL=C printf "%3d/100\n" "$total" + +rm results.txt diff --git a/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/tests/test.sh b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/tests/test.sh new file mode 100644 index 0000000000..164a08120f --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/bypassing-stack-protector/solution/tests/test.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause + +source graded_test.inc.sh + +binary=../src/stack_protector + +if test -z "$SRC_PATH"; then + SRC_PATH=./../src +fi + +test_bypassing-stackprotector() +{ + if echo $($binary) | grep "https://www.youtube.com/watch?v=JGWOCALy1LI&ab_channel=lou2u" > result; then + rm result + exit 0 + fi + + rm result + exit 1 +} + +run_test test_bypassing-stackprotector 100 diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/.gitignore b/chapters/data/memory-security/drills/tasks/exec-shellcode/.gitignore new file mode 100644 index 0000000000..54811d5f0f --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/exec-shellcode/.gitignore @@ -0,0 +1 @@ +support diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/Makefile b/chapters/data/memory-security/drills/tasks/exec-shellcode/Makefile new file mode 100644 index 0000000000..35ad62412c --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/exec-shellcode/Makefile @@ -0,0 +1,10 @@ +PYTHON = python3 +SCRIPT = generate_skels.py + +skels: + mkdir -p support/src + $(PYTHON) $(SCRIPT) --input ./solution/src --output ./support/src + $(PYTHON) $(SCRIPT) --input ./solution/tests --output ./support/tests + +clean: + rm -rf support/ diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/README.md b/chapters/data/memory-security/drills/tasks/exec-shellcode/README.md index 8c5c72ab5f..01da34895a 100644 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/README.md +++ b/chapters/data/memory-security/drills/tasks/exec-shellcode/README.md @@ -1,5 +1,8 @@ ## Shellcode Executor +Navigate to `chapters/data/memory-security/drills/tasks/exec-shellcode` and run `make skels` to generate the `support/` folder. +Then navigate to `support/src`. + Navigate to the `chapters/data/memory-security/drills/tasks/exec-shellcode/support/` directory. Your goal is to update the `src/exec-shellcode.s` source code file to be able to read and execute shellcodes from a given binary files. diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/generate_skels.py b/chapters/data/memory-security/drills/tasks/exec-shellcode/generate_skels.py new file mode 100644 index 0000000000..92ac3f0050 --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/exec-shellcode/generate_skels.py @@ -0,0 +1,152 @@ +#!/usr/bin/python3 -u +# SPDX-License-Identifier: BSD-3-Clause + +import sys +import argparse +import os.path +import re + + +def process_file(src, dst, pattern, replace, remove, replace_pairs, end_string=None): + if not pattern or not replace or not remove: + print( + f"ERROR: The script behaviour is not properly specified for {src}", + file=sys.stderr, + ) + sys.exit(1) + + fin = open(src, "r") + os.makedirs(os.path.dirname(dst), exist_ok=True) + fout = open(dst, "w") + remove_lines = 0 + skip_lines = 0 + uncomment_lines = 0 + end_found = True + + for l in fin.readlines(): + # Skip generation of file. + if "SKIP_GENERATE" in l: + fout.close() + os.remove(dst) + return + + if end_string and end_found == False: + fout.write(l) + if end_string in l: + end_found = True + continue + + if remove_lines > 0: + remove_lines -= 1 + continue + + if skip_lines > 0: + skip_lines -= 1 + m = re.search(pattern, l) + if m: + l = "%s%s\n" % (m.group(1), m.group(3)) + fout.write(l) + continue + + if uncomment_lines > 0: + uncomment_lines -= 1 + for fro, to in replace_pairs: + l = re.sub(fro, to, l) + fout.write(l) + continue + + m = re.search(pattern, l) + if m: + if m.group(2): + skip_lines = int(m.group(2)) + else: + skip_lines = 1 + + if end_string and end_string not in l: + end_found = False + + l = "%s%s\n" % (m.group(1), m.group(3)) + + m = re.search(replace, l) + if m: + if m.group(2): + uncomment_lines = int(m.group(2)) + else: + uncomment_lines = 1 + continue + + m = re.search(remove, l) + if m: + if m.group(2): + remove_lines = int(m.group(2)) + else: + remove_lines = 1 + continue + + fout.write(l) + + fout.close() + + +def main(): + parser = argparse.ArgumentParser( + description="Generate skeletons sources from reference solution sources" + ) + parser.add_argument( + "--input", help="input directory to process files", required=True + ) + parser.add_argument( + "--output", help="output directory to copy processed files", required=True + ) + args = parser.parse_args() + + for root, dirs, files in os.walk(args.input): + new_root = os.path.join(args.output, os.path.relpath(root, args.input)) + for d in dirs: + os.makedirs(os.path.join(new_root, d), exist_ok=True) + + for src in files: + if ( + re.match("Makefile.*$", src) + or re.match(r".*\.sh$", src) + or re.match(r".*\.[sS]$", src) + or re.match(r".*\.py$", src) + ): + pattern = r"(^\s*#\s*TODO)( [0-9]*)(:.*)" + replace = r"(^\s*#\s*REPLACE)( [0-9]*)" + remove = r"(^\s*#\s*REMOVE)( [0-9]*)" + replace_pairs = [("# ", "")] + end_string = None + elif re.match(r".*\.asm$", src): + pattern = r"(^\s*;\s*TODO)( [0-9]*)(:.*)" + replace = r"(^\s*;\s*REPLACE)( [0-9]*)" + remove = r"(^\s*;\s*REMOVE)( [0-9]*)" + replace_pairs = [("; ", "")] + end_string = None + elif ( + re.match(r".*\.[ch]$", src) + or re.match(r".*\.cpp$", src) + or re.match(r".*\.hpp$", src) + ): + pattern = r"(.*/\*\s*TODO)([ 0-9]*)(:.*)" + replace = r"(.*/\*\s*REPLACE)( [0-9]*)" + remove = r"(.*/\*\s*REMOVE)( [0-9]*)" + replace_pairs = [(r"/\* ", ""), (r" \*/", "")] + end_string = "*/" + elif re.match(r".*\.d$", src): + pattern = r"(.*//\s*TODO)([ 0-9]*)(:.*)" + replace = r"(.*//\s*REPLACE)( [0-9]*)" + remove = r"(.*//\s*REMOVE)( [0-9]*)" + replace_pairs = [(r"// ", "")] + end_string = None + else: + continue + + dst = os.path.join(new_root, src) + src = os.path.join(root, src) + print(dst) + process_file(src, dst, pattern, replace, remove, replace_pairs, end_string) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/src/.gitignore b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/src/.gitignore deleted file mode 100644 index 5b678bc248..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/src/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/exec_shellcode diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/src/Makefile b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/src/Makefile deleted file mode 100644 index 52e057a177..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/src/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -CFLAGS ?= -Wall -Wextra -CPPFLAGS ?= -I../utils - -.PHONY: all clean - -all: exec_shellcode - -exec_shellcode: exec_shellcode.o ../utils/log/log.o - -../utils/log/log.o: ../utils/log/log.c ../utils/log/log.h - -clean: - -rm -f exec_shellcode exec_shellcode - -rm -f *~ diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/src/exec_shellcode.c b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/src/exec_shellcode.c deleted file mode 100644 index b35d4284fc..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/src/exec_shellcode.c +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause - -#include -#include -#include -#include - -#include "utils.h" - -static void *shellcode_mapping; - -static void usage(const char * const argv0) -{ - fprintf(stderr, "Usage: %s shellcode_file\n", argv0); -} - -static void create_shellcode_mapping(void) -{ - /* TODO: Create mapping to fit the shellcode. */ -} - -static void read_shellcode(const char * const fname) -{ - /* TODO: Read content from file in shellcode. */ -} - -int main(int argc, char **argv) -{ - if (argc != 2) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - - create_shellcode_mapping(); - read_shellcode(argv[1]); - - ((void (*)(void)) shellcode_mapping)(); - - return 0; -} diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/.gitignore b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/.gitignore deleted file mode 100644 index 8c2194af9c..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/brk -/getpid -/helloworld -/openfile diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/brk.asm b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/brk.asm deleted file mode 100644 index 824430f8eb..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/brk.asm +++ /dev/null @@ -1,12 +0,0 @@ -BITS 64 - ; call brk(0) - ; rax <- 12 (__NR_brj) - ; rdi <- 0 - ; TODO 3: Make brk syscall. - - ; call exit_group(0) - ; rax <- 231 (__NR_exit_group) - ; rdi <- 0 (exit status) - mov rax, 231 - xor rdi, rdi - syscall diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/getpid.asm b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/getpid.asm deleted file mode 100644 index a1b19a1940..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/getpid.asm +++ /dev/null @@ -1,12 +0,0 @@ -BITS 64 - ; call getpid() - ; rax <- 39 (__NR_write) - mov rax, 39 - syscall - - ; call exit_group(0) - ; rax <- 231 (__NR_exit_group) - ; rdi <- 0 (exit status) - mov rax, 231 - xor rdi, rdi - syscall diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/helloworld.asm b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/helloworld.asm deleted file mode 100644 index 626f8f38c9..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/helloworld.asm +++ /dev/null @@ -1,25 +0,0 @@ -BITS 64 - ; use jmp / call trick to get string address in RCX - jmp hello -back: - ; call write(1, "Hello, World!\n", 14); - ; rax <- 1 (__NR_write) - ; rdi <- 1 (stdout fileno) - ; rsi <- "Hello, World!\n" - ; rdx <- 14 (string length) - mov rax, 1 - mov rdi, 1 - pop rsi - mov rdx, 14 - syscall - - ; call exit_group(0) - ; rax <- 231 (__NR_exit_group) - ; rdi <- 0 (exit status) - mov rax, 231 - xor rdi, rdi - syscall - -hello: - call back - db "Hello, World!", 10, 0 diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/openfile.asm b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/openfile.asm deleted file mode 100644 index a94813af89..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/openfile.asm +++ /dev/null @@ -1,25 +0,0 @@ -BITS 64 - ; use jmp / call trick to get filename address in RCX - jmp filename -back: - ; call open("uberfile", O_RDWR | O_TRUNC | O_CREAT, 0644) - ; rax <- 2 (__NR_open) - ; rdi <- "uberfile" - ; rsi <- 578 (O_RDWR | O_TRUNC | O_CREAT - 01102) - ; rdx <- 420 (0644) - mov rax, 2 - pop rdi - mov rsi, 578 - mov rdx, 420 - syscall - - ; call exit_group(0) - ; rax <- 231 (__NR_exit_group) - ; rdi <- 0 (exit status) - mov rax, 231 - xor rdi, rdi - syscall - -filename: - call back - db "uberfile", 0 diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/test_brk.sh b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/test_brk.sh deleted file mode 100755 index 20a70d1d6e..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/test_brk.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: BSD-3-Clause - -source graded_test.inc.sh - -shellcode=./brk - -if test -z "$SRC_PATH"; then - SRC_PATH=../src -fi - -test_brk() -{ - if test ! -f "$shellcode"; then - echo "No such file $shellcode" 1>&2 - exit 1 - fi - - objdump -D -M intel -b binary -m i386:x86-64 "$shellcode" > /dev/null 2>&1 - if test $? -ne 0; then - echo "Incorrect shellcode file" 1>&2 - exit 1 - fi - - timeout -k 1 3 "$SRC_PATH"/exec_shellcode "$shellcode" > /dev/null 2>&1 - if test $? -ne 0; then - echo "Program runs unsuccessfully" 1>&2 - exit 1 - fi - - timeout -k 1 3 strace "$SRC_PATH"/exec_shellcode "$shellcode" 2>&1 \ - | grep -A 1 close | tail -2 | grep 'brk(NULL)[ \t]\+= 0x' > /dev/null 2>&1 - if test $? -ne 0; then - echo "brk not called correctly" 1>&2 - exit 1 - fi - exit 0 -} - -run_test test_brk 25 diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/test_getpid.sh b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/test_getpid.sh deleted file mode 100755 index f651b020b8..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/test_getpid.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: BSD-3-Clause - -source graded_test.inc.sh - -shellcode=./getpid - -if test -z "$SRC_PATH"; then - SRC_PATH=../src -fi - -test_getpid() -{ - if test ! -f "$shellcode"; then - echo "No such file $shellcode" 1>&2 - exit 1 - fi - - objdump -D -M intel -b binary -m i386:x86-64 "$shellcode" > /dev/null 2>&1 - if test $? -ne 0; then - echo "Incorrect shellcode file" 1>&2 - exit 1 - fi - - timeout -k 1 3 "$SRC_PATH"/exec_shellcode "$shellcode" > /dev/null 2>&1 - if test $? -ne 0; then - echo "Program runs unsuccessfully" 1>&2 - exit 1 - fi - - timeout -k 1 3 strace "$SRC_PATH"/exec_shellcode "$shellcode" 2>&1 \ - | grep -A 1 close | tail -2 | grep 'getpid()[ \t]\+= [0-9]\+' > /dev/null 2>&1 - if test $? -ne 0; then - echo "getpid() not called (successfully)" 1>&2 - exit 1 - fi - exit 0 -} - -run_test test_getpid 25 diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/test_helloworld.sh b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/test_helloworld.sh deleted file mode 100755 index 0a0b3d7276..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/test_helloworld.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: BSD-3-Clause - -source graded_test.inc.sh - -shellcode=./helloworld - -if test -z "$SRC_PATH"; then - SRC_PATH=../src -fi - -test_helloworld() -{ - if test ! -f "$shellcode"; then - echo "No such file $shellcode" 1>&2 - exit 1 - fi - - objdump -D -M intel -b binary -m i386:x86-64 "$shellcode" > /dev/null 2>&1 - if test $? -ne 0; then - echo "Incorrect shellcode file" 1>&2 - exit 1 - fi - - timeout -k 1 3 "$SRC_PATH"/exec_shellcode "$shellcode" > /dev/null 2>&1 - if test $? -ne 0; then - echo "Program runs unsuccessfully" 1>&2 - exit 1 - fi - - timeout -k 1 3 "$SRC_PATH"/exec_shellcode "$shellcode" | grep 'Hello, World!' > /dev/null 2>&1 - if test $? -ne 0; then - echo "'Hello, World!' not printed" 1>&2 - exit 1 - fi - exit 0 -} - -run_test test_helloworld 25 diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/test_openfile.sh b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/test_openfile.sh deleted file mode 100755 index 05de282c65..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/tests/test_openfile.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: BSD-3-Clause - -source graded_test.inc.sh - -shellcode=./openfile - -if test -z "$SRC_PATH"; then - SRC_PATH=../src -fi - -test_openfile() -{ - if test ! -f "$shellcode"; then - echo "No such file $shellcode" 1>&2 - exit 1 - fi - - objdump -D -M intel -b binary -m i386:x86-64 "$shellcode" > /dev/null 2>&1 - if test $? -ne 0; then - echo "Incorrect shellcode file" 1>&2 - exit 1 - fi - - timeout -k 1 3 "$SRC_PATH"/exec_shellcode "$shellcode" > /dev/null 2>&1 - if test $? -ne 0; then - echo "Program runs unsuccessfully" 1>&2 - exit 1 - fi - - # shellcheck disable=2065 - test -f "uberfile" > /dev/null 2>&1 - if test $? -ne 0; then - echo "File not created" 1>&2 - exit 1 - fi - - test "$(stat --format="%s" "uberfile")" -eq 0 - if test $? -ne 0; then - echo "File is not truncated" 1>&2 - exit 1 - fi - - test "$(stat --format="%a" "uberfile")" = "644" - if test $? -ne 0; then - echo "File permissions not correctly set" 1>&2 - exit 1 - fi - - exit 0 -} - -run_test test_openfile 25 diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/log/CPPLINT.cfg b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/log/CPPLINT.cfg deleted file mode 100644 index 5aa9cb376c..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/log/CPPLINT.cfg +++ /dev/null @@ -1 +0,0 @@ -exclude_files=log\.c diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/log/log.c b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/log/log.c deleted file mode 100644 index ac65f4ed33..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/log/log.c +++ /dev/null @@ -1,197 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause - -/* - * Copyright (c) 2020 rxi - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -/* Github link: https://github.com/rxi/log.c */ - -#include "log.h" - -#define MAX_CALLBACKS 32 - -typedef struct { - log_LogFn fn; - void *udata; - int level; -} Callback; - -static struct -{ - void *udata; - log_LockFn lock; - int level; - bool quiet; - Callback callbacks[MAX_CALLBACKS]; -} L; - -static const char * const level_strings[] = { "TRACE", "DEBUG", "INFO", - "WARN", "ERROR", "FATAL" }; - -#ifdef LOG_USE_COLOR -static const char * const level_colors[] = { "\x1b[94m", "\x1b[36m", "\x1b[32m", - "\x1b[33m", "\x1b[31m", "\x1b[35m" }; -#endif - -static void -stdout_callback(log_Event *ev) -{ - char buf[16]; - - buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0'; -#ifdef LOG_USE_COLOR - fprintf(ev->udata, - "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", - buf, - level_colors[ev->level], - level_strings[ev->level], - ev->file, - ev->line); -#else - fprintf(ev->udata, - "%s %-5s %s:%d: ", - buf, - level_strings[ev->level], - ev->file, - ev->line); -#endif - vfprintf(ev->udata, ev->fmt, ev->ap); - fprintf(ev->udata, "\n"); - fflush(ev->udata); -} - -static void -file_callback(log_Event *ev) -{ - char buf[64]; - - buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0'; - fprintf(ev->udata, - "%s %-5s %s:%d: ", - buf, - level_strings[ev->level], - ev->file, - ev->line); - vfprintf(ev->udata, ev->fmt, ev->ap); - fprintf(ev->udata, "\n"); - fflush(ev->udata); -} - -static void -lock(void) -{ - if (L.lock) - L.lock(true, L.udata); -} - -static void -unlock(void) -{ - if (L.lock) - L.lock(false, L.udata); -} - -const char* -log_level_string(int level) -{ - return level_strings[level]; -} - -void -log_set_lock(log_LockFn fn, void *udata) -{ - L.lock = fn; - L.udata = udata; -} - -void -log_set_level(int level) -{ - L.level = level; -} - -void -log_set_quiet(bool enable) -{ - L.quiet = enable; -} - -int -log_add_callback(log_LogFn fn, void *udata, int level) -{ - for (int i = 0; i < MAX_CALLBACKS; i++) { - if (!L.callbacks[i].fn) { - L.callbacks[i] = (Callback) { fn, udata, level }; - return 0; - } - } - return -1; -} - -int -log_add_fp(FILE *fp, int level) -{ - return log_add_callback(file_callback, fp, level); -} - -static void -init_event(log_Event *ev, void *udata) -{ - if (!ev->time) { - time_t t = time(NULL); - - ev->time = localtime(&t); - } - ev->udata = udata; -} - -void -log_log(int level, const char *file, int line, const char *fmt, ...) -{ - log_Event ev = { - .fmt = fmt, - .file = file, - .line = line, - .level = level, - }; - - lock(); - - if (!L.quiet && level >= L.level) { - init_event(&ev, stderr); - va_start(ev.ap, fmt); - stdout_callback(&ev); - va_end(ev.ap); - } - - for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) { - Callback *cb = &L.callbacks[i]; - - if (level >= cb->level) { - init_event(&ev, cb->udata); - va_start(ev.ap, fmt); - cb->fn(&ev); - va_end(ev.ap); - } - } - - unlock(); -} diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/log/log.h b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/log/log.h deleted file mode 100644 index 7acb55aab6..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/log/log.h +++ /dev/null @@ -1,69 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause */ - -/** - * Copyright (c) 2020 rxi - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the MIT license. See `log.c` for details. - */ - -/* Github link: https://github.com/rxi/log.c */ - -#ifndef LOG_H -#define LOG_H - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -#define LOG_VERSION "0.1.0" - -typedef struct { - va_list ap; - const char *fmt; - const char *file; - struct tm *time; - void *udata; - int line; - int level; -} log_Event; - -typedef void (*log_LogFn)(log_Event *ev); -typedef void (*log_LockFn)(bool lock, void *udata); - -enum { - LOG_TRACE, - LOG_DEBUG, - LOG_INFO, - LOG_WARN, - LOG_ERROR, - LOG_FATAL -}; - -#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) -#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) -#define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) -#define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) -#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) -#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) - -const char *log_level_string(int level); -void log_set_lock(log_LockFn fn, void *udata); -void log_set_level(int level); -void log_set_quiet(bool enable); -int log_add_callback(log_LogFn fn, void *udata, int level); -int log_add_fp(FILE *fp, int level); - -void log_log(int level, const char *file, int line, const char *fmt, ...); - -#ifdef __cplusplus -} -#endif - -#endif /* LOG_H */ diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/sock/sock_util.c b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/sock/sock_util.c deleted file mode 100644 index 78581b2239..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/sock/sock_util.c +++ /dev/null @@ -1,114 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause - -/* - * Useful socket functions - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "utils/utils.h" -#include "utils/log/log.h" -#include "utils/sock/sock_util.h" - -/* - * Connect to a TCP server identified by name (DNS name or dotted decimal - * string) and port. - */ - -int tcp_connect_to_server(const char *name, unsigned short port) -{ - struct hostent *hent; - struct sockaddr_in server_addr; - int s; - int rc; - - hent = gethostbyname(name); - DIE(hent == NULL, "gethostbyname"); - - s = socket(PF_INET, SOCK_STREAM, 0); - DIE(s < 0, "socket"); - - memset(&server_addr, 0, sizeof(server_addr)); - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(port); - memcpy(&server_addr.sin_addr.s_addr, hent->h_addr, - sizeof(server_addr.sin_addr.s_addr)); - - rc = connect(s, (struct sockaddr *) &server_addr, sizeof(server_addr)); - DIE(rc < 0, "connect"); - - return s; -} - -int tcp_close_connection(int sockfd) -{ - int rc; - - rc = shutdown(sockfd, SHUT_RDWR); - DIE(rc < 0, "shutdown"); - - return close(sockfd); -} - -/* - * Create a server socket. - */ - -int tcp_create_listener(unsigned short port, int backlog) -{ - struct sockaddr_in address; - int listenfd; - int sock_opt; - int rc; - - listenfd = socket(PF_INET, SOCK_STREAM, 0); - DIE(listenfd < 0, "socket"); - - sock_opt = 1; - rc = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, - &sock_opt, sizeof(int)); - DIE(rc < 0, "setsockopt"); - - memset(&address, 0, sizeof(address)); - address.sin_family = AF_INET; - address.sin_port = htons(port); - address.sin_addr.s_addr = INADDR_ANY; - - rc = bind(listenfd, (SSA *) &address, sizeof(address)); - DIE(rc < 0, "bind"); - - rc = listen(listenfd, backlog); - DIE(rc < 0, "listen"); - - return listenfd; -} - -/* - * Use getpeername(2) to extract remote peer address. Fill buffer with - * address format IP_address:port (e.g. 192.168.0.1:22). - */ - -int get_peer_address(int sockfd, char *buf, size_t len) -{ - struct sockaddr_in addr; - socklen_t addrlen = sizeof(struct sockaddr_in); - - if (getpeername(sockfd, (SSA *) &addr, &addrlen) < 0) - return -1; - - snprintf(buf, len, "%s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); - - return 0; -} diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/sock/sock_util.h b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/sock/sock_util.h deleted file mode 100644 index 906976dc94..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/sock/sock_util.h +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause */ - -/* - * Useful socket macros and structures - */ - -#ifndef SOCK_UTIL_H_ -#define SOCK_UTIL_H_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -/* default backlog for listen(2) system call */ -#define DEFAULT_LISTEN_BACKLOG 5 - -/* "shortcut" for struct sockaddr structure */ -#define SSA struct sockaddr - - -int tcp_connect_to_server(const char *name, unsigned short port); -int tcp_close_connection(int s); -int tcp_create_listener(unsigned short port, int backlog); -int get_peer_address(int sockfd, char *buf, size_t len); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/utils.h b/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/utils.h deleted file mode 100644 index efdf6b59dd..0000000000 --- a/chapters/data/memory-security/drills/tasks/exec-shellcode/support/utils/utils.h +++ /dev/null @@ -1,36 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause */ - -#ifndef UTILS_H_ -#define UTILS_H_ 1 - -#include -#include -#include -#include -#include "log/log.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ERR(assertion, call_description) \ - do { \ - if (assertion) \ - log_error("%s: %s", \ - call_description, strerror(errno)); \ - } while (0) - -#define DIE(assertion, call_description) \ - do { \ - if (assertion) { \ - log_fatal("%s: %s", \ - call_description, strerror(errno)); \ - exit(EXIT_FAILURE); \ - } \ - } while (0) - -#ifdef __cplusplus -} -#endif - -#endif /* UTILS_H_ */ diff --git a/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/.gitignore b/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/.gitignore new file mode 100644 index 0000000000..54811d5f0f --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/.gitignore @@ -0,0 +1 @@ +support diff --git a/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/Makefile b/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/Makefile new file mode 100644 index 0000000000..35ad62412c --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/Makefile @@ -0,0 +1,10 @@ +PYTHON = python3 +SCRIPT = generate_skels.py + +skels: + mkdir -p support/src + $(PYTHON) $(SCRIPT) --input ./solution/src --output ./support/src + $(PYTHON) $(SCRIPT) --input ./solution/tests --output ./support/tests + +clean: + rm -rf support/ diff --git a/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/README.md b/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/README.md index 8d9f3b98f6..06e90cd746 100644 --- a/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/README.md +++ b/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/README.md @@ -1,5 +1,8 @@ # Wild Pointer Arithmetic Info Leak +Navigate to `chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak` and run `make skels` to generate the `support/` folder. +Then navigate to `support/src`. + Navigate to the `chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/support/` directory. Open and analyze the `buff_leak.c` file. diff --git a/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/generate_skels.py b/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/generate_skels.py new file mode 100644 index 0000000000..92ac3f0050 --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/generate_skels.py @@ -0,0 +1,152 @@ +#!/usr/bin/python3 -u +# SPDX-License-Identifier: BSD-3-Clause + +import sys +import argparse +import os.path +import re + + +def process_file(src, dst, pattern, replace, remove, replace_pairs, end_string=None): + if not pattern or not replace or not remove: + print( + f"ERROR: The script behaviour is not properly specified for {src}", + file=sys.stderr, + ) + sys.exit(1) + + fin = open(src, "r") + os.makedirs(os.path.dirname(dst), exist_ok=True) + fout = open(dst, "w") + remove_lines = 0 + skip_lines = 0 + uncomment_lines = 0 + end_found = True + + for l in fin.readlines(): + # Skip generation of file. + if "SKIP_GENERATE" in l: + fout.close() + os.remove(dst) + return + + if end_string and end_found == False: + fout.write(l) + if end_string in l: + end_found = True + continue + + if remove_lines > 0: + remove_lines -= 1 + continue + + if skip_lines > 0: + skip_lines -= 1 + m = re.search(pattern, l) + if m: + l = "%s%s\n" % (m.group(1), m.group(3)) + fout.write(l) + continue + + if uncomment_lines > 0: + uncomment_lines -= 1 + for fro, to in replace_pairs: + l = re.sub(fro, to, l) + fout.write(l) + continue + + m = re.search(pattern, l) + if m: + if m.group(2): + skip_lines = int(m.group(2)) + else: + skip_lines = 1 + + if end_string and end_string not in l: + end_found = False + + l = "%s%s\n" % (m.group(1), m.group(3)) + + m = re.search(replace, l) + if m: + if m.group(2): + uncomment_lines = int(m.group(2)) + else: + uncomment_lines = 1 + continue + + m = re.search(remove, l) + if m: + if m.group(2): + remove_lines = int(m.group(2)) + else: + remove_lines = 1 + continue + + fout.write(l) + + fout.close() + + +def main(): + parser = argparse.ArgumentParser( + description="Generate skeletons sources from reference solution sources" + ) + parser.add_argument( + "--input", help="input directory to process files", required=True + ) + parser.add_argument( + "--output", help="output directory to copy processed files", required=True + ) + args = parser.parse_args() + + for root, dirs, files in os.walk(args.input): + new_root = os.path.join(args.output, os.path.relpath(root, args.input)) + for d in dirs: + os.makedirs(os.path.join(new_root, d), exist_ok=True) + + for src in files: + if ( + re.match("Makefile.*$", src) + or re.match(r".*\.sh$", src) + or re.match(r".*\.[sS]$", src) + or re.match(r".*\.py$", src) + ): + pattern = r"(^\s*#\s*TODO)( [0-9]*)(:.*)" + replace = r"(^\s*#\s*REPLACE)( [0-9]*)" + remove = r"(^\s*#\s*REMOVE)( [0-9]*)" + replace_pairs = [("# ", "")] + end_string = None + elif re.match(r".*\.asm$", src): + pattern = r"(^\s*;\s*TODO)( [0-9]*)(:.*)" + replace = r"(^\s*;\s*REPLACE)( [0-9]*)" + remove = r"(^\s*;\s*REMOVE)( [0-9]*)" + replace_pairs = [("; ", "")] + end_string = None + elif ( + re.match(r".*\.[ch]$", src) + or re.match(r".*\.cpp$", src) + or re.match(r".*\.hpp$", src) + ): + pattern = r"(.*/\*\s*TODO)([ 0-9]*)(:.*)" + replace = r"(.*/\*\s*REPLACE)( [0-9]*)" + remove = r"(.*/\*\s*REMOVE)( [0-9]*)" + replace_pairs = [(r"/\* ", ""), (r" \*/", "")] + end_string = "*/" + elif re.match(r".*\.d$", src): + pattern = r"(.*//\s*TODO)([ 0-9]*)(:.*)" + replace = r"(.*//\s*REPLACE)( [0-9]*)" + remove = r"(.*//\s*REMOVE)( [0-9]*)" + replace_pairs = [(r"// ", "")] + end_string = None + else: + continue + + dst = os.path.join(new_root, src) + src = os.path.join(root, src) + print(dst) + process_file(src, dst, pattern, replace, remove, replace_pairs, end_string) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/solution/src/.gitignore b/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/solution/src/.gitignore new file mode 100644 index 0000000000..4f43498f49 --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/solution/src/.gitignore @@ -0,0 +1 @@ +/buff_leak diff --git a/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/support/Makefile b/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/solution/src/Makefile similarity index 100% rename from chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/support/Makefile rename to chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/solution/src/Makefile diff --git a/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/support/buff_leak.c b/chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/solution/src/buff_leak.c similarity index 100% rename from chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/support/buff_leak.c rename to chapters/data/memory-security/drills/tasks/pointer-arithmetic-leak/solution/src/buff_leak.c diff --git a/chapters/data/memory-security/drills/tasks/stack-protector/.gitignore b/chapters/data/memory-security/drills/tasks/stack-protector/.gitignore new file mode 100644 index 0000000000..54811d5f0f --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/stack-protector/.gitignore @@ -0,0 +1 @@ +support diff --git a/chapters/data/memory-security/drills/tasks/stack-protector/Makefile b/chapters/data/memory-security/drills/tasks/stack-protector/Makefile new file mode 100644 index 0000000000..35ad62412c --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/stack-protector/Makefile @@ -0,0 +1,10 @@ +PYTHON = python3 +SCRIPT = generate_skels.py + +skels: + mkdir -p support/src + $(PYTHON) $(SCRIPT) --input ./solution/src --output ./support/src + $(PYTHON) $(SCRIPT) --input ./solution/tests --output ./support/tests + +clean: + rm -rf support/ diff --git a/chapters/data/memory-security/drills/tasks/stack-protector/README.md b/chapters/data/memory-security/drills/tasks/stack-protector/README.md index d562233f45..1f85fee6a8 100644 --- a/chapters/data/memory-security/drills/tasks/stack-protector/README.md +++ b/chapters/data/memory-security/drills/tasks/stack-protector/README.md @@ -1,7 +1,24 @@ # Stack Protector +Navigate to `chapters/data/memory-security/drills/tasks/stack-protector` and run `make skels` to generate the `support/` folder. +Then navigate to `support/src`. + Comment the `-fno-stack-protector` switch from the `chapters/data/memory-security/drills/tasks/stack-protector/support/Makefile`, recompile and run the `bo_practice_write` executable. Examine the binary with `objdump` and identify the instructions that set and test the canary. Observe what happens when a buffer overflow occurs. If you're having difficulties solving this exercise, go through [this](../../../reading/memory-security.md) reading material. + +## Checker + +To run the checker, go into the `tests` directory located in `src`, then type `make check`. +A successful output of the checker should look like this : + +```console +student@os:~/.../drills/tasks/aslr/support/src/tests make check +test_stackprotector ........................ passed ... 100 + +======================================================================== + +Total: 100/100 +``` diff --git a/chapters/data/memory-security/drills/tasks/stack-protector/generate_skels.py b/chapters/data/memory-security/drills/tasks/stack-protector/generate_skels.py new file mode 100644 index 0000000000..0067849339 --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/stack-protector/generate_skels.py @@ -0,0 +1,159 @@ +#!/usr/bin/python3 -u +# SPDX-License-Identifier: BSD-3-Clause + +import sys +import argparse +import os.path +import re + + +def process_file(src, dst, pattern, replace, remove, replace_pairs, end_string=None): + if not pattern or not replace or not remove: + print( + f"ERROR: The script behaviour is not properly specified for {src}", + file=sys.stderr, + ) + sys.exit(1) + + fin = open(src, "r") + os.makedirs(os.path.dirname(dst), exist_ok=True) + fout = open(dst, "w") + + remove_lines = 0 + skip_lines = 0 + uncomment_lines = 0 + end_found = True + makefile_special_handling = "Makefile" in src + + for i, l in enumerate(fin.readlines()): + # Skip generation of file. + if "SKIP_GENERATE" in l: + fout.close() + os.remove(dst) + return + + if end_string and not end_found: + fout.write(l) + if end_string in l: + end_found = True + continue + + if remove_lines > 0: + remove_lines -= 1 + continue + + if skip_lines > 0: + skip_lines -= 1 + m = re.search(pattern, l) + if m: + l = "%s%s\n" % (m.group(1), m.group(3)) + fout.write(l) + continue + + if uncomment_lines > 0: + uncomment_lines -= 1 + for fro, to in replace_pairs: + l = re.sub(fro, to, l) + fout.write(l) + continue + + if makefile_special_handling and "TODO" in l and "Uncomment" in l: + fout.write(l) + next_line = fin.readline() + fout.write("# " + next_line) + continue + + m = re.search(pattern, l) + if m: + if m.group(2): + skip_lines = int(m.group(2)) + else: + skip_lines = 1 + + if end_string and end_string not in l: + end_found = False + + l = "%s%s\n" % (m.group(1), m.group(3)) + + m = re.search(replace, l) + if m: + if m.group(2): + uncomment_lines = int(m.group(2)) + else: + uncomment_lines = 1 + continue + + m = re.search(remove, l) + if m: + if m.group(2): + remove_lines = int(m.group(2)) + else: + remove_lines = 1 + continue + + fout.write(l) + + fout.close() + +def main(): + parser = argparse.ArgumentParser( + description="Generate skeletons sources from reference solution sources" + ) + parser.add_argument( + "--input", help="input directory to process files", required=True + ) + parser.add_argument( + "--output", help="output directory to copy processed files", required=True + ) + args = parser.parse_args() + + for root, dirs, files in os.walk(args.input): + new_root = os.path.join(args.output, os.path.relpath(root, args.input)) + for d in dirs: + os.makedirs(os.path.join(new_root, d), exist_ok=True) + + for src in files: + if ( + re.match("Makefile.*$", src) + or re.match(r".*\.sh$", src) + or re.match(r".*\.[sS]$", src) + or re.match(r".*\.py$", src) + ): + pattern = r"(^\s*#\s*TODO)( [0-9]*)(:.*)" + replace = r"(^\s*#\s*REPLACE)( [0-9]*)" + remove = r"(^\s*#\s*REMOVE)( [0-9]*)" + replace_pairs = [("# ", "")] + end_string = None + elif re.match(r".*\.asm$", src): + pattern = r"(^\s*;\s*TODO)( [0-9]*)(:.*)" + replace = r"(^\s*;\s*REPLACE)( [0-9]*)" + remove = r"(^\s*;\s*REMOVE)( [0-9]*)" + replace_pairs = [("; ", "")] + end_string = None + elif ( + re.match(r".*\.[ch]$", src) + or re.match(r".*\.cpp$", src) + or re.match(r".*\.hpp$", src) + ): + pattern = r"(.*/\*\s*TODO)([ 0-9]*)(:.*)" + replace = r"(.*/\*\s*REPLACE)( [0-9]*)" + remove = r"(.*/\*\s*REMOVE)( [0-9]*)" + replace_pairs = [(r"/\* ", ""), (r" \*/", "")] + end_string = "*/" + elif re.match(r".*\.d$", src): + pattern = r"(.*//\s*TODO)([ 0-9]*)(:.*)" + replace = r"(.*//\s*REPLACE)( [0-9]*)" + remove = r"(.*//\s*REMOVE)( [0-9]*)" + replace_pairs = [(r"// ", "")] + end_string = None + else: + continue + + dst = os.path.join(new_root, src) + src = os.path.join(root, src) + print(dst) + process_file(src, dst, pattern, replace, remove, replace_pairs, end_string) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/chapters/data/memory-security/drills/tasks/stack-protector/solution/src/.gitignore b/chapters/data/memory-security/drills/tasks/stack-protector/solution/src/.gitignore new file mode 100644 index 0000000000..b9bf9f88c1 --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/stack-protector/solution/src/.gitignore @@ -0,0 +1 @@ +/bo_write_practice diff --git a/chapters/data/memory-security/drills/tasks/stack-protector/support/Makefile b/chapters/data/memory-security/drills/tasks/stack-protector/solution/src/Makefile similarity index 85% rename from chapters/data/memory-security/drills/tasks/stack-protector/support/Makefile rename to chapters/data/memory-security/drills/tasks/stack-protector/solution/src/Makefile index f3cf9d66fb..e5d61a8b17 100644 --- a/chapters/data/memory-security/drills/tasks/stack-protector/support/Makefile +++ b/chapters/data/memory-security/drills/tasks/stack-protector/solution/src/Makefile @@ -1,7 +1,10 @@ CC = gcc SRCS = bo_write_practice.c OBJS = $(SRCS:.c=.o) + +# TODO: Comment the -fno-stack-protector line CFLAGS += -fno-stack-protector -fno-PIC + LDFLAGS += -no-pie TARGET = bo_write_practice diff --git a/chapters/data/memory-security/drills/tasks/stack-protector/support/bo_write_practice.c b/chapters/data/memory-security/drills/tasks/stack-protector/solution/src/bo_write_practice.c similarity index 100% rename from chapters/data/memory-security/drills/tasks/stack-protector/support/bo_write_practice.c rename to chapters/data/memory-security/drills/tasks/stack-protector/solution/src/bo_write_practice.c diff --git a/chapters/data/memory-security/drills/tasks/stack-protector/solution/tests/Makefile b/chapters/data/memory-security/drills/tasks/stack-protector/solution/tests/Makefile new file mode 100644 index 0000000000..96252fe070 --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/stack-protector/solution/tests/Makefile @@ -0,0 +1,34 @@ +SRC_PATH ?= ../src +FULL_SRC_PATH = $(realpath $(SRC_PATH)) +CPPFLAGS = -I. -I$(realpath $(SRC_PATH)) -I../utils +CFLAGS = -Wall -Wextra +# Remove the line below to disable debugging support. +CFLAGS += -g -O0 + +SRCS = $(wildcard *.asm) +SHELLCODES = $(patsubst %.asm,%,$(SRCS)) + +.PHONY: all src check lint clean + +all: $(SHELLCODES) src + +$(SHELLCODES): %:%.asm | src + nasm -o $@ $< + +src: + make -C $(FULL_SRC_PATH) + +check: $(SHELLCODES) + make -C $(FULL_SRC_PATH) clean + make clean + make -i SRC_PATH=$(FULL_SRC_PATH) + sudo bash ./run_all_tests.sh + +lint: + -cd .. && checkpatch.pl -f src/*.c + -cd .. && checkpatch.pl -f tests/*.sh + -cd .. && cpplint --recursive src/ + -cd .. && shellcheck tests/*.sh + +clean: + -rm -f *~ diff --git a/chapters/data/memory-security/drills/tasks/stack-protector/solution/tests/graded_test.inc.sh b/chapters/data/memory-security/drills/tasks/stack-protector/solution/tests/graded_test.inc.sh new file mode 100644 index 0000000000..8ff8cdb51f --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/stack-protector/solution/tests/graded_test.inc.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause + +# +# Print test result. Printed message should fit in 72 characters. +# +# Print format is: +# +# description ...................... passed ... NNN +# description ...................... failed ... NNN +# 32 chars 24 chars 6 3 3 +# + +print_test() +{ + func="$1" + result="$2" + points="$3" + + if test "$points" -gt 999; then + points=999 + fi + + printf "%-32s " "${func:0:31}" + printf "........................" + if test "$result" -eq 0; then + printf " passed ... %3d\n" "$points" + else + printf " failed ... 0\n" + fi +} + +run_test() +{ + func="$1" + points="$2" + # Run in subshell. + (eval "$func") + print_test "$func" "$?" "$points" +} diff --git a/chapters/data/memory-security/drills/tasks/stack-protector/solution/tests/run_all_tests.sh b/chapters/data/memory-security/drills/tasks/stack-protector/solution/tests/run_all_tests.sh new file mode 100755 index 0000000000..9736b66658 --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/stack-protector/solution/tests/run_all_tests.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause + +if test -z "$SRC_PATH"; then + SRC_PATH=../src/ +fi + +export SRC_PATH +echo "" +( + bash test.sh +) | tee results.txt +echo "" +echo "========================================================================" +total=$(grep '\( passed \| failed \)' results.txt | rev | cut -d ' ' -f 1 | rev | paste -s -d'+' | bc) +echo "" +echo -n "Total: " +echo -n " " +LC_ALL=C printf "%3d/100\n" "$total" + +rm results.txt diff --git a/chapters/data/memory-security/drills/tasks/stack-protector/solution/tests/test.sh b/chapters/data/memory-security/drills/tasks/stack-protector/solution/tests/test.sh new file mode 100644 index 0000000000..66dc319d23 --- /dev/null +++ b/chapters/data/memory-security/drills/tasks/stack-protector/solution/tests/test.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause + +source graded_test.inc.sh + +binary=../src/bo_write_practice + +if test -z "$SRC_PATH"; then + SRC_PATH=./../src +fi + +test_stackprotector() +{ + if nm "$binary" | grep -q "U __stack_chk_fail"; then + exit 0 + else + exit 1 + fi +} + +run_test test_stackprotector 100