zoukankan      html  css  js  c++  java
  • 使用wireshark抓包分析SOCKS5协议


    通信软件课选择了分析SOCKS5协议,想看一下这个协议在网络通信中是如何进行的,遂抓包实践如下。

    编写SOCKS5服务器运行代码(参考自Python编写socks5服务器

    import select
    import socket
    import struct
    from socketserver import StreamRequestHandler, ThreadingTCPServer
    SOCKS_VERSION = 5
    class SocksProxy(StreamRequestHandler):
        def handle(self):
            print('Accepting connection from {}'.format(self.client_address))
            # 协商
            # 从客户端读取并解包两个字节的数据
            header = self.connection.recv(2)
            version, nmethods = struct.unpack("!BB", header)
            # 设置socks5协议,METHODS字段的数目大于0
            assert version == SOCKS_VERSION
            assert nmethods > 0
            # 接受支持的方法
            methods = self.get_available_methods(nmethods)
            # 无需认证
            if 0 not in set(methods):
                self.server.close_request(self.request)
                return
            # 发送协商响应数据包
            self.connection.sendall(struct.pack("!BB", SOCKS_VERSION, 0))
            # 请求
            version, cmd, _, address_type = struct.unpack("!BBBB", self.connection.recv(4))
            assert version == SOCKS_VERSION
            if address_type == 1:  # IPv4
                address = socket.inet_ntoa(self.connection.recv(4))
            elif address_type == 3:  # Domain name
                domain_length = self.connection.recv(1)[0]
                address = self.connection.recv(domain_length)
                #address = socket.gethostbyname(address.decode("UTF-8"))  # 将域名转化为IP,这一行可以去掉
            elif address_type == 4: # IPv6
                addr_ip = self.connection.recv(16)
                address = socket.inet_ntop(socket.AF_INET6, addr_ip)
            else:
                self.server.close_request(self.request)
                return
            port = struct.unpack('!H', self.connection.recv(2))[0]
            # 响应,只支持CONNECT请求
            try:
                if cmd == 1:  # CONNECT
                    remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                    remote.connect((address, port))
                    bind_address = remote.getsockname()
                    print('Connected to {} {}'.format(address, port))
                else:
                    self.server.close_request(self.request)
                addr = struct.unpack("!I", socket.inet_aton(bind_address[0]))[0]
                port = bind_address[1]
                #reply = struct.pack("!BBBBIH", SOCKS_VERSION, 0, 0, address_type, addr, port)
                # 注意:按照标准协议,返回的应该是对应的address_type,但是实际测试发现,当address_type=3,也就是说是域名类型时,会出现卡死情况,但是将address_type该为1,则不管是IP类型和域名类型都能正常运行
                reply = struct.pack("!BBBBIH", SOCKS_VERSION, 0, 0, 1, addr, port)
            except Exception as err:
                logging.error(err)
                # 响应拒绝连接的错误
                reply = self.generate_failed_reply(address_type, 5)
            self.connection.sendall(reply)
            # 建立连接成功,开始交换数据
            if reply[1] == 0 and cmd == 1:
                self.exchange_loop(self.connection, remote)
            self.server.close_request(self.request)
        def get_available_methods(self, n):
            methods = []
            for i in range(n):
                methods.append(ord(self.connection.recv(1)))
            return methods
        def generate_failed_reply(self, address_type, error_number):
            return struct.pack("!BBBBIH", SOCKS_VERSION, error_number, 0, address_type, 0, 0)
        def exchange_loop(self, client, remote):
            while True:
                # 等待数据
                r, w, e = select.select([client, remote], [], [])
                if client in r:
                    data = client.recv(4096)
                    if remote.send(data) <= 0:
                        break
                if remote in r:
                    data = remote.recv(4096)
                    if client.send(data) <= 0:
                        break
    if __name__ == '__main__':
        # 使用socketserver库的多线程服务器ThreadingTCPServer启动代理
        with ThreadingTCPServer(('127.0.0.1', 9011), SocksProxy) as server:
            server.serve_forever()
    

    本文采用参考链接中curl请求的方法经由代理服务器获取目标网站的信息curl -v --socks5 127.0.0.1:9011 http://www.baidu.com
    对于python编写的client程序

    import socket
    import socks
    import requests
    socks.set_default_proxy(socks.SOCKS5, "127.0.0.1", 9011, username=None, password=None)
    socket.socket = socks.socksocket
    head={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'}
    print(requests.get('https://www.baidu.com', head).text)
    

    需要注意的一点是import的socks包是第三方库PySocks,pip安装时使用命令pip install PySocks(参考自No module named 'socks', i have tried everything

    使用SOCKS5服务器脚本和curl命令

    在本地运行SOCKS5服务器脚本,执行curl命令得到如图结果

    放在远端主机上运行SOCKS5服务器脚本,在本地执行curl命令得到如图结果

    这时查询listen的主机端口netstat -anp

    可能需要将Local Address 设置为0.0.0.0,外来的连接才可以连接,查相关的资料(全零网络IP地址0.0.0.0表示意义详谈Linux的netstat查看端口是否开放见解(0.0.0.0与127.0.0.1的区别))果然如此。
    遂将服务器脚本的倒数第二行"127.0.0.1"改为"0.0.0.0",重复之前步骤发现与本地测试的结果差不多,并在该过程中抓取到curl请求远程主机发送百度首页请求的数据包。

    分析抓取到的数据包理解SOCKS5协议的工作过程(感谢socks5代理服务器协议的说明让我预先知道SOCKS5协议数据消息传递的机理)


    握手

    本地发送认证请求,05表示SOCKS5,02表示接受2种认证方法,00表示无需认证的认证方法,01表示GSSAPI

    服务端确认无需认证

    本地查询DNS信息

    第一个01说明TCP,第二个01说明后面是(DNS查询出的)IP地址,3d87b920指目标网站的ip地址61.135.185.32,0050指80端口

    SOCKS5服务器成功连接上目标网站后发送成功响应,ac150007指服务器连接目标网站用到的ip地址172.21.0.7,8a10指使用的端口35344,也可以不说明连接的具体细节,直接0500后面接8个字节的0

    本机向SOCKS5服务器发送目标网站的http请求

    获取到目标网页信息

    挥手
    拓展阅读:SOCKS 5 协议抓包分析

  • 相关阅读:
    thinkphp5 tp5 命名空间 报错 Namespace declaration statement has to be the very first statement in the script
    开启 php 错误 提示 php-fpm 重启 nginx 500错误 解决办法 wdlinux lnmp 一键包 php脚本无法解析执行
    js 设置 cookie 定时 弹出层 提示层 下次访问 不再显示 弹窗 getCookie setCookie setTimeout
    php 二维数组 转字符串 implode 方便 mysql in 查询
    nginx 重启 ps -ef|grep nginx kill -HUP 主进程号
    jquery bootstrap help-block input 表单 提示 帮助 信息
    jquery 倒计时 60秒 短信 验证码 js ajax 获取
    jQuery如何获取同一个类标签的所有的值 遍历
    linux下C语言文件操作相关函数
    gcc,gdb用法
  • 原文地址:https://www.cnblogs.com/tellw/p/13862546.html
Copyright © 2011-2022 走看看