Fulcrum

Gaining Access

Nmap scan:

$ nmap -p- --min-rate 3000 10.129.136.254                
Starting Nmap 7.93 ( https://nmap.org ) at 2024-03-05 04:59 EST
Warning: 10.129.136.254 giving up on port because retransmission cap hit (10).
Nmap scan report for 10.129.136.254
Host is up (0.059s latency).
Not shown: 65173 closed tcp ports (conn-refused), 356 filtered tcp ports (no-response)
PORT      STATE SERVICE
4/tcp     open  unknown
22/tcp    open  ssh
80/tcp    open  http
88/tcp    open  kerberos-sec
9999/tcp  open  abyss
56423/tcp open  unknown

Port 4 was open, which was new.

Detailed scan:

$ nmap -p 4,80,88,9999,56423 -sC -sV --min-rate 3000 10.129.136.254 
Starting Nmap 7.93 ( https://nmap.org ) at 2024-03-05 05:01 EST
Nmap scan report for 10.129.136.254
Host is up (0.031s latency).

PORT      STATE SERVICE VERSION
4/tcp     open  http    nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
80/tcp    open  http    nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: 502 Bad Gateway
88/tcp    open  http    nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
| http-robots.txt: 1 disallowed entry 
|_/
|_http-title: phpMyAdmin
9999/tcp  open  http    nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: 502 Bad Gateway
56423/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-server-header: Fulcrum-API Beta
|_http-title: Site doesn't have a title (application/json;charset=utf-8).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kerne

Port 80 and 9999 had bad gateways, so I was left with port 4, port 88 and port 56423.

Web Enum -> XXE LFI

Port 4 had a really basic page:

The link was to http://10.129.136.254:4/index.php?page=home, which looked vulnerable for LFI.

However, the page was not returning anything at all, not even an error message. SSRF didn't work as well, so this isn't RFI.

Running a gobuster scan with the .php extension returned 3 results:

upload.php returned nothing. Moving on!

Port 88 had a phpMyAdmin login:

I had no credentials, and default credentials didn't work. Moving on!

Port 56423 was more interesting:

Based on nmap, this was an API. I started enumerating any other endpoints possible. This whole API was custom, since there weren't wasn't anything I could find.

As such, I resorted to just playing around with it, sending POST requests with random variables to see what it would load.

Sending regular parameters did not work, and sending JSON did nothing either. I couldn't find out what to do, so I referred to a writeup (too guessy).

Saw that I had to use <Heartbeat><Ping>Pong</Ping></Heartbeat> to trigger a different response:

From here, XXE should be the path forward. This seems to be a blind injection since this thing shows nothing but PingPong.

Using this payload triggers a callback on my machine:

Since this is blind XXE with SSRF, I can try to exfiltrate data out. I used the OOB with DTD and PHP filter method method from PayloadAllTheThings.

This involved me creating this dtd.xml file:

Afterwards, the payload to send to the website is:

Basically, this makes the website retrieve an external DTD, which loads the filename I want, and then sends it to another port:

This can be scripted using some Python sockets and requests.

Firstly, create the file dtd.xml with the filename I want to read. Afterwards, use a thread to open a port 8000 and listen for connections indefinitely.

Then, just retrieve the output from the socket, parsed using regex and decoded from base64. This took a bit longer to code than I would like, but it felt great making it work with sockets.

There's a short delay in-between files, but otherwise it works. Just start a Python HTTP server in another terminal, and there will be GET requests sent to that server.

File Enum -> Port 4 LFI

For this, nmap stated that this was an nginx server, so I took a look at those files. However, reading /etc/nginx/sites-available/default took too long.

A lucky guess gave me /var/www/api/index.php as a readable file:

RCE -> Webserver

Now that I had a working LFI script, I wanted to view the service on port 4. Guessing led me to /var/www/uploads/index.php.

It only allows requests from localhost to use include. Conveniently, XXE + SSRF was used to get here, so RCE is easy since include executes PHP code and allows for the http:// wrapper.

The exploit path is:

  1. Use XXE SSRF to visit port 4.

  2. Set page to a malicious PHP file hosted on my machine.

Here's the exploit script:

I included a zero-click exploit script at the end!

WebServer -> File

Surprising to see AD here.

Powershell Creds -> WebUser Pivot

First thing I noticed was this .ps1 file in the folder the shell spawned in:

Here are the contents:

This is a Powershell credential, and it can be decoded. This looked like Active Directory, and that there were other machines present. A quick check on ip route confirms this.

A quick ping sweep reveals there was only one other machine accessible:

I decoded this credential using pwsh. All you have to do is just run the entire script from $1 to $5:

Then, use $5.GetNetworkCredential().password:

I used chisel and proxychains to start pivoting:

From here, I downloaded the nmap binary to scan the ports on that one machine that is reachable, just to see what protocol is to be used with the credentials.

evil-winrm with proxychains is the next step since port 5985 is open.

Can use proxychains -q to remove those debug messages if you desire.

AD Enum -> BTables Creds

This user had no particularly interesting permissions, or files in their directory.

Within the C:\inetpub\wwwroot folder, there were some IIS files:

web.config had some interesting stuff:

There's a password here for LDAP here. There was also mention of dc.fulcrum.local. The current machine I was on was called webserver (based on hostname output).

Anyways, I relied on PowerView.ps1 to enumerate the domain. When I first tested it, all commands failed with this error:

Perhaps I needed to use the credentials from earlier to query LDAP:

This solved the error earlier, and I could view the users present:

923a was a domain admin, and BTables was another user. Using Get-DomainUsershows credentials for BTables:

++FileServerLogon12345++ was the password. However, this user was not present on my current machine.

Network Enum -> Pivot to File

I enumerated all computer objects within this network, which revealed 2 more.

I used ping to see their IPs:

I used chisel.exe to forward port 5985 from FILE, since the password was kinda obvious in telling me the next step.

Then, I could evil-winrm in and finally grab the user flag:

File -> DC

Enumeration -> Shares

This FILE server was empty. Most of the file system was just default Windows. As such, I tried to use the credentials I had to access the shares on the DC, which was something the CRTE lab taught me to do.

These were default shares, but honestly there was nothing else to look at anymore, so I went for it.

Shares Enum -> Admin Creds

The sysvol share had a ton of .ps1 files:

I read one of them, and noticed the user:

Using this, I can try to find 923a, which was a valid domain admin.

Great! Now, I had valid credentials. Using this, I can read the flag:

To get a shell, I did the following:

Then, I can evil-winrm in as the 923a user:

Fun box!

Noclick Scripts

Just made this for fun.

Initial RCE

The same can be done for the LFI.

Last updated