Vulnerability Development mailing list archives

Re: No-Exec Stack Smashing 101


From: woloszyn () IPARTNERS PL (M.C.Mar)
Date: Thu, 20 Apr 2000 20:48:11 +0200


On Thu, 20 Apr 2000 lamont () icopyright com wrote:

Also, I'm still trying to figure out what you need to make the stack look
like in order to do a return-into-libc exploit.  I've got Solar Designer's
lpr -C exploit, but I don't quite understand his comments (I mean I
understand what he's making the stack look like, but I don't understand
why).

Ok, so let me describe that :)

I will use memory memory oriented aproach, so if I say something is after
it will mean it is in highet address in memory and lower on the stack.
First thing you have to know is which byte in our buffer overwrites the ret
value. Let's say it's 4th byte in the buffer. So we put there address of
system() call (in libc). If our exploit will force vul program to call
system() it needs arguments! So you have to understand how does any
function (including system) take arguments! Let's write some example code:

[root@pipek ~/test]# cat p.c
void f (int a){
printf("%i\n",a);
}

main() {
f(10);
}

And dissassemble f function:
Dump of assembler code for function f:
0x8048150 <f>:  pushl  %ebp
0x8048151 <f+1>:        movl   %esp,%ebp
0x8048153 <f+3>:        movl   0x8(%ebp),%eax
0x8048156 <f+6>:        pushl  %eax
0x8048157 <f+7>:        pushl  $0x8059be8
0x804815c <f+12>:       call   0x8048190 <_IO_printf>
0x8048161 <f+17>:       addl   $0x8,%esp
0x8048164 <f+20>:       movl   %ebp,%esp
0x8048166 <f+22>:       popl   %ebp
0x8048167 <f+23>:       ret
0x8048168 <f+24>:       nop
0x8048169 <f+25>:       leal   0x0(%esi,1),%esi

as you can see every function stores %ebp on the stack and copies %esp to
%ebp, then if needed decreases %esp to make room for local variables on the
stack. So after it's done %ebp points to first byte after the value pushed
onto the stack by call (it's the same place where previous value of %ebp
is saved by pushl  %ebp).
Every function cares about %ebp and does not change it during execution to
address own arguments and local variables!
movl   0x8(%ebp),%eax moves value from %ebp+8 to %eax register (that's
where every function looks for its FIRST argument)!

So after first two instructions our stack looks like this:

|----------------|
| first argument |  <--  %ebp+8
|----------------|
|      RET       |  <--  %ebp+4  [&RET]
|----------------|
|      %ebp      |  <--  %ebp points here
|----------------|
| local variables|

[Remember that push first decreases the %esp and then stores there
value, so %esp allways points at the top of the stack]

Now we have to think how will our stack look like if the program will jump
to function not by call (that pushes RET onto stack) but by ret with
overwriten RET value!

At the end of function that we have exploited, %esp points to &RET. After
ret flow jumps to our function and %esp points to &RET+4 (from memory point
of view). So the stack just after doing ret (and before push in function)
looks like:

|----------------|
| first argument |  <--  %esp
|----------------|
|      RET       |
|----------------|
|      %ebp      |
|----------------|

By "first argument" I mean the argument of previous function!
Then function pushes %ebp onto the stack, so it overwrites RET with %ebp
and decreases %esp then moves %esp to %ebp. After that operation our
function will start to address its arguments like I described it above, so:

|                |  <--  %ebp+8
|----------------|
| first argument |  <--  %ebp+4
|----------------|
|   new %ebp     |  <-- %ebp points here (here was RET)
|----------------|
|                |

So as you can see our function will look for its first argument 8 bytes
after the place where was RET that we overwriten!

So from left to the right on bufor there should be:

Lower memory address          Higher memory address
        V                               V
X*data,RET,VALUE,1st_argument,2nd_argument and so on...

So if the RET is 4th byte in our buffer, VALUE is 8th, 1st argument is 12th
and so on...

If you understand this, you will know that if function will return from
function that we pointed to in RET it will try to return to VALUE :)

If you still does not understan this, please read this article:
199801301709.SAA12206 () galera icm edu 
pl">http://www.securityfocus.com/templates/archive.pike?list=1&date=1998-02-1&msg=199801301709.SAA12206 () galera icm 
edu pl</A>
it may help you :)

--
Mariusz Wo³oszyn
Internet Security Specialist, IT -- Internet Partners
E-mail: Mariusz.Woloszyn () it pl, woloszyn () it pl



Current thread: