15 July 2006 - Smashing the Stack
Topics
Smashing the Stack for Fun and Profit (by Loren Weith)
Attendance
>13
Presentation Resources
Meeting Announcement (txt)
Meeting Flyer (png)
Meeting Notes
We had a very nice meeting. Loren was ready to go by about 2:00pm, but I went to go get drinks and ice, so we didn't get started until 2:30pm. By that time there were at least 13 people present.
Ron Blanchett from MonroeLUG was kind enough to video tape the presentation. Hopefully we will soon be able to provide a link to that video for you...
I just made two quick announcements... September is a big month for us. Software Freedom Day is Saturday, September 16th. We need to choose leaders and register as a "team" at the website and start planning what we're going to do. Send a message to the main list to get involved. Also, Ohio LinuxFest is on Saturday, September 30th. We need to figure out who's going and arrange for a hotel room the night before and transportation (carpooling) each way. Again, send a message to the main email list if you're interested.
Loren then went right into it and started explaining stacks and memory and little-endianness and soon there were a lot of vacant stares. Fortunately, he noticed this and fell back to a simplified representation of memory and connected it to the rudimentary (and bad) C program:
int main (int argc, char **argv) {
char buf[100];
sprintf(buf, "%s", argv[1]);
}
Basically, buf is pre-allocated on the stack for this program. So, if you pass it a string longer than 100 bytes on the command-line, it will dutifully write to buf the first 100 bytes and continue writing each byte thereafter up the stack.
Loren then demonstrated that under some Linux kernels there is something called the "Linux gate" that lives at the end of the memory space for every program. You will find it as the last line of output from the following command (if executed under one of these kernels):
cat /proc/self/maps
It will be labeled [vdso] and will probably have a lot of 'f's in it. It works for me under Ubuntu (blue = unchanging, brown = random):
08048000-0804c000 r-xp 00000000 16:02 48887 /bin/cat
0804c000-0804d000 rw-p 00003000 16:02 48887 /bin/cat
0804d000-0806e000 rw-p 0804d000 00:00 0 [heap]
b7c3c000-b7db5000 r--p 00000000 16:02 537508 /usr/lib/locale/locale-archive
b7db5000-b7db6000 rw-p b7db5000 00:00 0
b7db6000-b7ede000 r-xp 00000000 16:02 244523 /lib/tls/i686/cmov/libc-2.3.5.so
b7ede000-b7edf000 r--p 00128000 16:02 244523 /lib/tls/i686/cmov/libc-2.3.5.so
b7edf000-b7ee2000 rw-p 00129000 16:02 244523 /lib/tls/i686/cmov/libc-2.3.5.so
b7ee2000-b7ee4000 rw-p b7ee2000 00:00 0
b7ef5000-b7ef7000 rw-p b7ef5000 00:00 0
b7ef7000-b7f0b000 r-xp 00000000 16:02 244652 /lib/ld-2.3.5.so
b7f0b000-b7f0d000 rw-p 00014000 16:02 244652 /lib/ld-2.3.5.so
bf8f5000-bf90b000 rw-p bf8f5000 00:00 0 [stack]
ffffe000-fffff000 ---p 00000000 00:00 0 [vdso]
Well, it turns out that this constant chunk of memory happens to contain (somewhere) the two bytes (ff e4) that correspond to a stack jump (ESP).
So, to exploit a buffer overflow like this, one need only fill the
buffer and then provide the address of this 2-byte code and the address
to jump to. That address could then contain the code of one's choosing.
NOTE: The code that would be run at this point would only have the permissions of the user running the program. This is why setuid root programs are a no-no. Of course, when the buffer is in a daemon that accepts input from the network and runs as root, that's how you get a remote root exploit.
Of course, all this buffer overflow stuff is old news and methods have been devised to prevent exploitation. For one, any OS that touts its security doesn't sport that constant block of memory at the end of each program space. Linux and most other OSes now randomize the locations of code in memory so that no one can know in advance where a particular byte of data will be located. More and more network-facing daemons are run as a lesser-privileged user. In addition, there are stack protection mechanisms that use so-called "canary" values (think canary in a coal mine). If the canary value gets overwritten (by a buffer overflow), then the program can detect this and stop execution. This is analogous to miners who note the death of a canary as an indication that the air is no longer safe.
But, there is another class of vulnerabilities that is far nastier and much harder to protect against: format string vulnerabilities. Let's look at another rudimentary piece of (very bad!) C code:
int main (int argc, char **argv) {
char buf[100];
printf(argv[1]);
}
The proper syntax for printf() is printf(const char *format, ...); where ... is a list of arguments of various types that correspond
sequentially with format indicators in the format string. Now, if you
use some element of argv (the array of arguments to the
program from the command-line) as the format string, the command will
work, but you've allowed an untrusted user of the program to specify
the format string! Loren then demonstrated how this can be exploited to
devastating effect...
Say our program above is compiled to an executable named vuln. If I run
./vuln "%x %x %x %x "
or
./vuln "%$30x "
I will see hexadecimal values like
bff65844 b7f67660 1 b7f51da8
or
bff250b4
What you're seeing here is raw stack data. Once an untrusted user can exploit a hole like this to read anything and everything on the stack, there goes your canary!
Loren can explain all the gory details of how 0wz0red you are at that point. Hopefully the video will be available soon and then you can hear him explain it for yourself.
After the presentation, we all drover over to Saigon Bistro (4102 Airport Hwy, 43615) and had Boba Tea, Taros, and yummy authentic Vietnamese dinners. The server was a little confused with the 12 separate checks, but it all worked out... [WARNING: Large portions! Order the small.]
Loren had to split early, but it was great seeing him and an interesting presentation. We hope he visits us in Toledo more often.


