Information, OpenSourceSoftware, Security, Snort, Suricata

www.NetworkTotal.com

Twenty months ago, I wanted to try something out, and made a proof of concept in just 3 hours (thats including the time it took to buy the domain networktotal.com and point it to the IP!).

The concept was to have a place where one could upload a pcap, and have Snort and Suricata (and other tools), with all the different rule sets (VRT-Registered, VRT-Subscription, ET Open and ET PRO), parse through a pcap and display the result. Other engines like Bro could also be added etc…

It would be what VirusTotal is for binaries, just for pcaps…. I did not announce my project anywhere, and I just kept it private, but some of my friends knew about the place. So during the the first year, I counted around 250 pcaps uploaded from different places around the world (not bad for not announcing it!).

My personal usage of networktotal.com was more for taking random pcap at different places and uploading it to look for infections easy.

First off, I liked the NetworkTotal idea, but keeping the IDS engines up2date and the rulesets up2date took some time. Also, the way Suricata and Snort used to work, made it so that it took like 5 to 10 minutes to process a pcap on the old hardware that NT is running on :/ (You needed to start and stop the engines for each pcap, and just starting them up takes some time). So when Suricata went stable with their unix-socket support, meant that it would take me around a second to process a pcap with Suricata on my old hardware (Still 5 minutes with Snort). My subscription for VRT-Subscriber rules also ran out, so I dropped Snort for this setup, and I might add it back one day, but I would need more powerful hardware and a new VRT-S license…

But I started to develop the NetworkTotal backend code more on a host I set up at home. There where many goals with this, among learning about different NoSQL/Document stores which I find necessary in today’s world of data. I stared out with Cassandra, but needed fulltext, so I tried ElasticSearch (ES), but had some trouble using the Ruby Tire to do what I wanted. I ended up doing a MongoDB setup along side the ES setup, and kept that for about 8 months. But now I got ES to behave like I want to, but I still got lots to learn about ES.

Anyways, I have now ported NetworkTotal.com to only use Suricata with the Emerging Threats PRO rules. Processing of a pcap should normally take around a second and the events are stored in ElasticSearch. For all the malware I process at home with my cuckoo setup, I send the pcap in the form of <md5sum of the malware>.pcap to NetworkTotal.com, so you can search for events generated by a malware on NetworkTotal.com. As I don’t have storage to save all the pcaps, I do save some metadata in ElasticSearch. Mainly because I want to search up malware I upload based on events that fired, IPs that it talked to, domains it resolved, User-agent or URIs. This also uses disk space, so I wounder how long I can keep doing that too. Luckily, ElasticSearch scales linearly, so I’m hoping that will save me somehow…

Virustotal has also began to run pcaps through Snort and Suricata, but its not always that a malware produces a pcap, so there will be times that there are no events etc…

Here is an example from VT: https://www.virustotal.com/en/file/a7a526177c4475d47cdd49ea1b3ead2b/analysis/ where there is no snort or suricata events from the network traffic. You can search for the same md5sum on NetworkTotal.com where there is a rule that tags this as SpyEye fires : http://www.networktotal.com/search.php?q=a7a526177c4475d47cdd49ea1b3ead2b

I made a simple bash-scripts to upload a pcap to NetworkTotal and one to Search for IDS Events on NetworkTotal.

Example of the search bash-script output:

$ nt-search.sh a7a526177c4475d47cdd49ea1b3ead2b
[i] Result URL: http://networktotal.com/search.php?q=a7a526177c4475d47cdd49ea1b3ead2b&json=1
[i] Results:
{
“events”: [
“[1:2012686:4] ET TROJAN SpyEye Checkin version 1.3.25 or later“,
“[1:2010706:8] ET USER_AGENTS Internet Explorer 6 in use – Significant Security Risk”,
“[1:2406376:303] ET RBN Known Russian Business Network IP (189)”
],
“md5”: “a7a526177c4475d47cdd49ea1b3ead2b”
}

I still have some more stuff to fix in the backend code, but having started to write this blog post for about 18 months ago, I figured Ill just blog it, and write updates as they come πŸ™‚

I’ll see if I can make my cuckoo module more generic and share that, ( it uploads the <malware-md5sum>.pcap to NT and gets back the events that fired).

Again, I hope this is useful for anyone out there. Suggestions on improvements are also appreciated πŸ™‚ Im also open to discuss what more data could be displayed publicly without showing off information from the uploaded pcaps that can be somehow sensitive (like Microsoft registration keys encoded in the URI of a malware checkin, or the name of a company etc.).

Standard
Information, OpenSourceSoftware, passivedns, Security

PassiveDNS version 1.0

Im happy to announce that my PassiveDNS has reach version 1.0 (stable)!

For those of you who has played with earlier versions, the biggest changes in the last tags is the log output format:

Old:
1341819126||1.2.3.4||8.8.8.8||IN||www.google.com.||A||173.194.32.7||300

New:
1341819126.845527||1.2.3.4||8.8.8.8||IN||www.google.com.||A||173.194.32.7||300||17

I added microseconds to the unix timestamps, and also added a count field (the last field). The count field outputs how many times it has seen a query answer since it last printed it as PassiveDNS if you use caching. If you run PassiveDNS with -P 0 (No caching), it should always output 1.

Running PassiveDNS with default options, it will look something like this for a domain:

1341500304.265705||1.2.3.4||8.8.8.8||IN||www.facebook.com.||A||69.171.247.21||45||1

1341779965.656576||1.2.3.4||8.8.8.8||IN||www.facebook.com.||A||69.171.247.21||107||11

This means that in the time PassiveDNS was running, a query for http://www.facebook.com. returned 69.171.247.21 12 times in total. 11 of the entries happened between the configured “print time”. ( -P Seconds between printing duplicate DNS info (default 86400). )

So if you have any custom tools for parsing the output, you probably need to update it, before you upgrade to v1.0. pdns2db.pl which you will find in the tools/ dir has patched to handle the change.

Now that v1.0 is out, I will work with releasing new versions of PassiveDNS. In versions to come, I will make it so that you can customize the output fields via the command line.

BTW, I have also added a bit more statistics when passivedns 1.0 ends. It looks something like this:

— Total DNS records allocated : 15726
— Total DNS assets allocated : 23259
— Total DNS packets over IPv4/TCP : 0
— Total DNS packets over IPv6/TCP : 0
— Total DNS packets over TCP decoded : 0
— Total DNS packets over TCP failed : 0
— Total DNS packets over IPv4/UDP : 222139
— Total DNS packets over IPv6/UDP : 0
— Total DNS packets over UDP decoded : 222133
— Total DNS packets over UDP failed : 6
— Total packets received from libpcap : 463374
— Total Ethernet packets received : 463374
— Total VLAN packets received : 0

You can download the 1.0 release in tar.gz or in zip.

Or you can find the project on github.

Version 1.0 has been tested extensively and should be considered stable and production ready. But if you find any issues, please don’t hesitate to report your findings here.

Hacky New Year by the way!

Standard
Information, OpenSourceSoftware, passivedns, Security

pdns-ui – by Philipp Hunold

A great thing about open source software, is that you can make something that works for you, and someone else might add stuff that works for them, and combined, you might have something all in all more powerful…

pdns.ui – A Minimalistic WebUI for PassiveDNS

phunold (Philipp Hunold) has made a webgui for my PassiveDNS πŸ™‚ I cloned it on git and have it up and running here at home. I’m not a webcoder, so seeing that someone made a GUI for my PassiveDNS makes me happy! (As I would have spent too much time on doing it than it would be worth). I’ve emailed with Philipp and I know that pdns-ui is in an early stage, but I would like to let other people know about the UI so that they can use it instead of making their own and maybe come with suggestions on how to improve it, come with patches etc.

Right click and view to show pdns-ui in bigger picture

So for people who wants a web-frontend to their PassiveDNS DB, try it out and give the feedback to Philipp!

Big thanks Philipp πŸ™‚

Standard
Information, OpenSourceSoftware, passivedns, Security

PassiveDNS 0.5.0

I have pushed PassiveDNS version 0.5.0.

According to the roadmap, I have been at 0.5.0 for a while, and even started to implement stuff for the 1.5.0 version. But my real aim is the 1.0.0 release, and I have started all the activities for the 1.0.0 release, but I lack the statistics that I set in the roadmap when PassiveDNS ends. I have played it against pcaps with DNS attacks, Im fuzzing pcaps being read by PassiveDNS etc. so a 1.0.0 is hopefully not that far away πŸ™‚

Some of the changes since my last blog post (v0.2.9):

