posts | commentsAdd to Google
30
Aug

ASP security case study

commentsNo comments

The Legacy

I recently worked on a legacy asp web application that had been hacked. The problem? The programmers didn’t think that hackers would/could attack them. This seems to be a prevalent problem in the development world. Developers have a zebra mentality. ‘Ok, we all have to cross the river, but if we all jump in at the same time hopefully I won’t be the one to get eaten’. If you don’t see the flaw in this logic please do not waste any more time with this article and go have loads of fun playing Click the Button. If you do see the logic continue on.

Case Study

One day this particular website (which I will leave unnamed) starts to attempt to download viruses on users computers from a malicious website whenever anyone visits their site. The results are devastating. Users are now getting infected with viruses. Google lists the site as a dangerous site and anyone using Firefox gets a big scary warning sign whenever they try to go to the site. This seriously hurts the reputation of the site and drives valuable traffic away.

Diagnosis

Upon close inspection of the site I noticed many ‘<script>’ tags who’s source was pointing to some suspicious looking urls. It didn’t take long to find on google that these were listed as malicious domains that were hosting viruses. The verdict; Cross Site Scripting. Cross site scripting attacks are usually malicious scripts that are inserted by hackers to force a non-malicious website to dish out malicious code.

How did they do that?

Malicious scripts are usually injected into a website on the back of SQL injection. SQL injection is a way for hackers to break into a database and inject their malicious code. A quick inspection of the database and sure enough, the database was full of malicious scripts in the content. I quickly ran some queries using the SQL ‘Replace’ function to strip out the maliciou scripts, but what would stop them from doing it again?

Understanding the Problem

Before you can fix a problem you have to be able to understand it first. SQL injection is the process of breaking a sql statement typically by adding SQL characters ( ‘ ; — ). For instance, lets say you have the following SQL statement being sent to your database:

Dim sSQL
Dim JobID
JobID = Request.QueryString("jid")
sSQL = "SELECT * FROM jobs WHERE jID = " & JobID

jid is being sent from the browser and can easily be changed. What if jid included the following ” testjob’; SELECT * FROM sysobjects — “. When this is concatenated into the SELECT query it produces the following:

"SELECT * FROM jobs WHERE jID = 'testjob'; SELECT * FROM sysobjects -- '"

As you can see, the single quote (’) breaks the sql statement and the semicolon character tells the SQL query that this is the end of this particular SQL statement and to start looking for the next command. You simply enter in the next list of SQL commands trailed by a SQL comment (–) to void out the extra single quote so that it doesn’t break the query.

In Microsoft SQL the sysobjects table gives you lots of critical information about your database including a list of all the user tables that you have created. You can imagine how valuable this information is to a hacker who now has the capability to run UPDATE INSERT and DELETE statements on your database. Once they have the list of tables, they can simply get the id of the table they want and query the syscollumns table. You can probably guess what that table has,,, yup,, an entire list of all the column names in your entire database along with the table ids that they are related to. The hackers are having a huge party at this point. All that’s left for them to do is run an update statement and concatenate an evil script tag to the end of all your content and your site is now aiding in making the internet a bad place.

The Fix

Ok, so now we understand the problem so we can take what we’ve learned and apply it to the problem. ‘Never trust any data that comes from a user’ isn’t a rule of thumb at all. It is an imperative principal that, if ignored, can/will wreak havoc on your application. What we need to do is disable the hackers ability to break the SQL queries. We do this by using ‘data sanitizing’ techniques. There are many different methods to do this, but I’ll show a couple here. This is applicable in many languages, but being that the case study we’ve been looking at is in ASP I’ll give some ASP code examples. Ok, enough talk, here’s the code:

