Wow, this challenge was a tough one for me. I ran into some huge problems that I had to work out. Considering this is a “standard buffer overflow”, I figured it’d be as easy as some of the others I’ve done in the past. I’ll explain my frustrations inline.
First, we’re given the following vulnerable program.
1 2 3 4 5 6 7 8 9 10 11
The first task with this challenge was to find the offset of the EIP. Like previous challenges, I used Metasploit’s pattern_create.rb and pattern_offset scripts on another machine.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Now we know that we have 76 characters we could put our shellcode in before the EIP. I was curious to see if we would have any after as well. I wanted to explore a little, so I ran this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Interestingly enough, it looks like we at least have 100 characters after our return address that we could use to store longer shellcodes. This could come in handy if using shellcodes generated from msfpayload.
So now we know that we can jump to 0xbffff7e0 to get into our C area. Let’s pad it with a couple NOPs just in case, and jump to 0xbffff7d6 instead.
Up until now, this was a simple buffer overflow problem. One may even call it a textbook problem. Now here’s the part that had me frustrated.
I decided I would try using msfpayload to generate some shellcode like I’ve done many times in the past. Since I just want to run /bin/sh, I figured it’d be an easy way. I also went through the exercise of finding all the badchars (I’ll cover this later, since it doesn’t matter here).
1 2 3 4 5 6 7 8 9 10
This generated shellcode looked awesome. I configured it to not have any of my badchars, to run “/bin/sh”, and to prepend that execution with a setresuid() so that the SUID bit would affect my result, giving me a root shell, instead of just a shell I already had. So I set it all up:
1 2 3
So um, I should have got a shell there right? There was no segmentation fault, it ran cleanly. I tinkered by putting “\xcc” before the shellcode, and it would give me a message letting me know that it hit it. I knew for sure my shellcode was being executed, but no results. To verify, I used gdb:
1 2 3 4 5 6 7
What this showed me was 2 interesting things. Firstly, I was not aware that many distributions now map /bin/sh to /bin/dash (more info here). Secondly, and more importantly, I knew for sure that my shellcode was executing, and creating the process. I just didn’t know why it exited after.
So this is the point that I spent 5 days on and off messing with. I found if I changed the msfvenom command from CMD=“/bin/sh” to CMD=“touch /tmp/iamawesome”, the file would be created with root permissions. Any command that didn’t need to return to me for interactive control worked fine. I tried a myriad of other shellcodes, and nothing just gave me a simple shell. I could bind a shell to a TCP port, or run a meterpreter with no problem, but for this challenge, I just wanted a simple rootshell from “execve()”.
So one night, I was reading on this, and just happened to get my search query perfect, because I stumbled upon an interesting stackoverflow page, here. This guy was having the same problem as me! And interestingly enough, he mentions problems with programs that use the “gets()” function. This makes sense, as your standard input/output could be configured in a mode just for the function call. Unfortunately, the shellcode that was mentioned was hosted at milw0rm, which has been down for a good long time. Many sites, such as Exploit-Db have popped up to fill the void that milw0rm left. However, they use a completely different url structure, so I had no idea what the shellcode was. Well, I used the Internet Way-Back Machine, and found an old cache of milw0rm. From there, I found the shellcode. I also found that Exploit-Db has it here as well. I read through the description of the shellcode, and it makes tons of sense. So I wire it up to try again, this time with the new shellcode.
1 2 3 4 5 6
Awesome. I have a root shell. I guess it’s also worth pointing out that since we are specifically jumping to a memory address in our exploit, that memory addresses can change based on how you call it. The address will be different if I call ./stack5 from inside the /opt/protostar/bin folder, than if I use the full path. Since I was using gdb, and it calls files using the full path, I did it as well for the exploit. For now, we have not yet covered how to dynamically get that value. That will be for a later post.