限定源端口拜访指标

1.1. 起因

在浸透测试时,客户须要对咱们的测试IP进行加白,然而此次客户要求准确到固定端口或者小范畴端口(不能1-65535),依据以前的教训,默认是加白IP和全端口,因为代理建设连贯应用的端口是随机的,所以这次算是从头查找材料总结一下各种指定源端口的形式。

这里的端口是指与指标建设连贯时应用的源端口,而不是代理监听的端口。

1.2. 留神

最好应用服务器(VPS)发送申请。如果在局域网外向外网发动申请,即便本机指定了端口,也杯水车薪,因为理论发出请求的是最外层网络设备。

1.3. 办法一:NC

# 指定12345端口,毛病是一次一用,比拟麻烦nc <IP> <Port> -p 12345

1.4. 办法二:批量占用端口

查找了很多材料,但都没能找到适合的工具。最终我想到了一种蠢笨的办法:强制占用所有可用的端口。这样当代理发动申请时,就会主动抉择未被占用的端口。python代码举例如下:

import socketimport time# 要占用的端口范畴start_port = 1end_port = 60000# 创立套接字socks = []for port in range(start_port, end_port+1):    try:        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)        sock.bind(('0.0.0.0', port))        sock.listen(1)        socks.append(sock)    except:        print(f"{port} 被其余利用占用")print(f'已占用端口范畴: {start_port} - {end_port}')# 长期占用端口while True:    time.sleep(60)

成果如下,可见都是60000后的端口连贯。

1.5. 办法三:手动实现代理转发

本人实现一个代理。监听一个端口,而后将流量发送到代理中,再由代理去固定源端口发送申请并返回后果。

Warning

因为都是走的这个端口去建设连贯,一旦出现异常状况,那这个端口可能会长期保持TIME_WAIT状态从而导致无奈失常应用。

python代码如下:

import http.server                  # 导入HTTP服务器相干的模块import socketserver                 # 导入socket服务器相干的模块import http.client                  # 导入HTTP客户端相干的模块import urllib.parse                 # 导入URL解析相干的模块import socket                       # 导入socket相干的模块from loguru import logger           # 导入日志库LISTEN_PORT = 8080                  # 本地监听端口CONNECT_PORT = 22333                # 用于建设代理服务器与指标服务器连贯的本地端口# 继承http.server.BaseHTTPRequestHandler类,实现代理服务器的申请解决class ProxyRequestHandler(http.server.BaseHTTPRequestHandler):    # 解决CONNECT办法    def do_CONNECT(self):        # 解析URL        u = urllib.parse.urlparse('http://' + self.path)        # 建设一个新的套接字        p_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)        # 将该套接字绑定到本地端口        p_sock.bind(('0.0.0.0', CONNECT_PORT))        # 建设连贯        p_sock.connect((u.hostname, u.port or 80))        # 返回200连贯已建设响应        self.wfile.write(b'HTTP/1.1 200 Connection Established\r\n\r\n')        # 将该套接字设置为非阻塞模式        p_sock.setblocking(False)        self.connection.setblocking(False)        while True:            try:                # 从代理服务器接收数据                data = self.connection.recv(1024)                if not data:                    break                # 将数据发送到指标服务器                p_sock.sendall(data)            except:                pass            try:                # 从指标服务器接收数据                data = p_sock.recv(1024)                if not data:                    break                # 将数据发送到代理服务器                self.connection.sendall(data)            except:                pass        # 敞开连贯        self.connection.close()        p_sock.close()    # 解决GET办法    def do_GET(self):        # 解析URL        u = urllib.parse.urlparse(self.path)        # 创立一个HTTP连贯        conn = http.client.HTTPConnection(u.hostname, port=u.port or 80, timeout=10, source_address=('0.0.0.0', CONNECT_PORT))        # 发送HTTP申请        conn.request(self.command, self.path, headers=self.headers)        # 获取HTTP响应        resp = conn.getresponse()        # 发送HTTP响应头        self.send_response(resp.status)        for header, value in resp.getheaders():            self.send_header(header, value)        self.end_headers()        # 发送HTTP响应体        while True:            data = resp.read(1024)            if not data:                break            self.wfile.write(data)    # 解决POST办法    def do_POST(self):        # 解析URL        u = urllib.parse.urlparse(self.path)        # 获取申请体长度        content_len = int(self.headers.get('Content-Length', 0))        # 读取申请体        content_len = int(self.headers.get('Content-Length', 0))  # 获取申请体长度        body = self.rfile.read(content_len)  # 读取申请体数据        conn = http.client.HTTPConnection(u.hostname, port=u.port or 80, timeout=10,                                          source_address=('0.0.0.0', CONNECT_PORT))  # 创立 HTTP 连贯对象        conn.request(self.command, self.path, body=body, headers=self.headers)  # 发送 HTTP POST 申请        resp = conn.getresponse()  # 获取响应对象        self.send_response(resp.status)  # 发送 HTTP 响应状态码        for header, value in resp.getheaders():  # 遍历响应头部信息            self.send_header(header, value)  # 发送响应头部信息        self.end_headers()  # 完结响应头部信息的发送        while True:            data = resp.read(1024)  # 依照每次读取 1024 字节的形式获取响应数据            if not data:  # 如果读取结束,跳出循环                break            self.wfile.write(data)  # 将响应数据写入连贯,响应给客户端if __name__ == '__main__':    try:        # 创立一个 TCPServer 对象,绑定到 0.0.0.0:LISTEN_PORT 的地址,用于监听来自客户端的连贯申请,当有连贯申请时,将应用 ProxyRequestHandler 类进行解决。        httpd = socketserver.TCPServer(('0.0.0.0', LISTEN_PORT), ProxyRequestHandler)        logger.info(f"Proxy server is listening on port {LISTEN_PORT}")        #  开始监听并承受来自客户端的连贯申请,直到呈现 KeyboardInterrupt 异样为止        httpd.serve_forever()    except KeyboardInterrupt:        httpd.server_close()

成果如下,均为22333端口。

1.6. 尝试过的失败办法记录

  • Nginx反向代理
  • SSH动静代理 ssh -N -D 0.0.0.0:9999 ubuntu@hongkong
  • socat sudo socat TCP-LISTEN:<new_source_port>,fork,reuseaddr TCP:<destination_IP>:<destination_port>