# 加载中...

• 博客等级：
• 博客积分：0
• 博客访问：415,028
• 关注人气：59
• 获赠金笔：0支
• 赠出金笔：0支
• 荣誉徽章：

## (转)整数溢出

(2011-06-13 18:28:06)

### 杂谈

1.0 目录

--1.1 什么是整数?

--1.2 什么是整数溢出?

--1.3 为什么那是危险的?

2.0 整数溢出

"A computation involving unsigned operands can never overflow,
because a result that cannot be represented by the resulting unsigned
integer type is reduced modulo the number that is one greater than
the largest value that can be represented by the resulting type."

大致的意思是:
涉及到无符号操作数计算的时候从不会溢出,因为结果不能被无符号类型表示的时候,

NB:取模的运算方法是2个数相除取余数的值

10 modulo 5 = 0
11 modulo 5 = 1

</NB>

b被赋值为1.然后我们让a和b相加然后存储结果到第3个无符号32位的整数r:

a = 0xffffffffff
b = 0x1
r = a + b

r = (0xffffffff + 0x1) % 0x100000000
r = (0x100000000) % 0x100000000 = 0

--2.1 Widthness 溢出

#include <stdio.h>

int main(void){
int l;
short s;
char c;

s = l;
c = l;

printf("l = 0x%x (%d bits)\\n", l, sizeof(l) * 8);
printf("s = 0x%x (%d bits)\\n", s, sizeof(s) * 8);
printf("c = 0x%x (%d bits)\\n", c, sizeof(c) * 8);

return 0;

nova:signed {48} ./ex1
l = 0xdeadbeef (32 bits)
s = 0xffffbeef (16 bits)
c = 0xffffffef (8 bits)

int i;
short s;

s = i;

----2.1.1 Exploiting

,我将提供一些能被利用的情况,希望读者能自己来探索.我将提供一些能被利用的情况的例子.

Example 1:

#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]){
unsigned short s;
int i;
char buf[80];
if(argc < 3){
return -1;
}
i = atoi(argv[1]);
s = i;
if(s >= 80){
printf("Oh no you don\'t!\\n");
return -1;
}
printf("s = %d\\n", s);
memcpy(buf, argv[2], i);
buf = \'\\0\';
printf("%s\\n", buf);
return 0;
}

nova:signed {100} ./width1 5 hello
s = 5
hello
nova:signed {101} ./width1 80 hello
Oh no you don\'t!
nova:signed {102} ./width1 65536 hello
s = 0
Segmentation fault (core dumped)

unsigned short存储的范围是0 - 65535),因次,可能绕过代码中的[w1]部分的边界检测,导致缓冲

--2.2 运算(Arithmetic) 溢出

#include <stdio.h>

int main(void){
unsigned int num = 0xffffffff;

printf("num is %d bits long\\n", sizeof(num) * 8);
printf("num = 0x%x\\n", num);
printf("num + 1 = 0x%x\\n", num + 1);

return 0;
}

nova:signed {4} ./ex2
num is 32 bits long
num = 0xffffffff
num + 1 = 0x0

Note:

-700       + 800   = 100
0xfffffd44 + 0x320 = 0x100000064

</note>

#include <stdio.h>

int main(void){
int l;

l = 0x7fffffff;

printf("l = %d (0x%x)\\n", l, l);
printf("l + 1 = %d (0x%x)\\n", l + 1 , l + 1);

return 0;
}

nova:signed {38} ./ex3
l = 2147483647 (0x7fffffff)
l + 1 = -2147483648 (0x80000000)

(标志符号位的)被重新设置,这个整数将被解释成一个负数.加法不仅仅是一个运算方法,它能导

#include <stdio.h>

int main(void){
int l, x;

l = 0x40000000;

printf("l = %d (0x%x)\\n", l, l);

x = l + 0xc0000000;
printf("l + 0xc0000000 = %d (0x%x)\\n", x, x);

x = l * 0x4;
printf("l * 0x4 = %d (0x%x)\\n", x, x);

x = l - 0xffffffff;
printf("l - 0xffffffff = %d (0x%x)\\n", x, x);

return 0;
}

nova:signed {55} ./ex4
l = 1073741824 (0x40000000)
l + 0xc0000000 = 0 (0x0)
l * 0x4 = 0 (0x0)
l - 0xffffffff = 1073741825 (0x40000001)

----2.2.1 Exploiting

int myfunction(int *array, int len){
int *myarray, i;

myarray = malloc(len * sizeof(int));
if(myarray == NULL){
return -1;
}

for(i = 0; i < len; i++){
myarray = array;
}

return myarray;
}

int catvars(char *buf1, char *buf2, unsigned int len1,
unsigned int len2){
char mybuf[256];

if((len1 + len2) > 256){
return -1;
}

memcpy(mybuf, buf1, len1);
memcpy(mybuf + len1, buf2, len2);

do_some_stuff(mybuf);

return 0;
}

len1 = 0x104
len2 = 0xfffffffc

memcpy(3)将拷贝数据到缓冲区的后面.

3 符号问题

--3.1 它们看起来像什么?

out for are:

