记某次加解密测试

admin 2025年6月13日12:33:12评论27 views字数 5609阅读18分41秒阅读模式

记某次加解密测试

记某次加解密测试

起因

测试时遇到了一个流量加密的系统,而加解密这块弄的比较少,所以记录下这次加解密的流程,该系统的加密流量如下:

记某次加解密测试

JsRpc+Galaxy

之前逛github的时候就看到过Galaxy这个插件,但一直没用过,就想着用着试试,同时找到了下面这篇参考文章:

JsRpc+Galaxy 实现网站HTTP报文自动加解密+自动更新签名

https://xz.aliyun.com/t/15252?time__1311=GqjxnD0GitMDlhzG7DyDI2DfxuxRiQOioD

简单说就是Galaxy实现了4个hook,分别是请求从浏览器到burp时解密,burp再将请求发送给服务端时加密,服务端返回到burp时解密,burp再将返回发送到浏览器时加密,详细的使用方式见如下地址:

https://github.com/outlaws-bai/Galaxy/wiki/%E5%8A%9F%E8%83%BD%E8%AF%A6%E8%A7%A3

记某次加解密测试

而这4个加解密需要我们自己去实现,这里我准备使用的是http的方式,可以使用任何语言实现这4个加解密http服务端,然后加解密时Galaxy会与这个http服务端进行通信,作者也有python实现好的一些加解密服务端可以直接使用,也可以根据实际情况修改再用:

https://github.com/outlaws-bai/GalaxyHttpHooker

记某次加解密测试

JsRpc简单说就是将浏览器和本地服务端建立一个WebScoket连接,然后就可以直接在本地执行浏览器中加载的js函数,比如加解密函数,所以配合Galaxy可以达到一些意想不到的效果,详细使用方式见如下地址:

https://github.com/jxhczhl/JsRpc

记某次加解密测试

加解密实现

首先需要定位到加解密的js,首先是加密流程,简单看下,采用了三段式加密SM3+SM4+SM2:

记某次加解密测试

解密流程则是传入服务端返回的密文和key,对密文进行截取后进行sm4解密:

记某次加解密测试

更详细的流程其实可以不用分析,因为这些函数都可以使用jsrpc去调用,然后就是尝试在浏览器控制台连接jsrpc本地启动的服务端,我在物理机上测试了一下是可以连接上的:

记某次加解密测试
记某次加解密测试

但由于目标系统需要使用ie加载一些控件,所以就用windows虚拟机测试了一下,发现连不上了,从报错信息来看是需要wss,后面配置了一下还是不太行就没深入研究了:

记某次加解密测试

于是想了另外一个方法,把加解密的js复制下来,在本地浏览器控制台运行下,然后再连接jsrpc就行了,如下在本地控制台运行js后可直接调用加解密函数:

记某次加解密测试

但这样还有一个问题,虽然可以调用加解密函数了,但key是由客户端随机生成的,这里无法和jsrpc建立连接就获取不到,然后就想到可以将传入key的那个js截断,然后修改成固定的key,如下每次客户端加密数据时的key都将会是111...,同时只要不关闭页面这个js都会一直生效:

记某次加解密测试

现在加解密函数能调用,key固定,就可以开始实现Galaxy的4个加解密hook了,首先是客户端到burp的解密,返回继续看下客户端加密流程,三部分,第一部分传入明文data和key,然后将data转换成byte,M1将其位数填充到16的整数倍后赋值给m1,m2为M2随机生成一段16位的byte,然后M3将m1和m2进行异或后再将m2拼接在最后赋值给m,最后使用sm4加密m,第二部分为sm2加密key用于服务端解密,第三部分为sm3加密明文、key和盐用于验签,然后将三部分拼接起来发送给服务端:

记某次加解密测试

很明显这里我们要获取到明文只需要用到第一部分就行了,对应的解密流程如下,在浏览器控制台注册对应解密函数如下:

