Lab 2: Sample Code
Last updated
Was this helpful?
Last updated
Was this helpful?
#include
#include
void do_something(char *Buffer)
{
char MyVar[128];
strcpy(MyVar,Buffer);
}
int main (int argc, char **argv)
{
do_something(argv[1]);
}
This applications takes an argument (argv[1] and passes the argument to function do_something(). In that function, the argument is copied into a local variable that has a maximum of 128 bytes. So… if the argument is longer than 127 bytes (+ a null byte to terminate the string), the buffer may get overflown.
00401290 /$ 55 PUSH EBP
00401291 |. 89E5 MOV EBP,ESP
00401293 |. 81EC 98000000 SUB ESP,98
00401299 |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] ; |
0040129C |. 894424 04 MOV DWORD PTR SS:[ESP+4],EAX ; |
004012A0 |. 8D85 78FFFFFF LEA EAX,DWORD PTR SS:[EBP-88] ; |
004012A6 |. 890424 MOV DWORD PTR SS:[ESP],EAX ; |
004012A9 |. E8 72050000 CALL ; \strcpy
004012AE |. C9 LEAVE
004012AF . C3 RETN
??????????????????????????????? Address [ebp-88]?????????????????????
MOV BYTE PTR DS:[EDI],DL
DL is LOWER EDX
ABABAB00
EDI = 0022FE54
EDX got moved to EDI
Padding to put Ptr to Argv[1] ???
Above EDI ??? 003d2480 = edi
Above EIP
77BD6F05 = MOV ECX,DWORD PTR SS:[ESP+C] > C = 12 mov “pointer to argv[1]” to ecx
77BD6F3C = MOV EDX,DWORD PTR DS:[ECX]
2ND TIME
77BD6F29 = MOV DWORD PTR DS:[EDI],EDX
???? ALREADY AT BYTE SITE
77BD6F80 = MOV BYTE PTR DS:[EDI],DL
> POINTS TO AAAA
So you control EIP Long story short, by controlling EIP, you basically change the return address that the function will uses in order to “resume normal flow” Of course, if you change this return address by issuing a buffer overflow, it’s not a “normal flow” anymore
In the upper left corner, you have the CPU view, which shows assembly instructions and their opcodes
NOTE the window is empty because EIP currently points at 41414141 and that’s not a valid address
In the upper right windows, you can see the registers
In the lower left corner, you see the memory dump of 00446000
In the lower right corner, you can see the contents of the stack (so the contents of memory at the location where ESP points at)
In both cases, we can see that the instruction pointer contains 41414141, which is the hexadecimal representation for AAAA
A quick note before proceeding: On intel x86, the addresses are stored little-endian (so backwards)
The AAAA you are seeing is in fact AAAA (or, if you have sent ABCD in your buffer, EIP would point at 44434241 (DCBA)
So, it looks like part of our m3u file was read into the buffer and caused the buffer to overflow
We have been able to overflow the buffer and write across the instruction pointer, so we may be able to control the value of EIP
Since our file does only contain A’s, we don’t know exactly how big our buffer needs to be in order to write exactly into EIP
In other words, if we want to be specific in overwriting EIP (so we can feed it usable data and make it jump to our evil code, we need to know the exact position in our buffer/payload where we overwrite the return address (which will become EIP when the function returns)
This position is often referred to as the “offset”
Determining location of EIP:
We know that the buffer is somewhere between 20000 and 30000
We could try and figure out where it is in there by cutting the number in half and replacing with “B” (0x42), and keep repeating until we can narrow down to the exact location
However, Metasploit has a nice tool (pattern_create.rb) to assist us with calculating the offset
NOTE: It will generate a string that contains unique patterns
Using this pattern (and the value of EIP after using the pattern in our malicious .m3u file), we can see how big the buffer should be to write exactly into EIP
Step 1 – Create example.c
Step 2 – Compile code
Step 3 – Access file from target machine
Step 4 – Launch Immunity Debugger
Step 5 – Launch example_[sid].exe in debugger
Step 6 – Run program
Step 7 – Create buffer overflow in example_[sid].exe
Feel free to go back and forth through this lab as we talk about the theory in class. It will help seeing what is happening in the CPU, the different registers, in the memory dump, and in the stack.
As we go through the labs, you can press [F2] to set break points in the program. When you run the program, it will stop at each of these break points.
When the software is paused, you can press [F7] to step through each step through each step, including stepping into each method called.
You can press [F8] to step through each step, except this will step over a function call, and simply go to the next line after the method has executed.
View associated .txt file
If there would not have been a strcpy() in this function, the function would now end and "unwind" the stack. Basically, it would just move ESP back to the location where saved EIP was, and then issues a RET instruction A ret, in this case, will pick up the saved EIP pointer from the stack and jump to it Thus, it will go back to the main function, right after where do_something() was called. The epilogue instruction is executed by a LEAVE instruction (which will restore both the frame pointer and EIP).
This function will read data, from the address pointed to it by [Buffer], and store it in, reading all data until it sees a null byte (string terminator) While it copies the data, ESP stays where it is The strcpy() does not use PUSH instructions to put data on the stack It basically reads a byte and writes it to the stack, using an index (for example ESP, ESP+1, ESP+2, etc) So after the copy, ESP still points at the beginning of the string That means… If the data in [Buffer] is somewhat longer than 0x98 bytes, the strcpy() will overwrite saved EBP and eventually saved EIP (and so on) After all, it just continues to read & write until it reaches a null byte in the source location (in case of a string) ESP still points at the begin of the string. The strcpy() completes as if nothing is wrong After the strcpy(), the function ends, this is where things get interesting… The function epilogue kicks in Basically, it will move ESP back to the location where saved EIP was stored, and it will issue a RET It will take the pointer (AAAA or 0x41414141 in our case, since it got overwritten), and will jump to that address