Example of a buffer overflow leading to a security leak - c

I read many articles about unsafe functions like strcpy, memcpy, etc. which may lead to security problems when processing external data, like the content of a file or data coming from sockets. This may sound stupid, but I wrote a vulnerable program but I did not manage to "hack" it.
I understand the problem of buffer overflow. Take this example code:
int main() {
char buffer[1];
int var = 0;
scan("%s", &buffer);
printf("var = 0x%x\n", var);
return 0;
}
When I execute the program and type "abcde", the program outputs 0x65646362 which is "edcb" in hexadecimal + little-endian. However I read that you could modify the eip value that was pushed on the stack in order to make the program execute some unwanted code (eg. right before a call to the system() function).
However the function's assembly starts like this:
push %ebp
mov %ebp, %esp
and $0xfffffff0, %esp
sub $0x20, %esp
Since the value of %esp is random at the start of the function and because of this "and", there seems to be no reliable way to write a precise value into the pushed eip value.
Moreover, I read that it was possible to execute the code you wrote in the buffer (here the buffer is only 1 byte long, but in reality it would be large enough to store some code) but what value would you give to eip in order to do so (considering the location of the buffer is random)?
So why are developpers so worried about security problems (except that the program could crash) ? Do you have an example of a vulnerable program and how to "hack" it to execute unwanted code? I tried this on linux, is Windows less safe?

Read the excellent article by Aleph One: Smashing the Stack for Fun and Profit.

Well for one thing, don't under estimate the hazards associated with being able to unreliably place a value inside EIP. If an exploit works one in 16 times, and the service it is attacking automatically restarts, like many web applications, then an attacker that fails when trying to get access can always try, try again.
Also in a lot of cases the value of ESP is less random than you think. For starters on a 32-bit system it is nearly always a multiple of four. That means that the extra padding offered by the and $0xfffffff0, %esp instruction will be either 0, 4, 8 or 12 bytes. That means that it is possible to just repeat the value that is to be written into the return EIP four times to cover all possible offsets to the address of return EIP.
There are actually much more aggressive stack protection / buffer overflow detection mechanisms around. However, there are ways and means around even these.
Also, for an example of where this sort of thing can be dangerous, consider if the value of var was important to you logic as in the following toy example.
int main() {
char buffer[1];
int var = 0;
var = SecurityCheck();
scan("%s", &buffer);
if (var != 0)
GrantAccess();
else
DenyAccess()
}

Further you don't have to overwrite EIP with a pointer to something in your string. For example you could overwrite it with a pointer to system() and overwrite the next word with a pointer to /bin/sh at a fixed location in the program image.
Edit: Note that system uses the PATH (actually it runs the command via a shell), so "sh" would be just as good; thus, any English word ending in "sh" at the end of a string provides the argument you need.

A classic example of an actual exploit based on buffer overruns is the Morris Worm of 1988.

As mentioned in other answers, absolute reliability is not always essential for the attack to succeed. Applications that restart automatically are an example. Locally exploitable buffer overflows on suid programs would be another. And there's the NOP sled technique to increase chances of successful exploitation, put a lot of NOPs before your shellcode so you have a much better chance to correctly guess the "start" of your shellcode.
There are many more techniques for increasing the reliability of attacks. On Windows, back in the day, many exploits overwrote the return address with the address of a "jmp %esp" located somewhere in the program (trampoline).
"Insecure programming by example" had a nice trick for Linux. Clean your environment and put your shellcode in an environment variable. Back in the day, this would lead to a predictable address near the top of the stack.
And there are also variants like return-into-libc and return-oriented programming.
There was even an article on Phrack on how to exploit 1-byte stack overflows (meaning the buffer was overrun by only one byte) (btw, 1-byte heap overflows are also exploitable in the vast majority of cases, barring protections).
To sum up, it's not that developers are paranoid, there are lots of ways to exploit even the strangest cases, and remember:
A program is of good quality when it does what it is supposed to do.
A program is secure when it does what it is supposed to do, and nothing more.

Here's a windows version and tutorial:
http://www.codeproject.com/KB/winsdk/CodeInject.aspx
The general case I was always warned about was:
printf( string );
Because the user can provide a "%n" in there, which allows you to insert anything you want into memory. All you need to do is find the memory offset for a system call, pass a few "%n"'s and junk characters, and thus insert the memory address onto the stack where the return vector would normally be. Voila -- insert any code you like.

Related

overcome stack randomization by brute force