* Logging of NXDOMAINs (-Xx -L nxdomain.log)
* DNS over UDP/TCP on IPv4 and IPv6 (Used to be just IPv4+UDP)
* Logging to stdout (-L – / -l -), both for NXDOMAINS and other DNS records.
* Implemented some hardening, including checking that client TID match server TID etc.
* Other small optimization and fixing a small memleak etc.

The way I implemented NXDOMAINS in PassiveDNS for now, makes it compete with the memory pool from “normal” domains/records. So if you have a fastflux or someone just querying for generated b0gus domains on your network, you might push out valid domains from the cache in favor for a NXDOMAIN. The reason I did this, is that it was faster than implementing an own memory pool for the NXDOMAINS and it give the possibility to log NXDOMAINS in current version with out to much hassle. If this way of implementing NXDOMAINS turns out to fight for memory more aggressively than one would like, one can always start two instances of PassiveDNS, one just looking for NXDOMAINS, and the other one looking for the regular domains. As I gain more experience with NXDOMAINS in PassiveDNS and get more feedback, Ill reconsider the implementation if needed πŸ™‚

One note, the current logfile format will be stable until the 1.5.0 release (that is my intention at least), After that, my plan is to implement a customizable log format, and also more fields of interest will be available. If you have any additional data that you want to output and thoughts about how the output for those data should be, don’t hesitate to let me know πŸ™‚

I ran into a security related bug on my Ubuntu 10.04 which might be triggered running PassiveDNS. I have emailed the Debian package maintainer and reported the bug to security@ubuntu.com and also filed a bug report. The bug is fixed upstream in ldns long time ago, so hopefully it will be fixed soon in Ubuntu 10.04 too πŸ™‚

For reporting issues or making feature request, please do so here.

Happy DNS Archiving πŸ™‚

Standard
Information, OpenSourceSoftware, passivedns

PassiveDNS 0.2.9

