Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon.

Pages: 1-

buffer overflow vulnerabilities

Name: Anonymous 2009-02-18 20:46

void f ( char * s ) {
    gets ( s );
}

int main () {
          char input [100]
          f ( input )
}

The input here isn't checked. If you enter more than 100 characters as input to this program, you can overwrite certain offsets of the stack. I'm told that you can overwrite it in such a way that the return address of gets() is overwritten to point to the beginning of input[], and you can craft the first 100 chars of input to be machine code, so then once gets() returns it executes your machine code.

The concept is pretty simple to understand, but I'm having some trouble grasping how exactly I would do that. Could a more knowledgeable person than myself help me understand how to do that?

For example, how would I craft the input to this program so that it prints "123"? Do I have to be familiar with x86 asm to be able to do this? (100 chars might not be enough, I don't know).

Thanks in advance for any help.

Name: Anonymous 2009-02-18 20:49

Go read Smashing the Stack for Fun and Profit

Name: Anonymous 2009-02-18 20:50

Wonderful! Thank you so much for that recommendation, reading it now.

Could you give me one quick example right now so I can check what I'm learning against your example as I go?

Thanks again, a million times over.

Name: Anonymous 2009-02-18 21:06

>>3
Example:

- You have some shit on the stack.
- An unchecked reader function records more shit than will fit there, overwriting other shit.
- Other shit is now compromised.

Name: Anonymous 2009-02-18 21:10

>>4
Yeah I know out that much, I was thinking of a concrete example of what I can input to the program I gave above to make it do something simple like print "123". Thanks anyway.

Name: Anonymous 2009-02-18 21:16

>>5
making the program crash is simple. making it print random garbage is simple. making it print "123" is not simple.

Name: Anonymous 2009-02-18 21:21

>>1
Do I have to be familiar with x86 asm to be able to do this?
Yes.

Name: Anonymous 2009-02-18 21:26

>>6
Okay, how might I make it print random garbage then? What input do I need to give it so that the return address of gets() points to the beginning of the array?

This is my thought: char[100] is allocated to the stack before the function call, and the function call add the argument and the return address, each being one word. If I give it 108 characters input, I should be able to set those last 8 characters to the address of the array, so then the return address is overwritten as the address of the beginning of the array and I can set the first 100 characters to print random garbage.

Again, the details elude me; what would be a good example of making it print random garbage, which you said is "simple"?

Name: Anonymous 2009-02-18 21:29

>>6
It's not that hard either:

all he has to do is overwrite the return address while overflowing that buffer. Providing he can predict his location on the stack and return to the stack, then he can just have some code which calls printf with a "123" string. Things required to do this usually include:

0)Good knowledge of target CPU
1)Understanding stack frames
2)Understanding the specific stack frame of the function you're exploiting
3)Understanding how to bypass various system and anti-overflow protections, such as security cookies on some safe MSVC built software, No Execute/DEP, Vista's heap/stack/process address space randomization,*nix specific heuristic based shellcode detection tools (for attempting to catch unknown exploits). Only needed when you know they are in use. Bypassing some can be quite complex, but almost always possible. For example, bypassing NX flag on the stack is possible by returning into known library code, which in turns returns to run your code, sometimes this will have to be written on a per-target basis if you want to be able to defeat the other security feats too.
4)Learn to write shellcode, this means know your asm, and be able to do various trickery with it, such as self-modifying/self-decrypting/self-contained/base-independent code. There are some newbie friendly shellcode generators out there for the lazy.

This is nothing hard in itself, but do you really need to do this?

Name: Anonymous 2009-02-18 21:35

make a simple program like
void main() {
   printf("123");
}


compile with gcc -S, make that into a machine code string (padded with NOPs) and smash away.

Name: Anonymous 2009-02-18 21:36

>>9
Do I really need to do it? No. Is that why it's fun/interesting? Yes.

Name: Anonymous 2009-02-18 21:46

Best way is to know a location that always contains "call esp" or some variation thereof.

For example, kernel32.dll in win32 is always in the same location (for a given OS and service pack that is). So, for Win XP SP2, 0x7c82385d always is Call ESP.

Then, you have a payload from, say, milw0rm.com as the first characters, padding till the function return, and overwrite the return pointer with 0x7c82385d (will need to be reverse byte order).

Name: Anonymous 2009-02-18 21:48

>>10
Won't necesarilly work since it puts strings in the data section, and may use absolute offsets. For shellcode, you'll have to take the address of the string which could be located randomly on the stack to be able to print it. A simple solution is something like this:

call @next

db '123',0

@next:
push expectedPrintfAddressInApplication ; for *nix you can use syscalls, or if you know the function is included in the application, find its address. Note that i did not use call expectedPrintfAddressInApplication, because calls are relative to location in memory of said code
ret

Another solution for this would be to overwrite the value before the stack pointer with the location of your string and the return address with printf's address, but that's less flexible.

Another tip:

Base-independent code can be made like this:

start:
call $+5
pop ebp
sub ebp,5 ; ebp now contains addr of start

push [ebp+((offset sz123)-(offset start))]
push printf
retn
sz123: db '123',0


In the event you're overflowing a string (NULL-terminated), you can just make a simple decryptor for your code and have it such that it doesn't contain nulls. This still leaves you with the problem of having nulls in offsets, this can generally be solved by adding an extra magic constant to the [ebp+((offset Data)-(offset start))+MAGIC] part, and making sure to sub ebp,MAGIC before this. In unavoidable cases such as:
call $+5 where it assembles as E8 00 00 00 05, you can instead do:

@1:
jmp short @2
pop ebp
jmp @3
...junk...
@2:
call @1
...junk...
@3:

This should make it possible to avoid having nulls in your code. Go read some papers on this if you want more advanced tips, I'm too lazy to write them up now, especially since they've all been discussed before.

Name: Anonymous 2009-02-18 21:51

>>13
Made a minor mistake there push [ebp+((offset sz123)-(offset start))], make that lea reg, [ebp+((offset sz123)-(offset start))] push reg.  Otherwise it dereferences the string, which is not what was intended.

Name: Anonymous 2009-02-18 21:58

>>13
Cool details. I like the "jump forward, call backward" trick to avoid null bytes.

Name: Anonymous 2009-02-19 6:30

Name: Anonymous 2009-02-19 10:47

Name: Anonymous 2010-12-24 1:39

Don't change these.
Name: Email:
Entire Thread Thread List