I'm reading a book that shows how buffer overflow attacks and one technique to stop it is called Stack Randomization, below is quoted from the book:
a persistent attacker can overcome randomization by brute force, repeatedly attempting attacks with different addresses. A common trick is to include a long sequence of nop (pronounced “no op,” short for “no operation”) instructions before the actual exploit code. Executing this instruction has no effect, other than incrementing the program counter to the next instruction. As long as the attacker can guess an address somewhere within this sequence, the program will run through the sequence and then hit the exploit code. If we set up a 256-byte(28) nop sled, then the randomization over n = 223 can be cracked by enumerating 215 = 32,768 starting addresses
I understand the first part, but don't get the second part about enumerating starting addresses. For example, %rsp points to the current start address as picture below shows (only show 8 bytes instead of 256 bytes for simplicity)
I think what the author mean is, try and guess different address to the stack memory where the %rsp is pointing to. And the padding between return address and %rsp are all nop, and then overwrite the return address with the guessed address which is highly likely points to part of padding(nop). But since Stack Randomization allocats a random amount of space between 0 and n bytes on the stack at the start of a program, so we can only say the probability of successful attack is 215/223 = 0.78%, how can we say try 32,768(a fixed number) addresses then it will be cracked? it is the same as toss a coin, you can only say the probablity of getiing a head is 0.5, you cannot say you will get a head in the second round, becuase you might get two tails
Stack Randomization allocats a random amount of space between 0 and n bytes on the stack at the start of a program
No, it doesn't allocate. It randomizes where in virtual address space the stack is mapped, leaving other pages unmapped. This is with page granularity.
Guessing wrong will typically result in the victim program segfaulting (or whatever the OS does on an invalid page fault). This is noisy and obvious to any intrusion-detection. And if the program does eventually restart so you can try again, its stack address will be re-randomized, as you suggest.
Wrong guesses that land in valid memory but not your NOP sled will also typically crash soon, on an invalid instruction or something that decodes to an invalid memory access.
So yes, you're right, you can't just enumerate the address space, it's only a probabilistic thing. Trying enough times will mean it's likely you succeed, not guaranteed. And trying to enumerate the possible ASLR entropy isn't particularly useful, or any more likely to succeed sooner than guessing the same page every time I think.
But trying different offsets within a single page is useful because OS-driven stack ASLR only has page granularity.
There is some amount of stack space used by env vars and command line args which will vary from system to system, but tend to be constant across invocations of the same program, I think. Unless the vulnerable function is reached from different call chains, or there's a variable-sized stack allocation in a parent function, in which case the buffer's offset within page could vary every run.
Although of course most processes these days run with non-executable stacks, making direct code-injection impossible for stack buffers. A ROP attack (injecting a return address to an existing sequence of bytes that decode to something interesting) is possible if there are any known static data or code addresses. If not, you have to deal with ASLR of code/data, but you don't get to inject NOP sleds.

Running own code with a buffer overflow exploit

I am trying to understand the buffer overflow exploit and more specifically, how it can be used to run own code - e.g. by starting our own malicious application or anything similar.
While I do understand the idea of the buffer overflow exploit using the gets() function (overwriting the return address with a long enough string and then jumping to the said address), there are a few things I am struggling to understand in real application, those being:
Do I put my own code into the string just behind the return address? If so, how do I know the address to jump to? And if not, where do I jump and where is the actual code located?
Is the actual payload that runs the code my own software that's running and the other program just jumps into it or are all the instructions provided in the payload? Or more specifically, what does the buffer overflow exploit implementation actually look like?
What can I do when the address (or any instruction) contains 0? gets() function stops reading when it reads 0 so how is it possible to get around this problem?
As a homework, I am trying to exploit a very simple program that just asks for an input with gets() (ASLR turned off) and then prints it. While I can find the memory address of the function which calls it and the return, I just can't figure out how to actually implement the exploit.
You understand how changing the return address lets you jump to an arbitrary location.
But as you have correctly identified you don't know where you have loaded the code you want to execute. You just copied it into a local buffer(which was mostly some where on the stack).
But there is something that always points to this stack and it is the stack pointer register. (Lets assume x64 and it would be %rsp).
Assuming your custom code is on the top of the stack. (It could be at an offset but that too can be managed similarly).
Now we need an instruction that
1. Allows us to jump to the esp
2. Is located at a fixed address.
So most binaries use some kind of shared libraries. On windows you have kernel32.dll. In all the programs this library is loaded, it is always mapped at the same address. So you know the exact location of every instruction in this library.
All you have to do is disassemble one such library and find an instruction like
jmp *%rsp // or a sequence of instructions that lets you jump to an offset
Then the address of this instruction is what you will place where the return address is supposed to be.
The function will return then and then jump to the stack (ofcourse you need an executable stack for this). Then it will execute your arbitrary code.
Hope that clears some confusion on how to get the exploit running.
To answer your other questions -
Yes you can place your code in the buffer directly. Or if you can find the exact code you want to execute (again in a shared library), you can simply jump to that.
Yes, gets would stop at \n and 0. But usually you can get away by changing your instructions a bit to write code that doesn't use these bytes at all.
You try different instructions and check the assembled bytes.

buffer overflow exploit: Why does "jmp esp" need to be located in a DLL?

I am trying to understand classical buffer overflow exploits where an input buffer overwrites the stack, the function return address that is saved on the stack and upper memory regions (where you usually place the shell code).
There are many examples of this on the internet and I think I have understood this pretty well:
You put more data in some input buffer that the developer has made fixed size
Your input overwrites the function arguments and the return address to the calling function on the stack
That address is loaded into EIP when the OS tries to return from the function the overflow happened in and that is what allows you to get data you control into the EIP register (when not reading carefully some articles you get the impression you can overwrite CPU registers. Of course, this is not the case, you can only overwrite the stack but the CPU will load addresses from the stack into its registers)
If the exploit is well designed the value loaded into EIP will make the program jump to the beginning of the shell code (see point 5)
The next thing I think I have understood well is the "JMP ESP" mechanism. When replicating the crash in your lab environment you look for a place in memory that contains the "JMP ESP" instruction and you overwrite the EIP (now my wording is not precise, I know...) with that address. That address needs to be identical no matter how often you run this, at what time, which thread is executing your stuff etc., at least for the same OS version and the address must not contain any forbidden bytes. The code will jump to that address (at the same time the stack is reduced by 4 bytes) so "jmp esp" will jump to the next address in my overflow buffer after the place where I had put the value to overwrite EIP with and that is usually the place where the shellcode goes, maybe prepended with NOPs.
Now comes the question.
All articles I've read so far are looking for the address of the "JMP ESP" instructions in a DLL (which must not be relocatable, not compiled with ASLR, etc.). Why not looking in exe itself for a "jmp esp"? Why does it need to be in a DLL?
I have run the "!mona modules" command in Immunity Debugger and the only module displayed that satisfies all these conditions is the exe itself. When I look in popular exploit databases the address is always in loaded DLLs.
I cannot see any obvious reason for this. The exe can also be located at the same address in memory the same way a DLL can. What is the difference?
Found another resource on this:
As I wrote in a comment before, the addresses of the exe usually contain a zero:
http://resources.infosecinstitute.com/in-depth-seh-exploit-writing-tutorial-using-ollydbg/#commands
A module you can consider using is the main executable itself, which
is quite often not subject to any compiler based exploit protections,
especially when the application has been written by a third party
developer and not Microsoft. Using the main executable has one major
flaw however, in that it almost always starts with a zero byte. This
is a problem because the zero byte is a string terminator in C/C++,
and using zero bytes as part of strings used to overflow a buffer will
often result in the string being terminated at that point, potentially
preventing the buffer from being appropriately overflowed and breaking
the exploit.
In position independent code jump addresses are relative to the program-counter, while in non-relocatable code they are absolute. DLLs in Windows do not generally use position independent code. Exploits that rely on knowing the offset of the executable code in the binary require non-relocatable code.
short answer: the address DOES NOT need to be in a DLL.
long answer:
ANY mapped unprotected executable memory in your process will be executed if the Instruction register is set to its address.
MAPPED: means the memory is mapped to your process by the operating system, some addresses may not be mapped and any and all access will cause operating system memory fault signals to be raised.
EXECUTABLE: mapped memory often has permissions set to it, sometimes it is enough for the memory to be readable yet with newer processors with NX-bits it may be required to be mapped executable
UNPROTECTED: means that the memory is not mapped as a guard page. memory pages that are protected by guard pages will raise processor interrupt. the handling of these depends on your operating system and may be used to implement non-executable pages on processors that do not implement NX-bits.
if the memory in your executable file fulfils these demands it CAN be used for your exploit. whether you can FIND this address during runtime is another question and can be very difficult for real world exploits. sticking to non relocatable DLLs and EXEs is a good idea for beginners.
as for your comment:
I am looking again at my example and I think the answer is a lot easier than I originally thought. The exe is loaded at base address 0x004.... and goes up to 0x009.... This simply means that the every address will contain a 0x00 which is probably a show stopper for each C like program...
trying to overrun previous addresses with new addresses that contain '\0' characters may cause problems for exploits that use an overrun in string based functions (eg. strcpy or gets) to overflow the buffer because those stop on '\0' characters.
if you can overflow your buffer with logic that is not limited by '\0' characters (eg memcpy) you may use those addresses as well.

