整数溢出(stack)
整数溢出(stack)
整数溢出的介绍
首先回顾一下C语言中的整形的数据分类。
按数据类型分类主要分三类:短整形(short)、整形(int)、长整形(long)
按符号分类:有符号,无符号
并且每种数据类型都有自己的大小范围:
类型 | 字节 | 范围 |
---|---|---|
short int | 2byte(word) | 0 -32768 |
unsigned short int | 2byte(word) | 0 |
int | 4byte(dword) | 0 -2147483648 |
unsigned int | 4byte(dword) | 0 |
long int | 8byte(qword) | 正:0 负:0x8000000000000000 |
unsigned long int | 8byte(qword) | 0~0xffffffffffffffff |
正是因为数据类型的大小范围才导致了整数溢出。
溢出类漏洞
计算机中有 4 种溢出情况,以 32 位整数为例。
① 无符号上溢:无符号数 0xffffffff 加 1 会变成 0。
② 无符号下溢:无符号数 0 减去 1 会变成 0xffffffff,即-1。
③ 有符号上溢:有符号正数 0x7fffffff 加 1 变成 0x80000000, 即从 2147483647 变成了-2147483648。
④ 有符号下溢:有符号负数 0x80000000 减去 1 变成 0x7fffffff,即从-2147483648 变成了 2147483647。
一个经典的整数溢出例子就是 c 语言的 abs 函数,int abs(int x),该函数返回 x 的绝对值。但当 abs()函数的参数是 0x80000000 即-2147483648 的时候,它本来应该返回2147483648,但正整数的范围是 0-2147483647,所以他返回的仍然是个负数,即本身-2147483648。
举个例子
源码:
1 |
|
观察源码,只有当a和b相等时,才输出信息
可以看出,程序中a和b是相等的,这就是b发生了溢出,原本数据长度最大为65535,所以溢出后为1。
符号转换类漏洞
符号转换类漏洞通常出在把范围大的变量赋值给范围小的变量,64 位下 long -> int,会造成截断,只把长整型的低 4byte 的值传给整型变量,比如把 long 类型的0x100000010 赋值给 int 类型的变量就会变成 0x10。
符号转换类漏洞也会出现在把signed变量赋值给unsigned变量,如下表2-6代码。如下就是 符号转换类漏洞 demo 代码。
源码:
1 |
|
len 变量是 signed int 类型该代码没有对 len 进行完善的约束,导致 len 可以是负数。比如我们输入-1,此时传入 read 参数的 size 就会是-1,read 的第三个参数 size 是size_t 类型,也就是 unsigned int 类型,它会将-1 解析成 0xffffffff,这就间接导致了栈溢出。
可以看到我们编译时gcc也会提醒我们。
整数溢出的例子
先检查程序保护机制
开启了NX(栈上不可执行)。ida静态分析一下
先输入1, 进入登陆函数
两处溢出(read),先进入到check_passwd函数查看一下
传入的参数s为输入的passwd地址,v3是unsigned_int8类型接收passwd的长度的
strcpy函数,参数dest和s大小不同,存在栈溢出漏洞
unsigned_int8表示8bit无符号整数,这里可能存在整数溢出漏洞。
由于max_passwd为0x199,这个数据过大,因此可以存在漏洞利用。
利用整数溢出,可以将v3的长度(48)转变为260264(还是截断)照样可以通过验证。
同时程序存在后门函数:
EXP
1 | from pwn import* |