CTF笔记: 跳转ESP与PEDA

之前在Intro to Infosec的课上有一道CTF题,大致就是一个常规的用了gets()的32位Linux二进制执行文件,没开NX、Canary、PIE但机器本身开了ASLR。程序没有format string漏洞来泄露栈地址,但可以通过劫持执行流程来让puts()泄露任意内存地址的数据。有问题的函数是这样的:

void vuln(){
  char buf[BUFSIZE];
  gets(buf);
  puts(buf);
  fflush(stdout);
}

乍一看不算很难,但仔细想想开了ASLR的时候栈的基地址就是随机的,就算没开NX也得先找到栈地址或者跳转到ESP才能运行栈溢出注入的Shellcode。问了问ChatGPT有没有通过固定地址里的数据(比如PLT/GOT表附近的数据)来泄露栈地址,回答是正常来说不会有,如果有的话那就是另外一个安全漏洞。那只能用ROP Chain来解决问题了,因为没开PIE所以.text里面指令地址都是固定的。然后用PEDA搜了 push espjmp espjump ebp 等等一系列可能的gadget,结果都是没找到,然后就尬住了。上网搜也没搜到怎么做。

只能说我思路是对的,但经验不够并且过于相信PEDA的 ropsearch 功能。最后我用的是return-to-libc的方式解决的。先劫持返回地址让它返回到 puts@plt 并且打印出GOT表,然后用GOT表里面的函数指针查询libc版本(依靠libc数据库),然后修改其中一个GOT指针指向 execve ,最后执行这个被修改了GOT表的函数来达成 cat flag.txt 。这样写下来脚本当然很长,写的时候就很疑惑了因为正常来说上课没教到return-to-libc而且这是入门课,应该不需要整的这么复杂。

然后交flag的时候看到旁边的Hint就傻眼了,旁边的Hint直接就告诉了我怎么去跳转到 esp ,之前读题的时候完全没看到。

大致是这样子:几乎每个ELF的程序入口都在 _start 例程,这个是gcc等编译器自动生成的。然后这个例程里面会有这么几个指令:

80491d1:       e8 9a ff ff ff          call   8049170 <__libc_start_main@plt>
80491d6:       f4                      hlt
80491d7:       8b 1c 24                mov    (%esp),%ebx
80491da:       c3                      ret

(还发现有一点,gcc的 --no-pie 是开PIE, -no-pie 才是关PIE,过于抽象,文档里也没说,我就说用 --no-pie 编译了半天怎么还是开着PIE的执行文件)

这几个指令乍一看没什么,但如果错位反汇编的话就能发现会变成这样:

80491d5:       ff f4                   push   %esp
80491d7:       8b 1c 24                mov    (%esp),%ebx
80491da:       c3                      ret

假如从 call 最后一个字节开始反汇编,它就会跟后面 hltf4 粘一块变成 push esp ,这样我们就有了一个 push esp; ret 的gadget。push之后ret也是等同于直接jmp的。也就是说,只要把 vuln() 的返回地址改成 0x80491d5 ,程序就会跳转到这个gadget,然后跳转到esp。这时候esp指向的就是返回地址下面的4字节的位置,不需要弄return-to-libc这么复杂的执行链。

看到这个Hint整个人都傻了,因为我谷歌没搜到这篇文章而且我也确实是用PEDA的 ropsearch 搜索过了这个gadget,提示是没有。我改了一下PEDA的源文件让它打印出来实际检索的数据,发现它并不会因为一个指令能被编译成多种形式就添加多个search—— push esp 还有一种写法是 54 ,然后PEDA搜索的是 \x54.{0,24}\xc3 ,所以才没找到这个 ff f4 ** ** ** c3 的gadget。看样子以后碰到 asmsearch 或者 ropsearch 提示没找到的时候得留个心眼,看看要找的指令是不是还有别的编码。

引用文献

  1. 上面JMP ESP小技巧的原文:https://blog.inndy.tw/2017/01/24/x86-ELF-stack-overflow-jmp-esp-trick/
  2. X86 PUSH 编码文档:https://c9x.me/x86/html/file_module_x86_id_269.html