0x00 unexploitable
最近在刷pwnable.tw(類似pwnable.kr,不過是臺灣的)的題,看到了一個unexploitable的題目。根據題目描述:
The original challenge is on pwnable.kr and it is solvable. This time we fix the vulnerability and now we promise that the service is unexploitable.
下載下來後丟到ida看到確實沒什麼變化,除了pwnable.kr那個題中最重要的一點syscall
沒有給。
.text:0000000000400544 ; int __cdecl main(int argc, const char **argv, const char **envp) .text:0000000000400544 public main .text:0000000000400544 main proc near ; DATA XREF: _start+1Do .text:0000000000400544 .text:0000000000400544 buf = byte ptr -10h .text:0000000000400544 .text:0000000000400544 push rbp .text:0000000000400545 mov rbp, rsp .text:0000000000400548 sub rsp, 10h .text:000000000040054C mov edi, 3 ; seconds .text:0000000000400551 mov eax, 0 .text:0000000000400556 call _sleep .text:000000000040055B lea rax, [rbp+buf] .text:000000000040055F mov edx, 100h ; nbytes .text:0000000000400564 mov rsi, rax ; buf .text:0000000000400567 mov edi, 0 ; fd .text:000000000040056C mov eax, 0 .text:0000000000400571 call _read .text:0000000000400576 leave .text:0000000000400577 retn .text:0000000000400577 main endp
0x01 思路
在pwnable.kr上這個題目用ROP和SROP均可以完成,不過有個重要個前提有syscall
。這個題目刪除了這個gadget,導致題目的難度上升了一個檔次。pwnable.kr的writeup在http://weaponx.site/2017/02/28/unexploitable-Writeup-pwnable-kr/
題目給出了libc,看來是讓我們用內存泄漏來計算出system/execve
等地址來執行system("/bin/sh")
。通常內存泄漏最終需要調用類似puts\write
等打印函數,然而程序中並沒有這些函數。只能通過syscall
和syscall_id
來調用需要的函數,但是又回到的最初沒有syscall
的情況。
所以只能尋求一個更有創造性的方法。
0x02 尋找syscall
在libc中搜索\x0f\x0f
–syscall
的機器碼。可以看到在read
函數中就有兩個gadget。
gdb-peda$ find "\x0f\x05" ... libc.so.6 : 0x7ffff7b0467e (<read+14>: syscall) libc.so.6 : 0x7ffff7b0469b (<read+43>: syscall) ... gdb-peda$ print read $1 = {<text variable, no debug info>} 0x7ffff7b04670 <read>
可以發現read
函數中的syscall
的距離函數入口的偏移量只有14和43,根據ASLR的原理。可以通過修改GOT表中read
函數的LSB(last significant bit
,最低有效位)爲0x7e
或者0x9b
就得到了syscall
!
0x03 how to exploit
第一段payload完成溢出,並調用read
將第二段payload寫入bss
段中,然後利用pop rbp;ret
和leave;ret
將棧遷移到bss
段上。
第二段payload完成修改GOT表中read
的LSB,變爲syscall
。利用syscall
調用write
泄漏sleep
的地址,計算出/bin/sh\x00
的地址pop rdi;ret
的地址和system
的地址。最後將棧遷移到第三段payload上。
第三段payload,將/bin/sh\x00
放入rdi
寄存器中,完成system("/bin/sh\x00")
。
0x04 syscall to system
通過syscall
來調用函數必須要將syscall_id
放入rax
寄存器中,但是經過搜索並沒有設置rax
相關的gadgets。必須利用函數的返回值來設置rax
。read
函數的返回值是讀入字符的個數,所以可以通過調用read
函數來設置rax
的值。
通過寫LSB得到syscall
後rax
的值爲1,即可通過syscall
調用write
來泄漏內存,此時可以通過泄漏內存的字節數來控制rax
。sleep
的返回值是0,所以可以通過調用sleep
來將rax
置0調用read
。
所以既可以通過偏移計算system
的地址,也可以通過syscall
和syscall_id = 59
來調用execve
。
寫出exploit後Boom shakalaka!
[+] [sleep base] => [0x7fb74adbe680] [+] [system] => [0x7fb74ad14102] [+] [pop rdi ret] => [0x7fb74ad38390] FINAL!!! [*] Switching to interactive mode $ cat /home/unexploitable/flag FLAG{********************************} $ [*] Interrupted [*] Closed connection to chall.pwnable.tw port 10403
0x05 exploit
因爲主辦方不讓公開高分的題目,所以exploit提交到主辦方的writeup系統中了,https://pwnable.tw/writeup/20/927