京麒ctf2024初赛
PREFACE:r1mao 师傅复健过程带着鼠鼠做的,tql;
算是第一次调 wasm,感觉挺好(?)
# 前戏
# 反调试
突破前端反调试–阻止页面不断 debugger - 技术足迹 - SegmentFault 思否
可以这样用条件断点直接绕
# 同源策略
需要关闭同源策略才能看到 wasm 附件
# firefox:
在网址栏中输入”about:config“ 再搜索栏中输入 "security.fileuri.strict_origin_policy", 并设置为 "false"
# chrome
快捷方式写一个:
"C:\Program Files\Google\Chrome\Application\chrome.exe" --allow-file-access-from-files
这里有两个问题:
- firefox 用前面的条件断点策略没办法绕反调(未解决)
- chrome 同源策略不能直接从文件夹里面打开
解决方法:
chrome 里面打开 python -m http.server
,即可看到 wasm 文件
# 调试
正确绕过反调以及配好浏览器,这里就可以调试了(暂时没觉得浏览器调试很不妥,先用着~)
# 静态分析
ghidra 插件选择好插件的压缩包即可
这里我们的 index.html 修改为了这样:
<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |
</head> | |
<script src="static/wasm_exec.js"></script> | |
<script> | |
const go = new Go(); | |
WebAssembly.instantiateStreaming(fetch("static/main.wasm"), go.importObject) | |
.then(function (result) { | |
document.getElementById("flag").value = "flag{this_1s_fake_f_l__Ag}"; | |
go.run(result.instance); | |
wasm = result.instance.exports; | |
memories = [wasm.mem]; | |
viewDWORD = (addr) =>{ | |
const arr = new Uint32Array(memories[0].buffer.slice(addr, addr + 16)); | |
return arr; | |
}; | |
viewChar = (addr, size = 16) =>{ | |
const arr = new Uint8Array(memories[0].buffer.slice(addr, addr + size)); | |
return String.fromCharCode.apply(null, arr); | |
}; | |
viewHEX = (addr, size = 16) =>{ | |
const arr = new Uint8Array(memories[0].buffer.slice(addr, addr + size)); | |
return (Array.from(arr, x =>x.toString(16).padStart(2, '0')).join(' ')); | |
}; | |
viewHexCode = (addr, size = 16) =>{ | |
const arr = new Uint8Array(memories[0].buffer.slice(addr, addr + size)); | |
return (Array.from(arr, x =>'0x' + x.toString(16).padStart(2, '0')).join(', ')); | |
}; | |
dumpMemory = (addr, size = 16) =>{ | |
const arr = new Uint8Array(memories[0].buffer.slice(addr, addr + size)); | |
return arr; | |
}; | |
viewString = (addr, size = 16) =>{ | |
const arr = new Uint8Array(memories[0].buffer.slice(addr, addr + size)); | |
let max = size; | |
for (let i = 0; i < size; i++) { | |
if (arr[i] === 0) { | |
max = i; | |
break; | |
} | |
} | |
return String.fromCharCode.apply(null, arr.slice(0, max)); | |
}; | |
search = function(stirng) { | |
const m = new Uint8Array(memories[0].buffer); | |
// vid=35402, 9AAizQZJ | |
// vid=20268, a3fMpSkB | |
const k = Array.from(stirng, x =>x.charCodeAt()); | |
const match = (j) =>{ | |
return k.every((b, i) =>m[i + j] === b); | |
}; | |
const max = Math.min(10_000_000, m.byteLength || m.length); | |
for (let i = 0; i < max; i++) { | |
if (match(i)) { | |
console.info(i); | |
} | |
} | |
console.info('done'); | |
} | |
} ); | |
function check_flag() { | |
var flag = document.getElementById("flag").value; | |
console.log("你输入的 flag 是:"); | |
console.log(flag); | |
// document.getElementById("flag").value = "aaaflag{this_1s_fake_f_l_A__g}"; | |
if (document.getElementById("flag").value === "flag{this_1s_fake_f_l__Ag}") { | |
console.log("I have a gift for you!"); | |
// console.log(console.gift("ABCCDDEE", "AABBCCDDEE")); | |
console.log(console.gift("f09f8dabf09f8daaf09f8db0f09f8daff09f8e8af09f8daaf09fa59bf09f8da9", "666c61677b746869735f31735f66616b655f665f6c5f415f5f677d")); //rc4 第一个是 key,第二个是 value,都是进去 hex bytes | |
alert("恭喜你,答对了!我想你应该知道 flag 是什么了 !"); | |
} else { | |
alert("答错了,再想想吧!"); | |
} | |
} | |
</script> | |
<body> | |
<input id="flag" type="text" /> | |
<button id="btn" onclick="check_flag();" >Click</button> | |
</body> | |
</html> |
# 正餐
# 总体流程
静态看一下
输入一个 fake flag 才会触发逻辑:
审一下 js
"syscall/js.valueCall": (sp) => { | |
sp >>>= 0; | |
try { | |
const v = loadValue(sp + 8); | |
const m = Reflect.get(v, loadString(sp + 16)); | |
const args = loadSliceOfValues(sp + 32); | |
const result = Reflect.apply(m, v, args); // 核心是这句 | |
sp = this._inst.exports.getsp() >>> 0; | |
storeValue(sp + 56, result); | |
this.mem.setUint8(sp + 64, 1); | |
} catch (err) { | |
sp = this._inst.exports.getsp() >>> 0; | |
storeValue(sp + 56, err); | |
this.mem.setUint8(sp + 64, 0); | |
} | |
}, |
这里的 Reflect.apply
是调用 wasm 函数的核心语句,后续对于 js 就是 hook 这里来观察函数调用的逻辑:
这里 hook 观察函数调用以及传参
loadString(sp + 16) + '(' + args + ');\n'; |
这样可以观察返回值:
console.log("ret:" + result); |
ƒ eval() { [native code] }
wasm_exec.js:352 eval(setInterval(function(){debugger;}, 1000););
wasm_exec.js:349 ƒ eval() { [native code] }
wasm_exec.js:352 eval(setInterval(function(){debugger;}, 1000););
wasm_exec.js:349 ƒ eval() { [native code] }
wasm_exec.js:352 eval(setInterval(function(){debugger;}, 1000););
wasm_exec.js:349 ƒ _makeFuncWrapper(id) {
const go = this;
return function () {
const event = { id: id, this: this, args: arguments };
go._pendingEvent = event;
go._resume();
return event.result;
…
wasm_exec.js:352 _makeFuncWrapper(1);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(2);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(3);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(4);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(5);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(6);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(7);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(8);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(9);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(10);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(11);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(12);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(13);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(14);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(15);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(16);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(17);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(18);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(19);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(20);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(21);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(22);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(23);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(24);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(25);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(26);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(27);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(28);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(29);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(30);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(31);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(32);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(33);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(34);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(35);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(36);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(37);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(38);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(39);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(40);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(41);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(42);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(43);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(44);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(45);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(46);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(47);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(48);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(49);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(50);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(51);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(52);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(53);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(54);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(55);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(56);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(57);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(58);
wasm_exec.js:349 <function>
wasm_exec.js:352 _makeFuncWrapper(59);
wasm_exec.js:349 <function>
wasm_exec.js:352 eval(setInterval(function() { debugger; }, 1000););
wasm_exec.js:349 <function>
wasm_exec.js:352 panda(你输入的 flag 是:);
wasm_exec.js:352 你输入的 flag 是:
wasm_exec.js:349 <function>
wasm_exec.js:352 eval(setInterval(function(){debugger;}, 1000););
wasm_exec.js:349 <function>
wasm_exec.js:352 😘😘❤️😘😘(flag{this_1s_fake_f_l__Ag});
wasm_exec.js:349 <function>
wasm_exec.js:352 segment🍪🥂(flag{this_1s_fake_f_l__Ag});
wasm_exec.js:349 <function>
wasm_exec.js:352 libc🍪🍹(flag{this_1s_fake_f_l__Ag});
wasm_exec.js:349 <function>
wasm_exec.js:352 glibc🎈🎂(flag{this_1s_fake_f_l__Ag});
wasm_exec.js:349 <function>
wasm_exec.js:352 malloc😅🍵(flag{this_1s_fake_f_l__Ag});
wasm_exec.js:349 <function>
wasm_exec.js:352 free🍪🎈(flag{this_1s_fake_f_l__Ag});
wasm_exec.js:349 <function>
wasm_exec.js:352 calloc🍷🎁(flag{this_1s_fake_f_l__Ag});
wasm_exec.js:349 <function>
wasm_exec.js:352 realloc🍭🍺(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 free🍬🍵(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 exit🍸🎁(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 abort🍫🍷(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 signal🍻🍻(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 raise☕🍩(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 setjmp🍺🍶(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 longjmp🍯🍶(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 sigaction🍮🍰(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 sigprocmask🎈🍼(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 sigpending🍻🍾(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 send🍷🍺(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 recv🎊🍼(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 socket🍵🍭(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 bind🎂🍻(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 listen🍾🎁(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 accept🎈🎉(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 connect🎉🍵(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 LoadLibrary🍶🍯(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 GetProcAddress🍯🎁(3ba81be59f57d55daf0ad10ff8300ddc252f299555699fbf0a75);
wasm_exec.js:349 <function>
wasm_exec.js:352 VirtualAlloc🍰🍵(10df5f7bce160be17e2d7cf7575b1688e0ded5f2efb3a707c1b1a7926eee1d40ccc856cfb3a86ecd54ceb03b841a679a57263ab7);
wasm_exec.js:349 <function>
wasm_exec.js:352 VirtualFree🎈🎁(10df5f7bce160be17e2d7cf7575b1688e0ded5f2efb3a707c1b1a7926eee1d40ccc856cfb3a86ecd54ceb03b841a679a57263ab7);
wasm_exec.js:349 <function>
wasm_exec.js:352 VirtualProtect😅🍹(10df5f7bce160be17e2d7cf7575b1688e0ded5f2efb3a707c1b1a7926eee1d40ccc856cfb3a86ecd54ceb03b841a679a57263ab7);
wasm_exec.js:349 <function>
wasm_exec.js:352 VirtualQuery🍯🎁(10df5f7bce160be17e2d7cf7575b1688e0ded5f2efb3a707c1b1a7926eee1d40ccc856cfb3a86ecd54ceb03b841a679a57263ab7);
wasm_exec.js:349 <function>
wasm_exec.js:352 CreateThread😅🍼(10df5f7bce160be17e2d7cf7575b1688e0ded5f2efb3a707c1b1a7926eee1d40ccc856cfb3a86ecd54ceb03b841a679a57263ab7);
wasm_exec.js:349 <function>
wasm_exec.js:352 CreateProcess🥂🍪(10df5f7bce160be17e2d7cf7575b1688e0ded5f2efb3a707c1b1a7926eee1d40ccc856cfb3a86ecd54ceb03b841a679a57263ab7);
wasm_exec.js:349 <function>
wasm_exec.js:352 GetThreadContext🎊🍻(10df5f7bce160be17e2d7cf7575b1688e0ded5f2efb3a707c1b1a7926eee1d40ccc856cfb3a86ecd54ceb03b841a679a57263ab7);
wasm_exec.js:349 <function>
wasm_exec.js:352 SetThreadContext🍪🎉(10df5f7bce160be17e2d7cf7575b1688e0ded5f2efb3a707c1b1a7926eee1d40ccc856cfb3a86ecd54ceb03b841a679a57263ab7);
wasm_exec.js:349 <function>
wasm_exec.js:352 ReadProcessMemory🍪🍮(10df5f7bce160be17e2d7cf7575b1688e0ded5f2efb3a707c1b1a7926eee1d40ccc856cfb3a86ecd54ceb03b841a679a57263ab7);
wasm_exec.js:349 <function>
wasm_exec.js:352 mutex🎊🍶(10df5f7bce160be17e2d7cf7575b1688e0ded5f2efb3a707c1b1a7926eee1d40ccc856cfb3a86ecd54ceb03b841a679a57263ab7);
wasm_exec.js:349 <function>
wasm_exec.js:352 semaphore🍭🍼(10df5f7bce160be17e2d7cf7575b1688e0ded5f2efb3a707c1b1a7926eee1d40ccc856cfb3a86ecd54ceb03b841a679a57263ab7);
wasm_exec.js:349 <function>
wasm_exec.js:352 condition🍰🎉(10df5f7bce160be17e2d7cf7575b1688e0ded5f2efb3a707c1b1a7926eee1d40ccc856cfb3a86ecd54ceb03b841a679a57263ab7);
wasm_exec.js:349 <function>
wasm_exec.js:352 pthread🍹🍫(10df5f7bce160be17e2d7cf7575b1688e0ded5f2efb3a707c1b1a7926eee1d40ccc856cfb3a86ecd54ceb03b841a679a57263ab7);
wasm_exec.js:349 <function>
wasm_exec.js:352 fork🍻🍭(10df5f7bce160be17e2d7cf7575b1688e0ded5f2efb3a707c1b1a7926eee1d40ccc856cfb3a86ecd54ceb03b841a679a57263ab7);
wasm_exec.js:349 <function>
wasm_exec.js:352 exec🍵🍾(806ce5ec9e156bed790d66949dc1949af31d9c14205f25ba6041fa9b94201469f2b0a7ef3e4cbcb660aa6535cd167f032794c25535875bad03fa96da336d3805ede3540424f81e2a8346bc3f4a4e7e978d3b697ff7d3445abe98210427ab434e1e15fe3d69679ba5);
wasm_exec.js:349 <function>
wasm_exec.js:352 pipe🍺🍫(806ce5ec9e156bed790d66949dc1949af31d9c14205f25ba6041fa9b94201469f2b0a7ef3e4cbcb660aa6535cd167f032794c25535875bad03fa96da336d3805ede3540424f81e2a8346bc3f4a4e7e978d3b697ff7d3445abe98210427ab434e1e15fe3d69679ba5);
wasm_exec.js:349 <function>
wasm_exec.js:352 dup🍼🍺(5aa21921dda7d9519a012f285b9b9e498f495fb521d4712b0075e47962bc2eed7fd840cba2f2ab48875fe765122d7b9f1a6ed992a07131902e4acde16fc02e1b23cc4d47ed7f65449df940601398c75fc6ddc425e1e81b678423ef284ad2a3d45b7f376d0067c820116fbb7ff9b30c9dad258352b00d7a1b4ca60ce7d4293898bc31a9131d7d7cb7efcadfe3d0e7b11f962917508987cc9b6511bb304f9a24e2c28ab4ee8bc4ccbbbaf8e3f4eb799dcca5bfdbc6943aeb4d69ad49f176fb87d56aae14de51901873d15ea0cb78ecbb66);
wasm_exec.js:349 <function>
wasm_exec.js:352 dup2🍰🍮(5aa21921dda7d9519a012f285b9b9e498f495fb521d4712b0075e47962bc2eed7fd840cba2f2ab48875fe765122d7b9f1a6ed992a07131902e4acde16fc02e1b23cc4d47ed7f65449df940601398c75fc6ddc425e1e81b678423ef284ad2a3d45b7f376d0067c820116fbb7ff9b30c9dad258352b00d7a1b4ca60ce7d4293898bc31a9131d7d7cb7efcadfe3d0e7b11f962917508987cc9b6511bb304f9a24e2c28ab4ee8bc4ccbbbaf8e3f4eb799dcca5bfdbc6943aeb4d69ad49f176fb87d56aae14de51901873d15ea0cb78ecbb66);
wasm_exec.js:349 <function>
wasm_exec.js:352 select☕🎉(5aa21921dda7d9519a012f285b9b9e498f495fb521d4712b0075e47962bc2eed7fd840cba2f2ab48875fe765122d7b9f1a6ed992a07131902e4acde16fc02e1b23cc4d47ed7f65449df940601398c75fc6ddc425e1e81b678423ef284ad2a3d45b7f376d0067c820116fbb7ff9b30c9dad258352b00d7a1b4ca60ce7d4293898bc31a9131d7d7cb7efcadfe3d0e7b11f962917508987cc9b6511bb304f9a24e2c28ab4ee8bc4ccbbbaf8e3f4eb799dcca5bfdbc6943aeb4d69ad49f176fb87d56aae14de51901873d15ea0cb78ecbb66);
wasm_exec.js:349 <function>
wasm_exec.js:352 poll🍮🎁(5aa21921dda7d9519a012f285b9b9e498f495fb521d4712b0075e47962bc2eed7fd840cba2f2ab48875fe765122d7b9f1a6ed992a07131902e4acde16fc02e1b23cc4d47ed7f65449df940601398c75fc6ddc425e1e81b678423ef284ad2a3d45b7f376d0067c820116fbb7ff9b30c9dad258352b00d7a1b4ca60ce7d4293898bc31a9131d7d7cb7efcadfe3d0e7b11f962917508987cc9b6511bb304f9a24e2c28ab4ee8bc4ccbbbaf8e3f4eb799dcca5bfdbc6943aeb4d69ad49f176fb87d56aae14de51901873d15ea0cb78ecbb66);
wasm_exec.js:349 <function>
wasm_exec.js:352 epoll🥛🎊(5aa21921dda7d9519a012f285b9b9e498f495fb521d4712b0075e47962bc2eed7fd840cba2f2ab48875fe765122d7b9f1a6ed992a07131902e4acde16fc02e1b23cc4d47ed7f65449df940601398c75fc6ddc425e1e81b678423ef284ad2a3d45b7f376d0067c820116fbb7ff9b30c9dad258352b00d7a1b4ca60ce7d4293898bc31a9131d7d7cb7efcadfe3d0e7b11f962917508987cc9b6511bb304f9a24e2c28ab4ee8bc4ccbbbaf8e3f4eb799dcca5bfdbc6943aeb4d69ad49f176fb87d56aae14de51901873d15ea0cb78ecbb66);
wasm_exec.js:349 <function>
wasm_exec.js:352 kqueue🍭🍻(5aa21921dda7d9519a012f285b9b9e498f495fb521d4712b0075e47962bc2eed7fd840cba2f2ab48875fe765122d7b9f1a6ed992a07131902e4acde16fc02e1b23cc4d47ed7f65449df940601398c75fc6ddc425e1e81b678423ef284ad2a3d45b7f376d0067c820116fbb7ff9b30c9dad258352b00d7a1b4ca60ce7d4293898bc31a9131d7d7cb7efcadfe3d0e7b11f962917508987cc9b6511bb304f9a24e2c28ab4ee8bc4ccbbbaf8e3f4eb799dcca5bfdbc6943aeb4d69ad49f176fb87d56aae14de51901873d15ea0cb78ecbb66);
wasm_exec.js:349 <function>
wasm_exec.js:352 sigwait🍩🎁(5aa21921dda7d9519a012f285b9b9e498f495fb521d4712b0075e47962bc2eed7fd840cba2f2ab48875fe765122d7b9f1a6ed992a07131902e4acde16fc02e1b23cc4d47ed7f65449df940601398c75fc6ddc425e1e81b678423ef284ad2a3d45b7f376d0067c820116fbb7ff9b30c9dad258352b00d7a1b4ca60ce7d4293898bc31a9131d7d7cb7efcadfe3d0e7b11f962917508987cc9b6511bb304f9a24e2c28ab4ee8bc4ccbbbaf8e3f4eb799dcca5bfdbc6943aeb4d69ad49f176fb87d56aae14de51901873d15ea0cb78ecbb66);
wasm_exec.js:349 <function>
wasm_exec.js:352 jmp_buf🎂🍺(5aa21921dda7d9519a012f285b9b9e498f495fb521d4712b0075e47962bc2eed7fd840cba2f2ab48875fe765122d7b9f1a6ed992a07131902e4acde16fc02e1b23cc4d47ed7f65449df940601398c75fc6ddc425e1e81b678423ef284ad2a3d45b7f376d0067c820116fbb7ff9b30c9dad258352b00d7a1b4ca60ce7d4293898bc31a9131d7d7cb7efcadfe3d0e7b11f962917508987cc9b6511bb304f9a24e2c28ab4ee8bc4ccbbbaf8e3f4eb799dcca5bfdbc6943aeb4d69ad49f176fb87d56aae14de51901873d15ea0cb78ecbb66);
wasm_exec.js:349 <function>
wasm_exec.js:352 sigjmp_buf🥂🎊(5aa21921dda7d9519a012f285b9b9e498f495fb521d4712b0075e47962bc2eed7fd840cba2f2ab48875fe765122d7b9f1a6ed992a07131902e4acde16fc02e1b23cc4d47ed7f65449df940601398c75fc6ddc425e1e81b678423ef284ad2a3d45b7f376d0067c820116fbb7ff9b30c9dad258352b00d7a1b4ca60ce7d4293898bc31a9131d7d7cb7efcadfe3d0e7b11f962917508987cc9b6511bb304f9a24e2c28ab4ee8bc4ccbbbaf8e3f4eb799dcca5bfdbc6943aeb4d69ad49f176fb87d56aae14de51901873d15ea0cb78ecbb66);
wasm_exec.js:349 <function>
wasm_exec.js:352 sigsetjmp🍹🎊(5aa21921dda7d9519a012f285b9b9e498f495fb521d4712b0075e47962bc2eed7fd840cba2f2ab48875fe765122d7b9f1a6ed992a07131902e4acde16fc02e1b23cc4d47ed7f65449df940601398c75fc6ddc425e1e81b678423ef284ad2a3d45b7f376d0067c820116fbb7ff9b30c9dad258352b00d7a1b4ca60ce7d4293898bc31a9131d7d7cb7efcadfe3d0e7b11f962917508987cc9b6511bb304f9a24e2c28ab4ee8bc4ccbbbaf8e3f4eb799dcca5bfdbc6943aeb4d69ad49f176fb87d56aae14de51901873d15ea0cb78ecbb66);
wasm_exec.js:349 <function>
wasm_exec.js:352 siglongjmp🍾🥛(5aa21921dda7d9519a012f285b9b9e498f495fb521d4712b0075e47962bc2eed7fd840cba2f2ab48875fe765122d7b9f1a6ed992a07131902e4acde16fc02e1b23cc4d47ed7f65449df940601398c75fc6ddc425e1e81b678423ef284ad2a3d45b7f376d0067c820116fbb7ff9b30c9dad258352b00d7a1b4ca60ce7d4293898bc31a9131d7d7cb7efcadfe3d0e7b11f962917508987cc9b6511bb304f9a24e2c28ab4ee8bc4ccbbbaf8e3f4eb799dcca5bfdbc6943aeb4d69ad49f176fb87d56aae14de51901873d15ea0cb78ecbb66);
wasm_exec.js:349 <function>
wasm_exec.js:352 stacK_t🎁🍭(5aa21921dda7d9519a012f285b9b9e498f495fb521d4712b0075e47962bc2eed7fd840cba2f2ab48875fe765122d7b9f1a6ed992a07131902e4acde16fc02e1b23cc4d47ed7f65449df940601398c75fc6ddc425e1e81b678423ef284ad2a3d45b7f376d0067c820116fbb7ff9b30c9dad258352b00d7a1b4ca60ce7d4293898bc31a9131d7d7cb7efcadfe3d0e7b11f962917508987cc9b6511bb304f9a24e2c28ab4ee8bc4ccbbbaf8e3f4eb799dcca5bfdbc6943aeb4d69ad49f176fb87d56aae14de51901873d15ea0cb78ecbb66);
wasm_exec.js:349 <function>
wasm_exec.js:352 ucontext_t🍫🍵(5aa21921dda7d9519a012f285b9b9e498f495fb521d4712b0075e47962bc2eed7fd840cba2f2ab48875fe765122d7b9f1a6ed992a07131902e4acde16fc02e1b23cc4d47ed7f65449df940601398c75fc6ddc425e1e81b678423ef284ad2a3d45b7f376d0067c820116fbb7ff9b30c9dad258352b00d7a1b4ca60ce7d4293898bc31a9131d7d7cb7efcadfe3d0e7b11f962917508987cc9b6511bb304f9a24e2c28ab4ee8bc4ccbbbaf8e3f4eb799dcca5bfdbc6943aeb4d69ad49f176fb87d56aae14de51901873d15ea0cb78ecbb66);
wasm_exec.js:349 <function>
wasm_exec.js:352 siginfo_t🍰🍼(5aa21921dda7d9519a012f285b9b9e498f495fb521d4712b0075e47962bc2eed7fd840cba2f2ab48875fe765122d7b9f1a6ed992a07131902e4acde16fc02e1b23cc4d47ed7f65449df940601398c75fc6ddc425e1e81b678423ef284ad2a3d45b7f376d0067c820116fbb7ff9b30c9dad258352b00d7a1b4ca60ce7d4293898bc31a9131d7d7cb7efcadfe3d0e7b11f962917508987cc9b6511bb304f9a24e2c28ab4ee8bc4ccbbbaf8e3f4eb799dcca5bfdbc6943aeb4d69ad49f176fb87d56aae14de51901873d15ea0cb78ecbb66);
wasm_exec.js:349 <function>
wasm_exec.js:352 btoa(5aa21921dda7d9519a012f285b9b9e498f495fb521d4712b0075e47962bc2eed7fd840cba2f2ab48875fe765122d7b9f1a6ed992a07131902e4acde16fc02e1b23cc4d47ed7f65449df940601398c75fc6ddc425e1e81b678423ef284ad2a3d45b7f376d0067c820116fbb7ff9b30c9dad258352b00d7a1b4ca60ce7d4293898bc31a9131d7d7cb7efcadfe3d0e7b11f962917508987cc9b6511bb304f9a24e2c28ab4ee8bc4ccbbbaf8e3f4eb799dcca5bfdbc6943aeb4d69ad49f176fb87d56aae14de51901873d15ea0cb78ecbb66);
wasm_exec.js:349 <function>
wasm_exec.js:352 panda(flag{this_1s_fake_f_l__Ag});
wasm_exec.js:352 flag{this_1s_fake_f_l__Ag}
wasm_exec.js:349 <function>
wasm_exec.js:352 panda(I have a gift for you!);
wasm_exec.js:352 I have a gift for you!
wasm_exec.js:349 <function>
wasm_exec.js:352 panda(45d15f24840006bd341478b36c084287e4e783cce7ddd63ef8eee9);
wasm_exec.js:352 45d15f24840006bd341478b36c084287e4e783cce7ddd63ef8eee9
以及 gift 函数,测试会发现它实际上就是一个 rc4,算是暗示你加密只有 rc4
# 加密
我们会看到这样的函数,rc4,做了 ollvm,调试发现这里是核心的加密段
好在逻辑不是很复杂,可以很快定位到核心加密的 xor:
key 的话,makeslice 的地方很可疑,以及下面的 %
可以调试看看,发现不对:
这里才是真的秘钥(可以测试出来,ollvm 跟起来还是有些难顶…)
打上条件断点:
但会发现这里触发次数太多,那我们换一个地方打:
这样就拿到了所有的 key
# 密文
上面的测试过程都是复现时候捋出来的思路,并不是从零开始的调试
实际上直接调试过一遍会看到函数调用栈,一个一个 func 走,最后一个是 main.remalloc.func1,里面调用了 main.malloc
这里如果绕过弯来,会知道 wasm 是没有 malloc 这种底层操作的,包括前面会看到其他几乎所有函数的命名,都是混淆成经典的系统函数的命名了
malloc 里面有我们非常想要看到的 memequal 了:
注意这里的条件:(即我们的输入长度需要控制,他给的输入是不行的,需要修改为自己的输入)
比较的位置,观察我们的输入长度是否满足要求:
这样的 flag 是可以的
点两次进里面,它就是我们想要的 check 结构:
前面的 log 中我们会发现几次加密最后返回的是一个 base64,这里我们也可以调试找到 base64:
这里的 var1 即为密文
解密脚本如下: