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 seemsratherprecarious: 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:
- question on buffer overflow (was RE: Extreme Hacking) Choi, Byoung (Jul 12)
- <Possible follow-ups>
- Re: question on buffer overflow (was RE: Extreme Hacking) Antonomasia (Jul 12)
- RE: question on buffer overflow (was RE: Extreme Hacking) Choi, Byoung (Jul 13)