demo.regAction("test1"function (resolve,param) {    //传入密文中sm4加密部分,进行sm4解密    var m = _Sm4.crypt(Code.hexStr2bytes(param),Code.str2bytes("11111111111111111111111111111111"),0);    //截取最后16位         var m2 = m.slice(Math.max(m.length - 160));    //截取m最后16位前和m2进行异或得到明文byte       var m1 = M3(m.slice(0,m.length - 16),m2);//这里由于编码问题,返回16进制字符串    resolve(Code.bytes2hexStr(m1));})
记某次加解密测试

可直接在浏览器访问url传入密文进行测试,获取16进制字符串转换成字符后即可获取明文:

记某次加解密测试

记某次加解密测试

galaxy对应的hook如下:

@app.post("/hookRequestToBurp", response_model=RequestModel)async def hookRequestToBurp(request: RequestModel):    """HTTP请求从客户端到达Burp时被调用。在此处完成请求解密的代码就可以在Burp中看到明文的请求报文。"""    method = request.get_method()    #仅处理post请求    if method == 'POST':        #获取原始密文        cryptedData = request.get_content().decode('utf-8')        #仅处理#10开头请求        if cryptedData[:3] == '#10':            #截取原始密文中sm4密文部分            start = cryptedData.find('u001d') + len('u001d')            end = cryptedData.find('u001d', start)            body = cryptedData[start:end]            #传入sm4密文到jsrpc进行解密            jsrpcUrl = "http://127.0.0.1:12080/go?group=zzz&action=test1&param=" + body            res = requests.get(jsrpcUrl)            #获取16进制明文            data = res.json()["data"]            #删除加密时M1填充的乱码            last_227d_index = data.rfind('227D')            #十六进制转换成byte传入请求体,在burp中显示明文            bytes_obj = bytes.fromhex(data[:last_227d_index + 4])            request.set_content(bytes_obj)            return request        else:            return request    else:        return request

实现的效果如下,当请求从浏览器到burp时调用上面的解密hook进行解密,然后会增加一个X-Galaxy-Http-Hook: HookedRequest请求头:

记某次加解密测试

然后就是加密,当我们修改了明文数据时,需要进行重新加密再发送给服务端,加密就很简单了,直接调用加密函数传入明文和key即可,如下在浏览器控制台注册对应解密函数:

demo.regAction("test2"function (resolve,param) {    //加密    var enbody = me.encrypt(param, "11111111111111111111111111111111")    resolve(enbody);})
记某次加解密测试

同样的可直接通过url调用进行加密:

记某次加解密测试

galaxy对应hook如下:

@app.post("/hookRequestToServer", response_model=RequestModel)async def hookRequestToServer(request: RequestModel):    """HTTP请求从Burp将要发送到Server时被调用。在此处完成请求加密的代码就可以将加密后的请求报文发送到Server。"""    #获取明文    decryptedData = request.get_content().decode('utf-8')    #传入明文到jsrpc进行加密    jsrpcUrl = "http://127.0.0.1:12080/go?group=zzz&action=test2&param=" + decryptedData    res = requests.get(jsrpcUrl)    #获取密文    data = res.json()["data"]    #设置密文为请求体发送给服务端    request.set_content(data.encode("utf-8"))    return request@app.post("/hookRequestToServer", response_model=RequestModel)async def hookRequestToServer(request: RequestModel):    """HTTP请求从Burp将要发送到Server时被调用。在此处完成请求加密的代码就可以将加密后的请求报文发送到Server。"""    #获取明文    decryptedData = request.get_content().decode('utf-8')    #传入明文到jsrpc进行加密    jsrpcUrl = "http://127.0.0.1:12080/go?group=zzz&action=test2&param=" + decryptedData    res = requests.get(jsrpcUrl)    #获取密文    data = res.json()["data"]    #设置密文为请求体发送给服务端    request.set_content(data.encode("utf-8"))    return request

实现效果如下,可通过右键进行加密测试功能是否正常,正常情况下有X-Galaxy-Http-Hook: HookedRequest请求头的请求包会自动进行加密:

记某次加解密测试
记某次加解密测试

然后是服务端返回的信息进行解密,也很简单直接调用解密函数,如下在浏览器控制台注册对应解密函数:

demo.regAction("test3"function (resolve,param) {    //这样添加了一个param参数,http接口带上它,这里就能获得    //解密    var debody = me.decrypt(param, "11111111111111111111111111111111")    resolve(debody);})

同样的可直接通过url调用进行解密:

记某次加解密测试

galaxy对应hook如下:

async def hookResponseToBurp(response: ResponseModel):    """HTTP响应从Server到达Burp时被调用。在此处完成响应解密的代码就可以在Burp中看到明文的响应报文。"""    #获取服务端返回密文    encryptedData = response.get_content()    #传入密文到jsrpc进行解密    url = "http://127.0.0.1:12080/go?group=zzz&action=test3&param="    jsrpcUrl = url + encryptedData.decode('utf-8')    res = requests.get(jsrpcUrl)    #获取明文    data = res.json()["data"]    #将明文和密文同时传入返回体,在burp中显示明文和密文    response.set_content(data.encode("utf-8") + "nenbody=".encode("utf-8") + encryptedData)return response

实现的效果如下:

记某次加解密测试

可以发现上面返回包中除了明文还有原本的密文,是为了方便实现最后一个加密hook,由于目标系统基本没有需要修改返回包的情况,所以为了方便就不需要重新加密了,直接返回原本的密文即可,可根据实际情况确定是否需要实现加密:

@app.post("/hookResponseToClient", response_model=ResponseModel)async def hookResponseToClient(response: ResponseModel):    """HTTP响应从Burp将要发送到Client时被调用。在此处完成响应加密的代码就可以将加密后的响应报文返回给Client。"""    #获取返回体    decryptedData = response.get_content().decode('utf-8')    #获取返回体中的密文    endata = re.search(r'(?<=enbody=).+', decryptedData).group(0)    #设置返回体为原本的密文,发送给客户端    response.set_content(endata.encode("utf-8"))return response

实现的效果如下:

记某次加解密测试

最后访问系统,burp中的明文流量如下,后面就可以开始进行测试了:

记某次加解密测试

监制丨船长、铁子

策划丨Cupid

美工丨molin

原文始发于微信公众号(千寻安服):记某次加解密测试

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年6月13日12:33:12
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   记某次加解密测试https://cn-sec.com/archives/4161379.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息