二进制-整数溢出漏洞

漏洞成因

  • 在计算机中,整数类型分为无符号整数有符号整数两种;
  • 有符号整数会在最高位用0表示正数,1表示负数,而无符号整数则没有这种规则;
  • 常见的整数类型有8位(单字节字符类型、布尔类型)、16位(短整型)、32位(长整型)等;
  • 当一个整数存入了比它本身小的存储空间中,超出了数据类型所能表示的范围时,就会发生整数溢出;

基础知识

整数数据类型

数据类型 关键字 占用字节 表示范围
字符型 char 1 -128~127
无符号字符型 unsigned char 1 0~255
布尔型 bool 1 0~1
短整型 short 2 -32768~32767
无符号短整型 unsigned short 2 0~65535
整型 int 4 ~
无符号整型 unsigned int 4 0~
长整型 long 4 ~
无符号长整型 unsigned long 4 0~
64位整型 long long 8 ~

漏洞原理

上溢

一个整数通过运算(赋值),超过它能表示的上限,则会变成一个很小的数;

  • 无符号

    • 一个unsigned short类型的变量a=65535,当a累加5时会变成4;
    • 这是因为在计算机中,$$(65535){10}+(5){10}=(1111111111111111)_2+(101)_2=(10000000000000100)_2(0000000000000100)2 = (4){10}$$;
  • 有符号

    • 一个short类型的变量a=32767,当a累加5时会变成-32764;
    • 这是因为在计算机中,$$(32767){10} + (5){10} = (0111111111111111)_2 + (0000000000000101)_2 = (1000000000000100)_2(1000000000000100)2 = (-32764){10}$$;
    • 在计算机中,整数以补码形式存储,正数的补码与原码一致,负数的补码等于原码按位取反+1:
      • 的补码,等于反码,再加1,等于$$(-11111111111100)2(-32764){10}$$;

下溢

一个整数通过运算(赋值),低于它能表示的下限,则会变成一个很大的数;

  • 由于无符号整数不能识别负数(无符号整数类型接收一个负数会变成一个大正数),因此一个short类型的变量b=-4赋给unsigned short类型的变量a时,a=65532
  • 这是因为-4是负数,在计算机中以补码形式存储,-4的补码为,而由于unsigned short数据类型的首位不表示符号位,所有位全部用来表示数据,因此b $$ = (1111111111111100)2 = (65532){10}$$;

截断

将数据放入了比它本身小的存储空间中,从而出现了溢出,例如:短整型接收整型时只能接收低16位);

  • 一个int类型的变量a=65537赋给short类型的变量b时,b=1
  • 这是因为short类型的空间是16位,,前16位为$$(0000000000000001)2=1{10}$$;

符号问题

符号问题引发的整数溢出漏洞,大致有三点需要注意:

  1. 有符号整数之间的比较
    • 从汇编中可以看到,当两个有符号整数比较大小时,是将两数作差,若结果为正则显示被减数大,若结果为负则显示减数大;
    • 当两个有符号整数作差时出现上溢或下溢时,比较结果会与事实相反;
    • 例如,short类型的32767与-5比较大小时,在计算机中,short类型的,从而得出32767<-5的错误结论;
  2. 有符号整数的运算
    • 当两个有符号整数运算时,有可能发生上溢或者下溢;
  3. 无符号整数和有符号整数的比较(运算)
    • 当无符号整数和有符号整数进行比较或运算时,会将有符号整数转化成无符号整数之后进行比较或运算,从而导致上溢下溢以及与事实相反的结论;
    • 例如,short类型的-5与unsigned short类型的13比较大小时,-5转化成无符号整数后等于65531>13,与事实相反;

漏洞分析

以如下程序为例进行漏洞分析;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* integer_overflow */
#include <stdio.h>
#define N 95
int main(){
int Number;
unsigned short number;
while(1){
printf("ID Number:");
scanf("%d", &Number);
number = Number;
if(number <= N && Number > N){
puts("Welcome!!!");
break;
}
else {
printf("%d\n", number);
printf("It is illegal, please check your id number.\n");
}
}
return 0;
}
  • number和Number的数据类型不同,可以表示的数据范围不同,因此,可以通过整数溢出 的方式实现输出Welcome!!!

  • 输入一个合适的较大的值给Number,使得在Number给number赋值时发生截断之后, number的值较小,从而满足if条件;

  • 通常情况下,整数溢出只是用来改变程序流程,需要结合其他漏洞类型进一步实现漏洞利用;

备注:实验程序下载