记一次APP加密数据包的解密过程与思路

华盟原创文章投稿奖励计划

0x01 前言

针对一次app加密数据包的分析和解密,简单提供下在js中寻找加密方法的思路。

0x02 过程

前几天朋友给我发来个app让我看下

app中的数据包进行了加密,而且还有WAF 动不动就会封IP

这有啥搞得 没啥搞得

自动草稿

虽然返回包加密了,但是请求包没加密,想看看能不能修改请求包做一些其他的操作,但是发现他竟然对请求包的内容进行了验签,更改请求包中的任意值都会提示签名失败

自动草稿

好了,那这下没得搞了,app也找不到js文件,不知道使用了什么加密方式,对称还好些,非对称直接g

到这我基本已经放弃了

过了几天闲来无事,又想看看这个app,实在不行直接反编译app试试

反编译好像有点费劲,去hunter看看能不能搜到什么东西吧

突然就在hunter发现了一个pc.xxxxx.com的子域名,打开一看,哎,这不是网页端吗

自动草稿

但是这个网页端登录还需要开网页端的会员,我的账号登录不上去

网站还对F12做了限制,无法使用F12,如果打开F12去访问网页,网页直接关闭,有点意思,看来还是做了一些防护的

看看burp吧,突然发现一个标绿的js文件自动草稿

把js文件复制下来,格式化一下,按照常规的思路,找一下有没有解密函数或者key什么的,这5w多行的代码找起来是有点费劲,直接搜索关键词吧

嘿  您猜我发现了什么

竟然把key和iv直接写在了js文件中

使用AES,CBC模式,Pkcs7进行加密

自动草稿

既然这样,那这个加密方式是不是和app一样的呢,本着代码能Ctrl+C绝对不重新写的原则,我猜是一样的

把app加密后的数据包丢进来解密一下,发现可以解密成功

自动草稿

这不就成了吗

返回包加密的难题解决了

那请求包签名校验应该怎么办,理论上来说js文件中应该有相应的签名校验的方法

请求包的内容如下:

phoneType=xxx&appVersion=xxx&apiVersion=xxx&phoneSystem=xxx&netType=xxx&channel=xxx&sign=xxx&deviceId=xxx&platform=xxx&timestamp=xxx&token=xxx

虽然参数中有时间戳,但是同一个数据包可以重放多次,意味着没有对时间戳进行校验,也就是这个时间戳可以一直用

参数中的sgin值应该就是签名值,猜测是个MD5,但是这个值怎么来的呢,只能继续寻找js文件

继续发现了这样的一段js

自动草稿

好嘛,t是盐值,把请求的参数以xxx=xxx拼接,然后用&连接成字符串,然后连接成的字符串加上t这个盐值,进行一下MD5,最后就是签名值

但是这里一开始代码Object.keys(e).sort()获取对象e的所有键,并按字典顺序排序,这个排序方式是怎么排序的没弄明白,一开始的时候写了个脚本把参数值各种排序方式的md5给爆破了一遍,发现是通过开头字母顺序进行排序的,其实直接去查这个函数也可以,就是通过首字母进行排序

自动草稿

那么既然知道了签名生成的方式,可以直接写个脚本,生成对应的签名值,

import hashlib def generate_md5_signature(params, salt):     sorted_params = sorted(params.items())
    raw_string = "&".join(f"{k}={v}" for k, v in sorted_params) + salt
    # print(raw_string)     return hashlib.md5(raw_string.encode()).hexdigest() def update_request(salt):     # 参数列表     params = {
        "phoneType""xxx",
        "appVersion""xxx",
        "apiVersion""xxx",
        "phoneSystem""xxx",
        "netType""xxx",
        "channel""xxx",
        "deviceId""xxx",
        "platform""xxx",
        "timestamp""xxx",
        "token""xxx"     }
    # 计算新的签名     new_sign = generate_md5_signature(params, salt)
    # 按照指定顺序输出     output_order = [
        "phoneType""appVersion""apiVersion""phoneSystem""netType",
        "channel""sign""deviceId""platform""timestamp""token"     ]
    # 构建输出字符串     request_string = "&".join(
        f"{key}={new_sign if key == 'sign' else params[key]}"         for key in output_order
    )
    return request_string
salt = "xxxxx" result = update_request(salt)
print(result)

使用脚本生成的参数请求一下,至此,请求成功~

自动草稿

0x03 总结

这次可能是凑巧app用了对称加密,又凑巧有个网页端,还凑巧把密钥和加密方式写到js中才能够解密数据包,整个过程可能看起来很简单,但是也用了我几天的功夫,同时也给我们提供了一个思路。

站在攻击者的角度来说:在分析加密数据包的过程中,首先要判断加密方式,是对称还是非对称,分析js文件是关键,一般情况下加密的方式都会写在js文件中,如果是对称加密还有的搞,非对称加密基本上是找不到私钥的。

如果是app找不到js文件,可以寻找一下是否有网页端,大概率和app的加密方式相同。

这里可以使用burp的一些插件,这里我用的是UnExInfo,也有其他的很多插件能够检测返回包中的敏感数据进行高亮处理,这样能够帮助我们快速定位到相应的js文件,有些js文件会直接以encrypt命名,如果js代码没有进行格式化不好读,可以使用在线格式化的工具对代码进行格式化,针对可疑的js文件可以搜索关键词key、encrypt、decrypt等,以我的经验来看搜索decrypt解密函数更容易找到相应的密钥信息。

站在开发者的角度来说:加密的方式如果使用对称加密方式,要使用密钥交换算法进行密钥传输,或者在js中对密钥进行混淆,增加被逆向的难度。当然也可以直接使用非对称的加密算法,相对来说安全性更高。

文章来源:Tide安全团队

黑白之道发布、转载的文章中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途及盈利等目的,否则后果自行承担!

如侵权请私聊我们删文


END

本文来源Tide安全团队,经授权后由华盟君发布,观点不代表华盟网的立场,转载请联系原作者。

发表回复