首页
社区
课程
招聘
[讨论] 看雪.安恒2020 KCTF春季赛 第三题 寻踪觅源 Writeup
发表于: 2020-4-19 11:34 6770

[讨论] 看雪.安恒2020 KCTF春季赛 第三题 寻踪觅源 Writeup

2020-4-19 11:34
6770

说明:本文分析的是修正多解 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.exeqjsc 本身生成的逻辑上做了一点改动,加入了读入用户名、序列号的部分,读入的用户名和序列号会直接 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 对应的 ml

得到 243377798925556026477314360n 66

再算出序列号:


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2020-4-19 11:34 被Riatre编辑 ,原因:
上传的附件:
收藏
免费 2
支持
分享
最新回复 (2)
雪    币: 6051
活跃值: (1441)
能力值: ( LV15,RANK:1473 )
在线值:
发帖
回帖
粉丝
2
太强大了
2020-4-20 07:48
0
雪    币: 7260
活跃值: (3602)
能力值: ( LV7,RANK:105 )
在线值:
发帖
回帖
粉丝
3
太强大了 
2020-4-20 09:16
0
游客
登录 | 注册 方可回帖
返回
//