-
-
2018 看雪 CTF 第十三题 机器人历险记
-
发表于: 2018-12-27 14:12 5619
-
早上的时候验证码出不来,补发一下
描述写着是“智能硬件PWN”,但是没有给出服务器地址。解压下载到的压缩包之后用给出的 QEMU 命令行运行起来,发现其实还是个传统的输入答案告诉你对不对的逆向题。
可以看出给出的程序是一个大端的 MIPS-I 机器上运行的 Linux 中运行的 ELF,静态链接。其采用 GCC 6.2.0 编译,使用了 GMP 这个库。观察 rootfs 可以看出其似乎是作者对着 CLFS 编译出来的一套系统,采用了 musl 作为 libc,soft-fp,还能看到若干命令行。
直接在反汇编器里裸分析 kanxuectf2018 显然是不太明智的,原因是程序中用到了大量 GMP 中的函数,如果不识别出来的话分析起来会比较困难。注意到上面提到的 CLFS 这个 tutorial 中给的 GCC 版本也是 6.2.0,不妨认为作者这一整套库就是这么编译出来的,于是照抄其中的 configure 参数,编译 cross GCC,交叉编译出 musl 和 GMP 的静态库,然后用 FLIRT 做出函数签名来,在 IDA Pro 里应用,即可识别出大部分 libc 函数和几乎所有的 GMP 函数,之后这个程序阅读起来就会容易很多。
接下来就是一通读代码了,可以找到 main 在 00405A00,逻辑十分简单,就是在一个 while (true)
中不断打出 banner,读入输入,验证,如果验证通过的话就退出(根据 init.d 里写的启动脚本来看,退出之后会被丢进一个 shell 里,可能就是这样强行掰成所谓的 PWN 的吧……)。
验证分几块:
k 是一串数字这个 hint 提示我们我们可能要跟某种密码学算法较一会儿劲。
00406614 和 0040615C 这两个验证函数里面不止有调用 GMP,还有使用一些自己写的函数,我们经过一番观察之后会发现其实现了一些 GF(p) 上的椭圆曲线操作(暂时没时间写具体的分析教程,不熟悉 ECC 的可以去看 这个教程,是我见过的所有 tutorial 里面质量最高的之一),贴一下标注好的函数名和结构体:
找到初始化曲线参数的地方,把曲线参数抄出来:
00406614 实现的是 ECDSA 签名验证,里面硬编码了一个公钥,验证输入是不是 "Welcome to KanXue CTF 2018"
的签名(hash 用的是 SHA-1)。到这里,0040602C 限制死的部分就很明确了,就是 ECDSA 签名的 (r, s) 里的 r。hint 里的 k 多半也就是签名过程中作为 "ephemeral key" 随机生成的那个 k 了。距离能还原还差一个私钥,考虑到 64 位对椭圆曲线上的离散对数来说算是一个不大不小的 key size,如果它没什么特殊性质的话要跑出来还是需要投入一些算力的,跑之前拿 sage 先胡乱算一算试一试:
等一会儿之后会发现居然跑了出来,dA = 997247,看来是这个 key 放了水啊。
0040615C 实现的是是把输入的点加上一个写死的点,判断必须等于另一个点,没有难度,直接算出来即可。
Sage 代码。
ECDSA 那个验证的时候验证输入的时候把本来应该是 if (r >= 1 && r < n && s >= 1 && s < n)
的判断写成了 if (r >= 1 || r < n || s >= 1 || s < n)
,相当于可以绕过对 r 和 s 的范围的检查。注意到 s + n 之后依然不超过 2**128
,所以这样自然就可以构造出另一组解 3f43ed6ff36724cae43cb416321007c25f1524ad31c1c5667111e3d30e553e0e
。
另外注意到输入的长度没有判断死,但是 buffer 的大小比较蛋疼,会有缺00的情况,但仔细构造的话应该还是能有办法构造出更多多解的,懒得搞了。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课