作为一个 ctfer 做题时的思维真的太重要了,有的题明明很简单却总是卡在最后一步,以几个题为例说一下啥是逆向思维和发散思维
逆向思维
逆向思维当然在逆向中是最常用的,但是misc,web中也会遇到
一个misc题:
# js逆向算法
/**
* Pseudo md5 hash function
* @param {string} string
* @param {string} method The function method, can be 'ENCRYPT' or 'DECRYPT'
* @return {string}
*/
function pseudoHash(string, method) {
// Default method is encryption
if (!('ENCRYPT' == method || 'DECRYPT' == method)) {
method = 'ENCRYPT';
}
// Run algorithm with the right method
if ('ENCRYPT' == method) {
// Variable for output string
var output = '';
// Algorithm to encrypt
for (var x = 0, y = string.length, charCode, hexCode; x < y; ++x) {
charCode = string.charCodeAt(x);
if (128 > charCode) {
charCode += 128;
} else if (127 < charCode) {
charCode -= 128;
}
charCode = 255 - charCode;
hexCode = charCode.toString(16);
if (2 > hexCode.length) {
hexCode = '0' + hexCode;
}
output += hexCode;
}
// Return output
return output;
} else if ('DECRYPT' == method) {
// DECODE MISS
// Return ASCII value of character
return string;
}
}
document.getElementById('password').value = pseudoHash('19131e18041b1d4c47191d19194f1949481a481a1d4c1c461b4d484b191b4e474f1e4b1d4c02', 'DECRYPT');
看到这个题目一般可能直接想到去逆推过程,写一个逆向脚本
import re
str = "19131e18041b1d4c47191d19194f1949481a481a1d4c1c461b4d484b191b4e474f1e4b1d4c02"
strs = re.findall(".{2}", str)
for i in strs:
item = 255-int(i, 16)
if item > 128:
item = item-128
print(chr(item), end="")
如果你的脚本能力不太行,或者短时间内想不过来逆向过程,可以用另一种方法
仔细看下 js 脚本,是将输入的一个字符变成了两个字符,而且是固定的,比如 a 加密之后是 1e
那么就可以直接把26个英文字符加数字全部加密一遍,19131e18041b1d4c47191d19194f1949481a481a1d4c1c461b4d484b191b4e474f1e4b1d4c02
然后替换为英文字符就ok了
pseudoHash('abcdefghijklmnopqrstuvwxyz0123456789{}', 'ENCRYPT');
'1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706054f4e4d4c4b4a494847460402'
新建一个文档把字符放进去
因为 terminal 是等宽字体,可以在这里做参考,然后文本中 ctrl+h 替换第一排字符串
最终得到flag
flag{db38fbff0f67e7eb3c9d274fd180a4b3}
当然如果脚本写的够快,别用这种方法,只是提供一种思路
web中可能会出现游戏题目,做这种题目是就需要多方面考虑
比如2021莲城杯-Minesweepe
题目提供了三个难度的扫雷,分别是flag的三部分,如果能玩通关是可以拿到flag的,但是不是每个人都是游戏高手,靠玩游戏通过花费的时间要比较多,而且这是一个ctf题,当然会有别的方法去拿到flag
这个题就是一个js题目,但是在源码中flag是被编码的,和上题类似你可以用逆向的方法倒推出flag
但是还有更简单的方法,你想一想,作为一个 js 本地扫雷游戏,需要啥数据直接改不就行了,找找有啥功能点、游戏是如何计分的、游戏有啥加分道具,改改改
以这个题目为例,发现js中保存了炸弹数量,那改就完了
就出现了第一张图的效果,直接通过
发散思维
发散思维就是联想呗,比如给你一句话你就能扩展做题思路的题目描述或者hint就是发散的起点
发散思维在misc中更是常见,啥稀奇古怪的图形密码和各种隐写
misc中用到发散思维的例子:WHUCTF-版权保护
下载附件得到两个 txt 文件,查看说明
小p发现自己的文章被别人复制粘贴了,感到很气愤,于是他偷偷地将flag藏到了文章中,你能找到flag吗? 格式 whuctf{}
再查看题目. txt
,能看到的里面都是重复的我很帅
三个字,结合题名版权保护和题目描述,很容易想到出题人利用零宽度字符进行隐写(因为零宽度字符可以用来作为一种水印,可参考这篇文章,用 vim 查看
这个题题目就是提示,能从版权保护想到零宽度字符就是发散思维,当然这个联想并不是凭空想象,而是做题经验
再举一个web方向的例子
web题目:virink_2019_files_share
源码中提示
<!-- Hint : flag in f1ag_Is_h3re -->
题目中存在文件读取,一般可能会想题目环境中存在一个 f1ag_Is_h3re
文件 flag 在这个文件中,但是实际上却没有这个文件,这时候就需要发散一下思维想一下会不会有别的可能,答案是有一个 f1ag_Is_h3re 文件夹,文件夹中有 flag 文件,文件包含 f1ag_Is_h3re/flag 即可
总的来说,这东西还是很靠经验和脑洞的,做的多了也就知道有啥可以利用的点了,才能确保你发散的方向是对的,所谓熟能生巧,发散逆向更是需要结合使用