奇安信实习(五)-Socks5协议抓包分析

奇安信实习(五)-Socks5协议抓包分析

刚来成都ateam这边实习,大佬们都去参加护网去了,只好一个人在公司摸鱼。最近同事们从北京护网回来基本都处于休息的状态,老牛给我安排了一些学习的任务,根据自己的方向比如看看Cobalt Strike的源码什么的。还有一个重写内网代理转发工具reGeorg的任务,为了用golang重写这个工具,打算先把ocks5协议的原理学习一遍。

首先分析socks协议之前,说一下代理的定义。

代理就是中间人,一人分饰两角:客户端眼中的目标服务器,目标服务器眼中的客户端——这意味着他必须同时满足C/S 双方的规范。再细分,如果只是简单的 pipe C/S 两端数据,那他就是个“透明代理”;一旦他对请求或响应进行了修改,那就是“非透明代理”。

而SOCKS5 协议并不负责代理服务器的数据传输环节,此协议只是在C/S两端真实交互之间,建立起一条从客户端到代理服务器的授信连接

SOCKS5  是一个C/S 交互的协议,交互大概分为这么几步:

  1. 客户端发送认证协商
  2. 代理服务器就认证协商进行回复(如拒绝则本次会话结束)
    1. 如需GSSAPI或用户名/密码认证,客户端发送认证信息
    2. 代理服务器就对应项进行鉴权,并进行回复或拒绝
  3. 客户端发送希望连接的目标信息
  4. 代理服务器就连接信息进行确认或拒绝
  5. 【非协议内容】:代理服务器连接目标并 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字节)
 固定为50x01: CONNECT
0x02: BIND
0x03:UDP 
ASSOCIATE
固定为 0x000x01: 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字节)
 固定为50x00
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!总算分析完了。

赞赏

微信赞赏支付宝赞赏

Zgao

愿有一日,安全圈的师傅们都能用上Zgao写的工具。

发表评论