Didier Stevens

Monday 11 May 2015

Detecting Network Traffic from Metasploit’s Meterpreter Reverse HTTP Module

Filed under: Networking — Didier Stevens @ 5:52

I teach a Wireshark class at Brucon 2015.

I took a closer look at Metasploit’s Meterpreter network traffic when reverse http mode is used.

The Meterpreter client will make regular HTTP requests to the Metasploit server to check if it has commands ready to be executed. This is how a request looks like:



The client sends an HTTP POST request with a 4-byte payload: RECV. The URI has the following pattern: 4 or 5 alphanumeric characters, an underscore and 16 alphanumeric characters. The 16 alphanumeric characters are chosen at random, and the 4 or 5 alphanumeric characters are some kind of checksum.

I checked Meteasploit’s source code: these characteristics of Meterpreter’s Reverse HTTP protocol are hardcoded.

What is not hardcoded, but parametrized with a variable, is the User Agent String. By default, it is “Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)”, but it is an option that can be changed.

I’ve tested the detection of Metasploit Meterpreter traffic with this User Agent String in several environments, and never encountered a false positive. You might think that “Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)” is quite common as a User Agent String, but it is not. “MSIE 6.1” is pretty rare (according to Wikipedia, there is no Internet Explorer version 6.1), and “Windows NT” without version number is also rare. Combined, I’ve never seen this User Agent String except for Metasploit Meterpreter traffic. The only User Agent String seen in-the-wild that comes close to this one is “Mozilla/4.0 (compatible; MSIE 6.1; Windows XP)”. But I suggest that you check your environment for this Metasploit User Agent String if you want to be sure no false positives will be generated in your environment.

But like I said, the User Agent String is an option, and can be easily changed by the Metasploit operator. That’s why I also developed a method to detect Metasploit Meterpreter Reverse HTTP traffic looking for its hardcoded characteristics: a POST request with RECV payload to a recognizable URI.

Here is the Snort rule:

# Snort rules by Didier Stevens (http://DidierStevens.com)
# 2015/05/01 - 2015/05/10
# Thanks to Nathan Fowler for helping out with performance optimization
# I start numbering my rules at SID 1618000
alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"Metasploit Meterpreter"; flow:to_server,established; content:"RECV"; http_client_body; depth:4; fast_pattern; isdataat:!0,relative; urilen:23<>24,norm; content:"POST"; pcre:"/^\/[a-z0-9]{4,5}_[a-z0-9]{16}\/$/Ui"; classtype:trojan-activity; reference:url,blog.didierstevens.com/2015/05/11/detecting-network-traffic-from-metasploits-meterpreter-reverse-http-module/; sid:1618008; rev:1;)

This Snort rule looks for traffic from your internal network to the outside. You need to change the rule if you want to detect internal-only traffic.

Here is an example of an alert:

