NOTE: This is definitely not the most elegant way to doing stack smashing and buffer overflow attacks. I am just putting my thoughts and notes here as a reference.
To generate a cookie for this project, I can simply run:
This time our team name is
alai3+sliu44, so our cookie is:
I found that typing the long command every time is very annoying. So I write two bash script to automate the process of testing and submitting. They are pretty much the same except for
-s part in the submitting script. When using
--all option on either of the script, I can just test all of my answers in the
Answer folder to get the outputs all at once:
This makes life so much easier.
The goal of this level is to overwrite the return address of a function (
getbuf() in this case) and let it return to the beginning of
smoke() in order to execute the code in
Since the return address is right after the frame base pointer, there are two things that I need to know in order to finish this level:
gets(), I don't really know where exactly it is by just looking at the disassembly code. Therefore I experimentally used a very long string consisting only
Acharacter to see where exactly it is. After I input the string, in gdb I checked the memory slots around the stack pointer:
41 is the hex for
A in ASCII. In this way I can tell where the buffer starts and where it ends.
Then I used the buffer to overwrite the return address to the address of
smoke() (0x08048b66) and executed it again:
This level is no different than the previous one except an argument is also overwritten by the buffer. So just a few changes is needed to finish this level.
The last few bytes in the input is the value of the cookie. In this way, it overwrites the value for
val on the stack and makes it to be the same as the value of my cookie.
Now if I run it:
The goal of this level is to inject some machine code to modify one of the global value in the memory and then jump to the address of a specific function (
bang() in this case).
After inspecting the assembly code of
bang(), I found the following lines of instructions doing the the comparisons of
Therefore, I can simply
x/x 0x804e140 and
x/x 0x804e138 in GDB to find the address and values of
Now that I know the address of
global_value, I just need to have an instruction dynamically injected into the process memory space and write to this memory location and then jump to the function
bang. Breaking this into steps, in the buffer I need:
movinstruction to write to memory location at
jmp instruction to perform a jump to
bang function at
The formula for
jmp instruction is:
JMP_Address + 2 + Second_Byte_value = Next_Instruction_Address
Now if I run it, sadly this is what I get:
The problem was that I was trying to run code in
_reserved() region. This region forbid me to execute code (I guess it is for memory safety reason). Also,
jmp instruction is not that easy to use since it is using PC-relative addressing, which is hard to configure. So I need another approach.
After referencing some on-line sources, I found this is actually much easier than I thought. Instead of using
jmp instruction, I can just use
push instruction to push the address of
bang() to the stack and then execute a
ret instruction to let it naturally jump to
bang(). Also, insdead of writing the hex version of the injected code, I can just write it in assembly and use
gcc to compile it into obj code. This makes things a lot easier.
Here is the assembly code for code injection on the stack later:
After assembling them into obj code using
gcc -m32 -c <asm file> and disassemble it using
objdump -d <obj file>:
I can just directly use the hex values in the disassembled file in the buffer to inject the code on the stack. I put the code right after the memory slot where the return address of
getbuf was stored.
e8 3c 68 55 is the address of the injected code (0x55683ce8). At that address, there is the hex version of the code modifying the value of
global_value (the last 16 bytes in the buffer shown above).
Now if I run the bomb in gdb:
Right after copying the input to the buffer, the memory around the stack look like this:
The return address is now overwritten to 0x55683ce8, which is the starting point of my injected code. After "return" to the injected code,
The instructions that I injected are decoded correctly, good.
After executing these few lines of instructions, I checked the value of
global_value to see if it is actually changed:
It is now set to the value of my cookie.
Stepping to the next instruction, I checked the return address to see if it was changed by pushing the value to the stack:
saved eip is now set to the address of
bang(). Now I just need it to
Level 2 solved.