Checking that there’s only one default gateway

(This post is another in our series on using our File String Presence Check that leverages powerful Search Expressions opening up new possibilities for creative new rules. It is a followup to our previous post, Checking that your default route is correct.)

While we normally think of our computers as having a single router leading to the Internet, it’s possible to have 2 or more routers that would be willing to carry our packets for redundancy.  In that case, we’d create extra routing table entries, one per gateway.  The operating system on the machine would take responsibility for deciding which one to use at any given time.

If an attacker wanted to read our network traffic, she might also create a second default gateway routing table entry, sending our traffic through a machine she controls, say  That gives her a chance to sniff and inspect the traffic coming from this machine.  Unlike the redundancy example above, this malicious default gateway entry is a silent way for an attacker to gain intelligence about us from the raw packets.

How would we detect that a second default route had been created?

Since there are 4 billion IPv4 IP addresses alone, we can’t put in a rule for each one saying

/proc/net/route Does not contain “^eth0s+00000000s+00000000s.*s00000000s”

/proc/net/route Does not contain “^eth0s+00000000s+01000000s.*s00000000s”

/proc/net/route Does not contain “^eth0s+00000000s+02000000s.*s00000000s”

/proc/net/route Does not contain “^eth0s+00000000s+03000000s.*s00000000s”

We have to get sneakier.  🙂

The alert I want is this: tell me if there’s a default route line (“^eth0s+00000000s+{something}s.*s00000000s”) that has something other than 010110AC in the default gateway column.  Instead of saying “I need the default gateway to be 010110AC”, I want to be warned if those characters are anything except 010110AC.

Our Search Expressions have something that looks promising; negating sets of characters with the caret symbol.  If I use paired brackets (“[{characters}]”), I match any character in between the brackets.  But if I place a caret right after the left square bracket, that says match any character except the ones in this set.  For example, “[0-9ABCDEF]” will match any digit or letter between uppercase A and uppercase F.  But if I put a caret right after the left square bracket: “[^0-9ABCDEF]”, that matches anything that isn’t an uppercase hexadecimal character ( %, &, j, d, H, L, etc.).

OK, so let’s try negating each character in the default gateway and see if that works:

 #Does this work?

/proc/net/route Does not contain “^eth0s+00000000s+[^0][^1][^0][^1][^1][^0][^A][^C]s.*s00000000s”

To test this, let’s assume we have a second default gateway line in /proc/net/route:

# cat /proc/net/route

Iface   Destination     Gateway         Flags   RefCnt  Use     Metric  Mask   MTU      Window  IRTT

eth0    00000000        010110AC        0003    0       0       0       000000000       0       0

eth0    00000000        FEDCBA09        0003    0       0       0       000000000       0       0

eth0    000110AC        00000000        0001    0       0       0       00FFFFFF0       0       0


Our second bogus default gateway is FEDCBA09.  That matches each of the above sets (F is a character other than 0, E is a character other than 1, D is a character other than 0, C is a character other than 1, etc.).  So we have a line that matches the Search Expression.  Since we specifically didn’t want any lines that match, that will set off an alert and the planet is safe again.

Not so fast.

There’s a problem there; in our example, every single character in FEDCBA09 was different from its corresponding character in 010110AC, and since each one had to be different for the alert to go off, the alert went off.  What happens if the second bogus default gateway is different but has some characters that do match?

For simplicity, let’s say that we get a second default route through  The reverse hex of that is FF0110AC.  Now see if that matches “^eth0s+00000000s+[^0][^1][^0][^1][^1][^0][^A][^C]s.*s00000000s”.

F is not 0, so we match there.  The second F is not 1, so we match there.  0 in our default gateway does equal 0, so we don’t match “[^0]”.  Oops, FF0110AC does not match [^0][^1][^0][^1][^1][^0][^A][^C], and since we only alert if there is a match, we won’t get an alert.

Is your head spinning like mine is?  Trust me; I had to both stop and think about this very carefully (especially because of the double negatives) and double check my logic with colleagues Apurva and Christian to make sure I got this right (thanks guys!).

So there’s the problem; we alert in the first case because all 8 characters we pulled (“FEDCBA09”) were different from their counterparts in the search expression ([^0][^1][^0][^1][^1][^0][^A][^C]).  But we didn’t alert in the second case because some of the characters in “FF0110AC” were different from that search expression and some were the same as their counterparts.  So this Search Expression doesn’t alert on every gateway except 010110AC.  🙁


OK, back to the drawing board.  What are we really trying to check anyways?

What we really want to know is this:  “Alert me if any of the hex characters of the default gateway are different than the ones I expected (“010110AC”).  We already tried checking them all at once and crashed and burned.  How about checking them one at a time?

Let’s put in the following 8 rules, each of which checks one character at a time:

Screen Shot 2013-04-08 at 3.07.27 PM

/proc/net/route Does not contain “^eth0s+00000000s+[^0]…….s.*s00000000s”

/proc/net/route Does not contain “^eth0s+00000000s+.[^1]……s.*s00000000s”

/proc/net/route Does not contain “^eth0s+00000000s+..[^0]…..s.*s00000000s”

/proc/net/route Does not contain “^eth0s+00000000s+…[^1]….s.*s00000000s”

/proc/net/route Does not contain “^eth0s+00000000s+….[^1]…s.*s00000000s”

/proc/net/route Does not contain “^eth0s+00000000s+…..[^0]..s.*s00000000s”

/proc/net/route Does not contain “^eth0s+00000000s+……[^A].s.*s00000000s”

/proc/net/route Does not contain “^eth0s+00000000s+…….[^C]s.*s00000000s”

Notice how we use periods as placeholder; each one stands in for a character, but I don’t really care what that character is.  That allows us to focus on one character at at time; the first rule checks the first character of the gateway address, the second rule focuses on the second character, etc.


From the top, these rules will respectively alert me if:

– The first character of the default gateway is anything other than a 0

– The second character of the default gateway is anything other than a 1

– The third character of the default gateway is anything other than a 0

– The fourth character of the default gateway is anything other than a 1

– The eighth character of the default gateway is anything other than a C

So how does that do with our three test cases?

1) If we compare our legitimate router (“010110AC”) to each of those expressions, it doesn’t match any of them because each character matches its counterpart in the rules.  That means we won’t get any alerts, and that’s a good thing.

2) When we compare the default gateway that has completely different characters (“FEDCBA09”), rule number 1 alerts because “F” is in the set [^0] .  Rule number 2 alerts because “E” is in the set [^1] .  Rule number three alerts because “D” is in the set [^0] , and so on.  Because all 8 characters are different from their legitimate counterparts, we’ll end up with 8 alerts.  It’s arguably noisy, but it will certainly get the point across.

3) Now we compare the final bogus gateway (“FF0110AC”) to our 8 rules.  The first rule will alert because “F” is in [^0] .  The second rule alerts because the second “F” is in [^1] .  The third rule does not alert because 0 is not in [^0] .  The fourth rule does not alert because 1 is not in [^1] .  In fact, all the rules from the third through the eighth do not alert because the characters in the second bogus gateway do match their counterparts in the rules.  We end up with just 2 alerts, one for each character that does not match the legitimate gateway.  And that’s enough to show us there’s a bogus gateway line.

You might not be interested in checking /proc/net/route, but the same techniques can be used to both look for a correct line in a file and look for any other incorrect lines in a file.


Stay up to date

Get the latest news and tips on protecting critical business assets.

Related Posts