Results 1 to 5 of 5

Thread: Web Exploits - Don't be a victim

  1. #1
    Senior Member
    Join Date
    Apr 2002
    Posts
    324

    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
    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, "") 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, "****") > 0 Then
          Tron.Trace "Validate", "Found Obscenity!"
          Tron.Trace "Validate", "Message contains word '****'."
          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
    \"I may not agree with what you say, but I will defend to the death your right to say it.\"
    Sir Winston Churchill.

  2. #2
    Senior Member
    Join Date
    Apr 2002
    Posts
    324
    To whomever just left the message:
    [{that} Looks like it was a lot of trial and error
    can I just say thank-you for the belly laugh! (Trial and error - validation - get it? nevermind)
    \"I may not agree with what you say, but I will defend to the death your right to say it.\"
    Sir Winston Churchill.

  3. #3
    really good actually

  4. #4
    Senior Member
    Join Date
    Jul 2002
    Posts
    154
    Nice one ntsa. Just wanted to add, people need to be extremely careful when implementing "get" scripts, because, another way somebody can exploit the server, is to add their own page "...?http://blah.com", and load their won page that does whatever to the server that runs it. Perhaps checks it out for vulnerabilities, or gives you a list of hard drives, physical locations, specs, there are many scripts that do that.

  5. #5
    Junior Member
    Join Date
    Mar 2003
    Posts
    20
    Nice leg work ntsa.
    There is a easy way to secure this on dbs like MS Access, on a physical level.
    When I do standard SQL Selects ( 90% of the time) I open the db in read only.
    When I actually update info in someway, that is when I open it for writing, the info passing through it is heavily analyzed.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •