一 漏洞简介
整数溢出漏洞(integer overflow):在计算机中,整数分为无符号整数以及有符号整数两种。其中有符号整数会在最高位用0表示正数,用1表示负数,而无符号整数则没有这种限制。另外,我们常见的整数类型有8位(单字节字符、布尔类型)、16位(短整型)、32位(长整型)等。关于整数溢出,其实它与其它类型的溢出一样,都是将数据放入了比它本身小的存储空间中,从而出现了溢出。由此引发的一切程序漏洞都可以成为整数溢出漏洞。
二 原理分析
2.1 整数表示:
最高位表示符号
0表示正数
1表示负数
+41和-41的符号绝对值表示
2.2 标准常见的类型如下:
signed char
short int
int
long int
long long int
typedef unsigned long DWORD
typedef int BOOL
typedef unsigned char BYTE
typedef unsigned short WORD
__int8, __int16, __int32, __int64
ATOM
BOOLEAN, BOOL
BYTE
CHAR
DWORD, DWORDLONG, DWORD32, DWORD64
WORD
INT, INT32, INT64
LONG, LONGLONG, LONG32, LONG64
2.3 类型转化
符号引起的溢出
int iNumber= -3;
unsigned short uNumber;
uNumber = iNumber;
printf("u = %hu\n", uNumber);
运算引起的溢出
char cResult, cNum1, cNum2, cNum3;//默认都是有符号
cNum1= 100;
cNum2= 50;
cNum3= 50;
cResult= cNum1+ cNum2+ cNum3;
三 漏洞测试
3.1 符号位引起溢出
//漏洞验证代码
#define BUFF_SIZE 10
int main(int argc, _TCHAR* argv[])
{
int iLength;
char buf[BUFF_SIZE];
iLength= atoi(argv[1]);//注意atoi这个函数
//_int __cdecl atoi(_In_z_ const char *_Str);
if (iLength< BUFF_SIZE)
{
unsigned int num=iLength;
memcpy(buf, argv[2], iLength);
//memcpy((_Size) void * _Dst,(_Size) const void * _Src, size_t _Size);
//typedef _W64 unsigned int size_t;
}
return 1;
}
3.2 运算超出范围引起的溢出
//漏洞验证代码
#include <Windows.h>int _tmain(int argc, _TCHAR* argv[]){ unsigned short int total; total = strlen(argv[1])+strlen(argv[2]) + 1; char *buff = (char *) malloc(total); strcpy(buff, argv[1]); strcat(buff, argv[2]); return 1;}
大家看看上面的两个示例,是不是溢出发生得很隐蔽,有的是隐式转化引起的,
有的是符号位出现变化引起的,有的是原酸范文超出边界引起的。上面的只是
进行的char和short类型示例,同样的只要是涉及符号位,运算,隐式转化等均
可能出现数字溢出。所以大家在编写代码或者审计代码时候特别留意这些基本
数据类型的转化和运算。
四 漏洞利用
下面我们来做个例题吧,来熟悉练习一下这个漏洞原理吧。
题目只有一个inter程序。先检查一下:
LINUX程序随便输入一下,测试发现命令运行程序怎么输入都显示参数不对。
先暂时用IDA载入测试一下。
找到输出位置F5转换一下
注意到输出位置特殊,只有参数大于等于4才不会输出参数错误,
于是乎得知参数是4个以上。往下看貌似后面还有输出。参数v3就是argv首地址。
参数1(v4),参数2(v6),参数3(nptr),参数4(v8),这几个数有符号位和长度差异,
因此不同类型转化可能出现溢出。
往下继续查看isComment函数。果真如此,那么必须实现进入这个函数逻辑,
那么就可以实现获取flag.txt文件了。于是回溯继续研究上面的参数输入比较逻辑。
那么来研究每个参数
参数1(v4)
注意v4和v5之间关系v4>79且v5还要小于等于79只能发生溢出,v4整数,v5无符号短整数
可以实现溢出满足条件比如65536
参数2(v6)
参数2主要出现在v6位置,参数2进行了整数类型转化成v6同时v6还要满足是个无符号短整数
满足条件比如65541
参数3(nptr)
也就是转化后的nptr是个指针类型,要求长度大于3而且转化成整数值后必须等于1
利用atoi函数特性构造1ABC即可满足条件
参数4(v8)
参数4经过转化为v8(v8是个整数)转化成了char*字符串。
满足等于1其实就是十六进制0x01
测试以下,成功可以自己提交一下flag
65536 65541 1ABC 1
FLAG{(:welldone!2016-5t4rk-winners-:)}