京麒ctf2024初赛

PREFACE:r1mao 师傅复健过程带着鼠鼠做的,tql;

算是第一次调 wasm,感觉挺好(?)

# 前戏

# 反调试

突破前端反调试–阻止页面不断 debugger - 技术足迹 - SegmentFault 思否

可以这样用条件断点直接绕

image-20240527103329524

# 同源策略

需要关闭同源策略才能看到 wasm 附件

# firefox:

在网址栏中输入”about:config“ 再搜索栏中输入 "security.fileuri.strict_origin_policy", 并设置为 "false"

# chrome

快捷方式写一个:

"C:\Program Files\Google\Chrome\Application\chrome.exe" --allow-file-access-from-files

image-20240527103631514

这里有两个问题:

  1. firefox 用前面的条件断点策略没办法绕反调(未解决)
  2. chrome 同源策略不能直接从文件夹里面打开

解决方法:

chrome 里面打开 python -m http.server ,即可看到 wasm 文件

# 调试

正确绕过反调以及配好浏览器,这里就可以调试了(暂时没觉得浏览器调试很不妥,先用着~)

# 静态分析

nneonneo/ghidra-wasm-plugin: Ghidra Wasm plugin with disassembly and decompilation support (github.com)

ghidra 插件选择好插件的压缩包即可

img

这里我们的 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 才会触发逻辑:

image-20240527111010649

审一下 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);

image-20240527114316766

ƒ 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

image-20240527114549565image-20240527114542798

# 加密

我们会看到这样的函数,rc4,做了 ollvm,调试发现这里是核心的加密段

image-20240527115425554

好在逻辑不是很复杂,可以很快定位到核心加密的 xor:

image-20240527115554093

key 的话,makeslice 的地方很可疑,以及下面的 %

image-20240527120646185

image-20240527121414644

可以调试看看,发现不对:

image-20240527122315547

这里才是真的秘钥(可以测试出来,ollvm 跟起来还是有些难顶…)

image-20240527122516394

打上条件断点:

image-20240527122611991

但会发现这里触发次数太多,那我们换一个地方打:

image-20240527123215824

这样就拿到了所有的 key

# 密文

上面的测试过程都是复现时候捋出来的思路,并不是从零开始的调试

实际上直接调试过一遍会看到函数调用栈,一个一个 func 走,最后一个是 main.remalloc.func1,里面调用了 main.malloc

image-20240527124531030

这里如果绕过弯来,会知道 wasm 是没有 malloc 这种底层操作的,包括前面会看到其他几乎所有函数的命名,都是混淆成经典的系统函数的命名了

malloc 里面有我们非常想要看到的 memequal 了:

image-20240527124750476

注意这里的条件:(即我们的输入长度需要控制,他给的输入是不行的,需要修改为自己的输入)

image-20240527130843887

比较的位置,观察我们的输入长度是否满足要求:

image-20240527131058774

这样的 flag 是可以的

image-20240527131143073

点两次进里面,它就是我们想要的 check 结构:

image-20240527124812434

前面的 log 中我们会发现几次加密最后返回的是一个 base64,这里我们也可以调试找到 base64:

image-20240527131243913

这里的 var1 即为密文

解密脚本如下:

From Base64, RC4, RC4, RC4, RC4 - CyberChef