Security Development
Flow of a Buffer Overflow Payload
Here is the flow of a buffer overflow payload with a NOP Sled.
- Jump to overwritten return address that (hopefully) points to somewhere in the NOPs (0×90)
- Consume the No Operations (NOPs)
- Execute the shell code
Trouble Spawning a Shell
I’ve been working on some of the examples out of the Hacking: The Art of Exploitation book which exploit a program with shellcode but I’m not having much luck. The exploit makes sense conceptually but I can’t get it to spawn the shellcode.
It uses the system() function to invoke the exploitable program from the shell with the payload as a commandline arg. I want to look at the stack in GDB of the command being invoked by the system() function … does anyone know how to do this or know if it’s even possible?
It’s possible for me to look at the stack when I pass the arguments myself from the commandline but the system() function is doing it instead cause it’s easier to construct the shellcode programmatically.
I also looked at the return value of the system() function and it’s zero meaning that the program exited normally. I’m curious if the somehow the command payload isn’t getting passed correctly so I was hoping to look at the stack…
Update
My problems were related to trying to execute the exploit on a 64-bit system when the code was developed for 32-bit. After switching over to a 32-bit OS, I was able to spawn a shell no problem!
32 bit vs 64 bit exploitation
The exploit code in Hacking: The Art of Exploitation is targeted towards overwriting 32 bit return addresses (size 4). It uses code like this:
unsigned int ret; ret = &var; *((unsigned int *)(buffer+sizeof(unsigned int))) = ret;
I’m working on a 64 bit machine and thus my addresses are double in size. I’m guessing this means that the above code won’t work on my machine (I’m not sure?). I searched around and found an “unsigned integer pointer type” which is defined per architecture and it is indeed size 8 on my 64 bit machine. I changed the code to this:
uintptr_t ret; ret = &var; *((uintptr_t *)(buffer+sizeof(uintptr_t)) = ret;
Quickly Use BC to Convert Hex to Dec
This post is mainly for my own benefit because I’ll forget this if I don’t put it down somewhere. A lot of the times I need to convert hex to dec when I’m on the command line and it’s a pain to open up the calculator so here is the command line equivalent
echo "ibase=16; FFFF" | bc
Turning off buffer overflow protections in GCC
As I’m learning more and more about exploiting buffer overflows I’m realizing that it’s actually pretty hard to run the examples that teach you how to exploit buffer overflows. GCC (and other compilers) have built in support for mitigating the simple buffer overflows and it’s turned on by default.
With GCC you have to compile with the -fno-stack-protector option otherwise you get “***stack smashing detected***,” this is pretty well known and documented all over the net.
However, additionally you’ll need to disable the FORTIFY_SOURCE option otherwise you’ll get “Abort trap” if you try to do a buffer overflow that uses something like strcpy or memcpy.
To disable it, simply compile with the flag -D_FORTIFY_SOURCE=0 (e.g. gcc -g -fno-stack-protector -D_FORTIFY_SOURCE=0 -o overflow_example overflow_example.c)
Adobe PDF Return Oriented Exploit
The news just keeps getting worse for Adobe. After releasing an out-of-band patch for their other 0-day PDF exploit used to jailbreak the iPhone, the people at McAfee discovered malware in the wild exploiting another 0-day PDF exploit. Apparently this exploit takes advantage of your typical buffer overflow exploit (come on Adobe!) but the way it’s exploited is very interesting; (more…)
Finding the Return Address on the Stack
Chapter 3 of Hacking: The Art of Exploitation is all about exploitation. As mentioned in my post on stack-based buffer overflows, one of the key points to exploiting these types of overflows is gaining control of the return address from a function call.
I’ll be using the source code from my stack-based buffer overflows post. First, lets look at what main() looks like disassembled. (more…)
Void Function Pointers in C
Hacking: The Art of Exploitation has a really nice crash course on C. The book has a paragraph or two about function pointers.
Every time I look at function pointers, I find myself referring back to some documentation or getting confused (one too many *’s! or the parenthesis are wrong)
Here is a very simple example to demonstrate void function pointers, hopefully so I can remember in the future!.
#include <stdio.h> void hello() { printf("Hello"); } void world() { printf("World"); } void space() { printf(" "); } void newline() { printf("n"); } void print(const void *f) { void (*f_ptr)() = f; f_ptr(); } int main(int argc, char **argv) { print(hello); print(space); print(world); print(newline); return 0; }
x86 64 Bit Stack Boundaries
While inspecting disassembled code on my Macbook Pro, I couldn’t figure out why the stack allocated so much space when I only requested a little. After some investigation into GCC I figured it out.
According to Apple’s developer documentation on GCC, “If -mpreferred-stack-boundary is not specified, the default is 4 (16 bytes or 128 bits).” That means that the stack will always allocate chunks in factors of 16 (2^4) unless you specify otherwise.
(more…)
Types of Overflows: Stack-Based Overflows
A buffer is simply some fixed space in memory used to store data. In C, you create a buffer by declaring an array of some primitive type such as a ‘char array[SIZE]‘ or int ‘array[SIZE]‘. (more…)
Types of Overflows: Integer Overflows
Integer overflows occur when either a signed positive integer turns negative, a signed negative integer turns positive, or a large unsigned number “wraps around” to (or starts over at) zero. This can happen when you add, subtract, or multiply integers.
Some languages raise an exception when integer overflow occurs. C does not raise an exception; handling of integer overflows is left up to the programmer.
Integer overflows by themselves are mostly useless since they are likely to cause unexpected behavior or program failure but given the right circumstances, they can be used for buffer overflows (heap or stack based depending on the situation).
Here’s an example of an exploitable integer overflow. By inputting the correct integer, we can trick malloc into allocating zero bytes. Memcpy would then start copying over other elements in heap memory. Assuming sizeof(char) is 1, we just need to make size wrap around to zero. 4294967295 is the max unsigned integer; adding 1 to it will cause it to wrap around to 0!
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <limits.h> void function(unsigned int size, char* input) { char *buf; buf = (char *) malloc(size * sizeof(char)); memcpy(buf, input, size); } int main(int argc, char **argv) { unsigned int size = atoi(argv[1]); function(size, argv[2]); return 0; }
Types of Overflows: Heap-Based Overflows
A heap-based buffer overflow is an overflow that occurs in dynamically allocated space called the heap. Data is stored in the heap when you call malloc(size). The concept is exactly the same as a stack-based overflow in the fact that you put more data in a buffer than was allocated but they are exploited in a much different way.
Exploitation of a heap based overflow varies greatly. Some heap overflows techniques overwrite data that another function may use. Other techniques involve overwriting heap data which contain pointers to control what those pointers point too. And still others overwrite heap metadata that will cause future allocation calls to allocate data in the wrong place, perhaps overwriting a function!
Suppose the following code had to be run to configure an application with a secret key. Since it writes to /etc you can only run this code as ‘root’. Suppose you really wanted to see the secret key but you don’t have root access. You can use a heap-based overflow when you provide the input filename to overwrite the heap space that contains the directory to write too (like your home directory!).
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main(int argc, char **argv) { char *file_name, *dir; file_name = (char *) malloc(8); dir = (char *) malloc(128); // Get the filename from the cmdline strcpy(dir, "/etc/conf/key/"); strcpy(file_name, argv[1]); strcat(dir, file_name); FILE *fd = fopen(dir, "w"); if (fd == NULL) { fprintf(stderr, "File open error."); } fputs("zvsda34", fd); return 0; }
Learning about rootkits
“It’s imperative that everybody working in the field of cyber-security read this book to understand the growing threat of rootkits.”
–Mark Russinovich, editor, Windows IT Pro / Windows & .NET Magazine
“This material is not only up-to-date, it defines up-to-date. It is truly cutting-edge. As the only book on the subject, Rootkits will be of interest to any Windows security researcher or security programmer. It’s detailed, well researched and the technical information is excellent. The level of technical detail, research, and time invested in developing relevant examples is impressive. In one word: Outstanding.”
–Tony Bautts, Security Consultant; CEO, Xtivix, Inc.
“This book is an essential read for anyone responsible for Windows security. Security professionals, Windows system administrators, and programmers in general will want to understand the techniques used by rootkit authors. At a time when many IT and security professionals are still worrying about the latest e-mail virus or how to get all of this month’s security patches installed, Mr. Hoglund and Mr. Butler open your eyes to some of the most stealthy and significant threats to the Windows operating system. Only by understanding these offensive techniques can you properly defend the networks and systems for which you are responsible.”
–Jennifer Kolde, Security Consultant, Author, and Instructor
“What’s worse than being owned? Not knowing it. Find out what it means to be owned by reading Hoglund and Butler’s first-of-a-kind book on rootkits. At the apex the malicious hacker toolset–which includes decompilers, disassemblers, fault-injection engines, kernel debuggers, payload collections, coverage tools, and flow analysis tools–is the rootkit. Beginning where Exploiting Software left off, this book shows how attackers hide in plain sight.
“Rootkits are extremely powerful and are the next wave of attack technology. Like other types of malicious code, rootkits thrive on stealthiness. They hide away from standard system observers, employing hooks, trampolines, and patches to get their work done. Sophisticated rootkits run in such a way that other programs that usually monitor machine behavior can’t easily detect them. A rootkit thus provides insider access only to people who know that it is running and available to accept commands. Kernel rootkits can hide files and running processes to provide a backdoor into the target machine.
“Understanding the ultimate attacker’s tool provides an important motivator for those of us trying to defend systems. No authors are better suited to give you a detailed hands-on understanding of rootkits than Hoglund and Butler. Better to own this book than to be owned.”
–Gary McGraw, Ph.D., CTO, Cigital, coauthor of Exploiting Software (2004) and Building Secure Software (2002), both from Addison-Wesley
“Greg and Jamie are unquestionably the go-to experts when it comes to subverting the Windows API and creating rootkits. These two masters come together to pierce the veil of mystery surrounding rootkits, bringing this information out of the shadows. Anyone even remotely interested in security for Windows systems, including forensic analysis, should include this book very high on their must-read list.”
–Harlan Carvey, author of Windows Forensics and Incident Recovery (Addison-Wesley, 2005)
Rootkits are the ultimate backdoor, giving hackers ongoing and virtually undetectable access to the systems they exploit. Now, two of the world’s leading experts have written the first comprehensive guide to rootkits: what they are, how they work, how to build them, and how to detect them. Rootkit.com’s Greg Hoglund and James Butler created and teach Black Hat’s legendary course in rootkits. In this book, they reveal never-before-told offensive aspects of rootkit technology–learn how attackers can get in and stay in for years, without detection.
Hoglund and Butler show exactly how to subvert the Windows XP and Windows 2000 kernels, teaching concepts that are easily applied to virtually any modern operating system, from Windows Server 2003 to Linux and UNIX. They teach rootkit programming techniques that can be used for a wide range of software, from white hat security tools to operating system drivers and debuggers.
After reading this book, readers will be able to
- Understand the role of rootkits in remote command/control and software eavesdropping
- Build kernel rootkits that can make processes, files, and directories invisible
- Master key rootkit programming techniques, including hooking, runtime patching, and directly manipulating kernel objects
- Work with layered drivers to implement keyboard sniffers and file filters
- Detect rootkits and build host-based intrusion prevention software that resists rootkit attacks
Examining x86_64 Memory with GDB
-g Produce debugging information in the operating system's native format (stabs, COFF , XCOFF , or DWARF 2). GDB can work with this debugging information.
set dis intel
set disassembly-flavor intel
nobody@nobody:~$ echo "set disassembly-flavor intel" > ~/.gdbinit
-q ``Quiet''. Do not print the introductory and copyright messages. These messages are also suppressed in batch mode.
nobody@nobody:$ gcc -g hello_world.c nobody@nobody:$ gdb -q ./a.out Reading symbols from a.out...done. (gdb)
(gdb) disass main Dump of assembler code for function main: 0x0000000000400524 <+0>: push rbp 0x0000000000400525 <+1>: mov rbp,rsp 0x0000000000400528 <+4>: mov edi,0x40062c 0x000000000040052d <+9>: call 0x400418 <puts@plt> 0x0000000000400532 <+14>: mov eax,0x0 0x0000000000400537 <+19>: leave 0x0000000000400538 <+20>: ret End of assembler dump.
Formats: o - octal d - decimal x - hexadecimal u - unsigned integer s - string t - binary Units: b - byte h - half w - word g - double word
(gdb) x/s 0x40062c 0x40062c: "Hello World!"
(gdb) x/12db 0x40062c 0x40062c: 72 101 108 108 111 32 87 111 0x400634: 114 108 100 33
0x000000000040052d <+9>: call 0x400418 <puts@plt>
Environment
I’m pretty comfortable with almost all operating systems. I like to use my MacBook Pro for school so this where I’ll be doing the work.
Hacking the Art of Exploitation comes with a LiveCD based on Ubuntu. All of the examples in the book are therefore targeted towards Linux. I opted to install the latest version of Ubuntu (10.04 at this time) using VirtualBox on Mac.