JsRpc+Yakit热加载实现明文编辑加密发包

admin 2026-01-04 01:48:40 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文介绍了一种结合JsRpc与Yakit热加载技术,绕过前端加密进行渗透测试的方法。通过JsRpc远程调用浏览器中的加密函数,无需还原复杂的运行环境即可生成签名。结合Yakit编写热加载脚本,实现明文参数自动加密发包,大幅提升了对前端加密接口的测试效率与便利性。 综合评分: 83 文章分类: 渗透测试,WEB安全,安全工具,实战经验,逆向分析


cover_image

JsRpc+Yakit热加载实现明文编辑加密发包

逐影安全

只会看监控的实习生

2026年1月2日 08:00 广东

引言

在渗透测试过程中,常常会遇到前端对请求数据进行加密的情况,增加了分析与利用的难度。传统方法通常依赖于 JavaScript 逆向工程,不仅可能需要搭建复杂的运行环境,即使完整提取了加密代码,也难以在本地准确还原加解密逻辑,严重影响测试效率。

为提升效率,本文将介绍一种基于 JsRpc + Yakit 热加载 的实用方法,实现前端明文数据的直接编辑与自动加密发包。通过 JsRpc 的远程方法调用机制,我们无需还原整个运行环境,只需定位加密函数即可调用,从而快速绕过加密层,专注业务逻辑测试。

本文测试环境基于 Yakit 自带靶场,所用工具及项目地址如下: JsRpc 项目地址:https://github.com/jxhczhl/JsRpc

Yakit 项目地址:https://yaklang.com/products/download_and_install/

操作步骤

安装并启动yakit靶场

如下图所示,在抓包过程中可以观察到请求中包含名为 signature 的参数,即请求的签名字段。

如下图所示,通过分析 JavaScript 代码可以确认,签名(signature)是对 username 和 password 两个参数进行加签生成的。

当然,靶场中的 JavaScript 加密逻辑相对简单,但实际测试的整体思路是通用的。本文不重点讲解如何定位加解密函数——在实际渗透过程中,常会遇到动态 key、接口返回参与签名的参数等情况,这些问题通过多构造几次 yak 函数即可应对。

根据 JavaScript 中的加密逻辑,在浏览器控制台手动执行一次加密操作,生成的 signature 与初始抓包结果一致,说明还原无误。

若加解密函数定义在局部作用域中(如某函数内部或模块作用域),在浏览器控制台中可能无法直接访问,此时可通过将函数挂载到 window 对象的方式,提升为全局可调用函数。在当前靶场环境中,加解密函数已位于全局作用域,因此无需额外处理

JsRpc食用

关于JsRpc的详细解释可移步至https://mp.weixin.qq.com/s/vHoVPINf4GKhR36LSQlDXw,小天师傅讲的很详细。

