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 的地址 - 利用缓冲区溢出覆盖返回地址为后门
题解
建议完成任务后再查看题解
- ret2win
- ret2win32
备注
本地测试64位程序时可能遇到的问题:
1 | movaps xmmword ptr [rsp + 0x40], xmm0 |
出现这个问题的原因是执行某些
-
ret2win 时尽量避开栈操作指令:1
2
3
4
5
6
7
8
9
10
11
12
13
14.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 endp0x400811 处的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.
与
将
/bin/cat flag.txt 作为参数传给system 函数
知识点
- 简单ROP链的编写
思路
- 使用ida或cutter反编译程序
- 找到指令
call system 的地址 - 找到字符串
/bin/cat flag.txt 的地址 - 构造rop链
- 利用缓冲区溢出覆盖返回地址为rop链
题解
建议完成任务后再查看题解
- split
- split32
②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.
这题提供了一个自定义的动态链接库,其中包含
知识点
- 动态链接库、PLT表
思路
- 使用ida或cutter反编译程序、动态链接库
- 在动态链接库中大致了解三个
callme 函数的功能 - 在程序中找到三个
callme 函数在PLT表中的地址 - 构造rop链,配置函数参数
- 利用缓冲区溢出覆盖返回地址为rop链
题解
建议完成任务后再查看题解
- callme
- callme32
③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可以实现内存任意写,目标是将字符串
知识点
- 任意写gadget
思路
- 使用ida或cutter反编译程序
- 找出可用于任意写的gadget
- 构造rop链,将字符串写入
bss 段 - 利用缓冲区溢出覆盖返回地址为rop链
题解
建议完成任务后再查看题解
- write4
- write432
备注
④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链
题解
建议完成任务后再查看题解
- badchars
- badchars32
懒得写异或的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链
题解
建议完成任务后再查看题解,出于练习的目的,建议使用预期解再看一遍
- fluff
- fluff32
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.
这题给了一个自定义的动态库,要求调用其中的
知识点
- 栈迁移、动态链接库、GOT表
思路
- 使用ida或cutter反编译程序
- 栈迁移至题目给出的新缓冲区
- 构造rop链:
- 从foothold_function的GOT表泄漏libpivot地址
- 根据偏移量计算ret2win的真实地址
- 执行ret2win
题解
建议完成任务后再查看题解,出于练习的目的,建议使用预期解再看一遍
- pivot
- pivot32
⑦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链
题解
建议完成任务后再查看题解,出于练习的目的,建议使用预期解再看一遍
- ret2csu