-
-
[讨论] 看雪.安恒2020 KCTF春季赛 第三题 寻踪觅源 Writeup
-
发表于:
2020-4-19 11:34
6770
-
[讨论] 看雪.安恒2020 KCTF春季赛 第三题 寻踪觅源 Writeup
说明:本文分析的是修正多解 bug 前的 binary,但相关方法应当是通用的。
题目给出了一个 Win32 控制台应用程序 lelfei.exe
,简单看下会发现它是由 GCC: (i686-posix-dwarf-rev2, Built by MinGW-W64 project) 6.3.0
构建的,且带有调试符号,IDA Pro 可正常识别。
这些像是 JS_NewObjectFromShape
的符号非常扎眼,搜索一下会发现它是 QuickJS 中的。下载 QuickJS,构建出来(直接打 make 就可以)之后试一试,可以发现它有一个 qjsc
,可以将一段 JavaScript 脚本编译为字节码后,和一个生成出的 stub 及 QuickJS 本身一起链接成一个可执行程序。使用 qjsc -e
可以让它输出嵌入字节码后,编译链接前的 C 代码。随便写一个 Hello World,这么做一下,观察得到的程序结构:
跟 lelfei.exe
基本是一样的。lelfei.exe
的 main 函数显著大,是因为构建时开了 LTO,自动 inline 了很多函数进来。
简单阅读一下可以发现,lelfei.exe
在 qjsc
本身生成的逻辑上做了一点改动,加入了读入用户名、序列号的部分,读入的用户名和序列号会直接 patch 进程序内嵌的字节码。
简单看下代码可以发现程序中嵌入的字节码在 0x458040 处,长度为 946 字节。
我们将它提取出来,照猫画虎换进一个像是上面那样的 .c
中,然后编译并和 QuickJS 链接起来,看看能不能执行:
呃……好像不可以。挂上调试器调一下(因为是源码构建的,可以源码调试 QuickJS),会发现看起来读入的字节码从中间某块往后就不太正确了。考虑到并不是全都不对,先不考虑是作者将它打乱了,而是考虑是否是版本不匹配。下载 QuickJS 的历史版本逐一尝试,尝试到 2020-01-19 版的时候:
执行成功了。得到了在 Windows 下直接执行这个程序并输入错误序列号一样的反应。
我们手动将作者给出的用户名和序列号 patch 进字节码里重新编译,可以发现确实能输出 Success!
。至此,原始的 lelfei.exe
已经没有了任何作用,可以抛在一边了。
事情进展到这种地步之后,基本的思路自然是在 QuickJS 中加入代码,将读取回来的字节码输出出来,然后逆向字节码。但稍微读一下 QuickJS 的代码就会发现,它本身就带有这个功能,修改相关宏定义启用即可;另外,当函数对象是读入而非编译出来的时,并没有打印字节码,修改 JS_ReadObjectRec
函数在 BC_TAG_FUNCTION_BYTECODE
这个 case 最后加一行输出即可。总之,对 quickjs.c
文件应用下面这个 patch:
再照上文编译并运行程序,即可得到一段比较漂亮的输出(编辑掉了无关的部分,完整文件见附件):
可以看到并不长,也很容易理解,对照着将验证逻辑还原回 JavaScript:
验证逻辑比较简单,解起来应该也相对容易,但比较无语的是,下面这一行做的变换显然不是双射(怀疑作者是想打 0x10,手滑打错了):
因此存在多解。
用上面逆向得出的 js 代码算出 KCTFKCTFKCTFKCTF
对应的 m
和 l
:
得到 243377798925556026477314360n 66
。
再算出序列号:
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2020-4-19 11:34
被Riatre编辑
,原因: