文章总结: 本文介绍Yakit中热加载技术的应用,该功能允许在WebFuzzer过程中动态加载Yak函数实现自定义fuzztag。作者通过实战案例演示如何利用热加载绕过RSA加密时间戳防重放机制:分析前端加密逻辑后编写热加载函数处理时间戳加密,最终成功实现字典爆破。文档包含具体函数定义、调用格式及注意事项。 综合评分: 87 文章分类: 渗透测试,WEB安全,安全工具,红队,实战经验
Yakit热加载
原创
白夜 白夜
Quest安全团队
2026年6月12日 19:20 北京
在小说阅读器读本章
去阅读
官方定义:
什么是热加载?
广义上来说,热加载是一种允许在不停止或重启应用程序的情况下,动态加载或更新特定组件或模块的功能。这种技术常用于开发过程中,提高开发效率和用户体验。
在Yakit 的Web Fuzzer中,热加载是一种高级技术,让 Yak 成为 Web Fuzzer 和用户自定a义代码中的桥梁,它允许我们编写一段 Yak 函数,在 Web Fuzzer 过程中使用,从而实现自定义 fuzztag 或更多功能。
我的理解:
热加载类似于面向切面编程,就是在渗透的过程中,在原本的某个环节上增加一个功能(一段代码),从而增强渗透的能力。可能也比较抽象,但是学过Java的同学应该比较好理解。
热加载里面会涉及到Yaklang的编程,这里提供一下对应的官方文档地址:
https://www.yaklang.com/docs/yak-basic/intro
调用热加载 fuzztag来插入热加载
实际上,我们调用热加载中编写的函数也使用 fuzztag 。我们也可以理解为热加载是一种特殊的 fuzztag ,它的格式为:
{{yak(funcname)}}
当我们需要传入参数时,则格式为
{{yak(funcname|param)}}
需要注意的是,我们传入的参数可以是 fuzztag ,也就是可以编写形如:
{{yak(funcname|{{x(pass_top25)}})}}
热加载函数定义来提供功能
我们可以在热加载页面中编写热加载函数,其函数定义如下:
// 函数名为funcname,参数只有一个,为param,类型是字符串
funcname = func(param) {
// 返回值可以是字符串或数组
return param
}
来到靶场,抓包
发现对方有防止重放的功能,没办法修改其中的数据,看前端js代码
发现他会进入一个叫generateRequestData的函数
然后分析代码
function generateRequestData() {
// 获取用户名和密码
const username = document.getElementById("username").value;
const password = document.getElementById("password").value;
// 生成13位毫秒时间戳,用于防重放校验
const timestamp = Date.now();
// RSA公钥(服务端对应保存私钥)
const publicKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRvA7giwinEkaTYllDYCkzujvi
NH+up0XAKXQot8RixKGpB7nr8AdidEvuo+wVCxZwDK3hlcRGrrqt0Gxqwc11btlM
DSj92Mr3xSaJcshZU8kfj325L8DRh9jpruphHBfh955ihvbednGAvOHOrz3Qy3Cb
ocDbsNeCwNpRxwjIdQIDAQAB
-----END PUBLIC KEY-----`;
// RSA加密函数
function rsaEncrypt(data, publicKey) {
// 创建JSEncrypt对象
const jsEncrypt = new JSEncrypt();
// 导入RSA公钥
jsEncrypt.setPublicKey(publicKey);
// 对时间戳进行RSA加密
// JSEncrypt返回值已经是Base64编码后的密文
const encrypted = jsEncrypt.encrypt(data.toString());
if (!encrypted) {
throw new Error("RSA encryption failed.");
}
return encrypted;
}
// 加密时间戳
// 实际加密内容:
// 1780985189238
// ↓
// RSA(PKCS#1 v1.5)
// ↓
// Base64密文
let encryptedTimestamp;
try {
encryptedTimestamp = rsaEncrypt(timestamp, publicKey);
} catch (error) {
console.error("Encryption error:", error);
return null;
}
// 构造请求数据
// 注意:
// random字段实际存放的是RSA加密后的时间戳
const dataToSend = {
username: username,
password: password,
random: encryptedTimestamp
};
return dataToSend;
}
function sendLoginRequest(url) {
// 获取最终请求数据
const dataToSend = generateRequestData();
// 发送JSON请求
fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8"
},
body: JSON.stringify(dataToSend)
})
.then(response => response.json())
.then(data => {
// 服务端处理流程推测:
// random
// ↓
// RSA私钥解密
// ↓
// 得到时间戳
// ↓
// 判断是否超出时间窗口
// ↓
// 验证账号密码
if (data.success) {
alert("登录成功");
window.location.href = "success.html";
} else {
alert(data.error || "用户名或密码错误");
}
})
.catch(error => console.error("请求错误:", error));
closeModal();
}
function closeModal() {
document.getElementById("modal").style.display = "none";
}
发现他是通过返回一个使用rsa加密的13位的时间戳来验证是否超时,那么写一个热加载
handle = func(ms) {
pubKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRvA7giwinEkaTYllDYCkzujvi
NH+up0XAKXQot8RixKGpB7nr8AdidEvuo+wVCxZwDK3hlcRGrrqt0Gxqwc11btlM
DSj92Mr3xSaJcshZU8kfj325L8DRh9jpruphHBfh955ihvbednGAvOHOrz3Qy3Cb
ocDbsNeCwNpRxwjIdQIDAQAB
-----END PUBLIC KEY-----`
enc, _ = codec.RSAEncryptWithPKCS1v15(pubKey, ms)
return codec.EncodeBase64(enc)
}
调用{{yak(handle|{{timestamp(ms)}})}}
!!!注意千万别写成{{yak(handle|timestamp(ms))}},会导致Yakit把
timestamp(ms) 当成了一个普通字符串参数传给 handle
然后就可以成功添加字典爆破啦
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:Quest安全团队 白夜 白夜《Yakit热加载》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论