ModSecurity Advanced Topic of the Week: Detecting Banking Trojan Page Modifications

image from ecx.images-amazon.comThe following blog post is taken from Recipe 10-5: Detecting Banking Trojan (Man-in-the-Browser) Attacks in my new book "Web Application Defender's Cookbook: Battling Hackers and Protecting Users"

Banking Trojans (Man-in-the-Browser)

Banking Trojan software such as Zeus and SpyEye have becomeextremely sophisticated and can manipulate a wide range of user interactionswith the web application. One of thetechniques used by the banking trojans is to attempt to phish extra user dataduring login. The banking trojan willmonitor HTTP stream data via the wininet.dll library and will modify content onthe fly. The data modificationcapability within Zeus is controlled by a file called webinjects.txt.

Here is an example section for modifying theWellsFargo Login page:

set_url* GPdata_before<input type="password"name="password"*<br />data_enddata_inject<tdwidth="225"><label for="password"class="formlabel">3. ATM PIN</label><br/><inputtype="password" name="USpass" id="atmpin"size="20" maxlength="14" title="Enter ATM PIN"tabindex="11" accesskey="A"/><br/>&nbsp;</td>data_enddata_afterdata_enddata_before<label for="account" class="formlabel">data_enddata_inject4. Sign on todata_enddata_after</label>data_end

This section of code will add in a new login form element whichattempts to obtain the user's debit card ATM PIN information. Here is an example screenshot of the updated HTML form data -


If the target victim fills in thisinformation, then Zeus will send this information off to it's command andcontrol host. This is but one smallexample of the power of banking trojans. Newer versions are also able to passively conduct form grabbing. This means that they can monitor for when the client submits their actual credentials and then it can send that information off to the criminals. In a previous SpiderLabs Research blog posts series entitled "Catch Me If You Can: Trojan Bankder Zeus Strikes Again" we highlighted how Zeus can inject JS code calls to remote files they control -

image from
This technique is useful to attackers as they no longer have to update their webinjects code if the target webpage HTML changes.

Identifying Banking Trojan Page Manipulations

The key defensive capability we need to identify if a banking trojan hasmanipulated the HTML data that left the web application is to be able tovalidate the data once it reaches the browser. With this concept in mind, we can leverage the work done by theUniversity of Washington Computer Science and Engineering team on a projectcalled "Detecting In-flight Page Changes with Web Tripwires."

The concept is that we can create an md5 hash of the responsebody content as it is leaving the web application and then validate it withinthe web browser to ensure its integrity.

Step 1: Injecting Initial Web Tripwire Hooks

The first step is to use ModSecurity to dynamically add inJavaScript calls in the HTML header tag to include our web tripwire code. Here are some example rules that will add thecode to the login page URL.

SecContentInjection OnSecStreamOutBodyInspection OnSecRule REQUEST_FILENAME "@streq /login" "chain,phase:4,t:none,nolog,pass"  SecRule &ARGS:tripwirecheck "@eq 0" "chain"    SecRule STREAM_OUTPUT_BODY "@rsub s/<head>/<head><scripttype=\"text\/javascript\" src=\"\/md5.js\"><\/script>|00|<script type=\"text\/javascript\" src=\"\/webtripwire-login.js\"><\/script>/"

When the client requests the login page, the response data willbe modified by ModSecurity to look like this:

<head>        <script type="text/javascript" src="/md5.js"></script><script type="text/javascript" src="/webtripwire-login.js"></script>       <meta http-equiv="Content-type" content="text/html;charset=UTF-8" />

The md5.js file is simply a helper file that providesmd5 hashing capabilities in JavaScript. The webtripwire-login.js file is based on the in-flight pagechanges code mentioned previously.

Screen Shot 2013-07-09 at 12.02.05 PM

Step 2: Initiating Web Tripwire XHR Sub-Request

When this JavaScript code executes in the browser, thewebtripwire-login.js code will initiate an XMLHttpRequest (XHR) request back tothe web server for the login page.

// URL of the page to test:WebTripwire.targetPageURL = "/";...// Make an asynchronous request for the test page  req.onreadystatechange = handler;"GET", WebTripwire.targetPageURL, true);  req.setRequestHeader("If-Modified-Since", "");  req.setRequestHeader("If-None-Match", "");  req.send(null);

Thisrequests the same login page again however this time it includes a new parameter called "tripwirecheck=on". Here is an examplerequest:

GET /login?tripwirecheck=on HTTP/1.1Host: online.wellsfargo.comUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OSX 10.6; rv:13.0) Gecko/20100101 Firefox/13.0.1Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: en-us,en;q=0.5Accept-Encoding: gzip, deflateDNT: 1Proxy-Connection: keep-aliveReferer:

Step 3: Return A Response Body Hash Header

When this request is received by ModSecurity, the following ruleswill now run against the response body HTML data:

SecRule REQUEST_FILENAME "@streq /login" "chain,phase:4,t:none,nolog,pass"  SecRule ARGS:tripwirecheck "@streq on" "chain"    SecRule RESPONSE_BODY ".*" "t:none,t:md5,t:hexEncode,setenv:response_body_hash=%{matched_var}" Header set WebTripwireHash "%{response_body_hash}e" env=response_body_hash

These rules will not inject any of the web tripwire JavaScriptcode into the HTML body but instead will calculate an md5 hash of the response body data. This data is then saved as a new response header called WebTripwireHash:

HTTP/1.1 200 OKDate: Fri, 20 Jan 2012 14:47:57 GMTServer: KONICHIWA/1.0Content-Type: text/html; charset=UTF-8Cache-Control: no-cachePragma: no-cacheExpires: Thu, 01 Jan 1970 00:00:00 GMTKONICHIWA5: banking/signon/SignonConsumerContent-Language: en-USX-Powered-By: Servlet/2.5 JSP/2.1Set-Cookie:COOKIE_SID=vqfrPZ2dg8CsKm6bRQnhGRY00PYs3jYFnhn0HnWvQYnhcMl6d279!853989531;secure;path=/;; HTTPOnlyWebTripwireHash: 82f51800e51f7fff40f1e08b95b63fd2Content-Length: 9937Keep-Alive: timeout=2, max=6Connection: Keep-Alive

Step 4: Compare Local and Server-side Webtripwire Hashes

Once the response body data is received by the browser, the webtripwire JavaScript code will then calculate an md5 hash and compare it with the hashvalue in the WebTripwireHash response header. Here is the example JavaScript code:

      // See if the actual HTML is the same as the expected HTML.      var tripwireHash = req.getResponseHeader("WebTripwireHash");      var responsetextHash = hex_md5(req.responseText);      if (responsetextHash != tripwireHash) {        // Detected modification        alert("WARNING - This web page has been modified since leaving the web server.  Your system may be infected with a Banking Trojan.");  // for debugging 

Step 5: Generate Alerts for Page Modifications

If the hashes do not match then the data was modified sinceleaving the web application. In thiscase, if the Zeus banking trojan modifies the HTML, it will be caught and analert popup will be issued for the user as shown below:

362118 F 1007

Additionally, when the webtripwire code identifies a modified page, it willalso send a POST request back to the web application to report the issue. Here is an example request:

POST /webtripwire-submit.cgi HTTP/1.1Host: online.wellsfargo.comUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:13.0) Gecko/20100101 Firefox/13.0.1Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: en-us,en;q=0.5Accept-Encoding: gzip, deflateDNT: 1Proxy-Connection: keep-aliveContent-Type: application/x-www-form-urlencoded; charset=UTF-8Referer: 20482Pragma: no-cacheCache-Control: no-cache actualHTML=%0A%0A%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20%20%20%0A%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20%3C!DOCTYPE%20html%20PUBLIC%20%22-%2F%2F…

By monitoring for these POST violation requests with ModSecurity, we can identify banking customers who may have banking trojan malware installed on their systems andrequire clean up assistance.

Deployment Considerations

As with most defensive techniques, they have an rather short half-life. Once the bad guys identify defensive mechanisms, they could then turn around and instruct the banking trojan to strip out our defensive code. To combat this scenario, we could d a few modifications:

  1. Generate rules that will flag clients that do not initiate the tripwire sub-requests. These clients should be placed on an increased fraud watch list.
  2. Hide where we are adding in our defensive tripwire code. For example, instead of injecting directly into the main HTML page context, we could instead modify the contents of valid JS calls to external files.
  3. Obfuscate our defensive code contents. We could take a page of Exploit Kit authors and optionally obfuscate our JS code to make it more challanging for Banking Trojan operators to identify our code.

Banking/Fraud Detection Assistance

If this blog post has piqued your interest into different methods of utilizing WAFs to help identify potential Banking Fraud/Trojan activity on your site, feel free to contact us at security at modsecurity dot org. We have professional services offerings to aid in advanced usage scenarios such as this.

Trustwave reserves the right to review all comments in the discussion below. Please note that for security and other reasons, we may not approve comments containing links.