奇安信实习(五)-Socks5协议抓包分析
刚来成都ateam这边实习,大佬们都去参加护网去了,只好一个人在公司摸鱼。最近同事们从北京护网回来基本都处于休息的状态,老牛给我安排了一些学习的任务,根据自己的方向比如看看Cobalt Strike的源码什么的。还有一个重写内网代理转发工具reGeorg的任务,为了用golang重写这个工具,打算先把ocks5协议的原理学习一遍。
首先分析socks协议之前,说一下代理的定义。
代理就是中间人,一人分饰两角:客户端眼中的目标服务器,目标服务器眼中的客户端——这意味着他必须同时满足C/S 双方的规范。再细分,如果只是简单的 pipe C/S 两端数据,那他就是个“透明代理”;一旦他对请求或响应进行了修改,那就是“非透明代理”。
而SOCKS5 协议并不负责代理服务器的数据传输环节,此协议只是在C/S两端真实交互之间,建立起一条从客户端到代理服务器的授信连接
SOCKS5 是一个C/S 交互的协议,交互大概分为这么几步:
- 客户端发送认证协商
- 代理服务器就认证协商进行回复(如拒绝则本次会话结束)
- 如需GSSAPI或用户名/密码认证,客户端发送认证信息
- 代理服务器就对应项进行鉴权,并进行回复或拒绝
- 客户端发送希望连接的目标信息
- 代理服务器就连接信息进行确认或拒绝
- 【非协议内容】:代理服务器连接目标并 pipe 到客户端
这边我先在一台linux的vps上搭建了ss5作为代理服务器,搭建的过程网上有很多文章故略过。直接进入正题开始抓包分析socks5协议。先开一个cmd窗口使用curl命令做试验。curl支持socks代理,通过命令行的方式非常方便。
ip.sb是一个获取ip的请求ip的网站,这里我分别请求了三次,获取了三个不同的ip作为对比,下面开始分析socks协议。
首先开启wireshark抓包,过滤指定ip的流量,这里就是我socks5代理服务器的ip,ip.addr== 106.15.73.80。当执行curl ip.sb –socks5 zgao.top:1080后,wireshark就会出现所有相关的流量报文。
如图这里是最简单的一个socks连接代理的过程,采用的是无用户密码认证的socks代理。我们这里忽略掉tcp三次握手和四次挥手的过程,只分析socks协议。
注意:默认情况下,只有socks代理的端口设置为1080时,wireshark才能识别为socks协议的流量。
为方便大家理解,我只选中了socks5协议的部分。选中之后下面的16进制会默认用蓝色显示。这里socks协议的内容只有蓝色部分的四个字节。wireshark会自动将每个字段的含义翻译出来,上面我都用箭头指出来了。
一,上图是socks5协议认证的第一步 客户端 -> 代理服务器,请求认证。
其中认证方法包括以下:
- 0x00: NO AUTHENTICATION REQUIRED
- 0x01: GSSAPI
- 0x02: USERNAME/PASSWORD
- 0x03: to X’7F’ IANA ASSIGNED
- 0x80: to X’FE’ RESERVED FOR PRIVATE METHODS
- 0xFF: NO ACCEPTABLE METHODS
版本号(1字节) | 可供选认证方法(1字节) | 选择的方法(1~255字节) |
固定为5 | 选了多少种 | 都有上面的哪些方法 |
以 05 02 00 01 为例:
Version: 5 #05,socks协议版本号
Authentication Method Count: 2 #02,客户端提供了两种认证方法
Method[0]: 0 (No authentication) #00对应的方法字段,无需身份验证
Method[1]: 1 (GSSAPI) #01对应的方法字段,GSSAPI
二,这里是第二步,代理服务器 -> 客户端,响应认证。
这里服务端的响应只有两个字节,版本号和确认认证的方法。
版本号(1字节) | 确认认证的方法 |
固定为5 | 认证方法列表的某项: 0x00,则无需客户端发送进一步认证的信息 0x01,则需要客户端进行进一步认证 0xFF,则相当于拒绝请求,客户端只能关闭连接 |
由于我搭建ss5在配置文件中设置的是无需用户密码认证,所以这里响应为 05 00 。
上图socks协议内容部分到 05 00 实际就结束了,后面的 00 00 00 00 并不是socks协议的内容了,而是以太网帧填充的字段。
IEEE规定了最小为64字节。所以在网路中传输时,以太网帧字节数小于64帧,将由padding段填充。抓包中看到接收包比发送包分别是60字节和56字节的原因,是因为wireshark抓取的发送包截获在发送之前,该数据包发送时才会由网卡驱动负责填充到64字节,我们只能看到原始的56字节长数据。而Response包,抓取时已经被网卡填充到了64字节,同时wireshark抓包是不显示4字节的校验字段的,再减去之,为60字节长。同时从服务器端抓包进行验证,可以发现从客户端过来的包长度也显示为60字节。
大家也许会好奇为什么抓包会发现有padding字段?感兴趣的小伙伴可以尝试一下。
三,第三步是客户端 -> 代理服务器,发送目标信息。
包含以下字段:
版本号(1字节) | 命令(1字节) | 保留(1字节) | 请求类型(1字节) | 地址(不定长) | 端口(2字节) |
固定为5 | 0x01: CONNECT 0x02: BIND 0x03:UDP ASSOCIATE | 固定为 0x00 | 0x01: IP V4 地址 0x03: 域名 0x04: IP V6 地址 | 如果请求 类型是域名, 第个1字节为 域名的长度 |
- CONNECT: 用于客户端请求服务器进行代理
- BIND: 用于客户端向服务器上报自己的反向连接监听地址
- UDP ASSOCIATE:用于请求建立到 UDP 数据报中继的连接
为什么curl的是域名,而socks协议里是ipv4地址呢?
是因为我们用的命令 curl ip.sb –socks5 zgao.top:1080,是在本地解析好域名将ip地址发送给socks代理服务器。如何让代理服务器来解析域名呢?这里我们再做个测试。
curl ip.sb –socks5-hostname zgao.top:1080
通过修改curl的命令参数使用–socks5-hostname代替即可,这样对比方便理解socks协议的协商过程。
四,socks连接的最后一步,代理服务器 -> 客户端,确认连接。
版本号(1字节) | 确认回应(1字节) | 保留(1字节) | 响应类型(1字节) | 地址(不定长) | 端口(2字节) |
固定为5 | 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 | 固定为 0x00 | 仅用于响应客 户端BIND命令: 0x01: IP V4 地址 0x03: 域名 0x04: IP V6 地址 | 仅用于响应客 户端BIND命令: 如果请求 类型是域名, 第个1字节为 域名的长度 | 仅用于响应客 户端BIND命令 |
在代理服务器确认回应为 0x00 时,此次 SOCKS5 协议协商部分顺利完成,然后就是数据传输阶段。
后续的数据报文还是有socks封装的报头,但是socks协议内部的封装的其他协议就与socks协议本身无关了。至此,socks5协议抓包分析的过程就结束了。深刻理解协议底层原理后,再开发socks协议相关的工具时就能更加得心应手了。
虽然上面完成了socks协议认证的整个过程,但是仅测试了无认证的情况。这里我在开启了用户密码认证后再继续抓包分析。这里我设置了用户名和密码均为zgao。
此时socks服务端的的响应是oxff为不接受的方法,拒绝了这次socks连接。接着我们在curl命令中带上用户密码再次请求。
很明显此时socks协商次数变多了,逐个分析每个socks数据包。
同时服务端响应接收的方式也变为了用户密码认证。
接着客户端开始传输用户密码。
不过这里我开始思考一个问题,既然socks协议的认证用户密码都使用明文传输。那么很可能会被别人抓包嗅探到,甚至被中间人攻击,并不是特别安全。
服务端响应认证成功后,后续的步骤和之前无密码的过程就一样了,这里就不赘述了。为了搞清楚这里Subnegotiation Version的含义,去官网学习下,是一个子协商版本。一旦 SOCKS V5 服务器启动,并且客户端选择了用户名/密码认证协议,用户名/密码子谈判开始。这开始于客户产生一个用户名/密码请求:
子协商版本号 | 用户名长度 | 用户名 | 密码长度 | 密码 |
1字节 | 1字节 | 1-255字节 | 1字节 | 1-255字节 |
Socks5协议分析完成!
虽然分析难度不大,但是内容很多,整整写了一天orz!总算分析完了。
赞赏微信赞赏支付宝赞赏
发表评论