I did the orw challange on pwnable.tw yesterday. It is very streight forward. You just have to send some x86 shellcode to stdin and the orw binary will execute it.
But I spend a few hours with getting this to work with gdb as the instructions in gdb were quite weird.
So it just writes the shellcode to
0x804a060 and jumps to the address using
I’m using pwntools to write my exploits as a lot of other people are doing.
The important part is the gdb script:
Alright so we are setting 2 breakpoints when the programm starts. These are probably software
breakpoints as internal documents of GDB state. These write an
INT instruction to the specified instruction:
“Since it literally overwrites the program being tested, the program area must be writable, so this technique won’t work on programs in ROM. It can also distort the behavior of programs that examine themselves, although such a situation would be highly unusual.”
So yes it can distort the behavior and in this example it did! So lets see what we can find at the
0x804a060 when reaching the second first or second breakpoint:
As you can see it seems like only 3 bytes got copied. The first byte is
This is because gdb wrote
0x90 (INT) to the address when the breakpoint was set.
After reaching the 1. breakpoing it wrote
0x90 again to make sure that the programm will stop at
the 2. breakpoint.
After reaching the 2. breakpoint it restored the byte to
0x00 because when the breakpoints were set it actually was.
So this is why gdb fucks our shellcode up! It restored the value where the
INT was to the wrong
You may notice that the following script will not corrupt the instructions:
This works because the code gets rewritten between setting the breakpoints and reaching it. So the breakpoint here will not work but also cause no problem.
The solution is to set the breakpoint at
0x804a060 after the shellcode was copied!
The other solution is to use hardware breakpoints which do not modify the code the CPU will execute! Note that there are only a limited amount of them!
Reason of confusion
The reson why I was so confused is that gdb never showed my the
INT instructions. So I did not
think that gdb would restore values to outdated values!
Even if you look at the assembler code in gdb it will not show it you
(Debugger flow control: Hardware breakpoints vs software breakpoints):
“Now, you might be tempted to say that this isn’t really how software breakpoints work, if you have ever tried to disassemble or dump the raw opcode bytes of anything that you have set a breakpoint on, because if you do that, you’ll not see an int 3 anywhere where you set a breakpoint. This is actually because the debugger tells a lie to you about the contents of memory where software breakpoints are involved; any access to that memory (through the debugger) behaves as if the original opcode byte that the debugger saved away was still there.”
Never set software breakpoints at addresses you are writing executable code to!