4

JS逆向实战23——某市wss URL加密+请求头+ws收发 - 始識

 11 months ago
source link: https://www.cnblogs.com/zichliang/p/17745739.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

声明

本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!
本文首发链接为: 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 这个请求不确定。

2721529-20231007101655660-2137992230.png

这里我们简单分析一下:

  1. 返回给我们的cookie的 dGg2aCfMMK97Ro270mqBFu5qjC8TQbL2opnHvbEpM 这个的value的值 对应的就是wssURL pr 的后缀
  2. v1/sessions这个请求返回给我们的值是一段加密的值。
  3. 其他的页面均无数据来源。

这里我们大胆猜测一下:这个v1session这个请求返回给我们的值。我们需要解密,解密出来的值,大概率就是这个 dGg2aCfMMK97Ro270mqBFu5qjC8TQbL2opnHvbEpM cookie的值。然后我们提取出来。完成对wss这个URL的拼接。从而请求。当然这些都是猜测。我们再来看看wss请求。

wss协议:

这里只有一个请求。就不搞那些弯弯绕绕了。话不多说 直接看contents里的内容。

2721529-20231007101712969-1844378596.png

从这张图我们可以知道很多

  1. 通过wss传输数据
  2. 数据很乱 肯定也是通过js进行的一些打乱和拼接。
  3. 这个WSS的连接的某个值是通过v1/session的请求的cookie来获得的。

其他的东西。我们还是需要一步一步来。首先需要把v1/sessions 这个请求请求且解密。

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

数据接口分析

v1/session 接口分析

我们直接去网页上找这个sessions栈。

2721529-20231007101725121-1361378259.png

根据我们的经验之谈。前两个请求不是。后面这个anonymous匿名函数值也不是。所以大概率就是这个t.startSession

追栈进去。

2721529-20231007102327387-1436022616.png

这个位置大概率就是加密点。并且还做了一层Json序列化。但这个是v1/session 传值的参数。那就很简单了。这个重点不就是把P的值搞出来。然后调用这个encryptSessions这个方法就行了吗。

首先打断点追进去看看是什么。

2721529-20231007102342734-888702867.png

可以看到 加密了一组名为P的值。这个P我们继续往上看。

2721529-20231007102350954-1741092540.png

可以看到 有些是浏览器的一些值。有一些则是自己封装的值。都在上面连在一起。到时候扣下来就行。但其实经过多次测试。只有这个 tabId:c 这组值 需要封装,其他的值写死即可。

2721529-20231007102405670-1447352485.png

其实可以发现这个文件是个webpack打包的文件。这个tabId赋值给了加载器函数,调用了其他的函数。那我们直接搜索这个tabId就好啦

2721529-20231007102413761-1266663474.png

我们找到了生成的这个值。可是这个值其实是找不到生成的位置的。但其实纵观全局。这个tabId是有很多相等的值。所以我们改写一下

function get_tabID() { return Math.random().toString(36).slice(-10)}

这样 tabId的值就出来了。

当然这只是第一步。后续把encryptSessions这个函数扣出来了。

当然 分析到这里还不算难。后续就是把如何把这个东西扣代码扣出来

wss接口请求分析

其实我们最主要的目的还是获取这个wss的连接。那我们就简单来看看这个wss连接是如何生成的。我们刚刚通过抓包软件已经简单分析了一下。可以通过伪造v1/sessions这个请求来获取cookie 从而填充wss链接。

2721529-20231007102429433-1770143583.png

老规矩 进堆栈>>>>>>>>

2721529-20231007102435233-1987210279.png

搜索this.channelURL

2721529-20231007102441778-1475755601.png

获取到this.channelURL的生成点。

经过大量测试可知

ws_url = 'ws://www.xxx.xxx/1ywuKELSO2ahQuWZ/pr/' + urlPrefixToken + '/b/ws/' + tabID

而这个urlPrefixToken的生成处如下图

2721529-20231007102450885-616583876.png

urlPrefixToken 也和我们一开始抓包分析的一样。就是通过cookie来生成的。

加密v1/sessions的data

我们进栈点。发现是这个dynamicEncrypt 这个函数生成的加密值。

2721529-20231007102503390-495187905.png

===⇒ 继续

2721529-20231007102507809-1780813614.png

那接下来我们只要封装这个dynamicEncrypt 函数即可。

因为这个是在webpack里面。所以我们扣除加载器。然后缺啥补啥就可以了。

当然。其实全部抠出来 内容很多。而且很麻烦。所以本文使用扣代码去解决。

这里就不讲怎么扣代码了

核心代码请查看原文链接>>>> https://mp.weixin.qq.com/s/o5UCJFhBg-4JFdS0aEwDuw

当然 值得注意的是这个iv。也是需要抠出来的。

2721529-20231007102543305-1448452957.png
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中运行试试。

2721529-20231007102555832-341370765.png

好。经过测试。我们发现请求返回给我们的状态码是500。这是咋回事????

经过我们反复测试。我们发现我们还需要添加上请求头。而请求头里还有一个值

'etag'而这个值恰恰又等于刚刚 AES加密中的IV值。

我们把这个值再添加进去 请求看看。

2721529-20231007102602118-2134199951.png

这样就能请求成功了。

在上文分析。我们可知。获取内容不是我们所需要的。我们真正需要的>>>>>>>> 获取cookie

我们获取这个cookie的value。然后拼接URL。

核心代码请查看原文链接>>>> https://mp.weixin.qq.com/s/o5UCJFhBg-4JFdS0aEwDuw

请求WSS连接

这里有两种方式

  1. 通过Python 模拟连接websocket 请求
    1. 缺点:后续需要手动解码。兼容性不好
    2. 优点:高效快速。
  2. 通过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)

结果>>>>>>

2721529-20231007102633742-442993222.png

这得到的是啥呀? 一堆乱码。

但是这也很简单判断。wss一般传输的数据就两种,文本和二进制数据

这个很明显是二进制数据。而这个是通过Message pack的方式去压缩的。再通过Message pack的方式去解包就行了。

这里简单介绍下什么是Message pack:

MessagePack是一种有效的二进制序列化格式。它使您可以在多种语言(如JSON)之间交换数据。但是它更快,更小。小整数被编码为一个字节,典型的短字符串除字符串本身外仅需要一个额外的字节。简单来讲,它的数据格式与json类似,但是在存储时对数字、多字节字符、数组等都做了很多优化,减少了无用的字符,二进制格式,也保证不用字符化带来额外的存储空间的增加。

官网: MessagePack: It's like JSON. but fast and small. (msgpack.org)

github:https://github.com/msgpack/

官网有示例代码。直接使用即可。下面贴一个本人用的方式

import msgpack def on_message(ws, message): import ormsgpack print(ormsgpack.unpackb(message))

然后我们去慢慢提取。

2721529-20231007102649397-275815157.png

然后发现可以成功提取。

但是这个请求中。标题和时间倒还比较好获取。

但是详情页的连接。好像还并没有发给我们。

获取详情页链接

我们继续去看wss的这个连接。

发现我们每次点进详情页。我们会向服务器发送一个请求。

2721529-20231007102238708-1840757674.png
2721529-20231007102247865-2033523054.png

然后服务器会再吐一个连接给我们。

并且详情页内容也是wss传给我们的。

说实话真的很麻烦>>>>>>>>>个人建议还是用其他方式去获取吧。本文只做研究。

2721529-20231007102659535-434382165.png

本文首发链接为: https://mp.weixin.qq.com/s/o5UCJFhBg-4JFdS0aEwDuw


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK