CTF 2024 Write up

CTF

本萌新刷推的时候无意间看见这个 CTF 2024 (opens in a new tab),虽然期末在即,但还是想玩一下。

第一次参加有关 CTF 的东西,所以写博客记录以下。

Check In

ctf-2024-write-up-1.png

点了 Submit,在 Console 中没有发现任何网络请求,所以答案一定在本地。

在 Sources 中搜索一番,发现了可疑目标。

ctf-2024-write-up-2.png

从正则可以看出,这是一个8位字符的字符串,且仅包含a-z A-Z 0-9

所以思路很简单,遍历这些可能字符的字符码进行爆破。

[['a', 'z'], ['A', 'Z'], ['0', '9']].forEach(range => {
    for (let i = range[0].charCodeAt(0); i <= range[1].charCodeAt(0); i++) {
        const realFlag = (0, _rust_sdk__WEBPACK_IMPORTED_MODULE_1__/* .getFlag1 */.S7)(i);
        if (realFlag.length > 0) {
            console.log(realFlag);
        }
    }
});

Hook 入代码后,点击按钮,得到了 Flag 1。

document.querySelector("body > main > div:nth-child(3) > div > button").click();

ctf-2024-write-up-3.png

Bytecode

Bytecode,字节码。

尝试逆向 WASM 无果后,我决定向第一题一样直接 Hook 入代码。

分析 Hook 入点

首先看 mangleBuffer 是什么,尝试 console.log(mangleBuffer),控制台运行:

document.querySelector("body > main > div:nth-child(4) > div > input").value = '1';
document.querySelector("body > main > div:nth-child(4) > div > button").click();

得到结果:

ctf-2024-write-up-4.png

Uint8Array 是 JavaScript 中的一种类型化数组,用于处理二进制数据。

Uint8Array 中的 "Uint" 表示 "无符号整数",而 "8" 表示每个元素占用 8 位(即 1 字节)。

因此,Uint8Array 的每个元素都是一个无符号的 8 位整数,其取值范围是 0 到 255。

接下来看到执行部分,可以看到一共有三次执行,前两次都是针对第一位和第二位的判断,第三次才是真正的执行。

vm.loadCode 表示使用 Uint8Array 用于表示某种虚拟机(注释中标记为:HumbleVM)可以理解并执行的代码。

这些代码可能是低级的机器码或字节码,它们直接控制虚拟机的操作。

爆破前两次执行

我们可以暴力破解前两次的运行,尝试得出规律:

for (let i = 0; i <= 256; i++) {
    if (vm.run(Uint8Array.from([i]))) {
        console.log(i);
    }
}

控制台直接得到结果162

对于第二次执行,我们也使用同样的方法:

for (let i = 0; i <= 256; i++) {
    if (vm.run(Uint8Array.from([162, i]))) {
        console.log(i);
    }
}

控制台得到结果154

所以接下来我们要找出输入什么值得到的 mangleBuffer 前两位为 [ 162, 154 ].

这里毫无技巧可言,人工暴力随机输入后得到以下条件:

ctf-2024-write-up-5.png

爆破第三次执行

我们针对第三次执行开始爆破。

思路:使用vm.loadCode分次载入Uint8Array,爆破结果。

for (let i = 0; i <= 256; i++) {
    if (vm.run(Uint8Array.from([162, 154, i]))) {
        console.log(i);
    }
}
输入输出
1, 1所有结果均为 true
1, 1, 4malformed bytecode (expected an operand for instruction 4)
1, 1, 4, 208208

以此类推可以得到正确的 mangleBuffer[162, 154, 208, 201, 155, 234, 192, 218,158]

爆破 Flag

得到了 mangleBuffer,我们还需要得到 flag

尝试对每一位进行爆破

for (let i = 0; i <= 255; i++) {
    const flag = `0${String.fromCharCode(i)}xxxxxx`
    const mangledBuffer = (0, _rust_sdk__WEBPACK_IMPORTED_MODULE_1__/* .mangle */.dW)(flag);
    if (mangledBuffer[3] === 208) {
        console.log(String.fromCharCode(i));
    }
}

得到:

Uint8Flag
第二位208z
第三位201c
第四位1551
第五位234@
第六位192j
第七位218p
第八位1584

所以 Flag 为 0z1@cjp4

总结

ctf-2024-write-up-6.png

这是我第一次参加 CTF,感觉过程很暴力,不知道是否有更好的方法。

Copyright © 2018 - 2023 AprilNEA's Blog