24_某市wss URL加密+请求头+ws收发

Date
Dec 7, 2023
Created
Mar 2, 2024 03:07 PM
Tags
JS逆向实战

声明

本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! 本文首发链接为: https://mp.weixin.qq.com/s/o5UCJFhBg-4JFdS0aEwDuw

前言

在此前。我们先来了解下什么是webscoket?什么是wss?什么是ws?
WebSocket协议是html5的一种通信协议,该协议兼容我们常用的浏览器。例如Chrome、 Firefox、IE等。 它可以使客户端和服务端双向数据传输更加简单快捷,并且在TCP连接进行一次握手后,就可以持久性连接,同时允许服务端对客户端推送数据。 外加传统模式的协议一般HTTP请求可能会包含较长的头部,但真正有效的可能只有小部分,从而就占用了很多资源和带宽。因此WebSocket协议不仅可以实时通讯,支持扩展;也可以压缩节省服务器资源和带宽。
WS协议和WSS协议两个均是WebSocket协议的SCHEM,两者一个是非安全的,一个是安全的。也是统一的资源标志符。就好比HTTP协议和HTTPS协议的差别。非安全的没有证书,安全的需要SSL证书。 (SSL是Netscape所研发,用来保障网络中数据传输的安全性,主要是运用数据加密的技术,能够避免数据在传输过程被不被窃取或者监听。) 其中WSS表示在TLS之上的WebSocket。WS一般默认是80端口,而WSS默认是443端口,大多数网站用的就是80和433端口。 (在高防防护过程中,80和433端口的网站是需要备案才可以接入国内的。)当然网站也会有别的端口,这种如果做高防是方案是可以用海外高防的。 WS和WSS的体现形式分别是TCP+WS AS WS ,TCP+TLS+WS AS WS。服务器网址就是 URL。

目标网站

aHR0cDovL3d3dy5sdXhpLmdvdi5jbi9jb2wvY29sNDQ0NC9pbmRleC5odG1s

抓包分析

我们掏出我们的抓包工具看看。我们这里选择charles去抓包。
这里吐出了两个数据包,一个是https协议的,一个是wss协议的。
https协议:
每个都看了 其他的请求都没用。只有这个v1 这个请求不确定。
notion image
这里我们简单分析一下:
  1. 返回给我们的cookie的 dGg2aCfMMK97Ro270mqBFu5qjC8TQbL2opnHvbEpM 这个的value的值 对应的就是wssURL pr 的后缀
  1. v1/sessions这个请求返回给我们的值是一段加密的值。
  1. 其他的页面均无数据来源。
这里我们大胆猜测一下:这个v1session这个请求返回给我们的值。 我们需要解密,解密出来的值,大概率就是这个 dGg2aCfMMK97Ro270mqBFu5qjC8TQbL2opnHvbEpM cookie的值。 然后我们提取出来。完成对wss这个URL的拼接。从而请求。当然这些都是猜测。我们再来看看wss请求。
wss协议:
这里只有一个请求。就不搞那些弯弯绕绕了。话不多说 直接看contents里的内容。
notion image
从这张图我们可以知道很多
  1. 通过wss传输数据
  1. 数据很乱 肯定也是通过js进行的一些打乱和拼接。
  1. 这个WSS的连接的某个值是通过v1/session的请求的cookie来获得的。
其他的东西。我们还是需要一步一步来。首先需要把v1/sessions 这个请求请求且解密。

目的

  1. 获取wss连接(伪造并且获取v1/sessions请求中的cookies)
  1. wss 数据的解码

数据接口分析

v1/session 接口分析

我们直接去网页上找这个sessions栈。
notion image
根据我们的经验之谈。前两个请求不是。后面这个anonymous匿名函数值也不是。所以大概率就是这个t.startSession
追栈进去。
notion image
这个位置大概率就是加密点。并且还做了一层Json序列化。但这个是v1/session 传值的参数。那就很简单了。 这个重点不就是把P的值搞出来。然后调用这个encryptSessions这个方法就行了吗。
首先打断点追进去看看是什么。
notion image
可以看到 加密了一组名为P的值。这个P我们继续往上看。
notion image
可以看到 有些是浏览器的一些值。有一些则是自己封装的值。都在上面连在一起。到时候扣下来就行。 但其实经过多次测试。只有这个 tabId:c 这组值 需要封装,其他的值写死即可。
notion image
其实可以发现这个文件是个webpack打包的文件。这个tabId赋值给了加载器函数,调用了其他的函数。那我们直接搜索这个tabId就好啦
notion image
我们找到了生成的这个值。可是这个值其实是找不到生成的位置的。但其实纵观全局。这个tabId是有很多相等的值。所以我们改写一下
function get_tabID() { return Math.random().toString(36).slice(-10) }
这样 tabId的值就出来了。
当然这只是第一步。后续把encryptSessions这个函数扣出来了。
当然 分析到这里还不算难。后续就是把如何把这个东西扣代码扣出来

