SQLiDetect: A WEB BASED INTRUSION DETECTION APPLICATION FOR SQL INJECTIONS Priyanka J. Hatwalne B.E., Pune University, India, 2006 PROJECT Submitted in partial satisfaction of the requirements for the degree of MASTER OF SCIENCE in COMPUTER SCIENCE at CALIFORNIA STATE UNIVERSITY, SACRAMENTO FALL 2011 SQLiDetect: A WEB BASED INTRUSION DETECTION APPLICATION FOR SQL INJECTIONS A Project by Priyanka J. Hatwalne Approved by: __________________________________, Committee Chair Scott Gordon, Ph. D. __________________________________, Second Reader Meiliu Lu, Ph. D. __________________________ Date ii Student: Priyanka J. Hatwalne I certify that this student has met the requirements for format contained in the university format manual, and that this project is suitable for shelving in the Library and credit is to be awarded for the Project. ______________________________, Graduate Coordinator Nikrouz Faroughi, Ph. D Department of Computer Science iii ________________ Date Abstract of SQLiDetect: A WEB BASED INTRUSION DETECTION APPLICATION FOR SQL INJECTIONS by Priyanka J. Hatwalne Databases often store personal information such as addresses, phone numbers, bank account details, and social security numbers. SQL injection attacks can cause serious threat to applications that access this kind of information through the internet, as with this kind of attack hackers can get unrestricted access to sensitive information. Though many individuals and organizations have proposed different methods to solve this problem, they either fail to address the entire scope of the problem or are too expensive for many users to adopt. SQLiDetect is an attempt to provide a comprehensive solution to SQL injections, incorporating a detection model and a business model. The detection model uses signature-based pattern matching to check for probable SQL injections, while the business model blocks the IP address from where a hacker attempts to intrude into the system. It also provides a flexible tracking and reporting system to monitor attacks. Approved by: _____________________________, Committee Chair Scott Gordon, Ph. D. __________________________ Date iv ACKNOWLEDGEMENTS While working on this project many people have helped me achieve my goal. I would like thank Dr Scott Gordon for investing his invaluable time reviewing this project. Without his support it would have been difficult to complete this project. I am also thankful to Dr Meiliu Lu for being second reader of this project I would like to take this opportunity to express my gratitude towards my parents, Mr. Jayant P. Hatwalne and Mrs. Anjali J. Hatwalne for their undying love and support. v TABLE OF CONTENTS Page Acknowledgements ..............................................................................................................v List of Tables ................................................................................................................... viii List of Figures .................................................................................................................... ix Chapter 1 INTRODUCTION ...................................................................................................1 2 BACKGROUND .....................................................................................................2 2.1 SQL ...................................................................................................................2 2.2 SQL Injections ..................................................................................................4 3 SQL INJECTIONS IN PRACTICE .........................................................................5 3.1 Finding Fields in a Table ...................................................................................6 3.2 Finding Tables in the Database .........................................................................6 3.3 Modify Records in the Table .............................................................................7 3.4 Multiple Queries or Stacking Queries................................................................8 3.5 Use of Union Keyword .....................................................................................9 3.6 String Manipulation .........................................................................................10 3.7 Multiline Comments ........................................................................................10 3.8 Blind SQL Injections .......................................................................................11 4 SQL INJECTION - EXISTING DETECTION SYSTEMS .................................... 12 vi 4.1 GreenSQL ........................................................................................................12 4.2 DotDefender .....................................................................................................12 4.3 Web Site Security Audit ..................................................................................13 4.4 Comparison Chart .................................................................................................... 14 5 DESIGN AND IMPLEMENTATION ..................................................................15 5.1 Basics ...............................................................................................................15 5.2 Component Interactions ...................................................................................15 5.3 SQLiDetect Database Design ..........................................................................16 5.3.1 Data Dictionary ....................................................................................18 5.3.2 Entity Relationship Model ...................................................................20 5.4 Detection Model...............................................................................................20 5.5 Business Model ................................................................................................21 5.6 Pseudocode for Business Checks ....................................................................23 5.7 Tracking Blacklisted IPs .................................................................................24 6 RESULTS ..............................................................................................................25 6.1 SQLiDetect User Interface ...............................................................................25 6.2 Test Cases ........................................................................................................28 7 CONCLUSION ......................................................................................................31 Appendix A: User Guide .............................................................................................33 Appendix B: SQLiDetect Source Code .......................................................................35 Bibliography ................................................................................................................57 vii LIST OF TABLES Page Table 4.1 Comparison of SQL Injection Prevention Systems ...........................................14 Table 5.3.1.1 USERS Table ...............................................................................................18 Table 5.3.1.2 BLACK_LIST Table ...................................................................................18 Table 5.3.1.3 INJECTIONS Table.....................................................................................18 Table 5.3.1.4 ATTACKS Table .........................................................................................19 Table 5.3.1.5 CONFIG_SETTINGS Table........................................................................19 Table 5.3.1.6 SETTING_TYPE Table ...............................................................................19 Table 5.3.1.7 SETTING_VALUE Table ...........................................................................19 viii LIST OF FIGURES Page Figure 3.1 Sample Query...................................................................................5 Figure 3.4 Languages - Databases Stack Query Support ..................................9 Figure 5.2 Component Interaction Diagram....................................................15 Figure 5.3 Entity Relationship Diagram for SQLiDetect ................................20 Figure 5.5 State Transition Diagram ...............................................................22 Figure 5.6 Pseudocode for Business Checks ..................................................23 Figure 6.1.1 Database Settings Interface ............................................................25 Figure 6.1.2 Register New Administrator Interface ...........................................25 Figure 6.1.3 Interface to Change Configuration Settings ...................................26 Figure 6.1.4 Attack Tracking Interface ..............................................................26 Figure 6.1.5 Attack Details Interface .................................................................27 Figure 6.1.6 Login Interface: Invalid Username or Password ...........................27 Figure 6.1.7 Login Interface: Input Contains Injection ......................................28 ix 1 Chapter 1 INTRODUCTION Database-backed applications are used widely all over. Databases are replacing the traditional spreadsheets in institutions such as hospitals, insurance providers, banks etc. To provide services at a faster pace to its customers these institutions provide information on the internet. The databases used in these places generally store sensitive personal information. People would never want their personal information like their names, addresses, phone numbers, credit card details and social security numbers to be disclosed. Great care must be taken to protect such information from reaching the wrong hands. In addition, as the information stored in these databases is accessed through the internet it increases the risk of being intercepted by external sources without being tracked. Databases not only used for storing and sharing purpose, they also provide features like fast and flexible searching, transactions, table structures, indexing, joins etc. These features simplify the work of the application developer to a large extent. The data can be retrieved from the database by writing SQL (Structured Query Language) code. Though SQL makes accessing data from the database easy, poorly written SQL code can be easily vulnerable to attacks. These attacks are called SQL injections. This report describes a system called as “SQLiDetect” that would be useful to secure sensitive information from such SQL exploits. It starts by introducing SQL injections, and then describes how SQLiDetect can be used to protect Databases against them. It also explains how the SQLiDetect system is implemented and provides a user guide. 2 Chapter 2 BACKGROUND 2.1 SQL SQL (pronounced as see-kwell) is standardized query language. It is specially designed for managing data in the database management systems. Databases store data in table format and each table contains a set of records. Each record in a table has same number of fields and same structure. Oracle, Sybase, Microsoft SQL Server, Access are some of the relational database management systems that use SQL. SQL was originally developed by IBM research center in 1975 but was first introduced commercially in 1979 by Oracle Corporation. It has been adopted as a standard by American National Standards Institute (ANSI) since 1986 and International Organization of Standards (ISO) since 1987. Its scope includes data insert, query, update and delete, schema creation and modification, and data access control [1]. It has gain popularity because its syntaxes are like simple sentences. Even a person with minimum programming skills can easily understand SQL code. Many applications combine SQL with other programming languages. SQL is used to store and retrieve data from the database, where as programming languages are used to process the data. These applications take input from the user and combine it with SQL statements which are then used to access data from the database. SQL statements are divided into four broad categories. 1. Queries: Queries or Select statements are the most common operations performed in SQL. Queries allow the user to describe desired data, leaving the database 3 management system (DBMS) responsible for planning, optimizing, and performing other operations necessary to produce the desired results [1]. Complex queries can be written in SQL, using different optional keywords and clauses like “from”, “where”, “and”, “or”, “order by”, “group by”, “having”, “Union”, “join” etc. 2. DML (Data Manipulation Language): DML is used to modify the data stored in the database. Insert, delete and update statements fall under this category. Each SQL DML statement is a declarative command. Sometimes query language is also considered to be a part of DML that involves information retrieval. 3. DDL (Data definition Language): DDL is used to define database objects. Database objects include schemas, tables, views, indexes, and aliases. Create, drop, truncate and alter statements of SQL belong to this category. 4. DCL (Data Control Language): DCL is used to secure a database. DCL statements control the access to the database by giving different privileges to different users. Grant and revoke statements belong to this category. Along with the standard SQL commands different database systems provide their own additional features. Example, in MySql “#” is used for single line comment while Oracle and MS SQL uses “--” to represent a comment. Similarly, MySQL uses concat() function for string concatenation. Whereas Oracle uses “||” between the strings to be concatenated and MS SQL uses “+” sign for the same purpose. Though these functionalities are provided to simplify the task of accessing data from the databases, bad guys can tweak these features to get access to restricted information. 4 2.2 SQL Injections SQL Injection is a code injection technique that exploits security vulnerability in some computer software [2]. The idea is to make the application run the SQL code that was not originally intended. These types of attacks are made to retrieve private information from the system, gain unauthorized access or to delete or change data from the system. SQL Injection Attacks are considered to be one of the top 10 web application vulnerabilities of 2010 by the Open Web Application Security Project [2]. SQL injection attacks can occur when user input is not properly filtered for escape characters or not checked for its type constraint and directly passed into SQL statements [2]. A special character can be escaped by adding a backslash before it. Some languages do provide inbuilt functions to filter user input. For instance in PHP, mysql_escpe_string () or mysql_real_escape_string () functions are used to escape special characters in a string that are used in a SQL statement. But there are some limitations to these functions and attackers can surpass these filters easily. 5 Chapter 3 SQL INJECTIONS IN PRACTICE Every application uses a user-name and a password for authentication purpose. Most of these applications have “forgotten password” link to retrieve the password. Using this link, password is emailed to the registered email address. The user has to confirm his/her registered email address. In this chapter, we will see how an attacker can retrieve password using SQL injections and some guess work. The attacker initially does not know anything about the database. He needs to find out the name of the table that stores the login information and name of the columns in that table. Attacker knows that query executed at the backend is of form: Select list_of_fields From table Where column_name = ‘$input’ Figure 3.1 Sample Query Here $input is the email address submitted by the user. Now let’s see a simpler form of injection. Suppose a user gives input as abc@example.com’ or ‘1’=’1. This would change the query to Select list_of_fields From table where column_name = ‘abc@example.com’ or ‘1’=’1’ Though the first part may evaluate to be false, the second part is always evaluated as true and hence the query returns all the records in the table. If the system does not 6 handle SQL injections then, depending upon how code handles the result of execution of such a query, either an error is produced or password would be sent to some random (mostly the first) email address in the result set. Though this will not cause any harm to the system, the random emails sent to different users may alert the system administrator. 3.1 Finding Fields in a Table Attacker intends to retrieve usernames and passwords to gain access over the targeted system. For this purpose, he needs to find the name of the table and fields of the query in Figure 3.1. This can be done through some guess work. Suppose attacker guesses the field name to be “email_id”. To check if the guess is right or wrong the attacker can give the input as “abc@ example.com’ and email_id = ’xyz@example.com”. The query executed at the backend will be Select list_of_fields From table Where column_name=‘abc@example.com’ and email_id= ’xyz@example.com’ [4] Though the above query will always return an empty record set, if email_id is not a field in the table then a SQL error will occur. Thus if the SQL error does not occur then the attacker knows that his guess is right. Also note that in the above query we have used “and” keyword instead of “or” keyword so that random emails containing passwords are not sent. 3.2 Finding Tables in the Database After finding out several field names using the method described in section 3.1, the attacker will want to find the name of the table used in the query shown in figure 3.1. 7 Suppose the attacker guess the name of the table as “users”. To confirm if the guess is write or wrong, he will give input as “xyz’ and 1<= select count (*) from users #”. The query executed at the backend will be Select list_of_fields From table Where email_id=‘ xyz’ and 1<= select count(*) from users #’ [4] In MySQL everything after “#” is ignored. “#” is used to represent single line comment. If the above query produces an error then either the guess is wrong or the database used in backend is not MySQL. Instead of using “#” one can try using “--”. MS SQL, Oracle and many other databases uses ‘--’ as single line comments. On the other hand if there is no error then the guessed table name exists in the database. Suppose the database used is MySQL then to confirm if the guessed table name is in fact the table used in the query the attacker can give input as “xyz’ and users.email_id is NULL #”. Thus the executed query is Select list_of_fields From table Where email_id=‘ xyz’ and users.email_id is NULL #’ [4] If the above query does not cause any SQL error then it is confirmed that the table used in the above query is named “users”. 3.3 Modify Records in the Table The attacker will try to update the email field of some random user in the users table. For this he will give input as “xyz’; Update users set email_id = ‘attackersid@examples.com’ where id = 1 #”. Here ‘id’ and ‘email_id’ are fields found 8 by the attacker using methods described in section 3.1. Thus two queries executed at backend. The first one is: Select list_of_fields From users Where email_id=‘xyz’; The second one is: Update users set email_id = ‘attackersid@examples.com’ where id = 1; Now the attacker can use the regular “forgot my password” link to get the password emailed to his email address. Using this password the attacker can get access to personal data of the original user. 3.4 Multiple Queries or Stacking Queries Sometimes the motive of the attack is not personal gains but to cause denial of service. If the attacker gave “xyz’; drop table users#” as an input to the query in figure 3.1 then, after executing the query “Select list_of_fields from users where email_id=‘xyz’;” the users table would be deleted and no one else would be able to access the system until the users table is restored. In the earlier example, the attacker could shut down the SQL server using “shutdown” keyword instead of “drop table users”. In these examples, two independent queries were executed in one transaction. This is called stacking of queries. But not all programming languages support stack queries. 9 Figure 3.4 Languages - Databases Stacked Query Support [3] Green: Stacked queries are supported. Red: Stacked queries not supported White: Unknown 3.5 Use of Union Keyword To recover the password, the query in Figure 3.1 can be manipulated in another way. Suppose the field list in this query was firstname, email_id, pass_word, then the user need to just guess the password field and the table name by the method specified in section 3.1 and give input as “xyz’ union select ‘some fake name’, ’attackersemail@abc.com’, pass_word from users limit 1” in this case the executed query is Select firstname, email_id, pass_word From users Where email_id = ‘xyz’ UNION select ‘some fake name’,’attackersemail@abc.com’, pass_word from users limit 1 Though the first part of the query does not return any record set the second part of the query will return password of the fist record in the table and spoof in firstname and email address with specified values. Note that this attack does not include two 10 independent queries. So it not an example stacking queries. It is thus supported by all the programming languages. 3.6 String Manipulation String related operations can be quite useful in building up injections and creating different variations. Earlier in this chapter we saw how “or ‘1’=’1’ ” was used to force the query to return result set. Using string concatenation, variations could be created which would make it difficult for parsers to recognize the injections. String concatenation in MS SQL is done using ‘+’ signs. Thus “or ‘aaa’= ‘aaa’ ” is equivalent to “or ‘aaa’ = ‘a’ + ‘aa’ ”. Similarly inbuilt factions like char() and ascii() can be used to build variations in injections. Example ‘a’ = ‘a’ can be written as ‘a’ = char(97) and 97 = 97 can be written as 97 = ascii(“a”). Instead of using a semicolon or quote characters, char (39) or char (59) can be used to build injection variations. Such Attacks cannot be caught by functions like mysql_escpe_string discussed earlier in section 2.2. 3.7 Multiline Comments Another very important string manipulation technique used to create variations is inserting multiline comments in between the SQL queries. In SQL /* */ is used for multiline comments. Consider the following query. Select firstname, email_id, pass_word From users where email_id = ‘xyz’ UNI/*a comment in between*/ON select ‘some fake name’,’attackersemail@abc.com’, pass_word from users limit 1 As everything between and including /* and */ is ignored, the above query is same as 11 Select firstname, email_id, pass_word From users where email_id = ‘xyz’ UNION select ‘some fake name’,’attackersemail@abc.com’, pass_word from users limit 1 3.8 Blind SQL Injections Application that use databases try to ensure, that errors and exceptions are not exposed to the front end user. So that it becomes difficult for attackers to come up to any conclusions while trying error based attacks. For this purpose blind SQL injections are used. There are two types of Blind SQL Injections. Normal Blind: Response cannot be seen but result of the query can be determined based on HTTP status code. Total Blind: No difference can be seen in the output. In normal blinds you can use if statements in the injection. In totally blinds you need to use some waiting functions and analyze response times. For this you can use WAIT FOR DELAY '0:0:10' in MS SQL Server, BENCHMARK() in MySQL, pg_sleep(10) in PostgreSQL, and some PL/SQL tricks in ORACLE [5]. 12 .Chapter 4 SQL INJECTION - EXISTING DETECTION SYSTEMS There are many individuals and organizations working to provide solutions for SQL injections. Some of them identify the injections at runtime while others identify vulnerabilities in the source code that should be fixed in order to protect the database against SQL Injections. Following are some services that are currently used in the software industry to protect SQL databases. 4.1 GreenSQL GreenSQL is an Open Source database firewall that is used to protect databases from SQL injection attacks [6]. It supports MySQL and MS SQL databases. It has two different releases for each of them. The MySQL version is free and open source software but the MS SQL version requires a license. GreenSQL maintains a list of white-listed queries and every time it finds a query with potential risk it is blocked. A user can modify this behavior by adding patterns to the white-list. GreenSql has advanced parsers to detect and block injections but it does have any functionality to block the users who persistently try to intrude into the system. Also nothing much is said in the documentation about reporting or monitoring of attacks. 4.2 DotDefender DotDefender is a web application firewall that offers security against known and emerging hacking attacks. It is a multi-platform solution running on Apache and IIS web servers. DotDefender helps you achieve compliance with the Payment Card Industry Data 13 Security Standard [7]. However it is expensive software. The annual license costs $1,810. This is unaffordable for applications that are developed on small scale. Architected as plug & play software, DotDefender provides optimal out-of-thebox protection against SQL Injection attacks, cross-site scripting, website defacement and many other web attack techniques. The Pattern Recognition web application security engine employed by DotDefender effectively protects against malicious behavior such as SQL Injection and Cross Site Scripting [7]. The patterns are regular expression-based and designed to efficiently and accurately identify a wide range of application-level attacks. DotDefender is characterized by an extremely low false positive rate. 4.3 Web Site Security Audit (WSSA) WSSA is a service provided to find SQL Injection security holes in a system by guys registered as “Beyond Security”. It is an inexpensive service that costs a fee of $29 for a monthly subscription. There is no need to install anything on the users system. Everything is done by servers of the service provider and the scan is done remotely over the Internet. The user’s just need to register their domain name and email address with Web Site Security Audit and WSSA will perform some scans and email the reports. ? The reports sent by WSSA contain information about the loop holes in the system. It is up to the application developer to fix these loop holes. Thus this system is not useful to block attacks at run time. 14 4.4 Comparison Chart Table 4.4 Comparisons of SQL Injection Prevention Systems Point of Distinction SQLiDetect GreenSql DotDefender WSSA Compares the input against predetermined injection patterns. Compares the query to be executed against white listed patterns. Databases Support Any MySQL, MS Sql Any Any Reports Web based repots with searching and sorting functionality. Text based logs Not available Email Cost Free MySQL support: Annual license Monthly Free, MS SQL $1810 License: $29 support: unknown Platform PHP Unknown Apache and IIS web servers Unknown Blocking queries yes Yes yes No How it works Uses a set of security rules Perform code scans to find loop holes in system. 15 Chapter 5 DESIGN AND IMPLEMENTATION 5.1 Basics SQLiDetect is a system used to protect Databases used by other applications from SQL injections. It detects the SQL injections from the user input and blocks execution of queries which are formed using such inputs. In addition it also bans the IP addresses of users who frequently try to intrude into the system using SQL injections. This system provides single solution to any type of database used in the backend of PHP applications. This means that if the application changes its database from MySQL to MS SQL the injection checks would not fail. 5.2 Component Interactions Figure 5.2 shows how the SQLiDetect components will interact with the system using it. Figure 5.2 Component Interaction Diagram 16 SQLiDetect is used to protect an application database. In the process, it also maintains its own database for tracking SQL attacks and business rules. In this document, these two databases will be referred to as the application database and the SQLiDetect database, respectively. Applications written in any language that can embed PHP code into it can use SQLiDetect. The end user will continue to interact with the application using the application interface. When the application code that resides on the server gets this input it is sent to SQLiDetect. SQLiDetect interacts with its own database and scans the input for SQL injections. If the input is free of injections and other business checks are passed then the SQLiDetect signals the application code that it is safe to access the application database by executing the query that contains this input. The business checks would be described later in this chapter. In addition the SQLiDetect code is divided into two parts. First part is used to interact with application code to detect injections and the second part is used for generating tracking reports for the attacks. 5.3 SQLiDetect Database Design SQLiDetect uses a MySQL database to store all the information related to SQL injections. The user needs to feed MySQL server details such as host address, username and password while installing the system. There are seven relational database tables, namely USERS, BLACK_LIST, INJECTIONS, ATTACK, CONFIG_SETTINGS, SETTING_TYPES and SETTING_VALUES used in this system. All these tables are created while installation. INJECTIONS, CONFIG_SETTINGS and SETTING_TYPES 17 tables store default values. These values are also inserted into the respective tables while installation. The USERS table stores the login details of the users who are allowed to access the SQLiDetect database to track the attacks on the application database. BLACK_LIST table is used for storing information of IP addresses of attackers who try to intrude into the system. INJECTIONS table stores all the types of injections the system can detect. ATTACK table stores type of injection a blacklisted user used to intrude into the system. CONFIG_SETTINGS table stores ways in which a black listed user can be blocked. SETTING_TYPES table contains the units of SETTING_VALUES. SETTING_VALUES table is used to store values of blocking limits for different configuration settings. It is a join of CONFIG_SETTING and SETTING_TYPE. CONFIG_SETTINGS, SETTING_TYPES and SETTING_VALUES together store business rules such as, “block IP temporarily for 8 hours” or “block IP permanently after 3 resets”. 18 5.3.1 Data Dictionary Table 5.3.1.1 USERS Table Table 5.3.1.2 BLACK_LIST Table Table 5.3.1.3 INJECTIONS Table Injection_name takes values like “comment attack”, “and/or attack”, “union attack”, “Stacked queries attack”, “string manipulation attack” etc. 19 Table 5.3.1.4 ATTACKS Table Table 5.3.1.5 CONFIG_SETTINGS Table Block_status takes values like “never blocked”, “temporary blocked”, “reset” and “permanent blocked”. Table 5.3.1.6 SETTING_TYPE Table Setting_unit column takes values such as “Minutes”, “Hours”, “Days”, “Months”, “Years”, “count” etc. Table 5.3.1.7 SETTING_VALUE Table 20 Though the contents of SETTING_VALUE table are configured while installation, they can be changed anytime as required. 5.3.2 Entity Relationship Model Figure 5.3 Entity Relationship Diagram for SQLiDetect 5.4 Detection Model SQLiDetect uses signature based method for detecting attacks. SQLiDetect tries to matches the input string with certain pre-configured and pre-determined attack patterns. These patterns are called signatures. Signatures are regular expressions. If input string matches with any of these patterns, then the system will signal the application code to forbid the execution of the query that will be formed using this input string. The 21 preg_match function in PHP is used for the pattern matching purpose. In addition, checks are also written in order to reduce false positive or false negative results. Following are some examples where additional checks are required. Consider the following query. Select * from table where column = ‘$input’ If the $input contains value “xyz’ or ‘a’ = ‘a” then the input contains SQL contains injection but if it contains value “ xyz’ or ‘a’ = ‘b” then it is not an injection. The right side of “or” keyword will always return a false value. Thus the outcome of this query still depends upon the left side part of the ‘or’ keyword. It is impossible to write a regular expression that will assure that both the side of equal to sign match. In this case a pattern match only means that there is a probability that the query may contain injection but we need more checks. Multiline comments all by themselves do not pose any danger to the database but they are used to produce variations in other types of attacks. For this purpose everything in between and including “/*” and “*/” is replaced by white spaces and then this newly formed string is check for injections. Similarly, functions like char, ascii or concat must be used in very specific way to make SQL query run successfully. To make sure that these functions are actually used for generating SQL injection attacks, these functions are replaced with their actual values and then checked for injections. 5.5 Business Model The user initializes following values during installation. 22 The IP address will be blocked temporarily after ____ injections are encountered from a particular IP. We will henceforth call this value as allowed_block_count. The Temporarily blocked IP address will be unblocked and its status would be made as reset after ____ amount of time. We will henceforth call this value as temp_block_time. The IP address will be blocked permanently after it is temporarily blocked for ____ times. We will henceforth call this value as allowed_reset_count. Figure 5.5 State Transition Diagram Figure 5.5 shows how business checks are performed in SQLiDetect. 23 5.6 Pseudocode for Business Checks If IP address not in blacklist table Set block_count and reset_count to 0 and block_status = 'never blocked' go to step Next Else if IP is permanently blocked Signal application code to block the query. Stop Else if it is temporarily blocked If time since last attack is more than temp_block_time Set block_status to reset Increment the reset_count and rest the block_count to 0. Go to step Next Else Signal the application code to block the query. Stop Endif Endif Next: Scan the input for probable injections. If the input is clean Signal the application code to proceed with the query Else Increment the block count. If block_count > allowed_block_count and rest_count allowed_reset_count Block status = 'permanent block' Else if block_count > allowed_block_count Block status = 'temporarily blocked' End if Add an entry to record the injection in the attack table. Send an email alert to the administrator of the application. If the IP address not in blacklist table add IP address to Blacklist Table Else update the entry of IP address in blacklist table EndIF signal the application code to block the query. End If Figure 5.6 Pseudocode for Business Checks > 24 5.7 Tracking Blacklisted IPs: SQLiDetect can generate reports to track the attacks. SQLiDetect provides a web based GUI for this purpose. The administrator will have to log into the SQLiDetect System to view the list of all the blacklisted IPs. The Administrator can search blacklisted IP according to last attack time or block status. There is a separate web page to view the attack history of a particular blacklisted IP. Administrator can manually block or unblock the blacklisted IP’s. While manually blocking any IP address, the block_status is changed to permanently block. On the other hand while manually unblocking an IP address, the reset_count is incremented and block_status is set to “reset”. 25 Chapter 6 RESULTS 6.1 SQLiDetect User Interface The system provides web interface to configure system settings and to monitor the attacks. Following are the screen shots of the web interfaces used in the system. Figure 6.1.1 Database Settings Interface Figure 6.1.2 Register New Administrator Interface 26 Figure 6.1.3 Interface to Change Configuration Settings Figure 6.1.4 shows the screen that is used to track blacklisted IP addresses. Along with the IP addresses it also shows time of last attack from the blacklisted IP, its block status and details about number of attempts. It also shows list of search criteria. Figure 6.1.4 Attack Tracking Interface 27 Figure 6.1.5 shows attack history screen. It displays details of all the attacks from a particular IP address. The administrator can also manually block or unblock IP address here. Figure 6.1.5 Attack Details Interface Figure 6.1.6 shows the Login screen with error message “invalid user name or password”. This message is displayed when the input username and password don’t match with those in the users table and the input does not contain any SQL injections. On the other hand error message “invalid input” is displayed when an SQL Injection is detected. . Figure 6.1.6 Login Interface: Invalid Username or Password 28 Figure 6.1.7 Login Interface: Input Contains Injection 6.2 Test Cases For the testing purpose an interface is designed. This Interface takes email address as an input. The message “Query executed successfully” is displayed if a valid email address is given as a input, else if input contains any SQL injections it echoes the message “Injection detected”, otherwise it simply displays message, “Invalid input”. The query that is fired to the application database is Select username from users where email = ‘$input’ This system has been successfully tested for following injections in the input. Case 1: Input: “validemail@xyx.com” Output: “Query executed successfully.” Attacks: No attacks detected. Case 2: Input: “invalidemail@xyx.com” Output: “Invalid Input” Attacks: No attacks detected. Case 3: Input: “‘or ‘a” Output: “Injection Detected” Attacks: and/or. Case 4: Input: “‘or 1--” 29 Output: “Injection Detected” Attacks: and/or, comment. Case 5: Input: “‘ o/*comment*/r ‘a’ = ‘a” Output: “Injection Detected” Attacks: and/or, Multiline comment. Case 6: Input: “ xyz‘ oR 1 != 2 #” Output: “Injection Detected” Attacks: and/or, comment. Case 7: Input: “ xyz‘ oR 1 > 2 #” Output: “Injection Detected” Attacks: and/or, comment. Case 8: Input: “ xyz‘ oR 1 < 2 #” Output: “Injection Detected” Attacks: and/or, comment. Case 9 Input: “ xyz‘ and column_name = ‘some text” Output: “Injection Detected” Attacks: and/or. Case 10: Input: “xyz‘ union ‘abc ” Output: “Injection Detected” Attacks: union. Case 11: Input: “xyz‘ union select ‘abc’# ” Output: “Injection Detected” Attacks: union, commet . Case 12: Input: “xyz‘ union select column_name from some table #” Output: “Injection Detected” Attacks: union, comment attack. Case 13: Input: “xyz‘ union concat(‘valid’,’user’,’@xyz.com’)# ” Output: “Injection Detected” Attacks: union, string manipulation, comment. Case 14: Input: “xyz‘ union ‘valid’||’user’||’@xyz.com’# ” Output: “Injection Detected” Attacks: union, string manipulation, comment. 30 Case 15: Input: “xyz‘ union char(118) + char(97) + char(108) + char(105) + char(100) + char(117) + char(115) + char(101) + char(114) + char(64) + char(120) + char(121) + char(122) + char(46) + char(99) + char(111) + char(109)# ” Output: “Injection Detected” Attacks: union, string manipulation, comment. Case 16: Input: “xyz‘; drop table table # ” Output: “Injection Detected” Attacks: multiple queries, comment. Case 17: Input: “xyz‘; update table set column = ‘something” Output: “Injection Detected” Attacks: multiple queries. Case 18: Input: “xyz‘; delete from table#’” Output: “Injection Detected” Attacks: multiple queries, comment. Case 19: Input: “xyz‘ or ascii(‘a’)#’” Output: “Injection Detected” Attacks: and/or, string manipulation, comment. 31 Chapter 7 CONCLUSION SQL injections are a major threat as they could be used to leak personal information that is stored electronically. SQLiDetect was successfully developed to protect application databases from SQL Injections. Though the security goal of not letting unauthorized user access the database using SQL Injection can be easily achieved using SQLiDetect, the system can be enhanced further to achieve following goals. The system uses IP address for identifying an attacker. A proxy server allows users to conceal their IP address. If the attacker is using such a server then proxy IP is blocked. If at later point another user uses same IP then he won’t be able to access the application. This shortcoming needs to be addressed as it denies service to the innocent users. It is possible that an input string may contain an “and” word, preceded by single or double quotes and followed by any characters. Currently checks for “and” attacks used for detecting table names and column names gives false positive result in such cases. Additional checks could be written to avoid this. Support applications developed in languages that cannot embed PHP within them. A tool similar to SWIG can help developers to wrap PHP functions for use them with programming languages of their choice. A mobile phone application that will immediately notify the administrator upon detection of injection. 32 As long as sensitive information is made available online for its users, cyber criminals are going to find new ways to access such information. So as an when new attacks are discovered there would be a need to improve this system. 33 APPENDIX A User Guide Steps for Installation: Install PHP 5.3.8, MySQL 5.5 and Apache 2.2. PHP 5.3.8 can be downloaded from http://www.php.net/downloads.php. MySQL 5.5 can be downloaded from http://dev.mysql.com/downloads/installer/ Apache 2.2 can be downloaded from http://httpd.apache.org/download.cgi Create a database in MySQL using following query. “create database databasename” Unzip the SQLiDetect into the htdocs folder. This folder is present in the directory where Apache is installed. In the browser type the host name/install.php. Enter name of the database you just created, MySql host name, username and password to the MySQL server. Also select the type of application database used. Click on save. It will redirect you to create administrator page. After creating an administrator the web page will be redirected to configuration setting page. Make the changes to the configuration settings and save it. Now you are ready to use SQLiDetect with your application. Steps for using SQLiDetect: Include globals.php in your code. 34 Call the function SQLiDetect_check() and pass the input from the user to this function. SQLiDetect_check returns a Boolean value. True indicates clean input and false indicates presence of injection. Tracking Attacks: Type in the host name in the url followed by “\login.php” After you login into the system attacks can be tracked. 35 APPENDIX B SQLiDetect Source Code Detection Model Functions.php <?php include 'ConfigClass.php'; function sqlidetect_check($input) { $config = new ConfigClass(); $config->getInfo(); $goAhead = $config->allowed(); if($goAhead) { $multiline_comment_remove = remove_multiline_comment($input); if (strcmp($input,$multiline_comment_remove)==0) $comment = 0; else $comment = 1; $ascii_char_remove = replace_ascii_char($multiline_comment_remove); if (strcmp($ascii_char_remove,$multiline_comment_remove)==0) $ascii_attack = 0; else $ascii_attack = 1; $str_concat_remove = replace_str_concat($ascii_char_remove); if (strcmp($ascii_char_remove,$str_concat_remove)==0) $concat_attack = 0; else $concat_attack = 1; $a_o_attack = check_and_or($str_concat_remove); $c_attack = check_comment($str_concat_remove); $u_attack = check_union($str_concat_remove); $multi_query_attack = check_multiple_query($str_concat_remove); if($comment || $ascii_attack || $concat_attack || $a_o_attack || $c_attack || $u_attack || $multi_query_attack) { //echo "injection detected"; $config->change (); if($config->BLACK_LISTED=='n') { //insert $qry = "insert into BLACK_LIST (ip, last_attack_time, block_status, blk_count, reset_cnt) values ('".$_SERVER["REMOTE_ADDR"]."',now(),".$config->BLOCK_STATUS.",".$config>BLOCK_COUNT.",".$config->RESET_COUNT.")"; mysql_query($qry) or die(mysql_error()) ; $config->BLACK_LIST_ID = mysql_insert_id(); } else { //update $qry = "update BLACK_LIST set last_attack_time=now(),block_status=".$config>BLOCK_STATUS.",reset_cnt= ".$config->RESET_COUNT.",blk_count=".$config->BLOCK_COUNT." where id = $config>BLACK_LIST_ID"; mysql_query($qry) or die(mysql_error()) ; } 36 if( $c_attack == 1) { $qry = "select id from INJECTIONS where injection_name = 'comment'"; $result = mysql_query($qry) or die(mysql_error()) ; while ($row = mysql_fetch_array($result)) { $injection_id = $row['id']; } $qry = "insert into ATTACK (injection_id ,black_list_id,attack_query) values (".$injection_id.",".$config>BLACK_LIST_ID.",'".mysql_real_escape_string($input)."')"; mysql_query($qry) or die(mysql_error()) ; } if($comment) { $qry = "select id from INJECTIONS where injection_name = 'multi line comments'"; $result = mysql_query($qry) or die(mysql_error()) ; while ($row = mysql_fetch_array($result)) { $injection_id = $row['id']; } $qry = "insert into ATTACK (injection_id ,black_list_id,attack_query) values (".$injection_id.",".$config>BLACK_LIST_ID.",'".mysql_real_escape_string($input)."')"; mysql_query($qry) or die(mysql_error()) ; } if($a_o_attack) { $qry = "select id from INJECTIONS where injection_name = 'and-or'"; $result = mysql_query($qry) or die(mysql_error()) ; while ($row = mysql_fetch_array($result)) { $injection_id = $row['id']; } $qry = "insert into ATTACK (injection_id ,black_list_id,attack_query) values (".$injection_id.",".$config>BLACK_LIST_ID.",'".mysql_real_escape_string($input)."')"; mysql_query($qry) or die(mysql_error()) ; } if($concat_attack) { $qry = "select id from INJECTIONS where injection_name = 'String concatination'"; $result = mysql_query($qry) or die(mysql_error()) ; while ($row = mysql_fetch_array($result)) { $injection_id = $row['id']; } $qry = "insert into ATTACK (injection_id ,black_list_id,attack_query) values (".$injection_id.",".$config>BLACK_LIST_ID.",'".mysql_real_escape_string($input)."')"; mysql_query($qry) or die(mysql_error()) ; } if($u_attack) { $qry = "select id from INJECTIONS where injection_name = 'union'"; $result = mysql_query($qry) or die(mysql_error()) ; while ($row = mysql_fetch_array($result)) { $injection_id = $row['id']; } 37 $qry = "insert into ATTACK (injection_id ,black_list_id,attack_query) values (".$injection_id.",".$config>BLACK_LIST_ID.",'".mysql_real_escape_string($input)."')"; mysql_query($qry) or die(mysql_error()) ; } if($multi_query_attack) { $qry = "select id from INJECTIONS where injection_name = 'multiple queries'"; $result = mysql_query($qry) or die(mysql_error()) ; while ($row = mysql_fetch_array($result)) { $injection_id = $row['id']; } $qry = "insert into ATTACK (injection_id ,black_list_id,attack_query) values (".$injection_id.",".$config>BLACK_LIST_ID.",'".mysql_real_escape_string($input)."')"; mysql_query($qry) or die(mysql_error()) ; } if($ascii_attack) { $qry = "select id from INJECTIONS where injection_name = 'ASCII'"; $result = mysql_query($qry) or die(mysql_error()) ; while ($row = mysql_fetch_array($result)) { $injection_id = $row['id']; } $qry = "insert into ATTACK (injection_id ,black_list_id,attack_query) values (".$injection_id.",".$config>BLACK_LIST_ID.",'".mysql_real_escape_string($input)."')"; mysql_query($qry) or die(mysql_error()) ; } $qry = "select * from users"; $result = mysql_query($qry); $from = "From:no-reply@sqliban.com"; $subject = "Injection detected"; $body = "Hello Adminstrator,\n\t An SQL injection has been encountered at".date("M-d-Y, h:i:s A") . ".\n The IP adress of the host is ".$_SERVER["REMOTE_ADDR"].". For details about the attack click <a href='http://localhost/wbide/index.php/attacks.php?id=".$config->BLACK_LIST_ID."'>here</a>."; while ($row = mysql_fetch_array($result)) { if ($to) $to = $to.",".$row["email"]; else $to = $row["email"]; } //mail($to, $subject, $body,$form); //echo $to." ".$body; return 0; } else if($config->BLACK_LISTED=='y') { //update $qry = "update BLACK_LIST set last_attack_time=now(),block_status=".$config>BLOCK_STATUS.",reset_cnt= ".$config->RESET_COUNT.",blk_count=".$config->BLOCK_COUNT." where id = $config>BLACK_LIST_ID"; return 1; } else return 1; } 38 else { return 0; } } function check_multiple_query($filter_qry) { //$filter_qry = "select abBc from xy.x"; //echo $filter_qry; $pattern = "/(\\s*)'(\\s*);(\\s*)[select[a-zA-Z0-9_.,(\*)(\()(\))(\\s)]+from[a-zA-Z0-9_.,(\()(\))(\\s)]+|insert[a-zA-Z09_(\\s)]*into[a-zA-Z0-9_.,(\()(\))(\\s)]+[VALUES|VALUE|select|set]|drop[a-zA-Z0-9_(\\s)]*[table|database|schema][azA-Z0-9_.,(\()(\))(\\s)]|delete[a-zA-Z_(\\s)]*from[a-zA-Z0-9_.,(\*)(\()(\))(\\s)]|update(\\s+)[a-zA-Z0-9_.]+(\\s+)set/i"; //print_r($pattern); if(preg_match($pattern,$filter_qry,$match)) { // echo "multiple "; return 1; } return 0; } function replace_str_concat($filter_qry) { // $filter_qry = "select * from users where name = '' or 1+2 = 2+1"; $pattern = "/(([c|C][o|O][n|N][c|C][a|A][t|T])[\(]([a-zA-Z0-9,']*)[\)])/"; while(preg_match($pattern,$filter_qry,$match)) { $filter_qry=str_replace($match[0], $match[3], $filter_qry); $filter_qry = str_replace("','", "", $filter_qry); $filter_qry = str_replace(",", "", $filter_qry); } $filter_qry = preg_replace("/'[+|\|]'/", '', $filter_qry); $pattern = "/(([0-9]+)(\+)([0-9]+))/"; while(preg_match($pattern,$filter_qry,$match)) { $sum = $match[4]+$match[2]; $filter_qry=str_replace($match[0], $sum, $filter_qry); } return $filter_qry; } function replace_ascii_char($filter_qry) { $pattern = "/([c|C][h|H][a|A][r|R])[\\s*][\(](\\d+)[\)]/"; while(preg_match($pattern,$filter_qry,$match)) { $val = chr($match[2]); $val = "'".$val."'"; $filter_qry = str_replace($match[0], $val, $filter_qry); } $pattern = "/([aA][sS][cC][iI][iI])[\\s*][\(]'([a-zA-Z0-9!=@#$%^&*,()\[\]{}\\s]+'[\)+])/"; while(preg_match($pattern,$filter_qry,$match)) { $val = ord($match[2]); $filter_qry = str_replace($match[0], $val, $filter_qry); } return $filter_qry; } 39 function remove_multiline_comment($qry) { $pattern = "/*(\\s*)[a-zA-Z0-9!@#$%^&*,()\[\]{}(\\s)]*(\\s*)*/"; if(preg_match($pattern,$qry,$match)) { $qry = preg_replace($pattern, '', $qry); } return $qry; } function check_union($qry) { $pattern = "/'(\\s*)(u|U)(n|N)(i|I)(o|O)(N|n) /"; if(preg_match($pattern,$qry,$match)) { return 1; } else return 0; } function check_comment($qry) { #$qry = "update temp set bal='1' where id = 1 -- where"; $patern1 = "/('|[0-9]+)(\\s*)(#|--)/"; $patern = "/('|[0-9]+)(\\s*)where(\\s*)[a-zA-Z0-9!=@#$%^&*,()\[\]{}\\s]+ (\\s*)(#|--)/"; if(preg_match($patern,$qry,$match)||preg_match($patern1,$qry,$match)) { print_r($match); return 1; } else return 0; } function check_and_or($qry) { $patern = "/'(\\s*)(or|OR|Or|oR)(\\s+)'[a-zA-Z0-9!@#$%^&*,()\[\]{}]+'(\\s*)(=|<>)(\\s*)'[a-zA-Z09!@#$%^&*,()\[\]{}]+/"; if(preg_match($patern,$qry,$match)) { $parts = explode("'", $match[0]); if(($parts[2]==$parts[4] && strstr($parts[3],"="))||(($parts[2]!=$parts[4] && strstr($parts[3],"<>")))) return 1; else return 0; } else { $patern = "/'(\\s*)(or|OR|Or|oR)(\\s+)[0-9]+(\\s*)(=|<>)(\\s*)[0-9]+/"; if(preg_match($patern,$qry,$match)) { $parts = explode($match[2], $match[0]); $parts[1] = str_replace(' ', '', $parts[1]); if(strstr($parts[1],"=")) { $cmp_str = explode("=",$parts[1]); if($cmp_str[0]==$cmp_str[1]) return 1; 40 } else { $cmp_str = explode("<>",$parts[1]); if($cmp_str[0]!=$cmp_str[1]) return 1; } print_r($parts); } else { $patern = "/'(\\s*)(or|Or|oR|OR)(\\s+)([0-9]+|'[\.]+')/"; if(preg_match($patern,$qry,$match)) { return 1; } return 0; } return 0; } } ?> ConfigClass.php <?php class ConfigClass { //put your code here var $TB_AFTER; var $PB_AFTER; var $RESET_AFTER; var $BLACK_LISTED; var $LAST_ATTACK_TIME; var $BLOCK_STATUS; var $RESET_COUNT; var $BLOCK_COUNT; var $BLACK_LIST_ID; function getInfo() { $qry = "select * from SETTING_VALUES"; $result = mysql_query($qry) ; while ($row = mysql_fetch_array($result)) { if($row["id"]==1) $this->TB_AFTER = $row["settings_value"]; else if ($row["id"]==3) $this->PB_AFTER = $row["settings_value"]; else if ($row["id"]==2) $this->RESET_AFTER = $row["settings_value"]; } $qry = "select * from BLACK_LIST where ip = '".$_SERVER["REMOTE_ADDR"]."' "; $result = mysql_query($qry) or die(mysql_error()) ; if(mysql_num_rows($result)==0) { $this->BLACK_LISTED = 'n'; 41 $this->BLOCK_COUNT = 0; $this->RESET_COUNT= 0; $this->BLOCK_STATUS= 1; $this->BLACK_LIST_ID = 0; } else { $this->BLACK_LISTED = 'y'; while ($row = mysql_fetch_array($result)) { $this->BLACK_LIST_ID = $row["id"]; $this->LAST_ATTACK_TIME = $row["last_attack_time"]; $this->BLOCK_COUNT = $row["blk_count"]; $this->RESET_COUNT= $row["reset_cnt"]; $this->BLOCK_STATUS= $row["block_status"]; } } } function allowed() { if($this->BLACK_LISTED == 'n' ) return true; else if ($this->BLOCK_STATUS==1||$this->BLOCK_STATUS==3) return true; else if($this->BLOCK_STATUS==2) { if(time()- strtotime($this->LAST_ATTACK_TIME) >= $this->RESET_AFTER) { $this->BLOCK_STATUS = 3; $this->BLOCK_COUNT = 0; $this->RESET_COUNT ++; return true; } else { return false; } } else if($this->BLOCK_STATUS==4||$this->BLOCK_STATUS==5) return false; } function change() { $this->LAST_ATTACK_TIME = time(); if($this->BLOCK_STATUS == 1) { $this->BLOCK_COUNT++; if($this->BLOCK_COUNT>=$this->TB_AFTER) $this->BLOCK_STATUS=2; } else if($this->BLOCK_STATUS == 3) { if($this->RESET_COUNT>=$this->PB_AFTER) $this->BLOCK_STATUS=4; else { 42 $this->BLOCK_COUNT++; if($this->BLOCK_COUNT>=$this->TB_AFTER) $this->BLOCK_STATUS=2; } } } } ?> Tracking Model AtackList.php <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link href="styles.css" rel="stylesheet" type="text/css"> <link rel="stylesheet" type="text/css" media="all" href="jsdatepick-calendar/jsDatePick_ltr.min.css" /> <title>List</title> </head> <body> <?php session_start(); if(!session_is_registered("USERNAME")) header("Location:http://localhost/wbide/index.php/access_denied.php"); include 'globals.php'; mysql_connect($db_host,$db_user,$db_password)or die("cannot connect"); mysql_select_db($db_name)or die("cannot select DB"); $start = ""; $end = ""; $status =""; $ip =""; //print_r($_POST); if($_POST["search"]=="Search") { if($_POST["inputField1"]) { $date_arr = explode("-", $_POST[inputField1]); $start = " and Year(last_attack_time) >= ".$date_arr[2]." and MONTH(last_attack_time)>=".$date_arr[0]." and DAY(last_attack_time) >= ".$date_arr[1]; } if($_POST["inputField2"]) { $date_arr = explode("-", $_POST[inputField2]); $end = " and Year(last_attack_time) <= ".$date_arr[2]." and MONTH(last_attack_time)<=".$date_arr[0]." and DAY(last_attack_time) <= ".$date_arr[1]; } if($_POST["ip"]) $ip = " AND ip = '".$_POST["ip"]."'"; if($_POST["status"]) $status = " and block_status = ".$_POST["status"]; } if($_GET["ob"] == 1) $orderby = " ORDER BY ip desc"; else if ($_GET["ob"] == 2) 43 $orderby = " ORDER BY last_attack_time desc"; else if ($_GET["ob"] == 3) $orderby = " ORDER BY type_name desc"; else if ($_GET["ob"] == 4) $orderby = " ORDER BY blk_count desc"; else if ($_GET["ob"] == 5) $orderby = " ORDER BY reset_cnt desc"; else $orderby = " ORDER BY last_attack_time desc"; $qry = "Select BLACK_LIST.id, ip, last_attack_time , blk_count , reset_cnt, type_name from BLACK_LIST,CONFIG_SETTINGS where CONFIG_SETTINGS.id = BLACK_LIST.block_status "; if($start) $qry = $qry . $start; if($end) $qry = $qry .$end; if($ip) $qry = $qry .$ip; if($status) $qry = $qry .$status; if($orderby) $qry = $qry. $orderby ." limit 10"; //echo $qry; $result = mysql_query($qry) or die(mysql_error()); $qry = "select * from CONFIG_SETTINGS" ; $config = mysql_query($qry) or die(mysql_error()); ?> <div class="header"><br/> <span style="font-size: 30px;font-weight: bold; vertical-align: bottom;">SQLiBan For Administrator</span> <span style="font-weight: bold; margin-left: 600px;">Tracking</span> </div> <br /><br /> <table align="center" width="50%"><tr><td> <div class="top_nav"><a href="uninstall.php">Uninstall</a> | <a href="attacksList.php">Attack list</a> | <a href="register.php">Add users</a> | <a href="step3.php">Change configeration settings</a> | <a href="logout.php">Log out</a> </div> </td></tr></table> <br /><br /> <form name="search" action="attacksList.php" method="post"> <table align="center" width="80%" border="0"> <tr> <td> <table width="100%" align="center"> <tr> <td width ="10%"> From</td> <td width="40%"> <input type="text" size="12" name="inputField1" id="inputField1" onclick="javascript:show('inputField1')" /> </td> <td width="10%">To</td> <td> <input type="text" size="12" name="inputField2" id="inputField2" onclick="javascript:show('inputField2')" /></td> </tr> </table> </td> </tr> <tr> <td> <br /> 44 <table width="100%"> <tr> <td width ="10%">IP</td> <td width ="40%"><input name="ip"></td> <td width ="10%">Status</td> <td> <select name="status"><option value="0">Select </option> <?php while ($row = mysql_fetch_array($config)) { ?> <option value="<?php echo $row["id"]?>"> <?php echo $row["type_name"];?> </option> <?php } ?> </select> </td> </tr> <tr> <td></td> <td><br /><input type="submit" name="search" value="Search"></td> <td></td> </tr> </table> </td> </tr> </table> </form><br/><br /> <table align="center" width="80%"> <tr> <td> <table width="90%" border ="1" cellspacing="0" cellpadding="1"> <tr class="heaing"> <th class="heaing"><a href="?ob=1"> IP </a></th> <th><a href="?ob=2">Last attack time</a></th> <th><a href="?ob=3">Status</a></th> <th><a href="?ob=4">Number of attempts <br/>since last reset</a></th> <th><a href="?ob=5">Resets</a></th> </tr> <?php $ctr = 0; while ($row = mysql_fetch_array($result)) { if($ctr%2 == 0) { ?> <tr class="row_odd"> <?php } else { ?> <tr class="row_even"> <?php } $ctr++; ?> <td><a href="attacks.php?id=<?php echo $row["id"]?>"><?php echo $row["ip"]; ?></a></td> <td><?php echo $row["last_attack_time"];?></td> 45 <td><?php echo $row["type_name"];?></td> <td><?php echo $row["blk_count"];?></td> <td><?php echo $row["reset_cnt"];?></td> </tr> <?php } ?> </table> </td> </tr> </table> </body> </html> attacks.php <script type="text/javascript"> function validate(str) { var r=confirm("Are you sure you want to"+str+"this IP?"); if(r==true) document.blk_ublk.submit(); } </script> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link href="styles.css" rel="stylesheet" type="text/css"> <title>Details</title> </head> <body> <div class="header"> <span style="font-size: 30px;font-weight: bold; vertical-align: bottom;">SQLiBan For Administrator</span> <span style="font-weight: bold; margin-left: 600px;">Attack Details</span> </div> <br /><br /> <table align="center" width="50%"><tr><td> <div class="top_nav"><a href="uninstall.php">Uninstall</a> | <a href="attacksList.php">Attack list</a> | <a href="register.php">Add users</a> | <a href="step3.php">Change Config settings</a> | <a href="logout.php">Log out</a> </div> </td></tr></table> <br /><br /> <?php include 'globals.php'; session_start(); if(!session_is_registered("USERNAME")) header("Location:http://localhost/wbide/index.php/access_denied.php"); mysql_connect($db_host,$db_user,$db_password)or die("cannot connect"); mysql_select_db($db_name)or die("cannot select DB"); $qry = "Select injection_name,attack_query from INJECTIONS,ATTACK where black_list_id =".$_GET["id"] . " and INJECTIONS.id = ATTACK.injection_id"; //echo $qry; $result = mysql_query($qry) or die(mysql_error()); 46 $qry = "Select BLACK_LIST.id, ip, last_attack_time , blk_count , reset_cnt, type_name from BLACK_LIST,CONFIG_SETTINGS where CONFIG_SETTINGS.id = BLACK_LIST.block_status and BLACK_LIST.id =".$_GET["id"]; $black_list = mysql_query($qry) or die(mysql_error()); ?> <table align="center" width="80%"> <tr> <td> <table width="90%" border ="0" cellspacing="0" cellpadding="1"> <tr class="row_even"> <?php $row = mysql_fetch_array($black_list)?> <td><b>IP Address: </b><?php echo $row["ip"] ?></td> <td><b>Last Attack Time: </b><?php echo $row["last_attack_time"] ?></td> </tr> <tr class="row_even"> <td><b>Block Count: </b><?php echo $row["blk_count"] ?> <br/><b>Reset Count: </b><?php echo $row["reset_cnt"] ?></td> <td><b>Block Status : </b><?php echo $row["type_name"] ?> <br/> <form name="blk_ublk" action="block_unblock.php" method="post"> <input type="hidden" name="bl_id" value="<?php echo $_GET["id"]?>" /> <?php if($row["type_name"]=="permanaent") { ?> <input type="hidden" name="change_status" value="unblock" /> Click <span class="link" onclick="javascript: validate('unblock');">here</span> to Unblock this IP <?php } else { ?> <input type="hidden" name="change_status" value="block" /> Click <span class="link" onclick="javascript: validate('block');">here</span> to Block this IP <?php } ?> </form> </td> </tr> <tr class="heaing"> <th>Attack Type</th> <th>Input</th> </tr> <?php $ctr = 0; while ($row = mysql_fetch_array($result)) { if($ctr%2 == 0) { ?> <tr class="row_odd"> <?php } else { ?> <tr class="row_even"> <?php } 47 $ctr++; ?> <td><?php echo $row["injection_name"];?></td> <td><?php echo $row["attack_query"];?></td> </tr> <?php } ?> </table> </td> </tr> </table> </body> </html> Block_unblock.php <?php include 'globals.php'; mysql_connect($db_host,$db_user,$db_password)or die("cannot connect"); mysql_select_db($db_name)or die("cannot select DB"); if($_POST["change_status"] == "block") $qry = "update black_list set block_status = 4 where id =".$_POST["bl_id"]; else if ($_POST["change_status"] == "unblock") { $qry = "select reset_cnt from black_list where id =".$_POST["bl_id"]; $result = mysql_query($qry) or die(mysql_error()); $row = mysql_fetch_array($result); $cnt = ++$row["reset_cnt"]; $qry = "update black_list set block_status = 3, reset_cnt =". $cnt ." where id =".$_POST["bl_id"]; echo $qry; } mysql_query($qry) or die(mysql_error()); header("Location: attacks.php?id=".$_POST["bl_id"]); ?> Installation Model Index.php <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link href="styles.css" rel="stylesheet" type="text/css"> <title>Install</title> </head> <body> <?php include 'globals.php'; include 'functions.php'; // put your code here if($_POST['Save']=='Save') { $fp=fopen("globals.php","w"); if($fp) 48 { $str = "<?php $db_user = '".$_POST["username"]."' ; $db_host = '".$_POST["hostname"]."'; $db_password = '".$_POST["pwd"]."'; $db_name = '".$_POST["databasename"]."'; $db_type = '".$_POST["db_type"]."'; $install = 1; ?>"; fwrite($fp, $str); mysql_connect($_POST["hostname"], $_POST["username"], $_POST["pwd"])or die("cannot connect"); mysql_select_db($_POST["databasename"])or die("cannot select DB"); $sql="Create table USERS (id integer NOT NULL AUTO_INCREMENT,first_name varchar(15), last_name varchar(15), user_name varchar(15), pass_word varchar (40), email varchar(40), last_login timestamp, primary key (id) )"; mysql_query($sql) or die("cannot create users table"); $sql="Create table CONFIG_SETTINGS(id integer NOT NULL AUTO_INCREMENT, type_name varchar(30) , primary key (id))"; mysql_query($sql) or die("cannot create CONFIG_SETTINGS table"); $sql = "insert into CONFIG_SETTINGS values (1,'neverblocked')"; mysql_query($sql) or die(mysql_error()); $sql = "insert into CONFIG_SETTINGS values (2,'temporary')"; mysql_query($sql) or die(mysql_error()); $sql = "insert into CONFIG_SETTINGS values (3,'reset')"; mysql_query($sql) or die(mysql_error()); $sql = "insert into CONFIG_SETTINGS values (4,'permanaent')"; mysql_query($sql) or die(mysql_error()); $sql = "insert into CONFIG_SETTINGS values (5,'autoblocked')"; mysql_query($sql) or die(mysql_error()); $sql="Create table SETTING_TYPES (id integer NOT NULL AUTO_INCREMENT, setting_type_name varchar(50) , primary key (id))"; mysql_query($sql) or die("cannot create SETTING_TYPES table"); $sql = "insert into SETTING_TYPES values (1,'time')"; mysql_query($sql) or die(mysql_error()); $sql = "insert into SETTING_TYPES values (2,'number')"; mysql_query($sql) or die(mysql_error()); $sql="Create table SETTING_VALUES (id integer NOT NULL AUTO_INCREMENT, settings_value integer, settings_type integer, config_type integer , primary key (id) , FOREIGN KEY (config_type ) references CONFIG_SETTINGS(id) , FOREIGN KEY (settings_type) references SETTING_TYPES(id))"; mysql_query($sql) or die("cannot create SETTING_VALUES table"); $sql = "insert into SETTING_VALUES values (1,3,2,2)"; mysql_query($sql) or die(mysql_error()); $sql = "insert into SETTING_VALUES values (2,480,1,2)"; mysql_query($sql) or die(mysql_error()); $sql = "insert into SETTING_VALUES values (3,2,2,3)"; mysql_query($sql) or die(mysql_error()); $sql="Create table INJECTIONS (id integer NOT NULL AUTO_INCREMENT, injection_name varchar(30) , primary key (id))"; mysql_query($sql) or die("cannot create INJECTIONS table"); $sql = "Insert into INJECTIONS (injection_name) value ('comment')"; 49 mysql_query($sql) or die(mysql_error()); $sql = "Insert into INJECTIONS (injection_name) value ('and-or')"; mysql_query($sql) or die(mysql_error()); $sql = "Insert into INJECTIONS (injection_name) value ('union')"; mysql_query($sql) or die(mysql_error()); $sql = "Insert into INJECTIONS (injection_name) value ('multple queries')"; mysql_query($sql) or die(mysql_error()); $sql = "Insert into INJECTIONS (injection_name) value ('String concatination')"; mysql_query($sql) or die(mysql_error()); $sql = "Insert into INJECTIONS (injection_name) value ('ASCII')"; mysql_query($sql) or die(mysql_error()); $sql = "Insert into INJECTIONS (injection_name) value ('multi line comments')"; mysql_query($sql) or die(mysql_error()); $sql="Create table BLACK_LIST (id integer NOT NULL AUTO_INCREMENT, ip varchar (30), last_attack_time timestamp, block_status integer, blk_count integer, reset_cnt integer, primary key (id) , FOREIGN KEY (block_status) references CONFIG_SETTINGS(id))"; mysql_query($sql) or die("cannot create BLACK_LIST table"); $sql="Create table ATTACK(id integer NOT NULL AUTO_INCREMENT, black_list_id integer, injection_id integer, attack_query text , primary key (id) , FOREIGN KEY (black_list_id) references BLACK_LIST (id), FOREIGN KEY (injection_id) references INJECTIONS(id) )"; mysql_query($sql) or die("cannot create ATTACK table"); } //redirect to register header('Location:http://localhost/wbide/index.php/register.php'); } else if($install) { if(mysql_connect($db_host,$db_user,$db_password)) { if(mysql_select_db($db_name)) { //check if all tables exist if( !mysql_num_rows( mysql_query("SHOW TABLES LIKE 'USERS'"))) { $sql="Create table USERS (id integer NOT NULL AUTO_INCREMENT, first_name varchar(15), last_name varchar(15), user_name varchar(15), pass_word varchar (40), email varchar(40), last_login timestamp, primary key (id) )"; mysql_query($sql) or die("cannot create users table"); } if( !mysql_num_rows( mysql_query("SHOW TABLES LIKE 'CONFIG_SETTINGS'"))) { $sql="Create table CONFIG_SETTINGS(id integer NOT NULL AUTO_INCREMENT, type_name varchar(15) , primary key (id))"; mysql_query($sql) or die("cannot create CONFIG_SETTINGS table"); } if( !mysql_num_rows( mysql_query("SHOW TABLES LIKE 'SETTING_TYPES'"))) { 50 $sql="Create table SETTING_TYPES (id integer NOT NULL AUTO_INCREMENT, setting_type_name varchar(50) , primary key (id))"; mysql_query($sql) or die("cannot create SETTING_TYPES table"); } if( !mysql_num_rows( mysql_query("SHOW TABLES LIKE 'SETTING_VALUES'"))) { $sql="Create table SETTING_VALUES (id integer NOT NULL AUTO_INCREMENT, settings_value integer, settings_type integer, config_type integer , primary key (id) , FOREIGN KEY (config_type ) references CONFIG_SETTINGS(id) , FOREIGN KEY (settings_type) references SETTING_TYPES(id))"; mysql_query($sql) or die("cannot create SETTING_VALUES table"); } if( !mysql_num_rows( mysql_query("SHOW TABLES LIKE 'INJECTIONS'"))) { $sql="Create table INJECTIONS (id integer NOT NULL AUTO_INCREMENT, injection_name varchar(30) , primary key (id))"; mysql_query($sql) or die("cannot create INJECTIONS table"); } if( !mysql_num_rows( mysql_query("SHOW TABLES LIKE 'BLACK_LIST'"))) { $sql="Create table BLACK_LIST (id integer NOT NULL AUTO_INCREMENT, ip varchar (30), last_attack_time timestamp, block_status integer, blk_count integer, reset_cnt integer, primary key (id) , FOREIGN KEY (block_status) references CONFIG_SETTINGS(id))"; mysql_query($sql) or die("cannot create BLACK_LIST table"); } if( !mysql_num_rows( mysql_query("SHOW TABLES LIKE 'ATTACK'"))) { $sql="Create table ATTACK(id integer NOT NULL AUTO_INCREMENT, black_list_id integer, injection_id integer, attack_query text , primary key (id) , FOREIGN KEY (black_list_id) references BLACK_LIST (id), FOREIGN KEY (injection_id) references INJECTIONS(id) )"; mysql_query($sql) or die("cannot create ATTACK table"); } } $result = mysql_query("select id from users"); //if yes check if user registered if(mysql_num_rows($result)) header("Location:http://localhost/wbide/index.php/login.php"); else header('Location:http://localhost/wbide/index.php/register.php'); } } ?> <div class="header"> <span style="font-size: 30px;font-weight: bold; vertical-align: bottom;">SQLiBan Configuration </span> <span style="font-weight: bold; margin-left: 600px;">Database Settings</span> </div> <br /><br /> <table align="center" width="50%"><tr><td> <div class="top_nav"><a href="uninstall.php">Uninstall</a> | <a href="attacksList.php">Attack list</a> | <a href="register.php">Add users</a> | <a href="step3.php">Change configeration settings</a> | <a href="logout.php">Log out</a> </div> </td></tr></table> 51 <br /><br /> <table class="main_content" > <tr> <td> <table width="70%"> <tr> <td width="30%" bgcolor="#736F6E"><b>Step 1 </b></td> <td width="35%">Step 2</td> <td width="35%">Step 3</td> </tr> </table> </td> </tr> <tr> <td> <table width="70%"> <form name="install" action="#" method="post"> <tr> <td>SQLiBan Database Name</td> <td><input type="text" name="databasename"></td> </tr> <tr> <td>Application Database Type</td> <td> <select name="db_type"> <option value="MySql">MySQL</option> <option value="MS-SQL">MS-SQL</option> <option value="Oracle">Oracle</option> <option value="PostgreSQL">PostgreSQL</option> </select> </td> </tr> <tr> <td>Host Name</td> <td><input type="text" name="hostname"></td> </tr> <tr> <td>User Name</td> <td><input type="text" name="username"></td> </tr> <tr> <td>Password</td> <td><input type="password" name="pwd"></td> </tr> <tr> <td><input type="SUBMIT" name="Save" value="Save"></td> <td></td> </tr> </form> </table> </td> </tr> </table> </body> </html> Register.php <html> <head> 52 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link href="styles.css" rel="stylesheet" type="text/css"> <title>Register</title> </head> <body> <?php session_start(); include 'globals.php'; // put your code here mysql_connect($db_host,$db_user,$db_password)or die("cannot connect"); mysql_select_db($db_name)or die("cannot select DB"); $result = mysql_query("select id from users"); if(mysql_num_rows($result)==1 && !session_is_registered("USERNAME") || !$install ) header("Location:http://localhost/wbide/index.php/access_denied.php"); ?> <div class="header"> <span style="font-size: 30px;font-weight: bold; vertical-align: bottom;">SQLiBan Configuration </span> <span style="font-weight: bold; margin-left: 600px;">Create New Administrator</span> </div> <br /><br /> <table align="center" width="50%"><tr><td> <div class="top_nav"><a href="uninstall.php">Uninstall</a> | <a href="attacksList.php">Attack list</a> | <a href="register.php">Add users</a> | <a href="step3.php">Change configeration settings</a> | <a href="logout.php">Log out</a> </div> </td></tr></table> <br /><br /> <table class="main_content" > <tr> <td> <table width="70%"> <tr> <td width="35%" ><b>Step 1 </b></td> <td width="30%" bgcolor="#736F6E">Step 2</td> <td width="35%">Step 3</td> </tr> </table> </td> </tr> <tr> <td> <table width="70%"> <form name="register" action="register_save.php" method="post"> <tr> <td>First Name</td> <td><input type="text" name="fname"></td> </tr> <tr> <td>Last Name</td> <td><input type="text" name="lname"></td> </tr> <tr> <td>Email</td> <td><input type="text" name="email"></td> 53 </tr> <tr> <td>User Name</td> <td><input type="text" name="username"></td> </tr> <tr> <td>Password</td> <td><input type="password" name="pwd"></td> </tr> <tr> <td>Retype Password</td> <td><input type="password" name="repwd"></td> </tr> <tr> <td><input type="button" name="Save" value="Save" onClick="javascript: validate();"></td> <td></td> </tr> </form> </table> </td> </tr> </table> </body> </html> Register_save.php <?php include 'globals.php'; // put your code here mysql_connect($db_host,$db_user,$db_password)or die("cannot connect"); mysql_select_db($db_name)or die("cannot select DB"); $qry = "insert into USERS (first_name, last_name , user_name , pass_word , email) values ('".$_POST["fname"]."','".$_POST["lname"]."','".$_POST["username"]."','".$_POST["pwd"]."','".$_POST["email"]."') "; echo $qry; $result = mysql_query($qry); if($result) header("Location:http://localhost/wbide/index.php/step3.php?msg='Registration Sucessfull'"); else { echo mysql_error(); } ?> Settings.php <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link href="styles.css" rel="stylesheet" type="text/css"> <title>Step 3</title> </head> <body> <?php session_start(); include 'globals.php'; // put your code here mysql_connect($db_host,$db_user,$db_password)or die("cannot connect"); mysql_select_db($db_name)or die("cannot select DB"); $result = mysql_query("select id from users"); if(mysql_num_rows($result)==1 && !$install ) 54 header("Location:http://localhost/wbide/index.php/access_denied.html"); $result = mysql_query("select * from SETTING_VALUES") or die(mysql_error()); while ($row = mysql_fetch_array($result)) { if($row["id"]==1) $tnumber = $row["settings_value"]; else if($row["id"]==2) { if($row["settings_value"]>=60 && $row["settings_value"]<24*60) { $ttime = $row["settings_value"]/60; $unit = "hrs"; } else if( $row["settings_value"]>=24*60) { $ttime = $row["settings_value"]/(24*60); $unit = "days"; } else { $ttime = $row["settings_value"]; $unit = "mins"; } } else if($row["id"]==3) $rnumber = $row["settings_value"]; } ?> <div class="header"> <span style="font-size: 30px;font-weight: bold; vertical-align: bottom;">SQLiBan Configuration </span> <span style="font-weight: bold; margin-left: 600px;">Configure Settings</span> </div> <br /><br /> <table align="center" width="50%"><tr><td> <div class="top_nav"><a href="uninstall.php">Uninstall</a> | <a href="attacksList.php">Attack list</a> | <a href="register.php">Add users</a> | <a href="step3.php">Change configeration settings</a> | <a href="logout.php">Log out</a> </div> </td></tr></table> <br /><br /> <table class="main_content" > <tr> <td> <table width="70%"> <tr> <td width="35%" ><b>Step 1 </b></td> <td width="30%" >Step 2</td> <td width="35%"bgcolor="#736F6E">Step 3</td> </tr> </table> </td> </tr> <tr> <td> <table width="70%"> <form name="step3" action="settings_save.php" method="post"> 55 <tr> <td> Temporary Block a user after <input type="text" name="temp_num" value="<?php echo $tnumber; ?> " maxlength="2" size="2"> number of injections. <br><br> User account would be reset after <input type="text" name="temp_time" value="<?php echo $ttime; ?>" size="2" maxlength="2"> <select name="time_unit"> <?php if($unit=="mins"){ ?> <option value="mins" Selected>Minutes</option> <?php } else {?> <option value="mins">Minutes</option> <?php } if($unit=="hrs"){ ?> <option value="hrs" Selected>Hours</option> <?php } else { ?> <option value="hrs" >Hours</option> <?php } if($unit=="days"){ ?> <option value="days" selected>Days</option> <?php } else { ?> <option value="days" >Days</option> <?php } ?> </select> <br><br> Block a user permanently after <input type="text" name="reset_num" value="<?php echo $rnumber; ?>" size="2" maxlength="2"> number of resets. <br> </td> </tr> <tr> <td><input type="button" name="Save" value="Save" onClick="javascript: validate();"></td> </tr> </form> </table> </td> </tr> </table> </body> </html> Settings_save.php <?php include 'globals.php'; // put your code here mysql_connect($db_host,$db_user,$db_password)or die("cannot connect"); mysql_select_db($db_name)or die("cannot select DB"); echo $qry = "update SETTING_VALUES set settings_value=".$_POST["temp_num"]." where id = 1 "; $result = mysql_query($qry); echo $qry = "update SETTING_VALUES set settings_value=".$_POST["reset_num"]." where id = 3 "; 56 $result = mysql_query($qry); if($_POST["time_unit"]=="hrs") $unit = $_POST["temp_time"]*60; else if($_POST["time_unit"]=="days") $unit = $_POST["temp_time"]*60*24; else $unit = $_POST["temp_time"]*1; echo $qry = "update SETTING_VALUES set settings_value=".$unit." where id = 2 "; $result = mysql_query($qry); if($result) header("Location:http://localhost/wbide/index.php/step3.php?msg='Registration Sucessfull'"); else { echo mysql_error(); } ?> 57 BIBLIOGRAPHY [1] SQL, http://en.wikipedia.org/wiki/SQL, Accessed on Sep, 10 2011. [2] SQL Injection, http://en.wikipedia.org/wiki/SQL_injection, Accessed on Aug, 6 2011. [3] Bernardo Damele, (April 2009), “Advanced SQL injection to operating system full control”, http://sqlmap.sourceforge.net/doc/BlackHat-Europe-09-Damele-AG-Advanced-SQL-injection-whitepaper.pdf, Accessed on Aug 20 2011 [4] Steve Friedl, “SQL Injection attacks by example”, www.unixwiz.net/techtips/sqlinjection.html , Accessed on July, 25 2011. [5] Ferruh Mavituna, “SQL Injection: Cheat Sheet”, Document Version 1.4, http://ferruh.mavituna.com/sql-injection-cheatsheet-oku/, Accessed on July, 25 2011. [6] [7] GreenSQL, http://www.greensql.net/, Accessed on Sep 17 2011 DotDefender, http://www.applicure.com/solutions/prevent-sql-injection-attacks, Accessed on Sep 17 2011 [8] Web Site Security Audit, http://www.beyondsecurity.com/sql-injection.html, Accessed on Sep 17 2011 [9] jsDatePick, http://javascriptcalendar.org/javascript-date-picker.php, Accessed on Sep 17 2011 58