The Module That Never Appeared and the Scan That Never Persisted
A junior consultant joins a five-person offensive security team and is handed a Kali workstation plus access to the team's shared msfconsole workflow. They drop a custom exploit module at /usr/share/metasploit-framework/modules/exploits/windows/http/acme_upload.rb, start the console, and search acme returns nothing. Separately, they run db_nmap -sS 10.20.30.0/24, watch 61 hosts scroll past, then close the console; on reopening, hosts is empty, although a colleague's earlier scan of the same range still lists 58 hosts in a workspace called q3-retail. The console also takes roughly 90 seconds to warm up after reload_all, and a background exploit job from an earlier attempt keeps interleaving output while the junior types. The team lead wants the framework's moving parts explained before the junior touches the client's production VLAN tonight.
1. Why is the custom module invisible, and what is the correct location and procedure for adding it?
Read the worked answer
Three explanations must be separated, in order of likelihood.
1. Wrong search-path priority. Metasploit's search walks the configured module paths at startup, and the user directory (~/.msf4/modules/) is consulted before the framework install directory. Both work, but files under /usr/share/metasploit-framework/ are overwritten or removed on the next package upgrade, so a custom module belongs in ~/.msf4/modules/ with the identical directory tree.
2. The file is not a valid, loadable module. The filename maps directly to the module name (exploits/windows/http/acme_upload.rb becomes exploit/windows/http/acme_upload). A syntax error, a missing MetasploitModule class, or a wrong Rank/Platform block causes the file to be skipped silently - no error is shown by search. Verify with ruby -c acme_upload.rb and load it explicitly with loadpath to see the parser error.
3. No reload since the file was created. Modules are loaded at console start or on reload_all. Because reload_all already costs 90 seconds against a large module tree plus the database, the practical sequence is: fix the file, run reload_all once, then search acme and show exploits to confirm.
A module that still fails to appear after loadpath reports success usually has an incompatible API mixin - worth ruling out before blaming the framework.
2. Why is `hosts` empty after reopening the console while a colleague's results persist, and what would you check?
Read the worked answer
Metasploit does not store scan results in the console; it stores them in the PostgreSQL database behind the workspace layer. Two things follow from the symptom.
Check the database connection first. db_status should report a live connection to the backend. If it does not, commands still execute - db_nmap shells out to nmap and prints results - but nothing is committed. The junior then treats console scrollback as the record, which is exactly the failure mode described. msfdb status (and msfdb init if the backend was never created) resolves this on a workstation.
Check the workspace second. The colleague's 58 hosts are in q3-retail; the junior is almost certainly sitting in the default default workspace, and hosts in a workspace only lists that workspace's data. workspace lists all workspaces, workspace q3-retail switches, and hosts -a shows everything the current workspace knows. The junior's 61 hosts may exist and be invisible.
If both are correct and data is genuinely lost, the recoverable path is to have db_nmap -oX output (or run nmap with -oX) and then db_import the XML - import merges by address rather than duplicating. Going forward: verify db_status before every engagement, name workspaces per client and date, and spool console output so evidence is not dependent on scrollback.
3. Distinguish jobs, sessions, and workspaces, and describe how the junior should manage the noisy background job.
Read the worked answer
The three are independent objects and confusing them is a common source of lost work.
- Workspace - a database partition. It scopes hosts, services, credentials, loot, and notes. It does not scope modules or sessions.
- Job - a module instance running in the background (
run -j,exploit -j). It consumes a handler slot or a scan thread and writes to the data store.jobs -llists them,jobs -k <id>kills one;reload_alldoes not clear them. - Session - an interactive channel from a successful exploit (shell, Meterpreter).
sessions -llists,sessions -i <id>interacts,sessions -kcloses.
Mechanically, a background job that keeps printing while you type is not a bug: module output goes to the console regardless of foreground activity. The clean fix is to list the jobs, decide which are still contributing, kill the rest, and start new work with run -j plus a resource script so configuration is reproducible.
Operational discipline: before a new scan or exploit wave, jobs -l to find orphaned handlers from earlier attempts; after the engagement, kill every job and close every session, because an open session is a live foothold on a client system and a session left open past the test window is a reportable incident. Record job/session IDs in notes so the cleanup evidence is complete.