国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

通過覆蓋__atexit進行緩沖區溢出攻擊

2019-11-17 05:31:22
字體:
來源:轉載
供稿:網友

  通過覆蓋__atexit進行緩沖區溢出攻擊
--靜態編譯版本的heap溢出

原作者: Pascal BoUChareine <pb@hert.org>
原文: <<__atexit in memory bugs -
specific PRoof of concept with statically linked binaries and heap overflows>>



譯者注:這片文章可能很早就出來了,我看國內也沒有人介紹,干脆就
翻譯出來一塊兒共享吧,如有什么錯誤的地方,歡迎指正。
mailto:alert7@21cn.com

介紹:
本文討論了類似通過覆蓋.dtors進行緩沖區溢出攻擊的技術。歸根結底
是想方設法改變程序的執行流程,使之最終執行我們想要執行的代碼。本文
假設讀者熟悉普通的緩沖區溢出技術。


鳴謝:
感謝Andrew R. Reiter看了這片文檔,糾正一些錯誤。


內容:

I. atexit()的基本知識
II. atexit()的執行
III. EXPloitation的概念
IV. Eggshell的定位
V. 一個exploit的例子



I. atexit()基本知識

先讓我們看看手冊:

NAME
atexit - 注冊一個在exit時候被調用的函數

SYNOPSIS
#include <stdlib.h>

int
atexit(void (*function)(void))

DESCRipTION
atexit()函數注冊一個給定的函數,該函數在程序exit時候被調用
(不管是通過exit(3)或者還是通過從程序的main函數中返回)。
注冊的函數是反序被調用的;沒有參數。至少32個函數總是可以被注冊
的,只要有充分的分配的內存,更多的函數也是答應的。

看看下面程序的基本指令:

char *glob;

void test(void)
{
printf("%s", glob);
}

void main(void)
{
atexit(test);
glob = "Exiting./n";
}
當執行時,應該在標準輸出上顯示"Exiting" .

II. atexit()的執行

atexit是做為libc函數導出的。
執行過程使用了一個靜態的atexit結構,該結構包含了那些在退出時候被
調用的函數的一個數組,在調用atexit函數的時候會插入一個結構(我們
將稱它為"fns"),在fns中有一個變量保存著下一個空的索引(我們稱
它為"ind"),當fns滿的時候,一個指針(我們稱為next)指向了下一個
被使用的atexit結構.

struct atexit {
struct atexit *next; /* next in list */
int ind; /* next index in this table */
void (*fns[ATEX99v_SIZE])(); /* the table itself */
};

當atexit()被調用時,它填充fns[ind],增加ind,這時ind就是下一個在fns中空的索引。
當fns滿的時候,一個新的atexit的結構被分配,并且它的next變量指向了最后
被使用的那個。

注重:一般atexit的使用的是不需要next的,它在初始化的時候被設置為
NULL。

當exit()被調用,它分析最后定義的atexit結構,并且執行在fns[ind]中的
函數,減少ind,依次執行。

當exit()被調用的時候,需要查看一些退出函數,然而,atexit()需要寫它,
atexit結構被分配是做為一個全局符號的,(在*bds上是__atexit, 在linux
是__exit_funcs), 并且導出給其他函數的。

譯者注:假如你第一次讀這片文章,你可能會忽視了atexit()和__atexit
(在*bds上是__atexit, 在linux上是__exit_funcs)的關系。

__atexit就是被atexit函數使用的一個內部變量,下面有個圖指
示了atexit()如何利用__atexit的。

III. Exploitation的概念

這部分不是很準確。需要依靠執行時候的內存映象,依靠你的OS,還受許多
其他的因數的影響。

我們首先要知道__atexit在內存中的分配地址,判定那里是可以重寫的地址。所以我
寫了個簡單的例子。

extern void * __atexit;

int main(void)
{
static char scbuf[128];
char *mabuf;

mabuf = (char *) malloc(128);

printf("__atexit at %p/n", __atexit);
printf("malloced at %p/n", mabuf);
printf("static at %p/n", scbuf);
return 0;
}

編譯一下,有以下的結果:

pb@nod [405]$ gcc -o at at.c
pb@nod [406]$ ./at
__atexit at 0x280e46a0
malloced at 0x804b000
static at 0x8049660

pb@nod [407]$ gcc -o at -static at.c
pb@nod [408]$ ./at
__atexit at 0x8052ea0
malloced at 0x8055000
static at 0x8052e20