Randomizing registers

If certain conditions are not met I want to crash my program by jumping to a random location. I also want to randomize the registers by statements like
asm("rdtsc \n");
asm ("movq %rax, %r15 \n");
...
asm ("xor %rbp, %r13 \n");
...
Is there a better/stealthier method to do this? I am concerned, because rdtsc is not a frequent statement in programs. Calling it continually generates similar results too. Beside this, can I somehow clear/randomize the stack content too?
If you just want to crash, your random choice of destination might jump somewhere legal. Just run the ud2 instruction (0F 0B), which is guaranteed to cause an invalid-instruction exception (leading to SIGILL) on every future x86 CPU. i.e. it's reserved, so no future instruction-set extension will ever use that two-byte sequence at the beginning of an instruction.
If you care about high-quality randomness to frustrate any potential backtrace or core dump, then call a random number generator to fill a buffer of random data (or just one 32bit random value which you repeat). Fill all the registers with that garbage data. In 32bit code, you could use a popa instruction to fill all the registers with that garbage data. In 64bit mode, you have to load them manually.
Then scribble over the stack with that data, so your program eventually stops with a segfault when you try to write to an unmapped address (because you've gone outside the stack area).
You could do that scribbling with a rep stosd or something.
As far as "stealthier", you'll need to be much more elaborate about what your threat model is, and what you're trying to stop anyone from learning / doing. i.e. defend against someone modifying your binary to not crash this way?
In addition to Peter Cordes suggestions, I would add that the OP wants to code responsible for this obfuscation to stay out of scope (stealthier). The instruction causing the crash needs to be somewhere else, otherwise the obfuscation code will be obvious from a crash dump and the code will be easy to patch to remove the bomb.
A rather easy solution is to locate the RET opcode from a common library function such as read or strlen and JUMP there by pushing the address on the stack and executing a RET statement. This solution is not perfect: advanced debuggers exist that store the execution trace and will be able to backtrack to the obfuscator from the crash location. In order to defeat that, you may prefer to enter an infinite loop instead of crashing, but that loop can be easily found and removed.
You can also embed some complex code in your app that computes for a while by executing many different functions in a random manner and use that as a honey pot to jump to from the obfuscator.

buffer overflow exploits - Why is the shellcode put before the return address

The code I'm reffering to is found here: Link to code
I read that the buffer overflow exploit uses a buffer that looks something like this:
| NOP SLED | SHELLCODE | REPEATED RETURN ADDRESS |
From what I understand the exploit happens when the buffer is put onto the stack as a function parameter and overwrites the function's return address.
I also understand that the repeated return address points to the NOP sled in the same buffer on the stack.
What I don't understand are the following:
Why does the return address have to point to the shellcode in the same buffer? Why not have the reapeated return addresses point to another part of the memory where the NOP sled and the Shellcode can be found?
How is the return address on the buffer perfectly aligned with the original one so the "ret" command will read the correct address and not read it from the middle for example.
The return address doesn't have to point to code in the same buffer, it is just often easier to do it this way. If you can put the shell code in and return address into the same buffer then this is the simplest. If the buffer that can be overflowed is too small to fit the shell code, it is feasible to put the shell code into another buffer and then jump to that when the vulnerable buffer is overflowed.
Also, protections such as Data Execution Prevention or (NX) prevent code being executed from a stack. In this case, techniques such as Return-Oriented Programming can be used to circumvent DEP. This technique involves using legitimate, executable code segments to run code the attacker wants to.
This can be tricky and may require some fiddling around with the payload. Usually the start of a buffer is at an address that is word aligned. In this case, ensuring the return address is correctly aligned means writing a buffer that is a multiple of the CPU word (4 bytes for 32-bit machines, 8 bytes for 64-bit). If the buffer is not word aligned, then an attacker may just experiment by adding or removing byte at a time until he thinks it is.
The reason it is simpler to do everything in one buffer is because not much will change between the injection of the shell code and the jumping to the newly modified return address. At the point of attack, it is very unlikely that an attacker can reference memory of another process, so we must look at buffers in process.
Putting shell code into a different buffer requires the attacker to understand how long the buffer will stay in place. Do different function calls cause one of the buffers to be deallocated? Is one of the buffers on the heap instead of the stack? So long as your single buffer is large enough, it is much simpler to put your NOP sled and shell code near the start and then just fill the rest with the return address. Compared to finding one buffer to populate with shell code and another to populate with the address of the previous buffer. Some shell code may also reference the stack pointer which means it needs to be set correctly.

Resources