Skip to content

Commit

Permalink
chapters/data: Add checkers for memory-security tasks
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
teodor994 committed Dec 14, 2024
1 parent dc21b9b commit c91171d
Show file tree
Hide file tree
Showing 63 changed files with 1,170 additions and 771 deletions.
1 change: 1 addition & 0 deletions chapters/data/memory-security/drills/tasks/aslr/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
support
10 changes: 10 additions & 0 deletions chapters/data/memory-security/drills/tasks/aslr/Makefile
Original file line number Diff line number Diff line change
@@ -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/
18 changes: 18 additions & 0 deletions chapters/data/memory-security/drills/tasks/aslr/README.md
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
```
159 changes: 159 additions & 0 deletions chapters/data/memory-security/drills/tasks/aslr/generate_skels.py
Original file line number Diff line number Diff line change
@@ -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())
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/aslr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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"

Check failure on line 36 in chapters/data/memory-security/drills/tasks/aslr/solution/tests/graded_test.inc.sh

View workflow job for this annotation

GitHub Actions / Checkpatch

ERROR:TRAILING_WHITESPACE: trailing whitespace
# Run in subshell.
(eval "$func")
print_test "$func" "$?" "$points"
}
Original file line number Diff line number Diff line change
@@ -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: "
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
support
Original file line number Diff line number Diff line change
@@ -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/
Original file line number Diff line number Diff line change
@@ -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
```
Loading

0 comments on commit c91171d

Please sign in to comment.