19.10. Using ngrep for Advanced Packet Sniffing

You know and love both tcpdump and Wireshark, and are pretty good at finding the information you want. But sometimes, you still end up dumping the output to a text file and using grep to look for strings or regular expressions that tcpdump and Wire-shark can't filter on. If only there were something like tcpdump and grep combined.

There is: ngrep, or "network grep." ngrep is a packet sniffer that is similar to tcpdump, with the added facility of being able to search on any text string or regular expression just like grep. Suppose you're snooping to see what your employees are saying about you on IRC. You want to get straight to the juicy stuff, so try this command:

	# ngrep -qpd eth0 host ircserver -i carla
	interface: eth0 (192.168.1.0/255.255.255.0)
	match: carla
	##
	T 192.168.1.10:33116 -> 140.222.222.107:6667 [AP]
	PRIVMSG #authors :that carla is truly wonderful and everyone loves her
	##
	T 192.168.1.32:39422 -> 140.222.222.107:6667 [AP]
	PRIVMSG #authors :yes, carla is great, the world would be dust and ashes without her

It looks promising, and you want some more context, so you add the -A 5 switch to include the five lines that follow your match:

	# ngrep -qpd eth0 -A5 host ircserver -i carla
	T 192.168.1.10:33116 -> 140.222.222.107:6667 [AP]
	PRIVMSG #authors :LOL thanks, I haven't laughed that hard in ages
	##
	T 192.168.1.32:39422 -> 140.222.222.107:6667 [AP]
	PRIVMSG #authors :NP, it's a good thing the bossy little dope can't eavesdrop on us

ngrep uses the same protocol options as tcpdump. This example shows only POP3 traffic:

	# ngrep -qpd eth0 '' tcp port 110

ngrep can tell the difference between Windows pings and Linux pings. Windows uses letters to fill out the payload, and Linux uses numbers, so you can tailor your search to see what OS certain pings are coming from:

	# ngrep -qpd eth0 'abcd' icmp
	interface: eth0 (192.168.1.0/255.255.255.0)
	filter: (ip or ip6) and ( icmp )
	match: abcd
	#
	I 192.168.1.77 -> 192.168.1.10 8:0
	  ....abcdefghijklmnopqrstuvwabcdefghi
	# ngrep -qpd eth0 '1234' icmp
	interface: eth0 (192.168.1.0/255.255.255.0)
	filter: (ip or ip6) and ( icmp )
	match: 1234
	#
	I 192.168.1.76 -> 192.168.1.10 8:0
	. .....F!s....
	..................... !"#$%&'()*+,-./01234567

That demonstrates how, if you can find something reasonably unique in the data pay-load, you can make some very fine-tuned searches. By default, ngrep displays the entire packet. The maximum size is 65,536 bytes; use the -S switch to view a smaller number of bytes. This example captures HTTP headers and views only the first 156 bytes:

	# ngrep -qpd -S 156 '' tcp port 80
	interface: eth0 (192.168.1.0/255.255.255.0)
	filter: (ip or ip6) and ( tcp port 80 )

	T 192.168.1.10:33812 -> 208.201.239.36:80 [AP]
	  GET / HTTP/1.1..User-Agent: Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.
	5.6 (like Gecko) (Kubuntu)..Accept: te
	  xt/html, image/jpeg, image/png, tex [...]

So, you can take a quick look at what web browsers your site visitors are using, without having to dig through logfiles or HTTP analyzers.

One of ngrep's nicest features is the classic grep inversion match, -v, which means "don't match this." This example excludes any Session Initiation Protocol (SIP) INVITES requests on an Asterisk server:

	# ngrep -qpd eth0 -vi invites port 5060
	interface: eth0 (192.168.1.0/255.255.255.0)
	filter: (ip or ip6) and ( port 5060 )
	don't match: invites

Protocols and hosts are excluded with not statements:

	# ngrep -qpd eth0 \(not port 22\)
	interface: eth0 (192.168.1.0/255.255.255.0)
	filter: (ip or ip6) and ( (not port 22) )
	# ngrep -qpd eth0 \(not host irc.ircserver1.org\)
	interface: eth0 (192.168.1.0/255.255.255.0)
	filter: (ip or ip6) and ( (not host irc.ircserver1.org) )

The parentheses must be escaped, or the Bash shell will try to interpret them.