Timothy Lau

码农小易

分析 Cyandev 发起的 CTF2024 挑战解题思路(一)

发布于 # 网络安全 # 逆向

免责声明

本文章所提到的技术仅用于学习用途,禁止使用本文章的任何技术进行发起网络攻击、非法利用等网络犯罪行为,一切信息禁止用于任何非法用途。若读者利用文章所提到的技术实施违法犯罪行为,其责任一概由读者自行承担,与作者无关。

0x01 前言

今天逛 404 网站的时候捕捉到一个来自 Cyandev.rs 大佬发起了一场跨年 CTF 挑战活动,因为刷到该帖子已经是 CTF 挑战活动开始 5 个小时之后了,所以就不求争取前两名,始终秉承学习至上的态度来看看这位大佬出的题目。经过一小时的折磨,终于顺利把两道题目给 Crack 成功了,排名 15,还行凑合玩玩吧。本文内容主要是想分享我解题时的一些想法和思路,后面文章内容可能会很大程度的剧透通关Flag,非常建议大家先自行尝试 Crack 无果后再看文章思路分析。

0x02 开始之前

这个 CTF 挑战题目其实只有两道,第一题是作者预设的签到题,对我来说其实可以直接秒了,第二题才是真正开始把玩的题目。可以直接访问 ctf.cyandev.app 直接参与本次 CTF 活动。由于文章篇幅的问题,我将文章分成两篇进行发布,这篇主要是讲解第一题的解题思路。

0x03 第一题挑战(签到题)

0x0301 定位 Flag 校验位置

一上来什么都不管,直接随便乱输入一通,直接点击 Submit 按钮,看浏览器作出什么反应。正常来说在输入错误的 Flag 情况下点击提交,无非就是弹窗警告或者修改某些 Doc 的样式以告诉用户输入错了,而我的目的是为了能够快速定位到校验 Flag 是否正确的逻辑代码行。

显然在代码全局直接搜 The flag is wrong! 就可以直接定位到 Flag 开始校验的位置,198行 处就是弹窗,而 195行onSubmit(value, username) 就是按钮点击之后需要进入的 Flag 校验函数,我们可以直接在 195行 打上断点,步入深入查看。

PS: 当然,定位校验位置不只有这种方式,且这种方式不是任何时候都可奏效,以后有具体案例可以再介绍。

0x0302 步入 onSubmit()

步入至 submitFlag1() 内,可以看到 34行 还需要进入 checkFlag1(),但为了可以让我们读者更理解代码,我在这里可以逐条分析,但实际我在 Crack 的过程中,并不会产生过多的分析,因为有些代码一看便知是 无关代码,实际上是可以跳过的。

行号代码作用
37 行(0, _backend_api__xxxxxx)(1, username, flag)当 checkFlag1 通过后,发送对应 username 和 flag 给服务器做进一步校验(为了防止有人混水摸鱼)

接下来,我们继续步入到 checkFlag1() 内一探究竟。

0x0303 步入 checkFlag1()

好戏正式开始,直接印入眼帘的就是 26行 的正则表达式,熟悉正则的小伙伴或者甚至刚入门正则的小伙伴都能看懂,这是一个 8 位且只能接受大小写字母以及 0-9 和一个感叹号的正则表达式。

0x0304 突破两层判断

显然这里要突破两层关卡,第一层就是通过 26行 的正则表达式,第二层就是通过 31行realFlag.length > 0 && flag === realFlag

0x0305 第一层:正则表达突破

这一层特别容易,只要你输入的内容满足8位字符,且字符只允许大小写、数字以及感叹号即可,第一层判断轻松拿下,光标步进到 29行

0x0306 第二层:realFlag 的突破

第二层判断不难看出,realFlag 是要与我们输入的 flag 进行比较的,如果我们在 31行 打个断点,然后直接去看 realFlag 的值不就可以轻松秒杀?然而…

不难发现,realFlag 返回了 ""空字符串,言外之意就是我们肯定漏了一个很关键的信息点。就是 29行protectionByte

显然这个变量作为参数传给了一个混淆过的函数名的函数,我们可以猜测 protectionByte 很大程度上决定了 realFlag 的正常输出,但我们怎么知道 protectionByte 应该是什么的时候才会输出正确的 realFlag 呢…

0x0307 穷举 protectionByte

遇事不决,穷举解决(当然不能乱用)。protectionByte 变量对应的就是你输入的字符串中的第一个字符的 ASCII 码,对于 ASCII 码来说,字符码最多也就不超过 127,况且还需要满足 第一层的正则表达式规则,所以完全可以穷举它,并直至 realFlag 返回一个不为空的字符串,那我们的目标就达到了。

0x0308 代码实现穷举并找出 realFlag

这个代码就太简单了,一个 for 循环搞定一切。

for(let _ascii = 0; _ascii < 127; _ascii++){
    const realFlag = (0,_rust_sdk__WEBPACK_IMPORTED_MODULE_1__/* .getFlag1 */ .S7)(_ascii);
    if (realFlag != ''){
        console.log(realFlag);
        break;
    }
}

直接把这代码在 Console 里面一粘贴,一执行,realFlag 自然就出来了。

0x04 滴!签到成功

第一题顺利打卡成功。