Skip to content

Auxiliary

Auxiliary modules do not execute payloads. They cover enumeration, login attempts, configuration changes, DoS, and listening servers. References are packages/metasploit-framework/modules/auxiliary/ and the bundled wiki How-to-get-started-with-writing-an-auxiliary-module.md.

The shared process is in Common Steps. This page covers auxiliary-specific types, usage examples, and modules that serve as writing references.

ConditionType
Open a payload sessionexploit
Only collect information, verify credentials, or perform administrative actionsauxiliary
Can run OS commands but does not yet deliver a payloadauxiliary for now; it can become an exploit later
DirectoryPurpose
scanner/Multi-host scanning with Msf::Auxiliary::Scanner
gather/Information collection from a single target
admin/Administrative actions such as changing settings or creating accounts
dos/DoS
fuzzers/fuzzer
server/Listening server
sniffer/sniffer
Reference moduleWhat it teaches
auxiliary/exampleActions / PassiveActions / minimal run
auxiliary/scanner/http/http_versionShort example of HttpClient + Scanner + report_service
auxiliary/scanner/http/titleAnother HTTP scanning example
auxiliary/scanner/ssh/ssh_loginAuthBrute + SSH + credential storage + session creation
auxiliary/scanner/smb/smb_versionSMB mixin + Scanner + fingerprinting
auxiliary/scanner/smb/smb_loginSMB login attempts
auxiliary/scanner/smb/smb_enumsharesEnumeration after authentication
auxiliary/scanner/winrm/winrm_loginWinRM login / CreateSession
auxiliary/admin/dcerpc/icpr_certExample of an admin-specific mixin (MsIcpr)
auxiliary/scanner/mssql/mssql_loginDatabase login scanner
auxiliary/server/socks_proxyHow to use a server module (listener)

Even among scanner and gather modules, the structure varies with storage, authentication, and request format.

class MetasploitModule < Msf::Auxiliary
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Sample Auxiliary Module',
'Author' => ['you'],
'License' => MSF_LICENSE,
'Actions' => [
['List', { 'Description' => 'Enumerate' }],
['Dump', { 'Description' => 'Dump config' }]
],
'DefaultAction' => 'List'
)
)
end
def run
case action.name
when 'List' then do_list
when 'Dump' then do_dump
end
end
end

1b. Gather with only one Action (qnap_lfi family)

Section titled “1b. Gather with only one Action (qnap_lfi family)”
'Actions' => [
['Download', { 'Description' => 'Download FILEPATH' }]
],
'DefaultAction' => 'Download'
def run
# Read FILEPATH and call store_loot / create_credential
end

2a. Fingerprint + report_service (http_version)

Section titled “2a. Fingerprint + report_service (http_version)”
def run_host(ip)
connect
res = send_request_raw('uri' => '/', 'method' => 'GET')
fp = http_fingerprint(response: res)
print_good("#{ip}:#{rport} #{fp}") if fp
report_service(host: rhost, port: rport, name: (ssl ? 'https' : 'http'), info: fp)
ensure
disconnect
end

2b. Get title + notes + follow redirects (title family)

Section titled “2b. Get title + notes + follow redirects (title family)”
def run_host(target_host)
http_opts = {
'uri' => normalize_uri(target_uri.path),
'method' => 'GET',
'query' => datastore['HttpQueryString']
}
res = if datastore['FollowRedirect']
send_request_cgi!(http_opts, datastore['HttpClientTimeout'] || 20, datastore['FollowRedirectDepth'])
else
send_request_cgi(http_opts)
end
return if res.nil?
title = res.body[/<title>(?<t>[^<]+)/i, :t]
print_good("#{target_host} [#{title}]") if datastore['SHOW_TITLES'] && title
report_note(host: target_host, port: rport, type: 'http.title', data: { title: title }, update: :unique_data) if datastore['STORE_NOTES']
end

2c. Lightweight scanner that only checks path existence

Section titled “2c. Lightweight scanner that only checks path existence”
def run_host(ip)
%w[/admin /login /api/v1].each do |path|
res = send_request_cgi('method' => 'GET', 'uri' => path)
next unless res && res.code == 200
print_good("#{ip}#{path} => #{res.code}")
report_note(host: ip, type: 'http.path', data: { path: path, code: res.code }, update: :unique_data)
end
end
include Msf::Auxiliary::AuthBrute
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::SSH::Options
def run_host(ip)
cred_collection = build_credential_collection(
username: datastore['USERNAME'],
password: datastore['PASSWORD']
)
# LoginScanner::SSH#scan! → create_credential_and_login / CreateSession
end

AuthBrute + SMB Client. Some examples call create_credential and create_credential_login separately on success.

def report_creds(ip, port, result)
report_service(host: ip, port: port, name: 'smb', proto: 'tcp')
credential_core = create_credential(result.to_h.merge(
workspace_id: myworkspace_id,
module_fullname: fullname
))
create_credential_login(
core: credential_core,
status: Metasploit::Model::Login::Status::SUCCESSFUL,
address: ip,
port: port,
protocol: 'tcp',
service_name: 'smb'
)
end

3c. Check one credential only (no wordlist)