[**] [1:1618008:1] Metasploit Meterpreter [**]
[Classification: A Network Trojan was detected] [Priority: 1] 
05/11-22:26:31.236007 ->
TCP TTL:64 TOS:0x0 ID:21177 IpLen:20 DgmLen:212 DF
***A**** Seq: 0x1B677291  Ack: 0x861008DD  Win: 0x7680  TcpLen: 20
[Xref => https://blog.didierstevens.com/2015/05/11/detecting-network-traffic-from-metasploits-meterpreter-reverse-http-module/]

Based on the Metasploit User Agent Strings I published a couple of months ago, I made these Snort rules:

# Snort rules by Didier Stevens (http://DidierStevens.com)
# 2015/04/30
# I start numbering my rules at SID 1618000
#alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"Metasploit User Agent String"; flow:to_server,established; content:"User-Agent|3a| Mozilla/4.0 (compatible\; MSIE 6.0\; Windows NT 5.1)|0d 0a|"; http_header; classtype:trojan-activity; reference:url,blog.didierstevens.com/2015/03/16/quickpost-metasploit-user-agent-strings/; sid:1618000; rev:1;)
alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"Metasploit User Agent String"; flow:to_server,established; content:"User-Agent|3a| Mozilla/4.0 (compatible\; MSIE 6.1\; Windows NT)|0d 0a|"; http_header; classtype:trojan-activity; reference:url,blog.didierstevens.com/2015/03/16/quickpost-metasploit-user-agent-strings/; sid:1618001; rev:1;)
#alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"Metasploit User Agent String"; flow:to_server,established; content:"User-Agent|3a| Mozilla/4.0 (compatible\; MSIE 7.0\; Windows NT 6.0)|0d 0a|"; http_header; classtype:trojan-activity; reference:url,blog.didierstevens.com/2015/03/16/quickpost-metasploit-user-agent-strings/; sid:1618002; rev:1;)
alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"Metasploit User Agent String"; flow:to_server,established; content:"User-Agent|3a| Mozilla/4.0 (compatible\; MSIE 7.0\; Windows NT 6.0\; Trident/4.0\; SIMBAR={7DB0F6DE-8DE7-4841-9084-28FA914B0F2E}\; SLCC1\; .N|0d 0a|"; http_header; classtype:trojan-activity; reference:url,blog.didierstevens.com/2015/03/16/quickpost-metasploit-user-agent-strings/; sid:1618003; rev:1;)
alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"Metasploit User Agent String"; flow:to_server,established; content:"User-Agent|3a| Mozilla/4.0 (compatible\; Metasploit RSPEC)|0d 0a|"; http_header; classtype:trojan-activity; reference:url,blog.didierstevens.com/2015/03/16/quickpost-metasploit-user-agent-strings/; sid:1618004; rev:1;)
#alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"Metasploit User Agent String"; flow:to_server,established; content:"User-Agent|3a| Mozilla/5.0 (Windows\; U\; Windows NT 5.1\; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/ Safari/525.13|0d 0a|"; http_header; classtype:trojan-activity; reference:url,blog.didierstevens.com/2015/03/16/quickpost-metasploit-user-agent-strings/; sid:1618005; rev:1;)
alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"Metasploit User Agent String"; flow:to_server,established; content:"User-Agent|3a| Mozilla/5.0 (compatible\; Googlebot/2.1\; +http://www.google.com/bot.html)|0d 0a|"; http_header; classtype:trojan-activity; reference:url,blog.didierstevens.com/2015/03/16/quickpost-metasploit-user-agent-strings/; sid:1618006; rev:1;)
#alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"Metasploit User Agent String"; flow:to_server,established; content:"User-Agent|3a| Mozilla/5.0 (compatible\; MSIE 10.0\; Windows NT 6.1\; Trident/6.0)|0d 0a|"; http_header; classtype:trojan-activity; reference:url,blog.didierstevens.com/2015/03/16/quickpost-metasploit-user-agent-strings/; sid:1618007; rev:1;)

Remark that I commented-out the Snort rules that I expect to generate too many false positives. But it’s best that you check what User Agent Strings are common in your environment, before you deploy and uncomment these rules.

Update: these rules are designed for an environment where egress traffic has to go to an HTTP port. If your environment allows all destination ports (like Metasploit’s default 4444 port), then replace $HTTP_PORTS by any in the rules you deploy. Thanks @securitygen for the remark.

snort-rules-V0_0_1.zip (https)
MD5: 526AAC1CE1E8576633498223DFA07E3D
SHA256: 7694E4E884E12068BC2A32714D3B0C48060B12C80E4093AFB6B1563E2EDA5E8D


  1. Thank you! Excellent Snort rules already created… That was my first thought when I saw the topic of this posting… 🙂

    Comment by poesterberg — Tuesday 12 May 2015 @ 6:49

  2. Fixed a few weeks ago (the predictable URLs). The “RECV” fingerprint will go away sometime soon as well.

    Comment by Anonymous — Wednesday 13 May 2015 @ 4:21

  3. […] you considered writing your own Snort rule to detect Meterpreter reverse HTTP […]

    Pingback by Security News #0x88 | CyberOperations — Monday 1 June 2015 @ 19:01

  4. slightly off topic, what is the display filter you are using on your “TCP Flags” column? I have not seen that format before.

    Comment by Brian — Sunday 28 June 2015 @ 2:30

  5. @Brian It’s a dissector I coded, you can find it on my blog: tcpflags https://blog.didierstevens.com/2014/04/28/tcp-flags-for-wireshark/

    Comment by Didier Stevens — Monday 29 June 2015 @ 20:29

  6. hi Didier,
    do you know why your snort rules SID:36611 and SID 36612 has been set to inactive by snort

    Comment by zied — Monday 2 November 2015 @ 19:16

  7. @aid No, I’ll try to find out.

    Comment by Didier Stevens — Monday 2 November 2015 @ 21:16

  8. @zied I was told they are off by default, they are probably off by default because of the amount of checks they do.

    Comment by Didier Stevens — Saturday 12 December 2015 @ 19:16

  9. Was wondering how to translate this into a Yara rule. Would strings search on UserAgent work you think?

    Comment by 0x (@macubergeek) — Thursday 5 May 2016 @ 16:38

  10. what would you be searching? Files, pcap files, memory dumps?

    Comment by Didier Stevens — Thursday 5 May 2016 @ 20:16

  11. The random URL length is now between 30 and 255 bytes

    Comment by Anonymous — Thursday 16 June 2016 @ 13:10

RSS feed for comments on this post. TrackBack URI

Leave a Reply (comments are moderated)

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Blog at WordPress.com.