Skip to content

Responses and fail_with

How to handle HTTP responses and report failures with fail_with. Failure constants are defined in lib/msf/core/module/failure.rb.

res = send_request_cgi(...)
fail_with(Failure::Unreachable, "#{peer} - no response") if res.nil?
code = res.code
body = res.body
headers = res.headers
server = res.headers['Server']
cookies = res.get_cookies
location = res.redirection if res.redirect?

A common pattern is to use CheckCode::* in check and fail_with in exploit or run.

def check
res = send_request_cgi('method' => 'GET', 'uri' => normalize_uri(target_uri.path))
return CheckCode::Unknown('no response') if res.nil?
return CheckCode::Safe('not ExampleApp') unless res.body.include?('ExampleApp')
return CheckCode::Appears('ExampleApp detected')
end
ConstantWhen to use it
Failure::BadConfigMissing or conflicting options
Failure::UnreachableCannot connect, or res.nil?
Failure::DisconnectedDisconnected mid-operation
Failure::NoAccessAuthentication failed or permissions are insufficient
Failure::NotFoundPath or file does not exist
Failure::NotVulnerableTarget is known not to be vulnerable
Failure::NoTargetSelected target does not match
Failure::UnexpectedReplyUnexpected response code or body
Failure::TimeoutExpiredTimed out
Failure::PayloadFailedPayload sent but no session opened
Failure::UnknownCannot determine the cause
Failure::UserInterruptUser interrupted the operation
fail_with(Failure::NoAccess, "login failed: HTTP #{res.code}") unless res.code == 302
fail_with(Failure::UnexpectedReply, 'token missing') if token.blank?
fail_with(Failure::BadConfig, 'PASSWORD is required') if datastore['PASSWORD'].blank?
%r{Version: (?<version>\d+\.\d+)} =~ res.body
if version && Rex::Version.new(version) <= Rex::Version.new('1.3')
return CheckCode::Appears("Version #{version}")
end
json = res.get_json_document rescue nil
fail_with(Failure::UnexpectedReply, 'invalid json') unless json.is_a?(Hash)

For basic HTML stripping, use strip_tags(html).