Section titled “3c. Check one credential only (no wordlist)”
def run_host(ip)
# Only USERNAME/PASSWORD; do not use USER_FILE
ok = try_login(ip, datastore['USERNAME'], datastore['PASSWORD'])
if ok
create_credential_and_login(...)
print_good("#{ip} login ok")
else
invalidate_login(...)
end
end
def run
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'login.php'),
'keep_cookies' => true,
'vars_post' => {
'username' => datastore['USERNAME'],
'password' => datastore['PASSWORD']
}
)
fail_with(Failure::NoAccess, "login failed: #{res&.code}") unless res && res.code == 302
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'config.php')
)
path = store_loot('example.config', 'text/plain', rhost, res.body, 'config.php')
print_good("Loot: #{path}")
end

4b. Unauthenticated LFI / arbitrary file read (qnap_lfi family)

Section titled “4b. Unauthenticated LFI / arbitrary file read (qnap_lfi family)”
def run
traversal = '../' * datastore['DEPTH']
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'cgi-bin', 'read'),
'vars_get' => { 'file' => traversal + datastore['FILEPATH'] }
)
fail_with(Failure::UnexpectedReply, 'read failed') unless res && res.code == 200
print_line(res.body) if datastore['PRINT']
store_loot('qnap.file', 'text/plain', rhost, res.body, File.basename(datastore['FILEPATH']))
# For /etc/shadow, consider create_credential too
end

4c. Fetch a page with Basic authentication

Section titled “4c. Fetch a page with Basic authentication”
def run
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'secret'),
'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD'])
)
fail_with(Failure::NoAccess, 'auth failed') unless res && res.code == 200
store_loot('example.secret', 'text/html', rhost, res.body)
end

4d. Identify the device in check before gathering

Section titled “4d. Identify the device in check before gathering”
def check
res = send_request_cgi('method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'cgi-bin', 'authLogin.cgi'))
return CheckCode::Safe unless res && res.code == 200
CheckCode::Appears('QNAP-like device')
end
def run
fail_with(Failure::NotVulnerable, 'not target') unless check == CheckCode::Appears
# Collection logic
end
include Msf::Exploit::Remote::Tcp
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
def run_host(ip)
connect
banner = sock.get_once(1024, 5).to_s
print_good("#{ip}:#{rport} #{banner.strip}") unless banner.empty?
report_service(host: ip, port: rport, name: 'unknown', info: banner.strip)
ensure
disconnect
end
include Msf::Exploit::Remote::SMB::Client
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
def run_host(ip)
connect
# Dialect negotiation / OS information
report_service(host: ip, port: rport, name: 'smb', info: info_string)
ensure
disconnect
end

Users start the listener with run -j. To write one yourself, use TcpServer or a dedicated mixin and consider PassiveActions.

include Msf::Exploit::Remote::HttpServer
def run
# Let the parent handle the equivalent of start_service / similar to on_request_uri in exploit modules
end
def on_request_uri(cli, request)
print_status("#{cli.peerhost} #{request.method} #{request.uri}")
store_loot('http.capture', 'text/plain', cli.peerhost, request.to_s)
send_response(cli, 'ok')
end
use auxiliary/scanner/http/http_version
set RHOSTS 10.10.11.0/24
set THREADS 10
set RPORT 80
run
services -p 80

For HTTPS:

set RPORT 443
set SSL true
run
use auxiliary/scanner/ssh/ssh_login
set RHOSTS 10.10.11.123
set USERNAME svc-user
set PASSWORD '...'
set STOP_ON_SUCCESS true
set CreateSession true
run
sessions -l
creds

With a wordlist:

unset PASSWORD
set PASS_FILE /usr/share/wordlists/rockyou.txt
set BRUTEFORCE_SPEED 3
run
use auxiliary/scanner/smb/smb_version
set RHOSTS 10.10.11.123
run
use auxiliary/scanner/smb/smb_enumshares
set RHOSTS 10.10.11.123
set SMBUser user
set SMBPass '...'
set SMBDomain .
run
use auxiliary/scanner/winrm/winrm_login
set RHOSTS 10.10.11.123
set USERNAME svc
set PASSWORD '...'
set DOMAIN .
set RPORT 5985
set CreateSession true
run
sessions -l
use auxiliary/server/socks_proxy
set SRVHOST 127.0.0.1
set SRVPORT 1080
run -j
jobs -l
~/.msf4/modules/auxiliary/scanner/http/my_banner.rb
reload_lib -a
use auxiliary/scanner/http/my_banner
set RHOSTS 10.10.11.123
run
TypeBase + mixinsEntry pointReference
One-off gatherAuxiliary + HttpClient + ReportrunLogin dump above
Multi-host scanner+ Scannerrun_hosthttp_version
Wordlist login+ AuthBrute (+ Scanner)run_hostssh_login
TCP / SMB banner+ Tcp / SMB + Scannerrun_hostsmb_version
Listening server+ HttpServer, etc.run / PassiveActionssocks_proxy
  1. Choose a Module Type and Location → auxiliary/<category>/...
  2. Base Classes and Mixins
  3. update_info
  4. register_options
  5. Entry Methods → run / run_host
  6. Saving Results
  7. Cleanup
  • For Scanner, implement run_host. Do not define run a second time.
  • Do not register RHOSTS / THREADS again if a mixin provides them.
  • Always check res.nil?.
  • Keep gather and admin in separate modules.
  • When you need to open a session, move to Exploit.