加载中...

【Root-Me】 ELF - CrackPass



前言

Cracking : ELF - Ptrace】的进阶版,区别在于:无法从静态源码中查看代码地址了~

其实除了不方便打断点之外,逆向流程还是一样的,不算太难。

不过两题的知识点还是共通的,建议先做【Cracking : ELF - Ptrace】。


试错

开启挑战后下载压缩包 ch8.zip ,解压后得到脚本 Crack

放到 Linux 上直接运行,发现给定不同的密码有不同的提示:

  • 若无密码,如执行命令 ./Crack, 提示 You must give a password for use this program !
  • 若密码有特殊字符,如执行命令 ./Crack exp-blog.com, 提示 Bad password !
  • 若密码无特殊字符,如执行命令 ./Crack exp, 提示 Is not the good password !

执行命令 gdb Crack 开启调试器,但是输入命令 layout asm 后却没有显示汇编源码。

执行命令 r 开始调试代码,此时才显示汇编源码,但是提示 Don't use a debuguer !

至此我们获得三个信息:

  • 源码地址只有在代码运行时才能查看,增加了打断点调试的难度
  • 程序被加壳了,需要绕过调试器检测
  • 一个常量字符串 Don't use a debuguer !


绕过壳

由于我们看不到代码的静态地址,因此就无法在 Don't use a debuguer ! 之前打断点进行绕过,此时要换个思路。

输入命令 info file 可以列出文件每个段的入口地址,其中 .text 是代码段的入口,亦即 main 函数的入口。

可以看到代码段的地址范围为 0x08048440 - 0x0804877c

执行命令 break *0x08048440 在入口地址打个断点,然后输入命令 r exp 开始调试 。

此处随便使用一个无特殊字符的密码 exp ,是为了绕过 Bad password ! 分支,后面用 IDA 一看源码时就知道为什么要这样做了。此处直接用无特殊字符的密码只是为了简化调试过程。

明显程序在入口位置中断了,我们看到了 main 函数入口 __libc_start_main@plt ,且还没有提示 Don't use a debuguer ! ,说明我们在检测点之前刹车了。问题是,检测点在哪 ?

此时同步在 Windows 下用 IDA 打开 Crack 文件。

找到 main 函数的代码附近有一个 jns short loc_804869F 跳转语句 (补全地址为 0x0804869F),该语句的其中一个分支就是 Don't use a debuguer !

因此现在的目标就是在 Linux 的 dbg 下找到这个位置进行绕过。

在 dbg 下通过键盘 滚动代码,很快找到 jns 0x804869f 语句,由于这是要绕过的语句,因此在其前一条语句 test %eax,%eax 打断点。

因其地址为 0x804868a ,输入命令 break *0x804868a

执行命令 c 让代码继续运行,在语句 test %eax,%eax 处中断。

此时输入命令 info reg 查看寄存器 eax 的值为,得知为 -1 。

若如常执行,由于 test 的结果为负数,即 SF 符号位会被置 1 ,jns 判断后必定会流转到 Don't use a debuguer ! 分支。

要改变分支走向,就需要在此时通过修改寄存器 eax 的值,间接改变 SF 符号位。

输入命令 set $eax=0 即可绕过。


找到密码

修改寄存器后,先不忙着执行代码,否则即使绕过了 debuguer 判定,由于密码是错的,程序还是会直接执行到 Is not the good password ! 的分支。

现在的目标是找到密码判定的位置,让程序中断在那里。

从 IDA 查看代码,接下来应该是会流转到 call sub_80485A5 模块,双击可以跳转到这个模块。

在这个模块里,很快就发现 call _strcmp 语句,以及其后的正确 / 错误密码的分支。

虽还有一个 Bad password ! 分支,但综合前面分析已经知道,因为这次调试输入的密码没有特殊字符,所以不用管这个分支。

唯一的问题是,没有这个语句的地址,不能直接打断点。

但是我们找到在其前面不远处的子模块入口地址 loc_80485E8 ,即 0x080485E8

回到 Linux 的 gdb ,输入命令 break *0x080485E8 打上断点,然后执行命令 c 让程序继续运行。

此时从 gdb 的源码已经可以直接看到密码比较语句 call 0x804842c <strcmp@plt> 了,其地址为 0x8048617

执行命令 break *0x8048617 在此处打上断点,然后执行命令 c 让程序运行到此处。

剩下的事情就简单,只需要查看比较函数 strcmp 的两个入参即可,必定有一个是正确密码。

须知道函数是存储在栈空间的,而栈指针为 esp ,因此先执行命令 x/8wx $esp 可以查到 esp 指针所指向栈顶的前 8 个地址。

在通过 x/s 地址 命令逐个地址查看,发现前两个地址就是 strcmp 函数入参。

其中一个是输入的密码,另一个是真正的密码,完成挑战。


答案下载

flag 下载后的 flagzip 的文件需要手动更改后缀为 *.zip,然后解压即可(为了避免直接刷答案)


文章作者: EXP
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 EXP !
  目录