Michael HowardSecure Windows Initiative
Abstract: Michael Howard has studied a commonly ignored code constructure that may result in a severe buffer overflow problem, and then introduce an alternative to an arithmetic operation without overflowing side effects.
Talk about the structure
Very strange, there is such a lot of safety guidance document that people pay attention to dangerous functions. In C and C , there are very dangerous functions, but there is a matter of affirmation, and there are many dangerous developers who are using C and C .
Therefore, you may ask, "Michael, what do you want to discuss?"
I have to admit that some of the tired of some documents say that some functions are dangerous, and you should use a safer type instead of them. For example, "Don't use strcpy, it is dangerous. You should use StrncPy because it is safe." Nothing is much more away from the actual situation. It is possible to use Strcpy's code to be safe, and the calling strNcPy is unsafe code.
Functions like Strcpy are potentially dangerous because the source data is larger than the target buffer, and it comes from untrusted sources. If the source data comes from a trusted source, the call strcpy is safe before replication.
Void func (char * p) {
Const int max = 10;
Char BUF [MAX 1];
MEMSET (BUF, 0, SIZEOF (BUF));
IF (P && Strlen (P) <= max)
STRCPY (BUF, P);
}
Letter don't believe you, I just want to use this example somewhere. There is a commonly ignored structure that can cause buffer overflow, it is not a function call. It is like this:
While ()
* D = * s ;
There is no function call here, which is the coding structure that causes the Blanter WORM worm in the DCOM. In Buffer Overrun In RPC Interface Could Allow Code Execution, you can read more about this virus fixing.
The code is as follows:
HRESULT GETMACHINENAME (Wchar * Pwszpath) {
Wchar WSZMACHINENAME [N 1])
LPWSTR PWSZSERVERNAME = WSZMACHINENAME;
While (* pwszpath! = l '//')
* PWSZSERVERNAME = * Pwszpath ;
...
}
The problem here is that the While loop is bound in some characters in the source string. It does not limit the size of the target buffer. In other words, if the source data is not trusted, the buffer overflow will occur.
I have written a simple Perl script to search for these types of configurations in C and C code. Note that each instance of this script tag is not a defect, you need to determine whether the source data is trusted.
Use strict;
Use file :: find;
MY $ Recurse = 1;
######################################################################################################################################################################################################################################################################################################## #
Foreach (@argv) {
Next if / ^-./;
IF ($ recurse) {
FindDepth (/ & processfile, $ _);
} else {
Find (/ & processfile, $ _);
}
}
######################################################################################################################################################################################################################################################################################################## #
Sub processfile {
MY $ file;
MY $ filename = $ _;
IF ($ recurse && ($ file :: find :: topdir ne $ file :: find :: dir)) {
$ FILE :: Find :: prune = 1;
Return;
}
# Only Accept C / C and Header Extensions
RETURN IF (! (//. [CH] (?: PP | XX)? $ / i));
WARN "$! / N" Unless File, "<". $ filename;
# RESET LINE NUMBER
$. = 0;
While () {
Chomp;
S / ^ / s //;
S // s $ //;
IF (// * / w / / / s {0,} = / s {0,} / * / w / / ) {
Print $ filename. "" "" "" $ _. "/ n";
}
}
Note this script only looks for * p constructs without looking for * p construction.
Assuming that you have discovered a defect, a method of safer code is to limit the copied data is not greater than the target buffer:
HRESULT GETMACHINENAME (Wchar * Pwszpath) {
Wchar WSZMACHINENAME [N 1])
LPWSTR PWSZSERVERNAME = WSZMACHINENAME;
SIZE_T CBMACHINENAME = N;
While (* pwszpath! = l '//' && --cbmachinename)
* PWSZSERVERNAME = * Pwszpath ;
...
}
Finally, any memory replication functions or constructs that do not limit the size of the target buffer should be strictly inspected.
Back to top
More introduction to integer overflow
In the previous article Reviewing Code for Integer Manipulation Vulnerabilities, I discussed the security defects related to the simple mathematical computing of the so-called integer overflow.
Recently, as part of Trustworthy Computing Engineering Series, I made a lecture on Microsoft's engineers a little overflow. In the lecture, I outline how to find an integer overflow and how to fix an integer overflow. What I am surprised is that many emails I have received are very good, but they are full of danger. Please allow me to do some explanations.
In this column, the code I mentioned is as follows:
IF (A B> max) Return -1;
It should be changed to this:
IF (A B> = A && A B // cool! } Three years ago, some people pointed out that some people will see this code, but I don't know what it uses, so it may delete the A B> = A section, because it looks purely, and now, the integer overflows and re-reable The appearance is in front of you. No way! In response, I wrote the header file below, and it's understandable. Yes, it looks like garbled, but this paragraph is the X86 assembly language. The reason why I use assembly language is because it allows me to directly access the JC operand, ie jump-on-carry. In other words, it detects whether the mathematical operation will result in overflow. #ifndef _inc_intoverflow_ #define _inc_intoverflow_ #ifdef _x86_ Inline bool uadd (size_t a, size_t b, size_t * r) { __ASM { MOV EAX, DWORD PTR [A] Add Eax, DWORD PTR [B] MOV ECX, DWORD PTR [R] Mov DWORD PTR [ECX], EAX JC SHORT J1 MOV Al, 1 JMP SHORT J2 J1: #ifdef _Debug INT 3 #ENDIF XOR Al, Al J2: } } Inline Bool Umul (size_t A, size_t b, size_t * r) { __ASM { MOV EAX, DWORD PTR [A] Mul DWORD PTR [B] MOV ECX, DWORD PTR [R] Mov DWORD PTR [ECX], EAX JC SHORT J1 MOV Al, 1 JMP SHORT J2 J1: #ifdef _Debug INT 3 #ENDIF XOR Al, Al J2: } } INLINE BOOL Umuladd (size_t mul1, size_t mul2, size_t add, size_t * r) { SIZE_T T = 0; IF (Umul (Mul1, Mul2, & T)) Return UADD (T, Add, R); Return False; } #ELSE # r "this code compiles only on 32-bit x86 #ENDIF / / _X86_ #ENDIF / / _INC_INTOVERFLOW_ Check this file, which includes explaining a simple document for these functions. Back to top Discover security vulnerability Although it took a little time, many people found a vulnerability. This comparison should be a comparison of regional constant comparisons or byte mode when making security decisions by comparing strings. In this example, the code I have written may allow access to Turkish sensitive data, because in Turkish, the letters "i" have four examples, two lowercase letters, two uppercase letters. You can read this in this area on http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemstringclasscomparetopic5.asp. Now let us go to the mistake of this month. What is the problem with this code? Void func (char * p) { Char BUF [10 1]; MEMSET (BUF, 0, SIZEOF (BUF)); // limited string to 10 chars Sprintf (buf, "% 10s", p); Printf ("Hello,% S / N", BUF); } A small intelligence game This intellectual game is actually unrelated with security, but when I think people are troubled by the integer overflow detection code, I pulled it from my memory. What is the use of this code? INT A = 0x42; INT b = 0x69; a ^ = b; B ^ = a; a ^ = b; The rules of this game are very simple, you can't compile or explain this code. Try only by observation to determine what it is.