WebSocket 实战:基于协议特点的漏洞挖掘
渗透测试
当传输协议从 HTTP 变成 WebSocket,漏洞挖掘这件事在思路上有哪些不同和突破点?本文结合多个真实案例,从协议特点、鉴权模型、并发利用、业务逻辑等角度,总结 WebSocket 场景下的安全测试思路
WebSocket 实战:基于协议特点的漏洞挖掘 ======================== 01 前言 ----- 前面介绍了渗透测试中一个比较恶心的环境,那就是websocket协议+protobuf传输,这种模式下对我们安全人员来说无论是数据可读或者更改都是非常难受并极其不便利的,最后的思路是利用AI下载对应zip包,分析逻辑,写全自动解析脚本。 当时我说过一句话就是,这种环境可能有些人用不上,但是你如果你碰到一定会回来感谢我的,所以本着有始有终的原则,想着将这种场景下的一些渗透测试注意点以及差异,同时附带一些实战经验和实际漏洞都讲解一下,一些差别或ws测试思路在实际举例的漏洞中会提到。(本篇重点讲ws协议中实战发现的漏洞,而非协议本身,协议本身的内容会提到但不作为重点) **相关请求和截图已脱敏** 02 回顾 ----- 前面文章一笔带过一个知识点,不知道有多少人注意到了,后来想想其实还是很重要的,所以今天再特意提一下 如今很多APP里面都会夹杂着一些脱离APP本体的一些H5页面,或者一些内嵌的小程序之类的内容,我记得我最开始遇到的时候是N年前,任务是某个APP内的一个小程序,到手之后一测,上来一个就是验签也就是sign校验,正常情况下如果web网站直接JS里面扣逻辑就好了,当时没遇到过,心想这可咋搞,哪怕是微信小程序也行啊,也可以用工具强开devtools或者逆向都行啊,于是本着不抛弃不放弃的原则深挖了一下,终于让我发现了端倪,其实像这种APP内部嵌入H5或者小程序的情况,你观察抓包工具历史记录去筛选`.zip`,没错你可以理解成它都是先去请求拉取对应的前端代码,然后渲染,所以大概率你会在请求历史中查找到对应小程序的前端代码,这样你直接访问下载--解压,里面的js文件就可以扣逻辑了 而且曾几何时,攻防或者SRC,很多人会说的一句话:“web资产都被人扫了多少遍了,建议去看看APP或者微信小程序这些资产”,其实我之前还有一个思路就是挖对应主体一些APP内部的小程序(如果有的话),这个更冷门,记得有一次上去随便点两下掏了两个高危出来 03 websocket ------------ 这里要介绍一些websocket的特点,放心不会去写那些很深的原理,因为对后续内容没什么帮助 ### 031 连接特点 首先我们要知道websocket是建立在http基础上的,它们都属于应用层协议,也就是websocket需要在http的基础上进行一个升级,然后双端建立起通道。与平时常用的http不同的是,http大概得感觉就是只有客户端主动建立连接发出请求报文然后服务端回复响应报文,结束连接关闭,websocket建立起通道后一般情况下是不关闭的,此时双方都可以主动发出数据,当然也包含像请求-响应这种模式,比如建立连接后客户端发出一个消息,服务端接收到后主动发过来一个响应消息,同时服务端也可以主动发起响应消息 举个例子,比如一个游戏场景,突然屏幕滚动一个全服公告【恭喜xxx获得一等奖--兰博基尼5元代金券一个】,那么如果是传统的http面对这种情况,由于HTTP通常是由客户端主动发起请求,服务端无法主动向客户端推送消息。因此客户端往往需要通过轮询或长轮询的方式,定期向服务器查询是否有新的全服公告。 但是websocket就简单了,因为此时建立连接服务端直接发过来就可以了,非常easy ### 032 权限相关 当我们从app内部进入到这种websocket通信的服务时,如何鉴权呢,app内部的HTTP自行控制就非常简单比如在请求头里面:`Authorization: xxx`,那么websocket呢,主要的其实大概分为下面两种 1. **握手即鉴权** 正常情况下升级成websocket通信,需要有一个握手包,这个握手包用于请求将HTTP连接升级为Websocket连接,大概样子如下,如果升级成功后端会返回101,而我们说的第一种`握手即鉴权`方式,就是在升级包的请求参数或者请求头里面加上认证信息比如下面在请求头里面`Authorization`字段,也可能会是在请求后面接个参数,比如`/ws?token=xxx` ```http GET /ws HTTP/1.1 Host: xxx.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: xxxxx Sec-WebSocket-Version: 13 Authorization: Bearer xxx ``` 2. **连接后鉴权** 这种方式也是非常常见的,握手包里面不包含任何权限信息,等到建立websocket连接,会有一个专门的消息号用于鉴权,比如当建立好websocket连接后,客户端发送如下鉴权消息 ```json { "action":"login", "token":"xxx" } ``` 这种鉴权方式也特别常见,比如游戏、IM网关、推送服务、第三方等,因为他们通常不是一个系统,所以如果采用第一种握手即鉴权方式,那么接入进来的三方服务必须耦合业务的jwt签名算法、耦合用户体系、还要知道业务的jwt秘钥,所以通常这种情况业务直接会为第三方开放一个鉴权解析接口,第三方服务直接调用业务的这个接口就能做到身份校验了 然后在啰嗦一下,像上个消息中`action`这个字段其实可以类比成HTTP里面的路由,因为WebSocket协议本身不提供类似HTTP URL的请求路由机制,所以必须让后端知道你发过来的消息走的是哪个逻辑,除 了上述方式的像action这种声明操作类型的消息路由标识,还有如下用`消息号`进行标识也比较常见 ```json { "msgId":"19", "token":"xxx" } ``` 04 漏洞 ----- ### 041 权限相关 业务最开始也就是跟权限相关的了,所以我们也先从权限相关的问题开始讲解。 另外有必要说一点,后文出现的ws消息表面看都是json格式,但是其实大部分原本都是`protobuf`的,而之所以是json的展示形式是因为我按之前的文章《[利用AI一键开启proto全自动明文时代](https://forum.butian.net/ai_security/90)》进行的自动转化,而我实际遇到ws服务的格式中确实是`protobuf`大于json的 #### 0411 房间游戏PK的任意开启 **业务逻辑:**正常一个房间分成AB两个队伍,除了日常的聊天还有一些其它功能外,有个类似现在短视频平台PK一样的功能,房主一般会气氛到位且人固定好后开始PK(这个`开始PK`操作正常只有房主有权限和功能按钮) ws消息数据: ```json { "direction": "request", "messageNo": 845271, "timestamp": 1780523417623, "userId": "", "data": { "roomId": "3157286", "gDuration": "45" } } ``` **漏洞问题** 这里漏洞思路很简单,既然看到了`roomID`参数,直接用普通用户进入房间(会创建ws连接),然后手动构造发送该消息,房间直接开始PK  #### 0412 越权登录 这个漏洞的逻辑很简单,对应业务是属于上文提到的`连接后鉴权`,也就是wss无参建立,然后发送login相关的ws包进行登录,登录包如下,ws请求信封模式中大概率最外层都带着一个`userID`,但是其实这个userID通常情况下没什么作用,不过看到下面这个登录包的时候,还是眼前一亮,因为多了个`baseInfo`,里面又来了两个userid相关的参数,其中uid就是userid,而userkey就是userid进行base64编码后的值 ```json { "userId": 28641, "accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjI4NjQxLCJyb2xlIjoidXNlciIsImV4cCI6MTgwMDAwMDAwMH0.demo_signature", "baseInfo": { "userKey": "Mjg2NDE=", "uid": "28641" } } ``` 就上方的包其实就可以通过将`uid`和`userkey`改为其他账号ID尝试越权了,然后测试结果也表明确实存在越权漏洞,服务端根据`userKey`作为用户判断依据,我准备两个客户端,客户端B正常登录游戏,然后客户端A正常登录游戏抓包,截取到上述登录包后,将`userKey`改成B的,如下图所示账号B直接提示网络异常重连中  这里因为客户端存在重连机制,所以当我用Burp发送ws的登录消息,客户端会通过重连的方式重发登录包抢夺控制权,所以其实可以通过不断发送ws登录包的方式实现任意账号的`拒绝服务` 同样的既然登录可以越权了,我们可以登录任意账号了,后续再发送其它消息一样也是越权执行,但是因为当前模式是这种ws建立后才发消息鉴权的模型,所以你要执行后面的其它功能,例如`查询金币`那就需要三步 1. 先建立wss 2. 再发送越权登录的消息 3. 再发送查询金币消息 所以其实在Burp中利用起来不是很方便(顺便吐槽一下一开始觉得burp原生对ws支持真的一般,然后我又试了其它安全工具发现还不如burp),所以我特意让AI写了个工具,能够非常方便的满足我在WS服务测试中的一些操作,例如上面那个尝试越权查询账号金币余额,用这个工具就可以很好的执行:建立ws--发送登录消息--查询金币 如下图所示,消息2越权登录成功了,然后查询金币里面的`userID`没用(上文提到一些信封最外层都有userID但是没什么用),直接查询的还是越权登录的28642的  - - - - - - #### 0413 越权操作 正如上面【越权登录】里提到的,我之前遇到很多信封模式消息体最外层基本上都带一个`userID`之类的参数,这个并没什么大作用,不过如果在消息体内部还有类似用户ID相关参数,那可就得注意了,例如下面这个服务的ws消息,几乎所有的操作消息都带一个AES密文 ```json { "msgid": 1005, "seqNo": "21", "action": "faPai", "data": ["U2FsdGVkX1+qFqOha1rJlDEbGH15mbocLQVXycdFiEM="] } ``` 然后这个密文解密就不多说了直接让AI去前端代码找秘钥就完事了,然后解开后发现竟然就是userID  直接将userID改成账号B的,然后越权多次发送这个消息,消息2都是账号A的信息也就是说此处正常登录账号A,而消息3里面为账号B的加密值,最后达到一直给对面发牌达到爆牌的效果  效果如下  - - - - - - 042 并发类 ------- 正所谓`万物皆可并发`,ws也是存在并发的,但是如果想挖掘ws并发漏洞,首先要搞清当前登录鉴权方式以及账号的共存情况,鉴权方式上文提到了,然后说下共存 1. **多连接并存** 顾名思义也就是当你建立多个WS连接,并且多个WS连接都发送鉴权包后,互相不会有什么影响,那这个时候直接构造多个`WS连接-登录消息-功能消息`就可以,例如`领取每日签到金币奖励`这个功能 > 一开始我在尝试并发利用的时候其实想找找有无特别好用的Burp插件之类的,或者其它网络安全相关抓包工具是否能便捷的测试,但是实际上浪费了很长时间并没有找到好用的 像这种情况之前我是用`k6`写脚本测的,但是每次一更换操作实在麻烦,所以在写这个辅助工具的时候也考虑到并发的功能  2. **单会话唯一** 实际上在我遇到的大部分WS通信的服务中,都是这种情况,当一个连接鉴权后,如果此时再来一个ws连接也登录相同账号,那么原来的就被会挤掉,但是这并不代表这个方式就不会存在并发 在实战中遇到过一个虽然也是单会话唯一,但是也利用成了,如下图  这个就有意思当时还是利用Burp里面的插件成功了的,用的是下面这个插件,这个插件其实使用起来场景很受限,首先它默认仅会发两个包,一个是右上边建立ws连接的http请求,另一个就是左上角的ws消息了,所以遇到`连接后发鉴权消息`这种类型的那就完全没用,而且如果你想自定义还是得修改脚本确实也不是很方便,但是上图中为什么还成功了,因为它除了并发还有个大问题那就是`领取每日金币`的这个消息并没有鉴权,仅仅是利用消息体里面的`用户id加密值`来进行指定账号的(所以这个消息存在两个漏洞1越权,2并发)  说完了上面那个特例,其实面对**单会话唯一**这种情况的`并发利用手法`还可以通过建立一个连接然后多次发一个消息来测试,例如下图配置中,先建立ws连接,然后发送鉴权的ws消息,最后工具在同一 WebSocket 连接上,将 10 个签到消息预先封装并拼接,通过单次 socket 发送一并送出,使其尽量落在同一 TCP 段内、几乎同时到达服务端,以此构造并发。  - - - - - - 043 信息泄露相关 ---------- 相较于权限与并发问题,信息泄露类问题在 WebSocket 场景中表现形式相对较弱,但仍存在一定的协议特性相关风险,不过我这里还是举两个例子吧 ### 0431 js造成的泄露 乍一看js造成的泄露,what?,跟ws有毛线的关系,但是正如我文章开头特意强调的,如果你仔细看了,如果你遇到一个app里面H5页面,采用的ws传输,那么此时你会干嘛?没错去找那个zip包,找到那个zip包里面就包含这个服务的相关前端文件了,也就包含js了,所以其实也有点关系 例如下面这个漏洞,这是个答题相关的活动,使用ws通信,然后在我找到zip包并且翻阅了前端js后直接发现了活动所有题库  ### 0432 S\_C消息泄露敏感信息 由于 WebSocket 是双向通信,在实际测试过程中,通常可以利用 Burp 的筛选功能去掉服务端推送的数据帧(S→C)。因为服务端推送消息更多体现为数据展示与业务结果返回,在常规漏洞挖掘中安全价值相对有限,主要可用于辅助排查是否存在敏感信息泄露问题。 如下图所示,当游戏开始的时候服务器直接就返回了全部问题的答案  - - - - - - ### 044 其它逻辑漏洞 其实我都不想写来着,因为上面那些相关安全问题针对WS服务还是有差异可以拿出来说说的,然后在实战过程中遇到的其它逻辑漏洞其实都跟HTTP服务差不多了,不过毕竟都写了这个文章所以干脆下文提一个还算跟ws沾边的业务逻辑漏洞吧 **隐藏技能攻击** 其实这个漏洞也是源于JS的发现,还是我《[利用AI一键开启proto全自动明文时代](https://forum.butian.net/ai_security/90)》这个文章里提到的手法,AI帮忙分析出来的WS消息文档里面存在服务/游戏所有ws消息体和介绍,通过抓包发现这个小游戏的攻击的消息体如下所示 ```json { "msgid": 62280, "action": 1 } ``` 这个小游戏是新出的,初版逻辑也很简单,游戏中对应的动作就三个,弓箭攻击相比于普通攻击伤害更高而且100%成功,而普通攻击伤害相对低一些而且存在一定被闪避几率,然后防御反击可以防御弓箭攻击并做出反击攻击  然后在AI分析出的文档中针对这个消息,还存在一个参数`skill_id`,于是我直接拼接并遍历`skill_id`发现确实存在一些隐藏技能,效果如下,这个漏洞不亚于在冷兵器作战时代让你扛着一个加特林出现了  - - - - - - 05 预告 ----- 本文算是我写的关于WS相关的第二篇文章了,后续我的想法就是进一步让AI全自动进行这种WS的漏洞挖掘,不过时间可能会久一点,因为当前还在做另一个事情,那就是`AI代码审计平台`,做了很久了目前初版已经开始测试了(不过是面向公司内部的),看到这个可能很多师傅有点反感了,确实自从AI热潮来临后,AI代码审计、AI全自动渗透测试各个项目像雨后春笋一样,我实际也用过测试过很多,但是说实话结果都差强人意,甚至说不好听的,有的纯是AI写点思路然后写点代码其余的全靠吹了,不过好的项目也是有的只不过可能都是自己私下用呢。 现在AI的发展中,有个特点那就是想法有,难落地,就算落地效果可能跟预期差了十万八千里,就比如我实际测试过得一些项目,我这个AI代码审计平台着实做了很长时间,而且我是边落地边设计的,也就是说是完全对照着数据确保质量的提升而不断完善的,不过这个AI代码审计平台并不通用,目前仅针对适配我们公司的代码风格以及架构进行不断优化,可能更加适合面向与企业使用,同时已经自动接入到了CI阶段,不过现在还存在一些问题和bug,等到逐步稳定,也会把思路拿出来讲讲
发表于 2026-07-22 09:39:15
阅读 ( 970 )
分类:
渗透测试
1 推荐
收藏
0 条评论
逐影安全
12 篇文章
×
温馨提示
您当前没有「奇安信攻防社区」的账号,注册后可获取更多的使用权限。
×
温馨提示
您当前没有「奇安信攻防社区」的账号,注册后可获取更多的使用权限。
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!