以上已經足夠說明問題了.可許你已經知道,動態編譯的版本是通過一個
mmap()調用來裝載libc庫函數的。 (0x280e46a0)現在看起來是我們不能修改
的, 但是靜態版本是可以的。

在靜態編譯的二進制中,libc被保存在程序的heap區,因此,__atexit的位置
在我們的靜態scbuf四周。在這個例子中,__atexit和scbuf相差0x80個字節。
它意味著他們是位置連續的。假如你了解heap溢出,構造它應該不是件很難的
事情。

在靜態的字符緩沖區后面構造自己的atexit結構,覆蓋__atexit變量,可以使
exit()執行在內存中的任何地方。比如執行我們的eggshell。為了構造它,我
們需要明白atexit()是如何利用__atexit變量的,看下面類似gdb的輸出:

0 127 128 132 136 140
(an eggshell with nops) (next) (ind) (fns[0]) (fns[1])
0x90909090 ..... 0x00000000 0x00000001 0xbffff870 0x00000000

for (p = __atexit; p; p = p->next)
for (n = p->ind; --n >= 0;)
(*p->fns[n])();

第一種方法你可以使'ind'為正值,比如上面圖使ind為1,fns[0]為
eggshell的地址,但是這樣構造出來的atexit結構中包含了'/0'。我
們沒有辦法使用。

第二種方法是使p->next指向一塊我們精心構造的atexit結構的內存。
我們僅僅需要使ind為負的,可以不管fns的數組。

但是,我們到底如何找到那塊空間呢?

IV. Eggshell的定位

我要為這件事干一兩杯啤酒。

讀了execue的手冊和內核execve的執行過程,使我想起了我寫的第一個
c語言程序。我們知道,argc是參數的個數,argv是以null結尾的數組
(包含了以null結尾的字符串),envp是環境變量。一個正在執行的程序
要得到這些信息是輕易的。
因此,在stack的頂部,一個 "vector table" 包含了這些信息當然還包括一些
其他的(例如信號掩碼)。讓我們看看在stack上的argv的存放:

0xbfbffb60: 0x00000000 0x00000005 0xbfbffc5c 0xbfbffc84
0xbfbffb70: 0xbfbffc8a 0xbfbffc8f 0xbfbffc92 0x00000000

在該例子中,argc是5。有5個指針指向5個argv元素。最后一個是以NULL結尾的。

上面看到的,使你想起那個atexit結構了嗎?:)


該圖完美的描繪了atexit的結構!ind=5,argv[4]是被調用函數的地址。所有
的工作預備就緒,但是還差點。我們只要猜測在stack上的 vector table的
正確地址就可以了,在__atexit->next填上該地址,在__atexit->ind填上負的,
這樣一切都OK了。

猜測argv[]的地址需要依靠你的OS。我看了一下/sys/kern/kern_exec.c,
讀了一下這個函數:


/*
* Copy strings out to the new process address space, constructing
* new arg and env vector tables. Return a pointer to the base
* so that it can be used as the initial stack pointer.
*/
register_t *
exec_copyout_strings(imgp)


這個函數解釋了如何計算argv的vector table地址,你的計算基于地址PS_STRING
(stack的基地址,less結構的ps_string大小),信號掩碼的大小,"SPARE_USERSPACE"
這個變量在我的freebsd上被定義256(可能這個變量被setproctitle()函數使用),和一些
其他復雜的東西。

為了使用可移植的計算方法,我使用了下面自我調用的方法來執行argv[]。
首先,假如你要利用有問題的程序的話,你需要把條件都預備好。但是不能以
非凡的參數調用自己。在第二次調用時,argv應該正確的被定位,然后再調
用有問題的程序。

有了這兩個技術,我想你應該有了一個高效率的緩沖區溢出的方法,而不再需要
計算offset了。

譯者注:這種兩次execve技術很不錯,兩次execve出來的進程的argv的地址是
一樣的。所以就不需要猜測argv的地址了

注重:對于format bug來說,這個技術聽起來很強大。_

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 留坝县| 高邑县| 大足县| 巴彦淖尔市| 兴文县| 深圳市| 鄂托克旗| 牡丹江市| 老河口市| 清原| 资兴市| 临汾市| 响水县| 通海县| 色达县| 巢湖市| 垫江县| 霍林郭勒市| 石首市| 巴彦县| 华坪县| 浮山县| 青浦区| 津南区| 周宁县| 鹤山市| 中江县| 湘乡市| 陆河县| 黄骅市| 富阳市| 广平县| 体育| 日土县| 剑阁县| 玉树县| 德化县| 平顶山市| 新疆| 鲁山县| 武清区|