wss接口请求分析

其实我们最主要的目的还是获取这个wss的连接。那我们就简单来看看这个wss连接是如何生成的。 我们刚刚通过抓包软件已经简单分析了一下。可以通过伪造v1/sessions这个请求来获取cookie 从而填充wss链接。
notion image
老规矩 进堆栈>>>>>>>>
notion image
搜索this.channelURL
notion image
获取到this.channelURL的生成点。
经过大量测试可知
ws_url = 'ws://www.xxx.xxx/1ywuKELSO2ahQuWZ/pr/' + urlPrefixToken + '/b/ws/' + tabID
而这个urlPrefixToken的生成处如下图
notion image
urlPrefixToken 也和我们一开始抓包分析的一样。就是通过cookie来生成的。

加密v1/sessions的data

我们进栈点。发现是这个dynamicEncrypt 这个函数生成的加密值。
notion image
===⇒ 继续
notion image
那接下来我们只要封装这个dynamicEncrypt 函数即可。
因为这个是在webpack里面。所以我们扣除加载器。然后缺啥补啥就可以了。
当然。其实全部抠出来 内容很多。而且很麻烦。所以本文使用扣代码去解决。
这里就不讲怎么扣代码了
核心代码请查看原文链接>>>> https://mp.weixin.qq.com/s/o5UCJFhBg-4JFdS0aEwDuw
当然 值得注意的是这个iv。也是需要抠出来的。
notion image
function get_iv() { var t = Math.random().toString(36).slice(-8) + "-" + Math.random().toString(36).slice(-8) + (new Date).getTime() , e = dynamicEncrypt(t, l, u).replace("_", ""); return e.substring(1, 17) }
上文提到的tabId 我们也重新封装成一个函数
function get_tabID() { return Math.random().toString(36).slice(-10) }

获取cookie

当然。我们废那么打力气去伪造这个请求。不是获取这里面的数据的。而是为了拿到请求v1/sessions中的cookie的。 因为在第一段我们就分析了。wss的有一部分值是可以通过v1/sessions中的cookie拿到的。
我们带入python中运行试试。
notion image
好。经过测试。我们发现请求返回给我们的状态码是500。这是咋回事????
经过我们反复测试。我们发现我们还需要添加上请求头。而请求头里还有一个值
'etag'而这个值恰恰又等于刚刚 AES加密中的IV值。
我们把这个值再添加进去 请求看看。
notion image
这样就能请求成功了。
在上文分析。我们可知。获取内容不是我们所需要的。我们真正需要的>>>>>>>> 获取cookie
我们获取这个cookie的value。然后拼接URL。
核心代码请查看原文链接>>>> https://mp.weixin.qq.com/s/o5UCJFhBg-4JFdS0aEwDuw

请求WSS连接

这里有两种方式
  1. 通过Python 模拟连接websocket 请求
    1. 缺点:后续需要手动解码。兼容性不好
    2. 优点:高效快速。
  1. 通过JS 连接webscoket
    1. 缺点:不好调用。需要手动扣代码
    2. 兼容性很好。得到的数据也比较完整。
这里我选择用Python 模拟连接。因为 扣代码的方式我试过。速度有点慢。而且好像也不太对的样子。
这里贴下连接webscoket的代码
ws = websocket.WebSocketApp(ws_url,on_message=on_message, ) ws.run_forever() def on_message(ws, message): print(message)
结果>>>>>>
notion image
这得到的是啥呀? 一堆乱码。
但是这也很简单判断。wss一般传输的数据就两种,文本和二进制数据
这个很明显是二进制数据。而这个是通过Message pack的方式去压缩的。再通过Message pack的方式去解包就行了。
这里简单介绍下什么是Message pack:
MessagePack是一种有效的二进制序列化格式。它使您可以在多种语言(如JSON)之间交换数据。 但是它更快,更小。小整数被编码为一个字节,典型的短字符串除字符串本身外仅需要一个额外的字节。 简单来讲,它的数据格式与json类似,但是在存储时对数字、多字节字符、数组等都做了很多优化, 减少了无用的字符,二进制格式,也保证不用字符化带来额外的存储空间的增加。
官网有示例代码。直接使用即可。下面贴一个本人用的方式
import msgpack def on_message(ws, message): import ormsgpack print(ormsgpack.unpackb(message))
然后我们去慢慢提取。
notion image
然后发现可以成功提取。
但是这个请求中。标题和时间倒还比较好获取。
但是详情页的连接。好像还并没有发给我们。

获取详情页链接

我们继续去看wss的这个连接。
发现我们每次点进详情页。我们会向服务器发送一个请求。
notion image
notion image
然后服务器会再吐一个连接给我们。
并且详情页内容也是wss传给我们的。
说实话真的很麻烦 个人建议还是用其他方式去获取吧。本文只做研究。
notion image