Metasploit Deep Dive Part 5: Transports Compared
Part 4 covered what’s inside a meterpreter packet. This post covers how the connection carrying those packets actually gets established, and the real framework ships a lot more than the three transports most tutorials mention.
The core three
reverse_tcp is the default most people reach for first: the target connects outbound to the attacker on a chosen port, a plain TCP socket with no framing beyond what meterpreter itself imposes. It’s the simplest transport to set up and the easiest to spot on a network, an unencrypted outbound connection to an unfamiliar host on an arbitrary port is exactly the kind of thing egress filtering exists to catch.
reverse_https wraps the same reverse-connection model in TLS and shapes it to look like ordinary HTTPS traffic: a GET or POST to a URI path, standard-looking headers, a response body carrying the actual payload data. reverse_http is the same thing without the encryption. Both blend into normal outbound web traffic far better than a bare TCP socket, which is exactly why they’re the more commonly reached-for choice once initial access moves past a lab exercise. The real handler source (lib/msf/core/handler/reverse_https.rb) builds directly on Rex::Proto::Http, the same HTTP client machinery the rest of the framework’s HTTP-based exploit modules use, not a bespoke implementation.
bind_tcp flips the direction: the target listens, and the attacker connects in. This only works when the attacker can actually reach the target’s listening port, which rules it out behind NAT or a stateful firewall doing anything sensible with inbound connections, but it’s the right choice in scenarios where outbound egress is tightly filtered and inbound access to the specific host is already available (post-lateral-movement, for instance, where the attacker is already routing through an established pivot).
Variants that address specific failure modes
The real handler directory has more than the core three, and each variant exists to solve one specific problem:
reverse_tcp_ssl adds TLS to plain reverse_tcp without the HTTP shaping of reverse_https, useful when encryption matters but blending into web traffic specifically doesn’t.
reverse_tcp_double and reverse_tcp_double_ssl perform the connection handshake twice before treating the session as live, a defense against automated sandbox and honeypot systems that complete a single TCP handshake to fingerprint a listener without actually running the payload through to completion.
reverse_tcp_all_ports retries the same target across a range of ports rather than a single fixed one, useful when the specific outbound port isn’t known in advance or when a chosen port turns out to be filtered.
bind_udp, reverse_udp, bind_sctp, reverse_sctp apply the same bind/reverse split to UDP and SCTP instead of TCP, for environments where TCP specifically is what’s being watched or filtered and a different transport protocol slips past that specific control.
reverse_named_pipe and bind_named_pipe use Windows named pipes instead of a network socket at all, relevant for local privilege escalation and lateral movement scenarios where the “connection” never needs to leave the local machine or a single SMB session.
reverse_ssh tunnels the meterpreter connection over an actual SSH session rather than a raw or TLS-wrapped socket, which is a genuinely different security profile: the traffic is indistinguishable from ordinary SSH at the network level, and if the target environment already has SSH egress allowed and monitored less closely than arbitrary outbound TCP, this handler routes around that gap directly.
bind_aws_ssm and bind_aws_instance_connect are the least obvious pair in the whole list, and worth calling out specifically: instead of a network listener at all, these use AWS’s own management APIs, Systems Manager Session Manager and EC2 Instance Connect, as the C2 channel. Against an EC2 instance where those services are already enabled for legitimate administration, this transport never touches a network port that a security group or NACL would filter, because the traffic goes through AWS’s control plane rather than the instance’s network interface. That’s a cloud-native C2 pattern this series hasn’t touched anywhere else on the site, closer in spirit to living-off-the-land than to a traditional reverse shell.
find_tag, find_shell, find_tty, find_port are a different category entirely: not transports that establish a new connection, but handlers that search an already-compromised host’s existing open file descriptors or sockets for a viable channel to attach to, useful when a payload has already achieved code execution through some other means and just needs to locate a way out.
generic and none round out the list: generic handles payloads that manage their own connection logic outside the standard handler framework, and none is exactly what it sounds like, for payloads (like a simple exec) that don’t need a callback channel at all.
Staged vs. stageless, revisited
Part 3 introduced the stager/stage split from the payload-generation side. From the transport side, that split has a direct network consequence: a staged payload’s handler has to manage two phases, the initial small connection and then the stage transfer, while a stageless payload’s handler only sees one connection carrying everything. That second-phase transfer in a staged setup is a fixed-size, fairly predictable event, the stage itself doesn’t vary in size the way user-supplied shellcode does, which is exactly the kind of pattern that shows up in network-based detection signatures. Choosing stageless isn’t a strictly better choice for evading that specific detection, since a stageless payload’s larger single transfer has its own fixed-size signature, but it does eliminate the two-distinct-phases pattern specifically.
What this sets up for Part 10
Every transport described here has a network shape: reverse_tcp is a bare unencrypted socket, reverse_https rides real TLS but with framework defaults that don’t always match genuine browser TLS behavior, bind_aws_ssm never touches the instance’s network interface at all. Part 10 picks this thread back up from the defender’s side, what’s actually visible to network-level detection for the transports someone is most likely to encounter in practice, narrowed deliberately to network-level signals since host-based detection is being handled by a separate series once the lab work for it lands.