Forgotten Implant
With almost no attack surface, you must use a forgotten C2 implant to get initial access. - by IngoKleiber
Last updated
With almost no attack surface, you must use a forgotten C2 implant to get initial access. - by IngoKleiber
Last updated
Scanning our target using Nmap we are not able to discover any open ports. Like the subtitle and room description state, the initial attack surface is quite limited, and we need to find a way to communicate with a forgotten C2 implant.
The victim does not provide a service directly through an open port through the C2 implant. Therefore the implant might to communicate directly with the C2 server, so the C2 server must have opened ports. Maybe it is possible to monitor the traffic on the network. For this, we use Wireshark.
The room icon indicates a hint that while scanning, there might be HTTP requests.
So we hit up Wireshark on tun0
while scanning the target. During the scan, we had a lot of noise from it, but eventually we saw at the end of the scan that the target was trying to connect to us on port 81.
For confirmation, we set up a listener on port 81 to see what is incoming. We receive a GET request for the web page /hearbeat/eyJ0aW1lIjogIjIwMjMtMDctMzBUMTE6NDA6MDIuMjE1NTIwIiwgInN5c3RlbWluZm8iOiB7Im9zIjogIkxpbnV4IiwgImhvc3RuYW1lIjogImZvcmdvdHRlbmltcGxhbnQifSwgImxhdGVzdF9qb2IiOiB7ImpvYl9pZCI6IDAsICJjbWQiOiAid2hvYW1pIn0sICJzdWNjZXNzIjogZmFsc2V9
.
The requested page seems like information encoded as base64 that the C2 implant tries to communicate to its server. Decoding it reveals the following:
We see the system information about the victim and the last executed job, the command whoami
, wrapped in JSON.
The heartbeat request reminds us of the following communication structure:
Perhaps there are also commands and results requested. For this, we set up a simple HTTP server using Python and looked at what happened.
And as suspected, a request for a command was made with /get-job/ImxhdGVzdCI=
which just translates to /get-job/"latest"
.
So, we should be able to provide the C2 implant with commands by providing the page /get-job/ImxhdGVzdCI=
on port 81 on our attacker machine. To test this, we plant an empty file in the given location and see if we get any results.
With the provided empty file, we get an error message as a result. There is a JSON error, so the implant expects the job to be formatted in JSON.
/job-result/eyJzdWNjZXNzIjogZmFsc2UsICJyZXN1bHQiOiAiSlNPTiBlcnJvciJ9
translates to {"success": false, "result": "JSON error"}
.
Thus we have to wrap the command in JSON. We remember, we already got a hint about the structure in the heartbeat.
{"time": "2023-07-30T11:40:02.215520", "systeminfo": {"os": "Linux", "hostname": "forgottenimplant"}, "latest_job": {"job_id": 0, "cmd": "whoami"}, "success": false}
Therefore, this might be the structure: {"job_id": 0, "cmd": "whoami"}
With that in mind we craft the job {"job_id": 1, "cmd": "id"}
and place it into the file ImxhdGVzdCI=
.
With the provided command, we get the following response /job-result/eyJzdWNjZXNzIjogZmFsc2UsICJyZXN1bHQiOiAiRW5jb2RpbmcgZXJyb3IifQ==
which translates to an encoding error {"success": false, "result": "Encoding error"}
. Maybe the content of the file has also to be encoded in base64. Next, we edit the job file again, encoding the JSON into base64.
The job-result response looks different again. It actually contains the result of our provided job:
/job-result/eyJqb2JfaWQiOiAxLCAiY21kIjogImlkIiwgInN1Y2Nlc3MiOiB0cnVlLCAicmVzdWx0IjogInVpZD0xMDAxKGFkYSkgZ2lkPTEwMDEoYWRhKSBncm91cHM9MTAwMShhZGEpXG4ifQ==
{"job_id": 1, "cmd": "id", "success": true, "result": "uid=1001(ada) gid=1001(ada) groups=1001(ada)\n"}
With our provided job file we are able to execute any commands we want to.
Now that we know that our job page works, we edit it slightly and place a nc mkfifo reverse shell instead.
Next, we set up a listener and start our Python web server again. We catch the reverse shell and are now the user ada on the target machine.
For a more convenient navigation we upgrade the shell.
In the home directory of ada we find the first user flag.
The first thing that stood out immediately was the python script products.py
, which just fetches the items from the table products of the MySQL database called app and displays them. In the script are also stored the credentials to access the database.
We are using the MySQL command line to fetch further information from the database, but we are not able to find anything of interest.
During the enumeration, a second user fi
was found, which ran a network sniffer to provide the C2 implant with hosts on the network to be able to reach us. At this point, it again seems like a machine without any attack surface. Even with LinPEAS nothing was found. But the description states that it is a straightforward CTF challenge. So the products.py
script might be there for a reason, placed as a little hint.
So, the mysql database is hosted locally. Maybe there are more services running on localhost. To check out further open ports on localhost a static version of Nmap is used provided by andrew-d.
Next, download and place the static Nmap binary in the root folder of our Python web server to provide the target machine with our tools.
Using wget we are able to retrieve the static Nmap binary from our already-running Python web server on port 81. Running Nmap we see that not only MySQL is running on the machine but also a web server on port 80.
With cURL, let's take a closer look. It is a phpMyAdmin web page.
For further investigation, we made use of a static socat binary, also provided by andew-d. With that, we are able to forward port 80 to 8080, which is then reachable by our attacker machine.
Lets move the binary to our web root folder.
And receive the binary using wget. Running ./socat TCP4-LISTEN:8080,fork TCP4:127.0.0.1:80
we are able to forward the port.
Now, we are able to reach the web page on Port 8080 with our attacker machine. We are prompted with the phpMyAdmin login page. To log in, we reuse the credentials found in the products.py
script.
And we are able to login with the reused credentials. On the page itself we see that the Version 4.8.1
of phpMyAdmin is running.
Through a little research, we found out that version 4.8.1
of phpMyAdmin is vulnerable and that scripts for remote code execution already exist. The script on exploit.db unfortunately did not run directly on the provided attack box, so now we continue with metasploit since a script for this exploit is also available there.
Running the search command on msfconsole we are able to find a suitable exploit for version 4.8.1.
being able to remotely execute code.
With use 0
we directly use the found module with the index 0.
Next, we list all possible options with the command options
and set all necessary parameters.
Using run
to execute the exploit and shell
to spawn a shell after getting a session we are now on the target machine as the user www-data
. At first glance a downgrade.
But on enumeration, we see that we are able to execute PHP with root permission without providing sudo with a password.
A quick visit to GTFOBins shows us how to escalate our privileges using php with sudo permissions.
With the command sudo /usr/bin/php -r "system('/bin/sh');"
we are able to spawn a shell with root permissions and are now able to retrieve the root flag in /root
.