适合初学者的ROP攻击入门教程 - [Pwn] ROP Emporium Guide

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位程序时可能遇到的问题:适合初学者的ROP攻击入门教程 - [Pwn] ROP Emporium Guide_第1张图片

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链

题解

建议完成任务后再查看题解

  • 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.

这题提供了一个自定义的动态链接库,其中包含callme_one,callme_twocallme_three,读者需要通过ROP配置好相应的参数,并依次调用这三个函数来解密并输出flag。

知识点

  • 动态链接库、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可以实现内存任意写,目标是将字符串/bin/sh$0写入内存。

知识点

  • 任意写gadget

思路

  • 使用ida或cutter反编译程序
  • 找出可用于任意写的gadget
  • 构造rop链,将字符串写入bss
  • 利用缓冲区溢出覆盖返回地址为rop链

题解

建议完成任务后再查看题解

  • write4
  • write432

备注

$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链

题解

建议完成任务后再查看题解

  • 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.

这题给了一个自定义的动态库,要求调用其中的ret2win函数,此外栈溢出的可利用空间不足,需要利用题目中给出的gadget进行栈迁移(交换rax和rsp)

知识点

  • 栈迁移、动态链接库、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

你可能感兴趣的:(pwn,CTF,知识总结)