yakit调用jsRpc加解密,免去抠代码补环境

admin 2025-12-29 00:58:15 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文介绍利用Yakit结合JsRpc实现前端加解密自动化,免除抠代码补环境。详细阐述了配置JsRpc服务器、编写Yakit插件及浏览器注入脚本的步骤,并演示通过WebFuzzer热加载功能对加密参数进行自动化爆破,提供了实战代码示例与解决方案,提升渗透测试效率。 综合评分: 91 文章分类: 渗透测试,WEB安全,安全工具,实战经验


cover_image

yakit 调用jsRpc加解密,免去抠代码补环境

原创

进击的hack

进击的HACK

2025年4月3日 07:50 江苏


声明:文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途给予盈利等目的,否则后果自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!


字数 1567,阅读大约需 8 分钟

前言

这个之前我也介绍过burpsuite的。 前端加密对抗练习靶场 encrypt-labs 正好最近在研究yakit,重新写一份用yakit的。

JsRpc

远程调用(rpc)浏览器方法,免去抠代码补环境。

项目地址

  • • 项目地址:https://github.com/jxhczhl/JsRpc

基本介绍

运行服务器程序和js脚本 即可让它们通信,实现调用接口执行js获取想要的值(加解密)

原理:在网站的控制台新建一个WebScoket客户端链接到服务器通信,调用服务器的接口 服务器会发送信息给客户端 客户端接收到要执行的方法执行完js代码后把获得想要的内容发回给服务器 服务器接收到后再显示出来

说明:本方法可以https证书且支持wss

基本使用方法

releases 下载编译好的文件,我是Windows,下载amd exe的,命名为jsrpc.exe。

下载 config.yaml 放置在jsrpc.exe同目录下

  • • https://github.com/jxhczhl/JsRpc/blob/main/config.yaml
BasicListen: "0.0.0.0:12080" # 不想暴露公网/局域网可改成127.0.0.1:port
HttpsServices:
  IsEnable: false # 是否启用https/wss服务
  HttpsListen: "0.0.0.0:12443"
  PemPath: "hl98.cn.pem"
  KeyPath: "hl98.cn.key"

DefaultTimeOut: 30 # 当执行端没有返回值时,等待%d秒返回超时
CloseLog: false # 关闭一些日志
CloseWebLog: false # 关闭Web服务访问的日志
Mode: release  # release:发布版本   debug:调试版   test:测试版本
Cors: false    # 是否开启CorsMiddleWare中间件--默认不开启

运行 jsrpc.exe

yakit插件 JsRPC解密

yakit 调用插件,有一个非常好的地方,那就是即写即用,不像burpsuite编写插件,需要额外的环境。

我们看一下JsRPC解密插件

handle = func(origin /*string*/) {
    //JSrpc的group,默认的
    group = "zzz";
    //jsrpc的action
    action = "decrypt";
    rsp,rep = poc.Post("http://127.0.0.1:12080/go",poc.replaceBody("group="+group+"&action="+action+"&param="+codec.EncodeUrl(origin), false),poc.appendHeader("content-type", "application/x-www-form-urlencoded"))~

    return json.loads(rsp.GetBody())["data"];
}

我们需要在意的点是

  • • group jsRpc配置的组,不过zzz是默认的,可以不修改
  • • action = “decrypt”; 这个需要和后续在浏览器中注入的action对应

顺带一提,上述代码在传递js时会报错,它没把json很好处理

我们重新修改一下脚本,将json转成字符串

handle = func(origin /*string*/) {
    //JSrpc的group
    group = "zzz";
    //jsrpc的action
    action = "decrypt";

    if (origin[0] == "{" && origin[-1] == "}"){
        rsp,rep = poc.Post("http://127.0.0.1:12080/go",poc.replaceBody("group="+group+"&action="+action+"&param="+json.dumps(origin), false),poc.appendHeader("content-type", "application/x-www-form-urlencoded"))~
        return json.loads(rsp.GetBody())["data"];
    } else{
        rsp,rep = poc.Post("http://127.0.0.1:12080/go",poc.replaceBody("group="+group+"&action="+action+"&param="+codec.EncodeUrl(origin), false),poc.appendHeader("content-type", "application/x-www-form-urlencoded"))~
        return json.loads(rsp.GetBody())["data"];
    }

}

OK

插件注意这两项

案例 encrypt靶场

项目地址:https://github.com/SwagXz/encrypt-labs

docker搭建:https://github.com/Ta0ing/encrypt-labs-docker/tree/main 默认密码:admin/123456

AES 固定 key

输入账号密码,选择第一个AES 固定 key

查看请求返回包

如果账号密码正确,后端会返回true

操作步骤

注入 JsEnv_Dev.js https://github.com/jxhczhl/JsRpc/blob/main/resouces/JsEnv_Dev.js

打开JsEnv 复制粘贴到网站控制台(注意:可以在浏览器开启的时候就先注入环境,不要在调试断点时候注入)

如果浏览器出现下面的警告,手动输入 allow pasting ,不能复制

不报错,说明注入成功

下断点调试,定位加解密位置 发现

下断点调试,是不是经过这里

找到加密点,传入的参数是json转的字符串

注入环境后连接通信 注意先关闭调试,取消断点

var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=zzz");

编写加密代码 分析加密函数的输入点和输出点,编写代码,在console控制台输入下面代码

function _0x2fe90c(_0x1d8ccd, _0x579d33) {
        return _0x4f79d5(_0x1d8ccd - -0x6d, _0x579d33);
    }
