依舊是Python黑帽子這本書
先附上代碼,我在原書代碼上加了注釋,更好理解
import sys
import socket
import threading#生成可打印字符映射
HEX_FILTER=''.join([(len(repr(chr(i)))==3) and chr(i) or '.' for i in range(256)])#接收bytes或string類型的輸入,并將其轉換為十六進制格式輸出
#數值存儲
def hexdump(src,length=16,show=True):if isinstance(src,bytes):src=src.decode()results=list()for i in range(0,len(src),length):word=str(src[i:i+length])printable=word.translate(HEX_FILTER)hexa=' '.join([f'{ord(c):02X}' for c in word])hexwidth=length*3results.append(f'{i:04x} {hexa:<{hexwidth}} {printable}')if show:for line in results:print(line)else:return results#接收本地或遠程數據
def receive_from(connection):buffer=b""connection.settimeout(5)try:while True:data=connection.recv(4096)if not data:breakbuffer +=dataexcept Exception as e:passreturn buffer#數據處理函數
#預留數據修改的鉤子,可以在這里修改客戶端請求或服務器響應
def request_handler(buffer):return bufferdef response_handler(buffer):return buffer#代理處理,負責處理客戶端與遠程服務器間的通信,是代理的核心
def proxy_handler(client_socket,remote_host,remote_port,receive_first):#創建遠程連接remote_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#創建TCP連接remote_socket.connect((remote_host,remote_port))#連接到遠程服務器#接收遠程服務器數據if receive_first:remote_buffer=receive_from(remote_socket)hexdump(remote_buffer)#處理服務器返回數據remote_buffer=response_handler(remote_buffer)if len(remote_buffer):print("[<==] Sending %d bytes to localhost." % len(remote_buffer))client_socket.send(remote_buffer)#循環監聽客戶端與服務器間的通信,直到連接關閉while True:#處理客戶端數據local_buffer=receive_from(client_socket)#讀取數據if len(local_buffer):line= "[==>]Received %d bytes from localhost." % len(local_buffer)print(line)#打印數據hexdump(local_buffer)local_buffer=request_handler(local_buffer)#數據修改remote_socket.send(local_buffer)#轉發給遠程服務器print("[==>]Sent to remote.")#處理遠程服務器返回的數據remote_buffer=receive_from(remote_socket)if len(remote_buffer):print("[<==] Received %d bytes from remote." % len(remote_buffer))hexdump(remote_buffer)remote_buffer=response_handler(remote_buffer)client_socket.send(remote_buffer)print("[<==] Sent to localhost.")#關閉連接if not len(local_buffer) or not len(remote_buffer):client_socket.close()remote_socket.close()print("[*] No more data. Closing connections.")#服務器監聽
def server_loop(local_host, local_port, remote_host, remote_port, receive_first):#創建socket并綁定端口server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)try:server.bind((local_host, local_port))except Exception as e:print('problem on bind: %r' % e)print("[!!] Failed to listen on %s:%d" % (local_host, local_port))print("[!!] Check for other listening sockets or correct permissions.")sys.exit(0)#監聽并等待客戶端連接print("[*] Listening on %s:%d" % (local_host, local_port))server.listen(5)while True:#處理客戶端連接client_socket, addr = server.accept()#輸出連接信息line = "> Received incomming connection from %s:%d" % (addr[0], addr[1])print(line)#啟動代理線程proxy_thread = threading.Thread(target=proxy_handler,args=(client_socket, remote_host,remote_port, receive_first))proxy_thread.start()def main():if len(sys.argv[1:]) != 5:print("Usage: ./proxy.py [localhost] [localport]", end='')print("[remotehost] [remoteport] [receive_first]")print("Example: ./proxy.py 127.0.0.1 9000 10.12.132.1 9000 True")sys.exit(0)local_host = sys.argv[1]local_port = int(sys.argv[2])remote_host = sys.argv[3]remote_port = int(sys.argv[4])receive_first = sys.argv[5]if "True" in receive_first:receive_first = Trueelse:receive_first = False#啟動服務器server_loop(local_host, local_port, remote_host, remote_port, receive_first)if __name__ == '__main__':main()
windows物理機和kali我都試了,不知道為什么只有kali能用
sudo python TCP_proxy.py 192.168.65.128 8887 www.baidu.com 80 True
再另起一個終端,輸入:
curl -x 192.168.65.128:8887 www.baidu.com
這時候我們的腳本就會接收到數據,并以hex的形式輸出
本來原書用的是ftp,但是我怎么也復現不出來,只能簡單用這個代替一下的,但是原理也差不了太多
但是我發現這個似乎不太穩定,我也是試了兩次才成功的
還有個問題就是程序沒加入ctrl+c退出的功能,雖然我也懶得加了喵(