I added some features and changes to PassiveDNS. The most important change is that the output now contains the TTL value, so you need to use the current tools/* (if you use them) as they are also changed to work with this new output format (or update your own tools).

I also added the ability to specify the DNS record types that you want to log from the command line and I added support for more record types. PassiveDNS now should be able to track: A, AAAA, CNAME, DNAME, NAPTR, SOA, PTR, RP, SRV, TXT, MX and NS.

Support for chroot and dropping privileges are also added.

I also added some features to tools/pdns2db.pl while I was at it:
1) You can now process a passivedns.log file in “batch” mode, exiting when finished.
2) You can now specify a file with a list of domains or IPs to skip insertion to the DB.
3) You can now specify a file with a list of PCRE (Perl Compatible Regular Expressions) of “domains/IPs” to skip insertion to the DB.
4) You can now specify a file with a list of domains or IPs to alert on!
5) You can now specify a file with a list of PCRE of “domains/IPs” to alert on!
6) You can now specify a file with a list of domains to whitelist and not alert on.
7) You can now specify a file with a list of PCRE of “domains/IPs” to whitelist and not alert on.

The skiplists will be checked first, and if the domain/IP is found/matched there, whitelist and blacklist will be ignored and insertion to DB will be ignored.

Next the whitelists will be checked, and if a domain/IP is found there or match a PCRE that you have defined it will not be checked by the blacklist.

Last the blacklists is checked, and if a domain/IP is found there or match a PCRE that you have defined, it will write the PassiveDNS record to the alert file that you specify (Default: /var/log/passivedns-alert.log).

There are different sources for getting lists of known bad domains. Here is one if you want to test the blacklist functionality: http://isc.sans.edu/feeds/suspiciousdomains_High.txt

Im pretty far as what it comes to planed features at this stage. Please try out PassiveDNS and beat the crap out of it πŸ™‚ I will probably “up” the version to 0.5.0 soon and from there on, it is just testing and testing and more testing before it will be a “one dot O” release.

If you have any issues with PassiveDNS, please submit them here.

Standard
Information, OpenSourceSoftware, PADS, PRADS, Security

PRADS, and how it compares to pads and p0fv2 and p0fv3

The question was brought up to me late last night on IRC, as p0fv3 RC was recently announced. This is a short answer to that question:

“People that find the PRADS page and already know p0f or pads may be interested in a comparison or essentially arguments why you would use one over the other.”

First off, its exiting to see Michal Zalewski back with p0fv3 πŸ™‚ I quickly read through his code yesterday and tested it out, and its rather interesting how he solves things. The fingerprint database at the moment is limited, but expect that to grow in the near future. I also love his non formal output in his applications πŸ™‚

[PRADS vs PADS]
So, back to the questions. First off, pads “Passive Asset Detection System” uses regexp syntax to look for common bytes in payload to identify server application. So if the server says ” Server: Apache/2.2.3 (Linux/SUSE)” that is collected as what service is running on the server port where this was detected. The “rules” can be written more specifically for each server software, but are rather general and small today. Some pads “rules” look for ASCII strings, and some for different bytes in hex etc. to identify stuff like SSL/TLS. Pads is no longer actively developed by the original author, but I do maintain a fork of the last version with enhancements added.

PRADS extended the way pads does asset detection. We have build in IPv6 support in PRADS, so it also detects asset listening on IPv6 addresses. We also have build in connection tracking, so that we can cut off detection in a stream after an amount of packets or bytes seen from the client or server. This to drop trying to look for server/client assets in connections that transfers big files or are encrypted etc. Most “banners/identifiers” are in the first packet etc. so limiting for how many packets in a stream to do detection on helps on performance etc.

To extend pads a bit, we also added detection for client applications using the same method as for detecting server applications.

My future thoughts on enhancing the pads/PRADS asset rules are to make them more like the Snort/Suricata rule language and use fast pattern matching before invoking the pcre method etc. Pads does no OS fingerprinting per say btw.

[PRADS vs p0f]
PRADS tcp fingerprinting was based on the p0fv2 way as p0f had the fingerprint DB and we thought that reusing the fingerprints would make it easier for people to migrate if they wanted, instead of recollecting and adding fingerprints. PRADS also added some touches of its own (for IPv6 etc) and the way we match the fingerprints (and fuzzing). We have thought about extending the fingerprints and re-write them, but thats in the future. Right now they are doing a good job. We also added all the p0fv2 ways of fingerprinting to the whole tcp session, from the syn to the rst/fin. p0fv2 could just use one method at a time, depending on how you started p0fv2. PRADS outputs all the info it gathers, and leaves the final correlation to the end user/program etc. A good example on that is prads-asset-report and prads2snort, which ads wight to each type of fingerprints, ranging the syn and syn+ack higher than stray-ack, rst and fin etc. You can also base the final guess on client or server applications to, say if the User-Agent contains: “Linux” or “Windows NT 6.1” or “Macintosh; Intel Mac OS X 10.7” etc.
or if the Server string of the web server is: “Microsoft-IIS 6.0” or “Apache 2.2.15 (FreeBSD)” or “Apache 2.2.3 (Red Hat)” etc.

The p0fv3 tcp fingerprints are new in the way they are written. A new fingerprint file format, that makes it easy to add different types of fingerprints into one and same file (TCP/HTTP/SMTP etc). The most significant enhancement in the TCP fingerprints that I see is the MSS and MTU multiplier field. p0fv3 also detects new quirks not measured in p0fv2. The rules are now also more human readable, Example:

# RULE
label = s:unix:Linux:2.6.x
sig = *:64:0:*:mss*4,6:mss,sok,ts,nop,ws:df,id+:0

# Will match:
.-[ X.X.X.X/58435 -> Y.Y.Y.Y/22 (syn) ]-
|
| client = X.X.X.X/58435
| os = Linux 2.6.x
| dist = 9
| params = none
| raw_sig = 4:55+9:0:1460:mss*4,6:mss,sok,ts,nop,ws:df,id+:0
|
`—-

The way the tcp fingerprints are matched are also changed a bit, and I believe Michal Zalewski has done this for good reasons and that it will enhance the detection.

Beside the new tcp fingerprint changes, p0fv3 also has application layer detection added. I looked at the HTTP stuff, and p0fv3 matches also on the HTTP header order and dont blindly trust the User-Agent, as we do in PRADS. We have thought about extending the “rule/signature” in PRADS to be more Snort/Suricata like, so you can have more content matches etc, but more accuracy can be achieved today using the pcre language, to verify header order etc, before blindly trusting the UA, but pcre is way too expensive used alone I think, so organizing the signatures/rules better internally and having something like a fast_pattern matcher would help alot. Quick pcre example for a User-Agent with specific HTTP header order:

# Detects Firefox/3.6.X with HTTP header order to add confidence in the match.
# PRADS rule:
http,v/MFF 3.6.X/$1//,rnHost: .*rnUser-Agent: Mozilla/5.0 (.*Firefox/3.6..*)rnAccept: .*rnAccept-Language: .*rnAccept-Encoding: .*rnAccept-Charset:

Running it in PRADS on an old pcap gives me:

# Client IPs deducted just to be kind
[client:MFF 3.6.X (X11; U; Linux x86_64; en-US; rv:1.9.2.12) Gecko/20101027 Ubuntu/10.04 (lucid) Firefox/3.:80:6],[distance:8]
[client:MFF 3.6.X (X11; U; Linux x86_64; en-GB; rv:1.9.2.12) Gecko/20101027 Ubuntu/10.10 (maverick) Firefox:80:6],[distance:11]
[client:MFF 3.6.X (Windows; U; Windows NT 5.1; de; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 ( .NET CLR 3.:80:6],[distance:10]
[client:MFF 3.6.X (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 (.NET CLR :80:6],[distance:14]
[client:MFF 3.6.X (X11; U; Linux x86_64; en-US; rv:1.9.2.12) Gecko/20101027 Linux Mint/10 (Julia) Firefox/3:80:6],[distance:15]
[client:MFF 3.6.X (X11; U; Linux x86_64; en-US; rv:1.9.2.12) Gecko/20101027 Ubuntu/10.10 (maverick) Firefox:80:6],[distance:9]
[client:MFF 3.6.X (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12:80:6],[distance:6]
[client:MFF 3.6.X (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6:80:6],[distance:12]
[client:MFF 3.6.X (Windows; U; Windows NT 6.1; es-ES; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12:80:6],[distance:14]
[client:MFF 3.6.X (X11; U; Linux x86_64; en-US; rv:1.9.2.10) Gecko/20101005 Fedora/3.6.10-1.fc14 Firefox/3.:80:6],[distance:8]
[client:MFF 3.6.X (X11; U; Linux x86_64; en-US; rv:1.9.2.12) Gecko/20101027 Ubuntu/10.04 (lucid) Firefox/3.:80:6],[distance:12]

Not the whole User-Agent is grabbed, and we need to extend that in the future. But the pcre language makes it possible to match on as much content as you want, to have the confidence you need in your signatures/rules for detecting assets. PRADS looks for client and server applications on all ports and both UDP and TCP and for IPv4 and IPv6.

[PRADS vs The World]
Right now we are working on adding the DHCP OS fingerprinting and ICMP OS fingerprinting. DHCP is pushed to the git master on github but is not fully integrated into the PRADS core yet, but printing and matching is working, so you can help add fingerprints if you want :). The ICMP part is tricky as I want to fingerprint on the protocol layer, and also the payload, so I kind of have to combine the p0f way with the pads way of detecting and matching.

PRADS has also lots of other stuff, like connection tracking/Flow gathering with output compatible with cxtracker and sancp. I have also been working on my passivedns project, and I tend to port the relevant function over to PRADS, so we can have domain names mapped with assets to.

p0fv3 has an API so you can talk to it, to fetch relevant info about the IPs it knows about. I see p0fv3 with this functionality aimed at mail and web servers etc, to determine if this is spam or ham stuff coming its way, but you can use it in lots of cool ways.
I know PRADS is used in much the same way from people I have talked too. An example that Kacper put up can be found on http://prads.delta9.pl/. On the road map for upcoming PRADS releases, we have access to assets via shared memory. That will make it easier for extracting info from the running PRADS process that is current. PRADS also ships with prads2db.pl which parses a prads asset log-file and inserts the info to a DB so you can query it for info.

PRADS philosophy is something like: “If it can be detect passively, PRADS should probably do it.”

So if you are comparing for deciding which application to go for, I would say use them all, and correlate the the knowledge that each tool gives you. You can even add the output from the active fingerprinting tool nmap into the mix.

That said, much of my view on PRADS comes from that I use it in my Network Security Monitoring setup and from my wish to “know as much as possible about my assets”. If you have any wishes or suggestions, god or bad etc, feel free to contact us.

E

Standard
Information, OpenSourceSoftware, Security, Snort, Sourcefire, Suricata

Suricata and some phun with flowints

I have been looking into malware traffic that is hard to make signatures for in a “regular” way. I’m not a malware reverser, so I don’t dig into a malware to determine byte-testes and jumps etc. in binary protocols. This lead me to use a lot of flowbits at first, for making my sigs, but the performance in Snort and Suricata was “crap” to say it nice. So I talked to Victor Julien, lead programmer of Suricata, discussing implementing packet and byte counting in Suricata. I want to count each packet sent by a client and server and the total amount of bytes sent by client and server. Talking back and forth, Victor convinced me that I might be best to go for byte count for reassembled streams. So I added a feature request to Suricata. I since then updated the feature request to add the packet and byte counters, as I think they will do great use.

Talking to Matt Jonkman (Emerging Threats Pro), he pointed me to flowint in Suricata to try to solve my packet counting. So in Suricata 1.1.1, you can do something like this to initialize the packet counters:

# Initialize the packet counter (Suricata 1.1.1 and some older versions)
#alert ip $HOME_NET any -> $EXTERNAL_NET any (msg:”Generic Client Established Flow IP Packet Counter set”; flow:established,from_client; flowint:client_packet,notset; flowint:client_packet,=,0; flowbits:noalert; classtype:not-suspicious; sid:1; rev:1;)

#alert ip $EXTERNAL_NET any -> $HOME_NET any (msg:”Generic Server Established Flow IP Packet Counter set”; flow:established,from_server; flowint:server_packet,notset; flowint:server_packet,=,0; flowbits:noalert; classtype:not-suspicious; sid:2; rev:1;)

In Suricata 1.2dev (rev 4c1e417) (I did my test for the blog on this version) and newer, you dont need to initialize the counter, as it will automagical be initialized to zero, so you don’t need sid:1 and sid:2:

## Generic packet counter: (This could be better done internally in Suricata/Snort? and not with rules?)
alert ip $HOME_NET any -> $EXTERNAL_NET any (msg:”Generic Client Established Flow IP Packet Counter”; flow:established,from_client; flowint:client_packet,+,1; flowbits:noalert; classtype:not-suspicious; sid:3; rev:1;)

alert ip $EXTERNAL_NET any -> $HOME_NET any (msg:”Generic Server Established Flow IP Packet Counter”; flow:established,from_server; flowint:server_packet,+,1; flowbits:noalert; classtype:not-suspicious; sid:4; rev:1;)

So, what can you do with packet counters?

First off, lets look at some generic rules I made up to test with, which basically should limit the detections in streams to the first 29 packets from the client:

# GENERiC GET
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:”GENERIC GET (classic)”; flow:from_client,established; content:”GET “; depth:4; content:!”connection: keep-alive”; nocase; http_header; classtype:not-suspicious; sid:5; rev:1;)

alert http $HOME_NET any -> $EXTERNAL_NET any (msg:”GENERIC GET (flowint)”; flow:from_client,established; flowint:client_packet,<,30; content:”GET “; depth:4; content:!”connection: keep-alive”; nocase; http_header; classtype:not-suspicious; sid:6; rev:1;)

# GENERiC UA
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:”GENERIC User-Agent (classic)”; flow:from_client,established; content:”User-Agent: “; http_header; content:!”connection: keep-alive”; nocase; http_header; classtype:not-suspicious; sid:7; rev:1;)

alert http $HOME_NET any -> $EXTERNAL_NET any (msg:”GENERIC User-Agent (flowint)”; flow:from_client,established; flowint:client_packet,<,30; content:”User-Agent: “; http_header; content:!”connection: keep-alive”; nocase; http_header; classtype:not-suspicious; sid:8; rev:1;)

Sid 5 and 6 looks for a HTTP GET request that is not a HTTP keep-alive. Sid 7 and 8 is looking for User-Agent in non HTTP keep-alive request. Common for the flowint versions of the rules, are that they are just limited to the first 29 packets in an established flow. So running Suricata against 2009-04-20-09-05-46.dmp etc. shows some interesting results:

Num Rule Gid Rev Ticks % Checks Matches Max Ticks Avg Ticks Avg Match Avg No Match
——– ———— ——– ——– ———— —— ——– ——– ———– ———– ———– ————–
1 4 1 1 1695335708 67.74 510720 510720 6412616 3319.50 3319.50 0.00
2 3 1 1 581354624 23.23 508970 82175 3602972 1142.22 3061.99 772.59
3 7 1 1 135943292 5.43 7900 2352 499972 17208.01 16156.62 17653.74
4 5 1 1 43040648 1.72 3313 2517 199052 12991.44 16247.74 2694.82
5 8 1 1 29172972 1.17 7900 2352 434592 3692.78 6588.51 2465.18
6 6 1 1 17917112 0.72 3313 2517 353684 5408.12 6528.93 1864.06

Sorry for the formating πŸ™‚
First, if we look at sid 5 and 6, we see that they both where checked 3313 times, and matched 2517 times. If we look at total ticks, sid 5 uses 43040648 ticks and sid 6 (flowint) uses 17917112 ticks. Average ticks for sid 5 is 12991.44 ticks and 5408.12 ticks for sid 6 (flowint).

Looking at sid 7 and 8, we see that they both where checked 7900 times, and matched 2352 times. If we look at total ticks, sid 7 uses 135943292 ticks and sid 8 (flowint) uses 29172972 ticks. Average ticks for sid 7 is 17208.01 ticks and 3692.78 ticks for sid 8 (flowint).

A basic conclusion for this test, is that the rules with the flowint check are faster and will give you the same alerts.
But if we look at the ticks sid 3 and 4 uses to count the all the packets, they are high in total, but low on average ticks. So they are not expensive for each check, but since they are checked (and possibly incremented) for each packet, the total ticks are relative high. Having this in the core of Suricata and Snort, would probably make them less expensive (hint hint).

So what more c00l stuff can we do with packet counters?

Some malware I stumbled upon will give you an example (Mostly used in the Gheg Spam bot, aka Tofsee/Mondera)
b31e4624cdc45655b468921823e1b72b
3c453e40ff63da3c2a914c29b6c62ee0
e8034335afb724d8fe043166ba57cd23

It seems to communicate in a binary way (encrypted), but looking at 5 different pcaps I got, I saw a pattern and my flowint counters came to good use. It seems like the client and server sends packets with a specific payload size in different parts of the communication. I did not see any obvious content to match on, so content matches didn’t seem trivial, and this is a great way to demonstrate my point: Flowint+packet counters to the rescue! Here is a tcpdump output of traffic on port 443 (not including the port 22050 traffic, which is much longer, but the start is the same), so you can see the packets sizes and in which order they do come in this short sessions:

reading from file b31e4624cdc45655b468921823e1b72b.pcap, link-type EN10MB (Ethernet)
03:47:02.571111 IP 192.168.1.10.1031 > 216.246.8.230.443: Flags [S], seq 910650996, win 65535, options [mss 1460,nop,nop,sackOK], length 0
03:47:02.608784 IP 216.246.8.230.443 > 192.168.1.10.1031: Flags [S.], seq 442582883, ack 910650997, win 5840, options [mss 1380,nop,nop,sackOK], length 0
03:47:02.608977 IP 192.168.1.10.1031 > 216.246.8.230.443: Flags [.], ack 1, win 65535, length 0
03:47:02.646959 IP 216.246.8.230.443 > 192.168.1.10.1031: Flags [P.], seq 1:201, ack 1, win 5840, length 200
03:47:02.647342 IP 192.168.1.10.1031 > 216.246.8.230.443: Flags [P.], seq 1:142, ack 201, win 65335, length 141
03:47:02.685098 IP 216.246.8.230.443 > 192.168.1.10.1031: Flags [.], ack 142, win 6432, length 0
03:47:02.718986 IP 216.246.8.230.443 > 192.168.1.10.1031: Flags [P.], seq 201:676, ack 142, win 6432, length 475
03:47:02.718999 IP 216.246.8.230.443 > 192.168.1.10.1031: Flags [F.], seq 676, ack 142, win 6432, length 0
03:47:02.719268 IP 192.168.1.10.1031 > 216.246.8.230.443: Flags [.], ack 677, win 64860, length 0
03:47:02.719584 IP 192.168.1.10.1031 > 216.246.8.230.443: Flags [F.], seq 142, ack 677, win 64860, length 0
03:47:02.757350 IP 216.246.8.230.443 > 192.168.1.10.1031: Flags [.], ack 143, win 6432, length 0

And here is how I sigged it:

# Backdoor:Win32/Tofsee (aka: Gheg / Mondera)
alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:”Possible Tofsee server Packet 2 (200 Bytes)”; flow:established,from_server; flowint:server_packet,=,2; dsize:200; flowbits:set,Tofsee_SERVER_200; flowbits:noalert; classtype:trojan-activity; sid:9; rev:1;)

alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:”Possible Tofsee client Packet 3 (141 Bytes)”; flow:established,from_client; flowint:client_packet,=,3; dsize:141; flowbits:isset,Tofsee_SERVER_200; flowbits:set,Tofsee_CLIENT_141; flowbits:noalert; classtype:trojan-activity; sid:10; rev:1;)

alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:”Possible Tofsee server Packet 4(475 Bytes)”; flow:established,from_server; flowint:server_packet,=,4; dsize:475; flowbits:isset,Tofsee_CLIENT_141; classtype:trojan-activity; sid:11; rev:1;)

Sid 9 looks only for the 2. packet in an established flow from the Server (C&C) and the packet has to have payload size/dsize 200. It then sets the flowbit Tofsee_SERVER_200 if this hits and the rule has noalert, because this could easily trigger a false positive just this check. So we got to do some more checks. Sid 10 checks only Client packet 3, it has to have a payload size/dsize of 141 and flowbit Tofsee_SERVER_200 has to be set for this too match. Sid 10 is also no alert, as we still can check some more, to not be spammed by falses. So sid 11 checks if server packet 4 has payload size/dsize 475, and that flowbit Tofsee_CLIENT_141 is set. No we can give an alert, as this would probably be an unique set of conditions. So testing again with out 2009-04-20-09-05-46.dmp test pcap, we get:

Num Rule Gid Rev Ticks % Checks Matches Max Ticks Avg Ticks Avg Match Avg No Match
——– ———— ——– ——– ———— —— ——– ——– ———– ———– ———– ————–
1 4 1 1 1727862376 63.39 510720 510720 14059784 3383.19 3383.19 0.00
2 3 1 1 508719672 18.66 508970 82176 3689732 999.51 2830.58 646.95
3 7 1 1 140271824 5.15 7900 2352 1013800 17755.93 18570.93 17410.42
4 9 1 1 101662288 3.73 28419 0 6625384 3577.26 0.00 3577.26
5 11 1 1 84264720 3.09 32938 0 612848 2558.28 0.00 2558.28
6 10 1 1 71553560 2.62 32938 0 576132 2172.37 0.00 2172.37
7 5 1 1 42053248 1.54 3313 2517 805736 12693.40 15831.10 2771.81
8 8 1 1 31547660 1.16 7900 2352 153972 3993.37 7039.04 2702.21
9 6 1 1 17944504 0.66 3313 2517 292508 5416.39 6476.95 2062.83

Overall, sid 9, 10 and 11 did not do that bad here. And the best thing is, they all have 0 matches. I ran this on many of my test pcaps, and I’ve not been close to false positives. Sid 10 seems to fire some times, but not the others, so rather unique combo of packets in a stream I guess and a way to sig malware like this. Also, we could add check for the TCP “PUSH” flag in sid 9, 10 and 11 etc to be more accurate if we need.

So the proof of the pudding, running it against a pcap of the malware:

Num Rule Gid Rev Ticks % Checks Matches Max Ticks Avg Ticks Avg Match Avg No Match
——– ———— ——– ——– ———— —— ——– ——– ———– ———– ———– ————–
1 3 1 1 443120 33.03 165 158 102108 2685.58 2731.72 1644.00
2 11 1 1 310420 23.14 259 2 2860 1198.53 2478.00 1188.58
3 4 1 1 302944 22.58 269 269 15376 1126.19 1126.19 0.00
4 10 1 1 257896 19.22 259 3 16484 995.74 7446.67 920.14
5 9 1 1 27088 2.02 10 3 7448 2708.80 5080.00 1692.57

Events:

[**] [1:11:1] Possible Tofsee server Packet 4(475 Bytes) [**] {TCP} 216.246.8.230:443 -> 192.168.1.10:1031
[**] [1:11:1] Possible Tofsee server Packet 4(475 Bytes) [**] {TCP} 84.16.252.136:22050 -> 192.168.1.10:1032

My Tofsee rules fire on all 5 pcaps I looked at initially (and lots more pcaps I tested after that), so hopefully it will fire on all current Tofsee traffic.

I also replied on an e-mail to the snort-user list 3. of November, making the same feature request as I did for Suricata. No one followed up :/ The email should probably be directed to the snort-devel list some time in the future…

I hope this post has been useful, and hopefully we can get some more flowint rules out there, and maybe even get native packet and byte counting in Snort and Suricata one day πŸ™‚

Standard