http://blog.csdn.net/habla/article/details/1834658
integer overflow 2007-10-20 18:39 1021 People read comments (0) Favorites Report table integer user compiler Linux kernel FreeBSD integer Overflow is also a common software vulnerability, which may cause more bugs than formatted word String defects and buffer overflow defects are more difficult to discover. A few days ago, a single integer overflow vulnerability was discovered in the Solaris system. Here we will translate an article about integer overflow in Phrack magazine, which is written in quite detail. Peacetime time is not a lot, so I will not be a full translation of this article after the blog out, I will translate a little bit up also please Haihan. Of course, due to the English proficiency and technical limitations, translation may not be very good grasp the meaning of the original, if there are errors, whether in English or technical aspects of the appeal to your treatise.
Original connection: Http://www.phrack.org/issues.html?issue=60&id=10#article
Author: blexim@hush.com
Integer overflow base
1: Introduction
1.1 What is an integer.
1.2 What is an integer overflow.
1.3 Why an integer overflow can be dangerous.
2: Integer overflow
2.1 width overflow
2.1.1 Overflow exploit
2.2 arithmetic overflow
2.2.1 Overflow exploit
3: integer notation mishandled bugs
3.1 what they look like.
3.1.1 Vulnerability exploits
3.2 integer overflow for symbolic processing error
4: instance
4.1 integer overflow
4.2 symbol processing error bugs
--[1.0 Introduction In this article I will describe two programming flaws that can be used by a malicious user to change the execution process of a program, unlike a buffer overflow or a formatted string that modifies the memory directly, but instead changes the program execution flow by making the program variable equal to the unintended value. All the examples in this article are written in C, so you need the basics of C to read this article.
How integers are stored in memory is helpful for you to understand this article, but it doesn't matter if you don't know this knowledge.
----[1.1 What is an integer. In calculations, an integer is a real number without a decimal part. Generally, integers have the same width as the pointer (in a 32-bit machine, such as i386, the integer is 32, and on a 64-bit machine, the integer is 64-bit.) Translator Note: The ILP32 model is used in the 32-bit x86 platform C language, meaning I (integer), L (Long), P (point) are 32-bit, in AMD64 platform C is LP64, integer or 32-bit, long and point is 64-bit.
Some compilers do not let integers and pointers have the same width, but for the sake of simplicity, all of the examples in this article assume that the target system uses the ILP32 model. Integers, like other types of variables, are just an area in memory.
When we talk about integers, we usually use the decimal notation that humans are accustomed to. Because the current computer cannot handle decimal numbers, integers are represented in the computer in binary notation. Binary uses only two numeric values of 0 and one to represent the number, it is not a decimal as 0-9 is a number to represent the number.
In addition to binary and decimal notation, the easily converted 16-in-binary system is often used to represent integers. Because you often need to represent negative numbers, you need a mechanism to represent them only in binary digits (0 and 1). Now the general approach is to use the highest bit to determine a number of symbols (translator Note: The CPU does not know whether a number is positive or negative, do not need to know, you need to know is only our program): If the highest bit is 1 to take it as a negative, Instead, if you're 0, take it as a positive number: here we are not as rigorous as math: 0 is neither positive nor negative. This may be somewhat confusing, for example, the symbol bug that will be described in the following section, because not all numbers are signed, that is, not all numbers in memory use the highest bits to denote the positive or negative of the number, which is our well-known unsigned number (unsigned) and therefore can only be given positive numbers. The number that can be either positive or negative is what we call a symbolic number: the original: Whereas variables which can be either positive or negative are called. ShouldIt's a clerical error.
----[1.2] What is an integer overflow. Because the integer in the computer has a width (32 bits in this article), it has a maximum value that can be represented. An integer overflow occurs when we try to save a number that is larger than the maximum value it can represent. The ISO C99 standard stipulates that integer overflows will result in "nondeterministic behavior", meaning that the standard compilers can do whatever they want, such as completely ignoring the overflow or terminating the process.
Most compilers ignore this overflow, which may result in an indeterminate or erroneous value being saved in an integer variable.
----[1.3 Why integer overflow is dangerous. Before an integer overflow does occur, we are not aware that it will overflow, so the program has no way of distinguishing whether the previously computed value is correct. This can be very dangerous if the result of the calculation is the size of a buffer or the subscript of an array. Of course, most integer overflows are not available because we cannot directly overwrite the memory cells, but sometimes integer overflows can cause other types of bugs, such as buffer overflows that are prone to occur.
Integer overflows are sometimes difficult to discover, and because of this, even carefully censored code is sometimes unavoidable. --[2.0 integer Overflow What happens when an integer overflows. The ISO C99 wrote: "An overflow does not occur when the calculation involves an unsigned number of operands, because if the result cannot be represented by an unsigned integer, the result of the calculation is truncated by the maximum value that can be represented by an unsigned integer and one for the value of the modulo operation.
The modulo operation is the remainder of the division that we often say. Example: 10 5 = 0 11% 5 = 1 [Translator: The following paragraph is not very good to express, the original text in this, meaning is still very clear. ] So reducing a large value modulo (maxint + 1) can is seen as discarding the portion of the value which cannot fit into a
n Integer and keeping the rest.
In C, the modulo operator is a% sign. Take an example to see what is "nondeterministic behavior": There are two 32-bit unsigned integers, a and B, and we assign the maximum value of a 32-bit integer to variable a, assigning a value of 1 to B. We assign a and B to another 32-bit integer R:A = 0xFFFFFFFF b = 0x1 r = A + b now due to A and B's and cannot be represented by 32 bits, according to the ISO standard, the result is with 0x100000000 modulo truncation is short. R = (0xFFFFFFFF + 0x1)% 0x100000000 r = (0x100000000)% 0x100000000 = 0
The truncation of the modulo method ensures that only the lowest 32 bits are valid, so the integer overflow causes the computed result to be truncated to the width that the variable can represent. This is often referred to as the "wrap around", as the result in the previous example returns to 0.
----[2.1 Width overflow so an integer overflow is the result of assigning a variable a value that it cannot accommodate.
The simplest simulation of this overflow is to assign a large width value to a variable of a smaller width:/* Ex1.c-loss of precision/#include <stdio.h> int main (void) {
int l;
Short S;
char c;
L = 0xdeadbeef;
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; /* EOF/Result: nova:signed {m}/ex1 L = 0xdeadbeef (bits) s = 0xffffbeef (bits) c = 0xfffff
FEF (8 bits) in the example above, because each assignment exceeds the range that the left value can represent, they are truncated to the width of the left value. It is necessary to mention the integral type elevation here. When an operand with a different width is included in the evaluation expression, the smaller-width operand is raised to the same width as the larger operand, which is then computed, and the result is truncated again to a smaller width if the calculation is saved in a smaller-width variable.
Example: int i;
Short S;
s = i; Here the two operands have different widths.
So S is promoted to 32 bits, and then the value of I is assigned to S, and S is truncated back to 16 bits and saved.
If the result is larger than the maximum value s can represent, it will be truncated. ------[2.1.1 Vulnerability leverages integer overflow Unlike common bugs, it does not allow direct overwriting of memory or direct program flow, but it is more difficult to capture. The root of the problem is that the program cannot be preceded by an integer overflowCheck to see if the result will overflow.
As a result, most integer overflows are not available, although in some cases it is possible for some key variables to contain incorrect values, causing other bugs. Because of the erratic nature of the integer overflow, there are still many situations where this flaw can be exploited and I will not enumerate all the available conditions, but I will provide some examples of how to exploit these vulnerabilities and hope to make a comment:) (Translator Note: Practice can make a true reality.) I most admire our high school math teacher to teach us a sentence: a look will be, a wrong. A lot of people look at the said, ah too simple, can let it really own to do not have this is typical impetuous. I remember a friend on the internet to tell me that he Win32 environment virus research, but I asked him to the PE file format thoroughly did not he actually asked what is called PE file ~ ~ ~ Crazy halo. Example 1:/* width1.c-exploiting a trivial widthness bug */#include <stdio.h> #include <strin
g.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 >=) {/* [W1]/printf ("Oh No you don ' t!/n");
return-1;
printf ("s =%d/n", s);
memcpy (BUF, argv[2], i);
Buf[i] = '/0 ';
printf ("%s/n", buf);
return 0; } like aboveThis constructed code may never appear in real code, but as an example he can play a good role in the demonstration. Look at the following input: nova:signed {}/width1 5 Hello s = 5 Hello nova:signed {/width1 Hello Oh no yo
u don ' t! nova:signed {102}./width1 65536 Hello s = 0 segmentation fault (core dumped) length parameter is taken from the command line and saved in the variable I, when assigned to a short integer variable s, if A truncation occurs when the value is greater than the range that the S can represent (for example, the value of I is greater than 65535). Therefore, we are likely to bypass the length limit.
In this way, the standard buffer overflow attack method can be used to attack the program. ----[2.2 arithmetic overflow can be seen from the previous content, when an integer is saved in a width that is not sufficient to save that number may overflow. If the save value is calculated by arithmetic, the program will make an error using this value later, let's look at the following example:/* ex2.c-an integer overflow/#include <stdio.h> int ma
In (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; /* EOF/* Program run Result: nova:signed {4}./ex2 num is-bits long num = 0xFFFFFFFF num + 1 = 0x0 Smart You may It has been noted that 0xFFFFFFFF is the decimal-1, so it looks as if we are doing 1 + (-1) = 0 However this is just an appearance, he may make us confused, because these variables are unsigned, thenAll operations should be unsigned. As it happens, many signed arithmetic operations depend on an integer overflow, as shown in the following example (assuming all operands are 32): -700 + 0xfffffd44 + 0x320 = 0x100000064 Because the result of the calculation is beyond the representation range of the variable, the result The minimum 32 digits were retained as a result.
The lowest 32 digits in the example above are 0x64, or 100 in decimal. Since integers are signed by default, the overflow can sometimes cause a change in positive or negative, which will cause some of the columns to behave in a very interesting way.
Consider the following example:/* Ex3.c-change of Signedness */#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; /* EOF * * Run Result: nova:signed {}/ex3 L = 2147483647 (0x7fffffff) L + 1 = -2147483648 (0x80000000)
In the example, the variable L is given the maximum positive integer value of the 32-bit integer, and when it is added, the result becomes a negative number.
Not only arithmetic operations may cause overflow, any operation that alters the value of the entire variable may cause an overflow, as in the following example:/* ex4.c-various arithmetic overflows * * #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; /* EOF * * Results: nova:signed {+}./ex4 L = 1073741824 (0x40000000) L + 0xc0000000 = 0 (0x0) L * 0x4 = 0 (0x0) l-0xffffffff = 1073741825 (0x40000001) The addition operation in this example causes an overflow, as in the previous case, the subsequent multiplication also creates an overflow, both of which are essentially the result of the operation being too large and a 32-bit integer without The overflow caused by the expression of law. The following subtraction is slightly different, resulting in an underflow rather than an overflow: to save an integer a number smaller than the smallest integer it can represent, which also causes wrapping.
Using this method, we can force an addition into subtraction, multiplication into division, or subtraction into addition. ------[One of the most likely scenarios for the 2.2.1 vulnerability to exploit an arithmetic overflow is to use the results to determine the size of the buffer to be allocated.
Typically, a program needs to allocate memory space for a set of objects, so it assigns memory by calling malloc (3) or calloc (3) The result of a single object size as a parameter.
If we can control one of these two operands, we may have the program allocate the wrong size buffer, as shown in the following fragment: int myfunction (int *array, int len) {int *myarray, I; MyArray = malloc (len * sizeof (int));
/* [1] */if (myarray = NULL) {return-1; for (i = 0; i < len; i++) {/* [2]/myarray[i] = array[I];
return myarray; The function of this implementation error may fail because the parameter Len is not checked. The multiplication at [1] may be overrun by Len too large, so we can use it to allocate a buffer of any length. By selecting the appropriate Len value, we can allow the program at [2] to rewrite the loop beyond the MyArray range of memory, which can result in a heap overflow, and then execute arbitrary code by overwriting the malloc control structure, but the attack on the heap overflow is beyond the scope of this article,
Therefore, there is no detailed description of how heap overflow attacks are carried out here. Another example: int catvars (char *buf1, char *buf2, unsigned int len1, unsigned int len2) {char mybuf
[256];
if ((Len1 + len2) > 256) {/* [3] */return-1; } memcpy (Mybuf, BUF1, len1);
/* [4] * * memcpy (mybuf + len1, buf2, len2);
Do_some_stuff (MYBUF);
return 0; In this example, a check of a parameter at [3] can be bypassed by providing the appropriate values for the two parameters to overflow the results of the calculation.
For example: len1 = 0x104 Len2 = 0XFFFFFFFC The addition of these two numbers is 0x100 (decimal 256), so the check at [3] can pass, so calling memcpy (3) can cause a buffer overflow. The--[3 symbol bug unsigned number is interpreted as a signed number or a signed number is interpreted as an unsigned number that can cause a symbol bug. This explanation error occurs because the same method of storing unsigned and signed numbers within the computer is the same.
Recently, several bugs have been incorrectly handled in the FreeBSD and OpenBSD cores.
----The representation of a 3.1-symbol bug. Symbol bugs have a large number of manifestations, common to: * Signed integers to compare * signed integers for arithmetic operations * unsigned integers and signed integer comparisons a classic bug-containing program: INT Copy_something (char *buf, int len) {char kbuf[800];
if (Len > sizeof (KBUF)) {/* [1] */return-1; Return memcpy (Kbuf, buf, Len); /* [2]/} The problem with this procedure is that the check at [1] is a comparison of signed integers, and [2] when calling memcpy, the parameters are unsigned, so by passing a negative value, it is possible to pass the check at [1], and then [2] will be interpreted as an unsigned number.
This will result in an overflow of kbuf.
Look again at an example: int table[800];
int insert_in_table (int val, int pos) {if (pos > sizeof (table)/sizeof (int)) {return-1;
} Table[pos] = val;
return 0;
} because Table[pos] = val;
Equivalent to * (Table + (POS * sizeof (int)) = Val;
We can see that the problem here is that the program does not realize that a negative number might be involved in the addition: it subjectively thinks (table + pos) is larger than the table, so passing a negative to the POS can cause problems. ------[3.1.1 Vulnerabilities exploit such bugs easily to be attacked, due to the fact that when a signed number is interpreted as an unsigned number, it can be large. For example, 1 will be decimal when it is unsigned (4,294,967,295), which is the maximum value of a 32-bit integer that is used as a memcpy parameter, and memcpy will attempt to copy 4G bytes. It is clear that this could lead to a break error or a corrupted stack. Sometimes it is possible to get around this problem by passing a very low value for the "source" and hope, but this is not always possible.
----[3.2 integer overflow caused by a symbolic bug may sometimes be able to overflow an integer to make it a negative number.
This can trigger a symbolic bug because the program may not be aware of this situation.
Example 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;
}/* Packet begins with length information/memcpy (&SIZE1, BUF1, sizeof (int));
memcpy (&size2, buf2, sizeof (int)); Size = size1 + size2;
/* [1] */if (size > Len) {/* [2]/return-1;
} memcpy (out, BUF1, size1);
memcpy (out + size1, buf2, size2);
return size; This code may appear in the network daemon, especially if the data length information comes from the network (in other words, from untrusted clients), and the program is easier to exploit. The wig at [1] is used to check whether the data length will exceed the buffer size, but if the client provides an appropriate value, the result of the addition becomes a negative number, for example: size1 = 0x7fffffff size2 = 0x7fffffff (0x7ffff FFF + 0x7fffffff = 0xfffffFfe (-2)). So the check at [2] passes smoothly, so the buffer out is likely to overflow.
(In fact, (out + size1) may be illegally controlled to point to arbitrary memory, which may be used to modify any value in any memory) the same kind of bug that is caused by an integer overflow is the same as a common symbolic bug.
--[4 Real Code real-world Products There are many programs that have integer overflow and symbolic bugs, especially the network daemon or operating system kernel. ----[4.1 integer Overflow The following example (but cannot be exploited) is excerpted from a security module in the Linux kernel, which runs at the kernel level: int rsbac_acl_sys_group (enum rsbac_acl_group_syscall_type_t
Call, Union rsbac_acl_group_syscall_arg_t Arg) {... switch (call)
{Case Aclgs_get_group_members:if (arg.get_group_members.maxnum <= 0)/* [A] * * ||
!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);
/* [B]/if (!user_array) Return-rsbac_enomem; Ttl_array = Vmalloc (sizeof (*ttl_array) * Arg.get_group_membeRs.maxnum);
/* [C]/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);
...
} The check at [A] in this example does not effectively prevent an integer overflow at [B] and [C]. Passing a large enough arg.get_group_members.maxnum (greater than 0XFFFFFFFF/4) will cause [b][c] to overflow, forcing the Ttl_array and user_array this buffer to be smaller than the program expects.
Because rsbac_acl_get_group_members copies user-controlled data to these buffers, it is possible to cause these buffer overflows. In this example, the program uses Vmalloc () to allocate the buffer, so when we intend to overflow these buffers, it will only cause an error, so it is not available. Even so, it provides a good example of what an integer overflow is like in real code.