注入JS,构建通信环境(/resouces/JsEnv_De.js

将https://github.com/jxhczhl/JsRpc/blob/main/resouces/JsEnv_Dev.js代码复制到控制台

远程调用: 浏览器预先注册js方法 传递函数名调用

resolve(Encrypt(decoded)); 实际上调用的是 JavaScript 文件中的 Encrypt(word) 函数。

// 注入环境后连接通信
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=Encrypt");
demo.regAction("Encrypt", function (resolve,param) {
var decoded = atob(param);
resolve(Encrypt(decoded));
})

如果目标函数需要传递多个参数,JsRpc 项目中(https://github.com/jxhczhl/JsRpc)提供了“多参数调用”的示例,可供参考。

运行服务端后,控制台会输出日志,并在有客户端连接时显示上线提示信息,方便实时监控调用情况。

通过调用接口并传递参数,可以获取加签后的结果。为了确保参数在传输过程中不被解析异常,建议对其进行 Base64 编码,尤其是在渗透测试过程中频繁修改参数的情况下。如果参数中包含特殊字符,未编码可能导致解析错误或请求失败。

在实际调用中,注入的代码中包含 var decoded = atob(param);,会先对传入的参数进行 Base64 解码,然后将解码后的值传入加签函数进行处理。 http://127.0.0.1:12080/go?group=Encrypt&action=Encrypt&param=dXNlcm5hbWU9YWRtaW4mcGFzc3dvcmQ9YWRtaW4=

yakit webfuzz热加载

yak runner运行调试

我们可以使用 yak 编写一个脚本,用于获取加签后的结果。脚本示例如下:

# port scan plugin
yakit.AutoInitYakit()

handleCheck = func(target,port,word){
    addr = str.HostPort(target, port)
    isTls = str.IsTLSServer(addr)
    packet = `
GET /go?group=Encrypt&action=Encrypt&param={{params(word)}} HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cache-Control: no-cache
Connection: keep-alive
Host: {{params(target)}}

`
    rsp,req,_ = poc.HTTP(packet,
    poc.params({"target":addr,"word":word}),
    poc.https(isTls),
    poc.redirectTimes(0),
    )
    println(req)

if len(rsp) > 0 {
        body = poc.GetHTTPPacketBody(rsp)
        printf("获取加密结果:\n"+string(body))
        jsonObj = json.loads(string(body))
// 获取字段值
        sign = jsonObj["data"]
return sign
    }else{
        println("失败")
    }
return
}

func base_word(name,passwd){
     word = "username=" + name + "&password="+passwd
return codec.EncodeBase64(word)

}
word = base_word("admin","admin")
sign = handleCheck("127.0.0.1",12080,word)
println("\nsign:"+sign)

// signRequest = result => {
//     pairs := result.SplitN("|", 2)
//     dump(pairs)

//     word = base_word(pairs[0], pairs[1])
//     sign = handleCheck("127.0.0.1",12080,word)

//     return sign
// }

经过运行调试,成功获取到加签结果,验证无误。

热加载脚本

热加载和 Yak Runner 仅有细微差别,脚本可直接按照 Yakit 语法编写。主要加密逻辑集中在 signRequest 函数中;如果加密参数需要动态获取,可通过封装多个辅助函数来实现。

# port scan plugin
yakit.AutoInitYakit()

handleCheck = func(target,port,word){
    addr = str.HostPort(target, port)
    isTls = str.IsTLSServer(addr)
    packet = `
GET /go?group=Encrypt&action=Encrypt&param={{params(word)}} HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cache-Control: no-cache
Connection: keep-alive
Host: {{params(target)}}

`
    rsp,req,_ = poc.HTTP(packet,
    poc.params({"target":addr,"word":word}),
    poc.https(isTls),
    poc.redirectTimes(0),
    )
    println(req)

if len(rsp) > 0 {
        body = poc.GetHTTPPacketBody(rsp)
        printf("获取加密结果:\n"+string(body))
        jsonObj = json.loads(string(body))
// 获取字段值
        sign = jsonObj["data"]
return sign
    }else{
        println("失败")
    }
return
}

func base_word(name,passwd){
     word = "username=" + name + "&password="+passwd
return codec.EncodeBase64(word)

}
// word = base_word("admin","admin")
// sign = handleCheck("127.0.0.1",12080,word)
// println("\nsign:"+sign)

signRequest = result => {
pairs := result.SplitN("|", 2)
    dump(pairs)

//接收两个参数,按照yakit语法写即可 {{yak(signRequest|admin|admin)}}
    word = base_word(pairs[0], pairs[1])
    sign = handleCheck("127.0.0.1",12080,word)

return sign
}

调试运行通过后,即可修改参数进行发包操作,批量处理同样支持,效率大幅提升。

参考资料:

https://github.com/jxhczhl/JsRpc

https://yaklang.com/articles/vulnerability_testing_after_being_encrypted_by_the_front-end

https://mp.weixin.qq.com/s/vHoVPINf4GKhR36LSQlDXw

原文链接:https://forum.butian.net/share/4452


免责声明:

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

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

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

本文转载自:只会看监控的实习生 逐影安全《JsRpc+Yakit热加载实现明文编辑加密发包》

评论:0   参与:  0