Firewall Wizards mailing list archives

RE: question on buffer overflow (was RE: Extreme Hacking)


From: "Choi, Byoung" <bchoi () visa com>
Date: Mon, 12 Jul 1999 16:12:54 -0700

thanx for the information.

again, it looks like i was lazy.  the following link has links to papers
describing stack overwriting exploits, as well as the mechanism of the
stackguard that helps to protect code against exploits that messes with
return addresses:

http://www.cse.ogi.edu/DISC/projects/immunix/StackGuard/mechanism.html

i remember stackguard being released while back, and i'm sure many of you
already know of it, but just in case there are more than a single lazy
ignoramus(me).

byoung


----------
From:         Antonomasia[SMTP:ant () notatla demon co uk]
Sent:         Monday, July 12, 1999 2:57 PM
To:   firewall-wizards () nfr net
Subject:      Re: question on buffer overflow (was RE: Extreme Hacking)


"Choi, Byoung" <bchoi () visa com>

i have a dumb question:

OK, I'll bite on this.   I'll point out in advance to any critics that
all of this is available already in many places.  And it's all in the
interests of keeping my CC charges down.

I believe a good understanding of the exploits is useful both in testing
and
proving flaws to pointy-haired types.  Actually writing safe software is a
different discipline, but whan you rely on software from typical vendors
you
(sometimes) have to prove every word of your complaint.

And despite the popularity of the overflow in recent years the systems I
see
are often more easily vulnerable to simple environment manipulation and
plain bad filemodes (at any rate as far as local users are concerned).


a local buffer can be overflown to overwrite the thread's stack (if the
code doesn't check for the EOB).  overwriting the stack can change the
flow of the code, and possibly redirect it to rogue code inserted.

but what's the "typical" (if there is one) technique?  it all seems
rather
precarious:
the rogue code is platform-dependent (machine code, etc.)
the exploit must anticipate the stack frame location where it will get
overwritten so that
1. the address depedence of the rogue code is satisfied
2. control flow is correctly redirected to the rogue code.

am i in the ball park?

Certainly in the ballpark.

The definitive paper is by Aleph One, called in Phrack 49, file 14.
"Smashing The Stack For Fun And Profit".   I've learned from that and
am going to ramble on about my own practice efforts here.

Once you have the shellcode (available for mainstream processors from
existing exploits) there are usually 3 things you have to fiddle with.

0) finding an exploitable bug - and you can write your own for practice
   Having source code to audit helps, but is not essential.

1) finding where in the input to put the return address

  This is done by reading core dumps with gdb or dbx.   In the case
  of set[ug]id programs you take an unpriviledged copy and hope it
  works the same at least up to the point you're interested in.  For
  network programs that's not necessary but you might need to remove
  a coresize resource limit from inetd and ensure the victim program
  runs as root so it can dump core in /.
  (It's assumed you are working on a box where you already have
  legitimate root access.)

  So feed different string lengths in with rough variation - in binary
search
  style (2000 -> coredump,  1000 -> normal execution, 1500 -> coredump
,...)
  and look at the cores. (typical input "AAAAAA", debugger command
"where")
  When you have it narrowed down try the alphabet in the target region for
the
  return address.   This confirms the position to the exact byte and shows
the
  byte order if you didn't know it.  You want to terminate the buffer
  correctly - either '\n' for gets() or '\0' for strcpy() and friends.

  The core dumps you've been getting so far result from the fact that
you've
  been supplying total rubbish as a return address and execution cannot
pick
  up at that point.  Just recognising your input in a stack trace is proof
of
  vulnerability and should be take seriously by a good vendor without an
  actual exploit.


2) Spot where the buffer is in memory.  If the victim code is using gets()
   or something recognisable you might find this using the debugger and
   noticing the address used by gets(). (Start it against an existing
process
   if called from inetd during the time it waits for your user input.)

   Or make your example program in step 0 print out the address of a
buffer
   it uses and take that as a first guess to do a search on with commands
like
   0x2ff22c00/128x in dbx.

   Next you need to insert the shellcode into the buffer (on a 4-byte
boundary)
   and set the return address to point to it.  I like to make these 2
separate
   steps so I set the address first and make sure the buffer contains
invalid
   code (07070707 or whatever for your processor).  The result should be a
core
   dump with confirmation that you hit the right address.

   Then you paste in your shellcode.  Some shellcode wants tuning to the
   kernel it runs under - examine the sploit you lifted it from.

   Then run it on a test system (what _is_ that shellcode doing ?).
   You should now be well on the way to writing a bug report for the
vendor,
   but don't expect quick fixes to result.

   Cheating ?   Of course.  In step 1 you can repeat the retuen address
many
   times to save the bother of getting exact placement.  In step 2 the
cheat
   is to pad the start of the shellcode with NOP instructions.
  
   That's mostly it.  There are variations such as pointing the return
address
   into your environment variables (useful if the buffer is too short for
the
   shellcode) and returning into the system() function if the stack is not
   executable (idea due to Solar Designer I think).

   If I don't illustrate anything more with this example I think the
   point is made that exploit software is not nearly as demanding to write
   as safe production software.

   It should also (can I say this too often?) show why procurement and
   security should be talking to each other.   30 minutes of evaluation
   from a security viewpoint will often give convincing evidence why you
   don't want a given product in your company.  What good is finding out
   after it's deployed ?


Linux, Intel: self-victim code as it overflows by itself without input.
You may have to adjust the numbers to suit your box, but that's what
this article is all about.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
 * using system() so that we don't need shellcode or an executable stack
 *
 * Victim code must use system() and must have a useful command name as a
 * string somewhere we can find, such as the SHELL environment variable.
 */
int myfunc(char *cp)
{
char lame[8];
strcpy(lame,cp);
return 0;
}

int main(int argc, char **argv, char **envp)
{
char nasty[]="@@@@@@@@@@@@@@@@@@@@6789";

/* system() at 0x0804841c  from gdb's "print system" */
nasty[12]=0x1c;
nasty[13]=0x84;
nasty[14]=0x04;
nasty[15]=0x08;
/***************/
/* "/bin/bash" in the environment, found with gdb's "x"  */
nasty[20]=0xb7;
nasty[21]=0xff;
nasty[22]=0xff;
nasty[23]=0xbf;

myfunc(nasty);

/* expect a seg fault after the exploit */

printf("program not smashed\n");
exit(0);
return system("date");
}

--
##############################################################
# Antonomasia   ant () notatla demon co uk                      #
# See http://www.notatla.demon.co.uk/                        #
##############################################################




Current thread: