ModSecurity Breach

ModSecurity: Features: Geographical IP Lookups


IP addresses are made for computers, not humans. Humans will have a difficult time mapping an IP address to a hostname or geographical location by themselves. This was the main reason why the Domain Name System (DNS) was created - to map these IP address into "human comsumable" data. One example of this idea is that this data may prove useful when checking log files for connections from notorious domain names, as IP addresses are not as user-friendly as hostnames. This information will allow you to possibly infer the intentions of some clients based on their hostname or domain of origin. The geographical location of transactions takes a different view as we are not interested in what they were requesting but rather where they came from.

With ModSecurity 2.5, you can now lookup and act on geographical information from an IP address. The new @geoLookup operator will create the GEO variable collection that includes Country, Region, City, Postal Code, Coordinates as well as DMA and Area codes in the US.

GeoIP Background

The @geoLookup operator in ModSecurity uses the GeoIP databases provided by MaxMind. Please refer to their website for background information. The following section presents some brief information on the technology.

What is GeoIP?

GeoIP® is the proprietary technology that drives MaxMind's IP geolocation data and services. GeoIP provides businesses with a non-invasive way to determine geographical and other information about their Internet visitors in real-time. When a person visits your website, GeoIP can determine which country, region, city, postal code, area code the visitor is coming from. Furthermore, GeoIP can provide information such as longitude/latitude, connection speed, ISP, company name, domain name, and whether the IP address is an anonymous proxy or satellite provider.

How does GeoIP work?

The idea behind GeoIP is simple but the process is complex. Maxmind employs user-entered location data from sites that ask web visitors to provide their geographic location. They then run millions of these datasets through a series of algorithms that identify, extract, and extrapolate location points for IP addresses.

What can GeoIP be used for?

To name a few applications, GeoIP can be used for delivering customized content, targeted ads, web log statistics, digital rights management, and regulatory compliance. In fact, you may already be using GeoIP without realizing it. MaxMind's GeoIP technology has been integrated by many organizations for ad-serving, fraud screening, web analytics, firewall/spam protection, and anti-phishing/anti-identity theft applications.

Geo Directive and Variable Usage


Description: Defines the path to the geograpical database file.

Syntax: SecGeoLookupDb /path/to/db

Example Usage: SecGeoLookupDb /usr/local/geo/data/GeoLiteCity.dat

Processing Phase: N/A

Scope: Any

Dependencies/Notes: Check out for free database files. We recommend using the GeoLite City DB.


GEO is a collection populated by the @geoLookup operator. It can be used to match geographical fields looked up by an IP address or hostname.

Available since 2.2.0.


COUNTRY_CODE: Two character country code. EX: US, UK, etc.

COUNTRY_CODE3: Up to three character country code.

COUNTRY_NAME: The full country name.

COUNTRY_CONTINENT: The teo character continent that the country is located. EX: EU

REGION: The two character region. For US, this is state. For Canada, providence, etc.

CITY: The city name.

POSTAL_CODE: The postal code.

LATITUDE: The latitude.

LONGITUDE: The longitude.

DMA_CODE: The metropoliton area code. (US only)

AREA_CODE: The phone system area code. (US only)


SecRule REMOTE_ADDR "@geoLookup" "chain,drop,msg:'Non-UK IP address'"
SecRule GEO:COUNTRY_CODE "!@streq UK" "t:none"

Testing the Geo Rule

If we test out the example rule above, we will get the following error_log message if a client with an IP address of (which is from Vietnam) connects to our web server.

[Sun Jan 20 12:00:56 2008] [error] [client] ModSecurity: Access denied with connection close (phase 2). Match of "streq UK" against "GEO:country_code" required. [file "/usr/local/apache/conf/rules/modsecurity_crs_15_customrules.conf"] [line "3"] [msg "Non-UK IP Address"] [hostname "webapphoneypot"] [uri "/cgi-bin/foo.cgi"] [unique_id "UbCGV8CoD4QAAFEXBLgAAAAA"]

Let's take a look at the modsec_debug.log file to see exactly how this new operator is functioning:

# cat modsec_debug.log | sed "s/^.*\[.\] //g" |less
Starting phase REQUEST_BODY.
This phase consists of 87 rule(s).
Recipe: Invoking rule 8d6daf8; [file "/usr/local/apache/conf/rules/modsecurity_crs_15_customrules.conf"] [line "3"].
Rule 8960ae8: SecRule "REMOTE_ADDR" "@geoLookup" "chain,drop,msg:'Non-UK IP Address'"
CACHE: Disabled - REMOTE_ADDR value length=12, smaller than minlen=15
T (0) lowercase: ""
T (0) replaceNulls: ""
T (0) compressWhitespace: ""
Executing operator "geoLookup" with param "" against REMOTE_ADDR.
Target value: ""
GEO: Looking up "".
GEO: Using address "" (0xcba0012f).
GEO: rec="\xe9\x34\x34\x00\x48\x61\x6e\x6f\x69\x00\x00\xdd\xac\x1e\x04\x9e\x2b\x26\x4e\x4c\x00\x53\x61\
GEO: country="\xe9"
GEO: region="\x34\x34\x00"
GEO: city="\x48\x61\x6e\x6f\x69\x00"
GEO: postal_code="\x00"
GEO: latitude="\xdd\xac\x1e"
GEO: longitude="\x04\x9e\x2b"
GEO: dma/area="\x26\x4e\x4c"
GEO:{country_code=VN, country_code3=VNM, country_name=Vietnam, country_continent=AS, regi
on=44, city=Hanoi, postal_code=, latitude=21.033300, longitude=105.849998, dma_code=0, area_code=0}
Operator completed in 890 usec.
Rule returned 1.
Match -> mode NEXT_RULE.
Recipe: Invoking rule 8d6e318; [file "/usr/local/apache/conf/rules/modsecurity_crs_15_customrules.conf"] [line "5"].
Rule 8d6e318: SecRule "GEO:COUNTRY_CODE" "!@streq UK" "t:none"
Expanded "GEO:COUNTRY_CODE" to "GEO:country_code".
CACHE: Disabled - GEO:country_code value length=2, smaller than minlen=15
Executing operator "!streq" with param "UK" against GEO:country_code.
Target value: "VN"
Operator completed in 24 usec.
Rule returned 1.
Match, intercepted -> returning.
Access denied with connection close (phase 2). Match of "streq UK" against "GEO:country_code" required.
[file "/usr/local/apache/conf/rules/modsecurity_crs_15_customrules.conf"] [line "3"] [msg "Non-UK IP Address"]


As you can see from the debug output, the data that is extracted out of the Geo DB is in binary format. This is much more efficient than using a plain text DB and it is the @geoLookup operator that translates it into the text format when it populates the GEO collection variables.

Combining Geo and RBL Lookups

While using the Geo lookups on their own may provide some valuable usage in certain circumstances, there may be situations where you can instead add the @geoLookup operator to a chained rule as to simply provide better information about the blocked request. The following rule set first does an RBL check on the remote IP address. If the RBL check returns true (meaning that the IP address was in fact listed), then the Geo lookup operator is run and the Country Code is then captured for use in the error log message data.

SecRule REMOTE_ADDR "@rbl" "chain,drop,msg:'Client Denied By RBL Check',logdata:'%{TX.0}'"
SecRule REMOTE_ADDR "@geoLookup" "chain"
SecRule GEO:COUNTRY_CODE "^(.*)$" "t:none,capture"

With this rule in place, the error_log message that you recieve will now include the Country Code data for the originating client.

[Sun Jan 20 12:34:41 2008] [error] [client] ModSecurity: Access denied with connection close (phase 2). Pattern match "^(.*)$" at GEO:country_code. [file "/usr/local/apache/conf/rules/modsecurity_crs_15_customrules.conf"] [line "3"] [msg "Client Denied By RBL Check"] [data "CN"] [hostname ""] [uri "/cgi-bin/foo.cgi"] [unique_id "ylaiZcCoD4QAAFJmAhoAAAAA"]