<%
Class libStrings
	Function sanitize(strData, removeHTML)
 
	  Dim strOutput
	  strOutput = strData
 
	  If (removeHTML = "true") Then
	  	strOutput = stripHTML(strOutput)
	  End If
 
	  strOutput = Replace(strOutput, "'", "''")
	  strOutput = Replace(strOutput, ";", "")
	  strOutput = Replace(strOutput, "--", "")
	  strOutput = Replace(strOutput, "update", "update_", 1, -1, 1)
	  strOutput = Replace(strOutput, "insert", "insert_", 1, -1, 1)
	  strOutput = Replace(strOutput, "delete", "delete_", 1, -1, 1)
	  strOutput = Replace(strOutput, "drop", "drop_", 1, -1, 1)
	  strOutput = Replace(strOutput, "select", "select_", 1, -1, 1)
 
	  sanitize = strOutput
	End Function
 
	Function stripHTML(byVal strHTML)
	  Dim objRegExp, strOutput
	  Set objRegExp = New Regexp
 
	  objRegExp.IgnoreCase = True
	  objRegExp.Global = True
	  objRegExp.Pattern = "<(.|\n)+?>"
	  strOutput = objRegExp.Replace(strHTML, "")
 
	  strOutput = Replace(strOutput, "<", "<")
	  strOutput = Replace(strOutput, ">", ">")
 
	  stripHTML = strOutput 
 
	  Set objRegExp = Nothing
	End Function
 
 
	Function isEmail(byVal strEmail)
 
		Dim objRegExp, matched
		Set objRegExp = New Regexp
 
		objRegExp.IgnoreCase = True
	    objRegExp.Global = True
	    objRegExp.Pattern = "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]{3}?"
 
		matched = objRegExp.Test(strEmail)
 
		If matched Then
			isEmail = true
		Else
			isEmail = false
		End If
 
	End Function
 
	Function isPhone(byVal strPhone)
 
		Dim objRegExp, matched
		Set objRegExp = New Regexp
 
		objRegExp.IgnoreCase = True
	    objRegExp.Global = True
	    objRegExp.Pattern = "^(\(?\d{3}\)?[ .-]\d{3}[ .-]\d{4})|(\+\d{2}[ -]\d{2,4}[ -]\d{3,4}[ -]\d{3,4})$"
 
		matched = objRegExp.Test(strPhone)
 
		If matched Then
			isPhone = true
		Else
			isPhone = false
		End If
 
	End Function
 
	Function isZip(byVal strZip)
 
		Dim objRegExp, matched
		Set objRegExp = New Regexp
 
		objRegExp.IgnoreCase = True
	    objRegExp.Global = True
	    objRegExp.Pattern = "^\d{5}([\-]\d{4})?$"
 
		matched = objRegExp.Test(strZip)
 
		If matched Then
			isZip = true
		Else
			isZip = false
		End If
 
	End Function
 
Function isAlpha(byVal string)
	dim regExp, match, i, spec
	For i = 1 to Len( string )
		spec = Mid(string, i, 1)
		Set regExp = New RegExp
		regExp.Global = True
		regExp.IgnoreCase = True
		regExp.Pattern = "[A-Z]|[a-z]|\s|[_]"
		set match = regExp.Execute(spec)
		If match.count = 0 then
			IsAlpha = False
			Exit Function
		End If
		Set regExp = Nothing
	Next
	isAlpha = True
End Function
 
End Class
%>

This is a simple class that encapsulates several string functions. The ’sanitize’ function strips out the SQL characters I mentioned earlier and also concatenates an ‘_’ to SQL commands and invalidates them. This function also makes use of the ’stripHTML’ function (thanks to 4guys for this function) and strips out any malicious scripts from getting to your database. Here’s how to use it:

Dim strObject
Dim strSQL
Set strObject = libStrings
 
varToSanitize = strObject.sanitize(varToSanitize)
 
strSQL = "SELECT * FROM table WHERE criteria = '" & varToSanitize & "'"

This strips the ability to break the SQL statement by injecting characters and malicious scripts. A couple more methods you’ll notice validate what type of string is being received, such as a phone number or email address. These are common values that are inserted into a database. Not only is this kind of validation good for your application and data ‘correctness’ but it can also deter hacker attacks. When your application ‘knows’ what data it’s supposed to receive it can handle data in a much more stable manner. Also, there is an isAlpha function that helps to validate things such as a name or other string you know should not contain numbers or special characters. ASP also has built in functions such as isNumeric that help you to validate variables you know should be only numbers.

Conclusion

This is by no means an exhaustive article on SQL injection or website security, but it can get you going. The techniques here can be implemented in many other languages such as PHP, Perl or Python. If you take nothing more away from this article please remember one thing… never trust any data that comes from a user. Treat all data that comes from users as though it has been tainted.

Categories: ASP
Bookmark and Share

Saturday, August 30th, 2008 at 10:37 pm and is filed under ASP. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Leave a reply