int copy_something(char *buf, int len){
char kbuf[800];

if(len > sizeof(kbuf)){
return -1;
}

return memcpy(kbuf, buf, len);
}

int table[800];

int insert_in_table(int val, int pos){
if(pos > sizeof(table) / sizeof(int)){
return -1;
}

table[pos] = val;

return 0;
}

table[pos] = val;

*(table + (pos * sizeof(int))) = val;

pos)比table大,因此提供一个负的pos值将引起程序的运行状况在预料之外,也就不能正

----3.1.1 Exploiting

dest, char *src, int len),memcpy这类的函数只会单一的执行从 src中拷贝len大小的数据

--3.2 符号问题导致的缓冲区溢出

int get_two_vars(int sock, char *out, int len){
char buf1[512], buf2[512];
unsigned int size1, size2;
int size;

if(recv(sock, buf1, sizeof(buf1), 0) < 0){
return -1;
}
if(recv(sock, buf2, sizeof(buf2), 0) < 0){
return -1;
}

memcpy(&size1, buf1, sizeof(int));
memcpy(&size2, buf2, sizeof(int));

size = size1 + size2;

if(size > len){
return -1;
}

memcpy(out, buf1, size1);
memcpy(out + size1, buf2, size2);

return size;
}

size1 = 0x7fffffff
size2 = 0x7fffffff
(0x7fffffff + 0x7fffffff = 0xfffffffe (-2)).

4 真实的例子

--4.1 整数溢出

int rsbac_acl_sys_group(enum  rsbac_acl_group_syscall_type_t call,
union rsbac_acl_group_syscall_arg_t arg)
{
...
tch(call)
{
case ACLGS_get_group_members:
if(   (arg.get_group_members.maxnum <= 0)
|| !arg.get_group_members.group
)
{
...
rsbac_uid_t * user_array;
rsbac_time_t * ttl_array;

user_array = vmalloc(sizeof(*user_array) *
arg.get_group_members.maxnum);
if(!user_array)
return -RSBAC_ENOMEM;
ttl_array = vmalloc(sizeof(*ttl_array) *
arg.get_group_members.maxnum);
if(!ttl_array)
{
vfree(user_array);
return -RSBAC_ENOMEM;
}

err =
rsbac_acl_get_group_members(arg.get_group_members.group,
user_array,
ttl_array,

arg.get_group_members.max
num);
...
}

SS X-Force的安全公告).在这个例子里面,用户提交的数据用来计算动态分配缓冲区的大小,该缓冲区

bool_t
xdr_array (xdrs, addrp, sizep, maxsize, elsize, elproc)
XDR *xdrs;
u_int *sizep;
u_int maxsize;
u_int elsize;
xdrproc_t elproc;
{
u_int i;
u_int c;
bool_t stat = TRUE;
u_int nodesize;

...

c = *sizep;
if ((c > maxsize) && (xdrs->x_op != XDR_FREE))
{
return FALSE;
}
nodesize = c * elsize;

...

*addrp = target = mem_alloc (nodesize);

...

for (i = 0; (i < c) && stat; i++)
{
stat = (*elproc) (xdrs, target, LASTUNSIGNED);
target += elsize;
}

unsigned int nresp,
nresp = packet_get_int();
if (nresp > 0) {
response = xmalloc(nresp * sizeof(char*)); [1]
for (i = 0; i < nresp; i++)
response = packet_get_string(NULL);
}

packet_get_int是从用户提交的数据中取得一个int值,保存在整数变量nresp中,由于没有考虑到[1]处的乘法会导致程序的异常
(在32位的系统环境中,unsigend int的最大值是0xffffffff,我们只要提供0xffffffff/4 的值,比如0x40000000).程序执行如下

0x40000000 + 1      (nresp的值)
= 0x40000001  (满足 nresp > 0的要求)
0x40000001 * 4        (分配 nresp * 4 的缓冲区空间)
= 0x100000004 (计算结果已经超出了32位的值)

for (i = 0; i < 0x40000001; i++ )
response = packet_get_string(NULL);

packet_get_string函数从用户数据中读取4个字节的内容写入 response + i的地址.经过0x40000001的循环,用户的数据早已覆盖

--4.2 符号问题的漏洞

static int
getpeername1(p, uap, compat)
struct proc *p;
register struct getpeername_args *uap;
int compat;
{
struct file *fp;
register struct socket *so;
int len, error;

...

if (error) {
fdrop(fp, p);
return (error);
}

...

len = MIN(len, sa->sa_len);
error = copyout(sa, (caddr_t)uap->asa, (u_int)len);
if (error)
gotnothing:
if (sa)
FREE(sa, M_SONAME);
fdrop(fp, p);
return (error);
}

MIN宏将会一直返回len.当这个负数的参数传递给copyout函数,它会被解释成一个巨大的正整数导致copyout

0

• 评论加载中，请稍候...

发评论

以上网友发言只代表其个人观点，不代表新浪网的观点或立场。

新浪BLOG意见反馈留言板　电话：4000520066 提示音后按1键（按当地市话标准计费）　欢迎批评指正

新浪公司 版权所有