WEB
EXPLOITS - DON'T BE A VICTIM
This excellent tutorial is the work of NTSA, who has very kindly
consented to the TAZ hosting it.
You can find the original post here:
http://www.antionline.com/showthread.php?s=&threadid=235743
Enjoy!
Web Exploits - Don't be a victim
Overview
There are three things to remeber about web programming security that
you have to bear in mind when designing your applications. These are,
respectively, validation, validation and validation. The first thing a
cracker will do to your site is to see where it breaks.
(note: Cracker is the correct use of the term here. Hackers build
things, crackers break things)
Quote:
Most real hackers think that crackers are lazy, irresponsible and not
very bright and object that being able to break security no more makes
you a hacker that being able to hotwire cars makes you an automotive
engineer
Eric Raymond
Common exploitative techniques
First Johnny Cracker will browse your site until he finds a script that
accepts GET input in the format:
Code:
scriptname.ext?parameter=value
More experienced crackers will also be able to use the same sort of
explotative techniques to attack scripts that accept POSTed variables,
so don't assume that POSTing form data will deter a serious cracker
(but it might exclude some of the more lame kiddies). For the examples
in this tutorial I'm going to stick to basic GETs however.
Next our cracker will play with the URL to see what he can get to
break. For example:
Code:
scriptname.ext?parameter=
If our script does not validate that the parameter has been passed then
this will likley generate an error. If our code contains an SQL
statement that looks like this:
Code:
set myRS = cn.execute("select * from pubs where parameter=" &
request("parameter"))
then the cracker will get an error message containing the SQL statement
and probably some infomation about the physical location of the script
on the server. These are not good things to be giving out to Johnny
Cracker.
TIP: In IIS and Apache it is possible to stop the server sending
detailed error messages to the client (in IIS this is under
application/debugging). Whenever you are not actively debugging your
application you should ensure that this option is checked. Otherwise
every error message is a bit more information for Johnny Cracker to
work with.
Let's say our cracker is malicious - They now know that we have a table
called pubs in our database. They can now rework the URL to include SQL
stuffing like this:
Code:
scriptname.ext?parameter=1;delete * from pubs
Bye-bye pubs table. Our code above will assume that everything after
the semi-colon is another SQL query and run it with the same
permissions that were set up to run the first query. If those
permissions were to the master database of an MSSQL database then the
cracker now has access to all the stored procedures, including
xp_cmdshell to run programs from the command line, xp_sendmail to mail
himself the contents of your tables etc.
TIP:Never connect a web script to the master database of a MSSQL
server. Never run your web page scripts from an administrative account.
Overcoming these techniques through validation
In both of these instances we could have stopped these attempts with
proper validation. For example if we had nested our SQL statement in
the following clause:
Code:
IF NOT (Len(request("parameter")>0 AND
INSTR(LCASE(request("parameter")),"delete") =0) THEN
...Whatever...
END IF
then our cracker would not have been able to perform either of the
above 'exploits'.
Now re-writting these validation sequences for each of your scripts is
a real waste of time and can really get quite tedious. Me personally I
prefer to throw each of my validation sequences into a class that I can
re-use time and again.
NTSA's Validation script
Don't try to copy and paste this script (not least because it's taken
from one of my ActiveX controls and probably won't run as is in ASP). I
am including it in this tutorial only as an example of what YOUR
validation class might include - mine is tied into a number of sub
classes that I'm not including here (debugging classes, INI file
class,etc), but you can get the gist of what I'm doing. This class
encapsulates all my validation routines and on completion allows an
array of reported errors to be passed back to the calling script for
display to the user.
You would call the routines in this class like this:
Code:
Dim ers As Boolean
Dim Er As Variant
ers = False
Validate.ClearErrors
If Not Validate.isvalid("number", tInteger, "1") Then ers = True
If Not Validate.isvalid("password", tPassword, "123456") Then
ers = True
If Not Validate.isvalid("Date", tDate, "28/3/75") Then ers = True
If Not Validate.isvalid("Email", tEmail, "si@ntsa.org.uk") Then
ers = True
If Not Validate.isvalid("Required", tRequired, "sdgv") Then ers
= True
If Not Validate.isvalid("NoSpaces", tNoSpaces, "12345") Then ers
= True
If Not Validate.isvalid("Message", tNotHTML, "<a
href=''></a>") Then ers = True
If Not Validate.isvalid("SQL Statement", tNotSQL, "select * from
sysobjects") Then ers = True
If Not Validate.isvalid("Card Number", tLUHN, "4121111111119")
Then ers = True
Validate.BadWordsINI = "c:\badwords.ini"
If Not Validate.isvalid("Message", tNotObscene, "Message") Then
ers = True
If ers = True Then
Er = Validate.GetErrors
For n = 0 To MyArrayCls.uboundc(Er)
Debug.Print Er(n, 0) & Er(n, 1)
Next
End If
The Class file
Code:
Enum etType
tInteger = 0
tDate = 1
tEMAIL = 2
tNoSpaces = 3
tRequired = 4
tPassword = 5
tNotObscene = 6
tNotHTML = 7
tNotSQL = 8
tLUHN = 9
End Enum
Dim Errors()
'Default Property Values:
Const m_def_BadWordsINI = ""
'Property Variables:
Dim m_BadWordsINI As String
Private Sub UserControl_Initialize()
UserControl.Height = 250
UserControl.Width = 250
End Sub
Private Sub UserControl_Resize()
UserControl.Height = 250
UserControl.Width = 250
End Sub
Public Function IsValid(tName As String,
tType As etType,
tValue As String) As Boolean
Tron.Trace "Validate", "Evaluating [" & tValue & "] as
type " & _
TypeDescription(CInt(tType))
Select Case LCase(Trim(tType))
Case tInteger
If AllowedChars(tValue,
"0123456789.") = True Then
IsValid = True
Else
IsValid = False
ReDimErrors tName, " is not
a valid number."
End If
Case tDate
If IsDate(tValue) Then
IsValid = True
Else
IsValid = False
ReDimErrors tName, " is not
a valid date"
End If
Case tEMAIL
If Strings.CountInString(tValue, "@") = 1
And
Strings.CountInString(tValue, ".") > 0
And
Strings.CountInString(tValue, " ") = 0 Then
IsValid = True
Else
IsValid = False
ReDimErrors tName, " is not
a valid E-mail address"
End If
Case tNoSpaces
If InStr(tValue, " ") = 0 Then
IsValid = True
Else
IsValid = False
ReDimErrors tName, " cannot
contain spaces"
End If
Case tRequired
If Len(tValue) > 0 And tValue
<> "" Then
IsValid = True
Else
IsValid = False
ReDimErrors tName, " cannot
be nothing"
End If
Case tPassword
If Len(tValue) > 5 Then
IsValid = True
Else
IsValid = False
ReDimErrors tName, " must be
at least 6 characters long"
End If
Case tNotObscene
If Not IsObscene(tValue) Then
IsValid = True
Else
ReDimErrors tName, " may contain
obscenity"
End If
Case tNotHTML
If Not ContainsHTML(tValue) Then
IsValid = True
Else
IsValid = False
ReDimErrors tName, " cannot
contain HTML"
End If
Case tNotSQL
If Not ContainsSQL(tValue) Then
IsValid = True
Else
IsValid = False
ReDimErrors tName, " cannot
contain SQL statements"
End If
Case tLUHN
If LUHNCheck(tValue) Then
IsValid = True
Else
IsValid = False
ReDimErrors tName, " is not
a valid credit card number"
End If
End Select
Select Case IsValid
Case True
Tron.Trace "Validate", tName & _
" value [" &
tValue & "] is a valid " & _
TypeDescription(CInt(tType)) & " value."
Case false
Tron.Trace "Validate", tName & _
" value [" &
tValue & "] is NOT a valid " & _
TypeDescription(CInt(tType)) & " value."
End Select
End Function
Private Sub ReDimErrors(tName As String, tErrDesc As String)
Dim Rec()
' Select Case MyArrayCls.UboundC(Errors)
' Case -1
' ReDim Errors(0, 1)
' End Select
ReDim Rec(1)
Rec(0) = tName
Rec(1) = tErrDesc
Errors = MyArrayCls.AppendRecord(Errors, Rec)
End Sub
Public Function ClearErrors()
Dim nowt()
Errors = nowt
End Function
Public Function GetErrors() As Variant
GetErrors = Errors
End Function
Private Function AllowedChars(CheckString As String,
p_AllowedList As String) As Boolean
Dim l As Integer
AllowedChars = True
For l = 1 To Len(CheckString)
If Not InStr(p_AllowedList, Mid(CheckString, l, 1)) > 0 Then
AllowedChars = False
Exit Function
End If
Next
End Function
Private Function TypeDescription(TypeVal As Integer) As String
Select Case TypeVal
Case 0
TypeDescription = "Integer"
Case 1
TypeDescription = "Date"
Case 2
TypeDescription = "Email"
Case 3
TypeDescription = "NoSpaces"
Case 4
TypeDescription = "Required"
Case 5
TypeDescription = "Password"
Case 6
TypeDescription = "NotObscene"
Case 7
TypeDescription = "NotHTML"
Case 8
TypeDescription = "NotSQL"
Case 9
TypeDescription = "LUHN"
End Select
End Function
Public Property Get BadWordsINI() As String
BadWordsINI = m_BadWordsINI
End Property
Public Property Let BadWordsINI(ByVal New_BadWordsINI As String)
m_BadWordsINI = New_BadWordsINI
PropertyChanged "BadWordsINI"
End Property
'Initialize Properties for User Control
Private Sub UserControl_InitProperties()
m_BadWordsINI = m_def_BadWordsINI
End Sub
'Load property values from storage
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
m_BadWordsINI = PropBag.ReadProperty("BadWordsINI",
m_def_BadWordsINI)
End Sub
'Write property values to storage
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
Call PropBag.WriteProperty("BadWordsINI",
m_BadWordsINI,
m_def_BadWordsINI)
End Sub
Private Function IsObscene(tValue As String) As Boolean
Dim BWCount As Integer
Dim NoSpaces As String
IsObscene = False
NoSpaces = Strings.JustLetters(tValue)
Tron.Trace "Validate", "Checking message: '" &
tValue & "'"
If InStr(NoSpaces, "fuck") > 0 Then
Tron.Trace "Validate", "Found Obscenity!"
Tron.Trace "Validate", "Message contains
word 'fuck'."
IsObscene = True
Exit Function
End If
tValue = " " & tValue
lenmesstext = Len(tValue)
badwords = "rudeword1,rudeword2,etc"
If Not Len(m_BadWordsINI) = 0 Then
Tron.Trace "Validate", "Using Bad Words
INI file."
If Not
INIFile.LoadINIFile(m_BadWordsINI) Then
Tron.Trace "Validate",
"Could not load the INI file: " & _
m_BadWordsINI
badword = Split(badwords,
",")
Else
badword =
INIFile.GetKey("BadWords")
Tron.Trace "Validate",
"Loaded word list from INI File: " & _
m_BadWordsINI
End If
Else
badword = Split(badwords, ",")
End If
INIFile.CloseINI
bwc1 = UBound(badword)
badwords = ""
bwc2 = -1
Tron.Trace "Validate", "Pass 1 - Checking for all
words..."
' Pass 1
For BWCount = 0 To bwc1
If InStr(NoSpaces, badword(BWCount))
> 0 Then
Tron.Trace "Validate",
"Found what may be: '" & _
badword(BWCount)
& "'"
badwords = badwords &
badword(BWCount) & ","
bwc2 = bwc2 + 1
End If
Next
If bwc2 > -1 Then
'Pass 2 - Dynamic Array
badwords = Left(badwords, Len(badwords)
- 1)
Tron.Trace "Validate",
"Pass 2 - Message may be
obscene - Checking: " & badwords
badword = Split(badwords, ",")
For N = 1 To lenmesstext
For BWCount = 0 To bwc2
testbw = " "
& badword(BWCount)
NoSpaces =
Mid(tValue, N, 1) &
Strings.JustLetters(Mid(tValue, N + 1, lenmesstext))
'Trace(
"NoSpaces:" & nospaces)
'Trace(
"Testing:" & mid(nospaces,1,len(testbw)))
'Trace(
"Against:" & testbw)
If
LCase(Mid(NoSpaces, 1, Len(testbw))) = LCase(testbw) Then
Tron.Trace "Validate", "Found Obscenity!"
Tron.Trace "Validate", "Message contains word '" & Trim(testbw)
& "'."
IsObscene = True
Exit
Function
End If
Next
Next
End If
End Function
Private Function ContainsHTML(tValue As String) As Boolean
If InStr(tValue, "<") > 0 Then
ContainsHTML = True
Else
ContainsHTML = False
End If
End Function
Private Function ContainsSQL(tValue As String) As Boolean
tValue = LCase(tValue)
If InStr(tValue, "delete") > 0 Or InStr(tValue, "select")
> 0 & _
Or InStr(tValue, "insert")
> 0 Or InStr(tValue, "update") > 0 & _
Or InStr(tValue, "exec")
> 0 Or InStr(tValue, "xp_") > 0 Then
ContainsSQL = True
Else
ContainsSQL = False
End If
End Function
Private Function LUHNCheck(CardNumber As String) As Boolean
Dim N, tot, x, chk, checkdigit
If Len(CardNumber) = 0 Then
LUHNCheck = False
Tron.Trace "Validate",
"Card Number [ " & CardNumber &
" ] is not a number"
Else
tot = 0
chk = Right(CardNumber, 1)
CardNumber = Left(CardNumber, Len(CardNumber) - 1)
For N = Len(CardNumber) To 1 Step -2
x = CInt(Mid(CardNumber, N, 1)) * 2
If Len(x) > 1 Then
tot = tot + CInt(Mid(x, 1,
1))
'debug mid(x,1,1)
tot = tot + CInt(Mid(x, 2,
1))
'debug mid(x,2,1)
Else
tot = tot + CInt(Mid(x, 1,
1))
'debug mid(x,1,1)
End If
Next
For N = Len(CardNumber) - 1 To 1 Step -2
tot = tot + CInt(Mid(CardNumber, N, 1))
'debug mid(CardNumber,n,1)
Next
'debug tot
checkdigit = CInt(CStr(CInt(Left(CStr(tot), 1)) + 1)
& "0") - tot
Tron.Trace "Validate",
"LUHN Checkdigit should be " &
checkdigit
Tron.Trace "Validate",
"Actual LUHN Check Digit " & chk
If CInt(chk) = CInt(checkdigit) Then
LUHNCheck = True
Else
LUHNCheck = False
End If
End If
End Function
Original Tutorial
Submitted by nokia for TheTAZZone-TAZForum
Originally posted on March 7th, 2006 here
Do not use, republish, in whole or in part, without the consent of
the Author. TheTAZZone policy is that Authors retain the rights to the
work they submit and/or post...we do not sell, publish, transmit, or
have the right to give permission for such...TheTAZZone merely retains
the right to use, retain, and publish submitted work within it's
Network.

