ROP Emporium
ROP Emporium 是一个ROP攻击入门教学网站,提供了一系列的挑战任务,这些挑战对逆向工程或debug的要求不高,因此对初学者十分友好,适合初学者了解ROP攻击。网站中共有8个挑战任务,每个挑战都引入了一个新概念/知识点,其复杂性和难度逐渐增加,循序渐进,而且每个挑战都有32/64位两个版本的程序,适合初学者了解二者之间的差异。
本文提供ROP Emporium所有挑战的说明文件、二进制文件、在线动态靶机环境以及一些相关解题线索。读者可前往动态靶场完成任务后,再返回本文查看相应题目的知识点、解题思路以及解题脚本。
附件下载:rop_emporium_all_challenges.zip
动态靶场:CTFq动态靶机练习平台
靶机环境:Ubuntu 18.04
读者可前往动态靶场完成任务后,再返回本文查看相应题目的知识点、解题思路以及解题脚本。
⓪ret2win
ret2win means ‘return here to win’ and it’s recommended you start with this challenge.
ret2win就是利用漏洞直接将程序控制流劫持到程序预置的后门函数win
win函数通常是可以打印flag,或者getshell
知识点
- 缓冲区溢出(覆盖返回地址)
思路
- 使用ida或cutter反编译程序
- 找到后门函数
ret2win
的地址 - 利用缓冲区溢出覆盖返回地址为后门
题解
建议完成任务后再查看题解
备注
本地测试64位程序时可能遇到的问题:
movaps xmmword ptr [rsp + 0x40], xmm0
出现这个问题的原因是执行某些libc
函数(如printf
, system
)时,栈指针rsp
没有对齐0x10
字节,解决方法如下:
-
ret2win
时尽量避开栈操作指令:.text:0000000000400811 ret2win proc near .text:0000000000400811 ; __unwind { .text:0000000000400811 push rbp .text:0000000000400812 mov rbp, rsp .text:0000000000400815 mov edi, offset aThankYouHereSY ; "Thank you! Here's your flag:" .text:000000000040081A mov eax, 0 .text:000000000040081F call _printf .text:0000000000400824 mov edi, offset command ; "/bin/cat flag.txt" .text:0000000000400829 call _system .text:000000000040082E nop .text:000000000040082F pop rbp .text:0000000000400830 retn .text:0000000000400830 ; } // starts at 400811 .text:0000000000400830 ret2win endp
0x400811
处的push rbp
将使得rsp=rsp-0x8
,导致rsp
不能对齐0x10
稍作调整,跳过栈操作,改用
0x400815
即可 -
使用gadget (ret) 调整栈指针
①split
Combine elements from the ret2win challenge that have been split apart to beat this challenge. Learn how to use another tool whilst crafting a short ROP chain.
与ret2win
相比,这题将后门执行的命令由cat flag
改为了/bin/ls
,因此不能直接获取flag,但程序中给出了/bin/cat flag.txt
这个字符串,因此可以通过构造简单的ROP链获取flag
将
/bin/cat flag.txt
作为参数传给system
函数
知识点
- 简单ROP链的编写
思路
- 使用ida或cutter反编译程序
- 找到指令
call system
的地址 - 找到字符串
/bin/cat flag.txt
的地址 - 构造rop链
- 利用缓冲区溢出覆盖返回地址为rop链
题解
建议完成任务后再查看题解
②callme
Chain calls to multiple imported methods with specific arguments and see how the differences between 64 & 32 bit calling conventions affect your ROP chain.
这题提供了一个自定义的动态链接库,其中包含callme_one
,callme_two
和callme_three
,读者需要通过ROP配置好相应的参数,并依次调用这三个函数来解密并输出flag。
知识点
- 动态链接库、PLT表
思路
- 使用ida或cutter反编译程序、动态链接库
- 在动态链接库中大致了解三个
callme
函数的功能 - 在程序中找到三个
callme
函数在PLT表中的地址 - 构造rop链,配置函数参数
- 利用缓冲区溢出覆盖返回地址为rop链
题解
建议完成任务后再查看题解
③write4
Find and manipulate gadgets to construct an arbitrary write primitive and use it to learn where and how to get your data into process memory.
在这道题中,通过gadget可以实现内存任意写,目标是将字符串/bin/sh
或$0
写入内存。
知识点
- 任意写gadget
思路
- 使用ida或cutter反编译程序
- 找出可用于任意写的gadget
- 构造rop链,将字符串写入
bss
段 - 利用缓冲区溢出覆盖返回地址为rop链
题解
建议完成任务后再查看题解
备注
$0
的含义是第0个参数,即argv[0]
,默认情况下程序是通过/bin/sh
启动的,因此argv[0]
就是/bin/sh
,在本题32位程序的题解中,使用$0
代替/bin/sh
作为system
执行的命令。
④badchars
Learn to deal with badchars, characters that will not make it into process memory intact or cause other issues such as premature chain termination.
这道题与③write4相比,新增了对badchar的检测,并且将用于任意写的gadget换成了具有异或(写内存)功能的gadget,因此目的是练习通过异或对badchar进行绕过。
badchar为 b i c / f n s,所以其实也可以通过
$0
绕过
知识点
- 异或功能gadget
思路
- 使用ida或cutter反编译程序
- 找出可用于异或写内存的gadget
- 构造rop链,通过多次异或绕开badchar,将字符串写入
bss
段 - 利用缓冲区溢出覆盖返回地址为rop链
题解
建议完成任务后再查看题解
懒得写异或的exp了,大概就那个意思…
⑤fluff
Sort the useful gadgets from the fluff to construct another write primitive in this challenge. You’ll have to get creative though, the gadgets aren’t straight forward.
这题还是和③write4类似,与之相比,去掉了可以直接写内存的gadget,换成了一些更为复杂的gadget,因此需要利用多个gadget组合、配合实现写内存的功能。
知识点
- 组合gadget,间接实现任意写
思路
- 使用ida或cutter反编译程序
- 找出可用于写内存的gadget(这题多个gadget组合才能完成任意写)
- 构造rop链,将字符串写入
bss
段 - 利用缓冲区溢出覆盖返回地址为rop链
题解
建议完成任务后再查看题解,出于练习的目的,建议使用预期解再看一遍
32位程序的解法是预期解,64位的我偷了个懒:-p
⑥pivot
Stack space is at a premium in this challenge and you’ll have to pivot the stack onto a second ROP chain elsewhere in memory to ensure your success.
这题给了一个自定义的动态库,要求调用其中的ret2win
函数,此外栈溢出的可利用空间不足,需要利用题目中给出的gadget进行栈迁移(交换rax和rsp)
知识点
- 栈迁移、动态链接库、GOT表
思路
- 使用ida或cutter反编译程序
- 栈迁移至题目给出的新缓冲区
- 构造rop链:
- 从foothold_function的GOT表泄漏libpivot地址
- 根据偏移量计算ret2win的真实地址
- 执行ret2win
题解
建议完成任务后再查看题解,出于练习的目的,建议使用预期解再看一遍
⑦ret2csu
Learn a ROP technique that lets you populate useful 64 bit calling convention registers like rdi, rsi and rdx even in an environment where gadgets are sparse.
知识点
__libc_csu_init
中的gadget
思路
- 使用ida或cutter反编译程序
- 构造rop链:
- 通过
__libc_csu_init
中的gadget给rdx赋值 - 调用
fini_array
中的函数,保持rdx不变 - 执行ret2win函数
- 通过
- 利用缓冲区溢出覆盖返回地址为rop链
题解
建议完成任务后再查看题解,出于练习的目的,建议使用预期解再看一遍