int 整数溢出学习

发布于 2021-02-06  861 次阅读


0x00 写在前面

之前写题的时候遇到过 int 整数溢出的题,正好今天在看 CSAPP 的视频(CMU真diao),又在ctfshow上看见了一道题,就来写一写整数溢出。

0x01 数据类型

在 C 语言中,整数的基本数据类型分为短整型 (short),整型 (int),长整型 (long),这三个数据类型还分为有符号和无符号,每种数据类型都有各自的大小范围,由编译器决定。

64位下各数据类型大小范围:

数据类型 字节数 最小值 最大值
char 1 -128 127
unsigned char 1 0 255
short 2 -32768 32767
unsigned short 2 0 65535
int 4 -2147483648 2147483647
unsigned int 4 0 4294967295
long 8 -9223372036854775808 9223372036854775807
unsigned long 8 0 18446744073709551615
  • Int8, 等于Byte, 占1个字节.
  • Int16, 等于short, 占2个字节.
  • Int32, 等于int, 占4个字节.
  • Int64, 等于long, 占8个字节.

当程序中的数据超过其数据类型的范围,则会造成溢出

0x02 上界溢出

上界溢出分为两种,比如说有两个字节的 short 型,一种是 0x7fff + 1 ,一种是 0xffff + 1

第一种对无符号型没有影响,第二种对有符号型没有影响。

在计算机的底层,数据是以二进制进行保存的,0x7fff的二进制形式为 0111 1111 1111 1111 ,加了1之后就等于 1000 0000 0000 0000 ,十六进制就为0x8000,转化为unsigned char就是32768没有影响,但是转化为signed char的话就是-32768,发生了溢出。

第二种溢出,0xffff的二进制形式为 1111 1111 1111 1111 ,加了1之后等于 0001 0000 0000 0000 0000 ,这里short只有两个字节的空间,而现在显然超出了他的大小范围,这个时候就会将最高位的1舍去,只留下了 0000 0000 0000 0000 ,也就是0,也就相当于 65535 + 1 == 0 成立。

0x03 下界溢出

下界溢出与上界溢出同理,0x8000 - 10x000 - 1

第一种对于无符号型来说没有影响,32678 - 1 = 32677,但是对于有符号型来说就是 -32678 - 1 = 32677

第二种对于有符号型来说没有影响,0 - 1 = -1,但是对于无符号型来说就是 0 - 1 = 65535

0x04 漏洞触发

当我们的代码在进行类型转化时没有过多注意,进行了错误的类型转化,或者对用户的输入范围没有进行限制或只进行了单边的限制,就有可能触发整数溢出漏洞。

0x05 例题 ctfshow 数学99

下载文件,反编译一下,可以看到,他给了我们几个数学问题,让我们进行输入,如果有一个不满足条件则退出程序。

第一个 a-b=9,0<=a<9,0<=b<9 ,输入的a和b都是signed int型,四个字节大小。题中对输入进行检测,存在负号的话返回0,

输入a为8,b为4294967295,4294967295的二进制表示为0xffffffff,转化为signed int型就等于-1,8 - (-1) = 9

第二个 a*b=9,a>9,b>9 ,对我们输入的上限没有限制,我们可以找到一个溢出为9的数,然后对他进行分解。比如说 4294967305 = 48145 * 89209

第三个 a/b=ERROR,b!=0 。当输入的b不为0时,有 signal(8, (__sighandler_t)handler);

signal函数的value为8,也就是说存在 Floating point exception 时触发handler,而handler恰好可以帮我们读取flag。但是常规的触发 Floating point exception 是使得分母为0,可是b已经被限制不能为0。

SIGFPE:
According to POSIX, the behavior of a process is undefined after it ignores a SIGFPE, SIGILL, or SIGSEGV signal that was not generated by kill(2) or raise(3). Integer division by zero has undefined result. On some architectures it will generate a SIGFPE signal. (Also dividing the most negative integer by -1 may generate SIGFPE.) Ignoring this signal might lead to an end‐ less loop.

除了分母为0,最小的整数除以-1也会触发 Floating point exception ,于是输入2147483648或者-2147483648,以及-1即可。

from pwn import *

io = remote("pwn.chall.ctf.show", 28005)
io.sendlineafter("a:", "8")
io.sendlineafter("b:", "4294967295")
io.sendlineafter("a:", "48145")
io.sendlineafter("b:", "89209")
io.sendlineafter("a:", "-2147483648")
io.sendlineafter("b:", "-1")
io.interactive()