6.2.1 re XHPCTF2017 dont_panic

下载文件

题目解析

第一步当然是 file 啦:

$ file dont_panic
dont_panic: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped

64 位,静态编译,而且 stripped。

看一下段吧:

$ readelf -S dont_panic
There are 13 section headers, starting at offset 0xfa388:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000401000  00001000
       000000000007ae40  0000000000000000  AX       0     0     16
  [ 2] .rodata           PROGBITS         000000000047c000  0007c000
       0000000000033f5b  0000000000000000   A       0     0     32
  [ 3] .typelink         PROGBITS         00000000004b0080  000b0080
       0000000000000b4c  0000000000000000   A       0     0     32
  [ 4] .itablink         PROGBITS         00000000004b0bd0  000b0bd0
       0000000000000038  0000000000000000   A       0     0     8
  [ 5] .gosymtab         PROGBITS         00000000004b0c08  000b0c08
       0000000000000000  0000000000000000   A       0     0     1
  [ 6] .gopclntab        PROGBITS         00000000004b0c20  000b0c20
       0000000000044d5d  0000000000000000   A       0     0     32
  [ 7] .noptrdata        PROGBITS         00000000004f6000  000f6000
       0000000000002608  0000000000000000  WA       0     0     32
  [ 8] .data             PROGBITS         00000000004f8620  000f8620
       0000000000001cf0  0000000000000000  WA       0     0     32
  [ 9] .bss              NOBITS           00000000004fa320  000fa310
       000000000001a908  0000000000000000  WA       0     0     32
  [10] .noptrbss         NOBITS           0000000000514c40  000fa310
       00000000000046a0  0000000000000000  WA       0     0     32
  [11] .note.go.buildid  NOTE             0000000000400fc8  00000fc8
       0000000000000038  0000000000000000   A       0     0     4
  [12] .shstrtab         STRTAB           0000000000000000  000fa310
       0000000000000073  0000000000000000           0     0     1

我们发现一些奇怪的东西,.gosymtab.gopclantab,Google 一下才知道,它其实是一个用 Go 语言编写的程序。好吧,运行它:

字符串“Nope.”应该是判断错误时的输出,我们顺便找到了使用它的地址为 0x47ba23,接下来在去 r2 里看吧,经过一番搜索,找到了最重要的函数 fcn.0047b8a0

根据我们的分析(详见注释),密码判断逻辑应该如下:

如果要硬着头皮调试的话当然也可以,但我们这里采取暴力破解的办法。还记得章节 5.2 里说的 pin 吗,”由于程序具有循环、分支等结构,每次运行时执行的指令数量不一定相同,于是我们可是使用 Pin 来统计执行指令的数量,从而对程序进行分析”。这里就是这样,程序对输入的密码逐位判断,如果错误,就跳出来,所以根据我们密码正确字节数的不同,程序会执行有明显差异的次数。我们还讲过一个官方示例 inscount0.cpp,我们针对这一题稍微做一点修改,如下:

主要是修改了两个地方:

该函数会在每条指令执行之前被调用,判断是否是我们需要的 0x0047b96e 地址处的指令。

然后由于函数 docount 需要一个参数,所以 Instruction 函数也要修改,加入指令的地址 IARG_INST_PTR

好,接下来 make 并执行。其实我们是知道 flag 结构的,”hxp{...}“ ,总共 42 个字节。

注意,这里的 5 是执行次数,匹配正确的个数是 5-1=4,即 "hxp{"。但是最后一次是例外,因为完全匹配成功后直接跳转返回,不会再进行匹配。

和预期结果一样,下面写个脚本来自动化这一过程:

可惜就是速度有点慢,大概跑了一个小时吧。。。

参考资料里的 gdb 脚本就快得多:

在最后一篇参考资料里,介绍了怎样还原 Go 二进制文件的函数名,这将大大简化我们的分析。

参考资料

Last updated

Was this helpful?