适合初学者的ROP攻击⼊门教程-[Pwn]ROPEmporiumGuide
ROP Emporium
是⼀个ROP攻击⼊门教学⽹站,提供了⼀系列的挑战任务,这些挑战对逆向⼯程或debug的要求不⾼,因此对初学者⼗分友好,适合初学者了解ROP攻击。⽹站中共有8个挑战任务,每个挑战都引⼊了⼀个新概念/知识点,其复杂性和难度逐渐增加,循序渐进,⽽且每个挑战都有32/64位两个版本的程序,适合初学者了解⼆者之间的差异。
本⽂提供ROP Emporium所有挑战的说明⽂件、⼆进制⽂件、在线动态靶机环境以及⼀些相关解题线索。读者可前往动态靶场完成任务后,再返回本⽂查看相应题⽬的知识点、解题思路以及解题脚本。
附件下载:
动态靶场:
靶机环境:Ubuntu 18.04
读者可前往动态靶场完成任务后,再返回本⽂查看相应题⽬的知识点、解题思路以及解题脚本。
ret2win means ‘return here to win’ and it’s recommended you start with this challenge.
ret2win就是利⽤漏洞直接将程序控制流劫持到程序预置的后门函数win
win函数通常是可以打印flag,或者getshell
知识点
缓冲区溢出(覆盖返回地址)
思路
使⽤ida或反编译程序
到后门函数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/"
.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) 调整栈指针
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/这个字符串,因此可以通过构造简单的ROP链获取flag
将/bin/作为参数传给system函数
知识点
简单ROP链的编写
思路
使⽤ida或反编译程序
到指令call system的地址
到字符串/bin/的地址
构造rop链
利⽤缓冲区溢出覆盖返回地址为rop链
题解
建议完成任务后再查看题解
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或反编译程序、动态链接库
在动态链接库中⼤致了解三个callme函数的功能
在程序中到三个callme函数在PLT表中的地址
构造rop链,配置函数参数
利⽤缓冲区溢出覆盖返回地址为rop链
题解
建议完成任务后再查看题解
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或反编译程序
出可⽤于任意写的gadget
构造rop链,将字符串写⼊bss段
利⽤缓冲区溢出覆盖返回地址为rop链
题解
建议完成任务后再查看题解
备注
$0 的含义是第0个参数,即argv[0],默认情况下程序是通过/bin/sh启动的,因此argv[0]就是/bin/sh,在本题32位程序的题解中,使
⽤$0代替/bin/sh作为system执⾏的命令。
Learn to deal with badchars, characters that will not make it into process memory intact or cause other issues such as premature chain termination.
这道题与③相⽐,新增了对badchar的检测,并且将⽤于任意写的gadget换成了具有异或(写内存)功
能的gadget,因此⽬的是练习通过异或对badchar进⾏绕过。
badchar为 b i c / f n s,所以其实也可以通过$0绕过
知识点
异或功能gadget
思路
使⽤ida或反编译程序
出可⽤于异或写内存的gadget
构造rop链,通过多次异或绕开badchar,将字符串写⼊bss段
利⽤缓冲区溢出覆盖返回地址为rop链
题解
建议完成任务后再查看题解
懒得写异或的exp了,⼤概就那个意思…
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.
这题还是和③类似,与之相⽐,去掉了可以直接写内存的gadget,换成了⼀些更为复杂的gadget,因此需要利⽤多个gadget组合、配合实现写内存的功能。
知识点
组合gadget,间接实现任意写
思路
使⽤ida或反编译程序
出可⽤于写内存的gadget(这题多个gadget组合才能完成任意写)
构造rop链,将字符串写⼊bss段
利⽤缓冲区溢出覆盖返回地址为rop链
题解ubuntu使用入门教程
建议完成任务后再查看题解,出于练习的⽬的,建议使⽤预期解再看⼀遍
32位程序的解法是预期解,64位的我偷了个懒:-p
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.