function _0x4f79d5(_0x8e93b8, _0x5e1416) {
    return _0x30d2(_0x8e93b8 - 0x26, _0x5e1416);
}
function _0x30d2(_0xb85c4e, _0xd19a71) {
    const _0x30d2f4 = _0xd19a();
    return _0x30d2 = function(_0x37ab03, _0x251c3f) {
        _0x37ab03 = _0x37ab03 - 0x156;
        let _0x362566 = _0x30d2f4[_0x37ab03];
        return _0x362566;
    }
    ,
    _0x30d2(_0xb85c4e, _0xd19a71);
}

function encrypts_aes(data){
    const _0x67b862 = CryptoJS['enc']['Utf8']['parse']('1234567890123456')
      , _0x2d9cd5 = CryptoJS['enc'][_0x2fe90c(0x118, 0x11a)]['parse']('1234567890123456')
      , _0x1375d7 = CryptoJS['AES'][_0x2fe90c(0x119, 0x11c)](data, _0x67b862, {
        'iv': _0x2d9cd5,
        'mode': CryptoJS[_0x2fe90c(0x11a, 0x11b)]['CBC'],
        'padding': CryptoJS[_0x2fe90c(0x11b, 0x11e)][_0x2fe90c(0x11c, 0x12c)]
    })[_0x2fe90c(0x11d, 0x10e)]()
    return _0x1375d7;

}

因为这次环境是混淆,缺少什么函数,就在console控制台输入指定函数

测试函数能否成功执行:

带参获取值

//写一个传入字符串,返回base64值的接口(调用内置函数btoa)
demo.regAction("decrypt", function (resolve,param) {
    //这样添加了一个param参数,http接口带上它,这里就能获得
    var base666 = encrypts_aes(param)
    resolve(base666);
})
  • • action的字符串”decrypt”和yakit上的对应

yakit jsRpc加密尝试 右边——》插件扩展——》jsRpc

复制右侧的字符串

后端正常返回,说明后端解密成功

yakit webfuzzer 热加载

如果只是右键加密,不符合我们的需要,我们想要在burpsuite中autodecoder插件一样的效果。 在webfuzzer中的encryptedData中输入明文,yakit自动加密,然后发送到后端

我们可以使用热加载功能 关闭禁用热加载选项(默认关闭)

本次案例,只涉及修改请求,不涉及修改响应,所以只需关注beforeRequest

// beforeRequest 允许在每次发送数据包前对请求做最后的处理,定义为 func(https bool, originReq []byte, req []byte) []byte
// https 请求是否为https请求
// originReq 原始请求
// req 请求
beforeRequest = func(https, originReq, req) {
    // 我们可以将请求进行一定的修改
    /*
    一个替换请求参数a的例子
    poc.ReplaceHTTPPacketQueryParam(req, "a", "bbb")
    */
    // 将修改后的请求返回
    return []byte(req)
}

我们将插件中的函数复制到热加载中,命名为jsrpcReq

jsrpcReq = func(origin /*string*/) {
    //JSrpc的group
    group = "zzz";
    //jsrpc的action
    action = "decrypt";

    if (origin[0] == "{"){
        rsp,rep = poc.Post("http://127.0.0.1:12080/go",poc.replaceBody("group="+group+"&action="+action+"&param="+json.dumps(origin), false),poc.appendHeader("content-type", "application/x-www-form-urlencoded"))~
        return json.loads(rsp.GetBody())["data"];
    } else{
        rsp,rep = poc.Post("http://127.0.0.1:12080/go",poc.replaceBody("group="+group+"&action="+action+"&param="+codec.EncodeUrl(origin), false),poc.appendHeader("content-type", "application/x-www-form-urlencoded"))~
        return json.loads(rsp.GetBody())["data"];
    }

}

// beforeRequest 允许在每次发送数据包前对请求做最后的处理,定义为 func(https bool, originReq []byte, req []byte) []byte
// https 请求是否为https请求
// originReq 原始请求
// req 请求
beforeRequest = func(https, originReq, req) {
    // 我们可以将请求进行一定的修改
    postParams = poc.GetAllHTTPPacketPostParams(req /*type: []byte*/)

    encryptedParam =jsrpcReq(postParams["encryptedData"])
    req = poc.ReplaceHTTPPacketPostParam(req, "encryptedData", encryptedParam)
    // 将修改后的请求返回
    return []byte(req)
}

加密流程

  • • poc.GetAllHTTPPacketPostParams 从传入的req数据包中获取所有Post参数
  • • jsrpcReq 将 encryptedData 的值发送到jsRpc的API中,返回值是加密后的参数值
  • • poc.ReplaceHTTPPacketPostParam 替换req中Post参数名为 encryptedData 的参数值,然后将修改后的数据包返回

保存

发送请求

在请求包中插入fuzz标签,进行密码爆破 注意设置并发线程为1

结果

预告

Yakit的web fuzzer是一个很棒的模块。 后续我会讲一下它的序列功能,它能把多个数据包组合起来,很方便的从上一个响应中拿出需要的变量,并通过热加载修改为我们想要的值,在加解密或者过校验中很有用。 提前预告一下,师傅们可以点个关注哦~


往期推荐

代码审计 | 一次JWT任意用户登录审计

Yakit JWT Token 弱口令枚举

yakit 弱口令爆破与未授权检测

yakit 验证码识别 进行webfuzzer

yakit 安装和初次使用

数据库自动取样工具DataMiner

burpsuite指纹识别插件合集

如何最大限度的利用poc发现漏洞

Slack 安全服务集成化工具平台

unidbg补环境实战


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:进击的HACK 进击的hack《yakit 调用jsRpc加解密,免去抠代码补环境》

评论:0   参与:  0