Skip to content

Entry Methods

After defining metadata and options, implement the entry method that the framework calls. Its name depends on the module type.

TypeEntry pointWhen it is called
exploitexploitrun / exploit command
exploit / some auxiliarycheckcheck command or AutoCheck
auxiliary (ordinary)runrun
auxiliary + Scannerrun_host(ip)Once per host (run is provided by the mixin)
auxiliary + Scanner checkcheck_host(ip)Check for each host
postrunrun (requires SESSION)

This method only determines whether a target is vulnerable and does not send a payload (or uses only minimal proof). It returns CheckCode::*. Return a CheckCode rather than using fail_with.

CheckCodeMeaning
UnknownInsufficient information (for example, a timeout)
SafeNot vulnerable / not applicable
DetectedService found, but vulnerability status unknown
AppearsPassive evidence, such as a version, suggests vulnerability
VulnerableBehavior confirms vulnerability
UnsupportedCheck is unsupported
def check
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'index.php')
)
return CheckCode::Unknown('no response') if res.nil?
return CheckCode::Safe('not ExampleApp') unless res.body.include?('ExampleApp')
if res.body =~ /Version: 1\.[0-2]/
return CheckCode::Appears('ExampleApp 1.0-1.2 detected')
end
CheckCode::Detected('ExampleApp found, version unknown')
end

For Scanner modules, use:

def check_host(ip)
# Check each ip
CheckCode::Safe
end

Prefer vprint_* for messages, and avoid asserting “Vulnerable” yourself without enough evidence. The framework displays the CheckCode.

This is the body of an exploit. A common flow is connect → exploit the vulnerability → deliver the payload → call handler if needed.

def exploit
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'ping'),
'vars_post' => { 'ip' => "127.0.0.1;#{payload.encoded}" }
)
fail_with(Failure::Unreachable, 'no response') if res.nil?
end

When using CmdStager:

def execute_command(cmd, _opts = {})
send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'ping'),
'vars_get' => { 'ip' => "127.0.0.1;#{cmd}" }
)
end
def exploit
if target['Arch'] == ARCH_CMD
execute_command(payload.encoded)
else
execute_cmdstager(linemax: 1500)
end
end

In the TCP template (example.rb), the flow is connect → sock.put → handler.

Use fail_with(Failure::..., message) on failure. See Response Handling and fail_with for the constants.

def run
print_status("Running against #{peer}")
# Process
print_good('Done')
end

In a post module, session is available.

def run
print_status(cmd_exec('id'))
end
def run_host(ip)
res = send_request_cgi('method' => 'GET', 'uri' => '/')
return if res.nil?
print_good("#{ip}:#{rport} #{res.code}")
report_service(host: ip, port: rport, name: 'http', info: res.headers['Server'])
end

Do not define run yourself and override Scanner’s behavior. Keep host-specific state in local variables.

With prepend Msf::Exploit::Remote::AutoCheck, check runs automatically before exploit / run. See AutoCheck for details.

MethodPurpose
print_statusOrdinary progress [*]
print_goodSuccess [+]
print_errorError [-]
print_warningWarning
vprint_*Only when VERBOSE true

Next is Saving Results.