Archive for September, 2010

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.

(gdb) disassemble main
Dump of assembler code for function main:
0x0000000100000ecd <main+0>:    push   rbp
0x0000000100000ece <main+1>:    mov    rbp,rsp
0x0000000100000ed1 <main+4>:    sub    rsp,0x10
0x0000000100000ed5 <main+8>:    mov    DWORD PTR [rbp-0x4],edi
0x0000000100000ed8 <main+11>:   mov    QWORD PTR [rbp-0x10],rsi
0x0000000100000edc <main+15>:   mov    rax,QWORD PTR [rbp-0x10]
0x0000000100000ee0 <main+19>:   mov    rdi,QWORD PTR [rax]
0x0000000100000ee3 <main+22>:   call   0x100000e88 <function>
0x0000000100000ee8 <main+27>:   mov    eax,0x0
0x0000000100000eed <main+32>:   leave
0x0000000100000eee <main+33>:   ret
End of assembler dump.

I’ve highlighted the call to the function and one instruction after it. The return address is always the next instruction address after the function call. The ‘call’ instruction pushes the return address onto the stack.

Let’s set a break point in function() so we can examine the stack after the ‘call’ instruction

(gdb) break 13
Breakpoint 1 at 0x100000ea4: file ../src/main.c, line 13.
(gdb) run hello
Breakpoint 1, function (in=0x7fff5fbff2e8 "/TheXploit/Debug/TheXploit") at ../src/main.c:14
(gdb) x/16xw $rsp
0x7fff5fbff0c0: 0x5fbff288      0x00007fff      0x5fbff2e8      0x00007fff
0x7fff5fbff0d0: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fff5fbff0e0: 0x00000000      0x00000000      0x282afe15      0xa5aa35fb
0x7fff5fbff0f0: 0x5fbff110      0x00007fff      0x00000ee8      0x00000001

Here we’ve examined 16 words from the top of the stack frame for function(). You may not notice it at first but the return address is the last 8 bytes (0x7fff5fbff0f9 – 0x7fff5fbff0ff) in the output above. It’s in Little Endian byte order so it appears backwards; the lower order bytes appear first. Look back at the disassembled main() function at the address after the call to function(), it’ll be 0x0000000100000ee8, exactly what’s on the stack (remember to swap them for lower order bytes first)!

More to come about overwriting this address to gain control of the program!

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.

That means that the following code

int main(int argc, char **argv) {
        char buf[1];
        return 0;
}

Translates to allocating 16 bytes on the stack even though it’s only 1 byte.

...
0x0000000100000ef2 :    sub    rsp,0x10 # 16 bytes
...

Update
This is not specific to Mac, all 64 bit platforms use this stack alignment. Here is the Windows documentation and here is the Linux documentation. Thanks Pascal!

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]‘. When these arrays are declared, the space for their data is allocated on the stack. The key point is that the space is fixed.

A stack based buffer overflow occurs when more data than what was allocated is put into the buffer and the excess data “overflows” into other stack memory space.

Stack-based buffer overflows are exploitable because of the way the stack allocates stack frames when functions are called. Every time a function is called the return address to jump back to the previously executing function is stored on the stack.

The data that overflows in the current stack frame can overwrite data in the previous stack frame, manipulating the return address. Here’s an example of an exploitable buffer overflow.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void function(char *in) {
	char buf[16];
	strcpy(buf, in);
}

int main(int argc, char **argv) {
	function(argv[0]);
	return 0;
}

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;
}

PS3 Heap Overflow Exploit Explained

As of very recently the PS3′s security has been finally been compromised!

Commercially, a company is selling a USB device called PSJailBreak (for a steep $130) which takes advantage of this exploit but it was reverse engineered and released as an open source project, yesterday, called PSGroove. The open source release is targeted towards homebrew developers who want to develop their own things on the PS3.

The guys over at lan.st have a really nice wiki post about the reverse engineering they did on PSJailBreak. Be sure to check out the original article for a more in depth explanation. I’ve summarized the exploit below. I take no credit for any of these findings. All the credit goes to the awesome PS3 hackers out there (GeoHot)!

Summarizing the Exploit

The exploit takes advantage of a heap overflow by making the PS3 think the single USB device that’s plugged in is a 6 port USB hub. The single USB then tells the PS3 to allocate/unallocate large chunks of heap space (4K) (using large device descriptors) by faking that devices are being plugged and unplugged from the USB hub.

One of the fake USB devices thats plugged in manages to overwrite another USB device’s heap space when allocating it’s configuration data. The key point here is that when it overwrites this data, it overwrites malloc’s pointer to where the next free memory block is. That means when malloc gets called again, it allocates space to wherever that pointer is pointing. The exploit overwrites it with a pointer to a function that it knows the PS3 will need to call. The function has something to do with freeing memory when a USB device is unplugged. (You might see where this is going)

All PS3′s have special built in functionality that allows an authorized USB “Jig” device to be plugged into the PS3 which turns it into development/debug mode. Sony uses this for repairing PS3′s and likely distributes it to game developers.

The exploit takes advantage of this fact and tells the PS3 that a “Jig” device has been plugged in. The PS3 sends an authentication challenge to the device to verify it’s authenticity. A real device with a key from Sony would be able to compute the response, respond, and continue on it’s merry way but the exploit takes advantage of the fact that the PS3 has to call malloc to allocate space for the challenge response. Malloc’s pointer to the next free space in memory was overwritten earlier. That means malloc will allocate space in the wrong place, overwriting a function the PS3 calls when a USB device gets unplugged. That means we can send a function of our choice (the shellcode) as the challenge response and the PS3 will overwrite another function with our function!

This is where the exploit gets invoked. The exploit explicitly unplugs one of it’s fake USB devices causing the PS3 to call the function related to freeing device memory which was overwritten with our challenge response data. The PS3 happily starts executing our code. From here we can now start patching memory to tell the PS3 that it’s in debug mode!

So what can you do in debug mode? You can start writing code and developing on the PS3!

Sony is very likely to patch this ASAP. In the meantime, you better hurry and get yourself a PS3. I know I’m thinking about it!

 

Learning about rootkits

Rootkits are fascinating to me. When classes are over, I’m hoping I can find some time to read more about them. I have yet to find a computer with a rootkit on it until recently. My brother had a rootkit that would intercept web requests from any browser and redirect them to ad pages. It was done in a random manner so you didn’t recognize it at first; you think you clicked on the wrong link. Pretty sneaky! This book appears to be the best book out there to learn about rootkits on Windows (the more popular target)

 

“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

 

Mac OS X Eclipse CDT Missing Binaries

I was hoping to do some code samples in C from the book tonight but unfortunately I ran into a snag. After installing Eclipse CDT to Eclipse Helios I thought I was good to go. For some reason though, after explicitly building my project with ⌘B no Binaries menu would shows up in Eclipse

Without no Binaries menu, that means that Eclipse can’t run your project and spits out an error.

I made sure I was choosing the MacOSX GCC but binaries still wouldn’t show up. I searched around for a while and others had similar problems when Eclipse didn’t have support for a 64 bit Mach-O parser. However looking at my project properties Eclipse shows a Mach-O 64 Parser.

I was stumped at this point since all the suggestions mentioned to make sure your Mach-O Parser was checked or add “-arch i386″.

I really wanted to compile in 64 bit so I played around a little more and figured out that if your Binaries menu is missing from Eclipse, try checking and unchecking the Mach-O 64 Parser then click OK. After doing that – success! I can now see the Binaries menu and Eclipse doesn’t give me “Launch Failed. Binary not found.” error.

 

Go to Top