M M Waseem Iqbal
Cause: Unverified/unsanitized user input Effect: the application runs unintended SQL code. Attack is particularly effective if the application is creating SQL strings on the fly and running them.
No prior knowledge of the application or access to the source code. A bit of poking showed that the server ran Microsoft's IIS 6 along with ASP.NET, and this suggested that the database was Microsoft's SQL server.
The login page had a traditional username- and-password form, but also an -me- my-password link. We assume that the underlying SQL code for -me-my-password looks like: SELECT fieldlist FROM table WHERE field = '$ '; No knowledge of the specific names of the fields or table involved.
Entering a single quote as part of the data To see if an SQL string is constructed without sanitizing. For constructed SQL: SELECT fieldlist FROM table WHERE field = '; Result: A 500 error (server failure) SQL parser finds an extra quote mark Suggests that the "broken" input is being parsed.
For anything' OR 'x'='x constructed SQL: SELECT fieldlist FROM table WHERE field = 'anything' OR 'x'='x'; Possible Result: Should return every item in the table, but the response can be different for different applications. Actual Result: Your login information has been mailed to (possibly the first record returned by the
Observed three different responses to various inputs: "Your login information has been mailed to " "We don't recognize your address" Server error Well-formed SQL Bad SQL
Guessing some field names. Reasonably sure that the query includes " address" and "password", and there may be things like "Mail address" or "userid" or "phone number". Cannot do a SHOW TABLE because: Table name is not known. Output of the command will not be shown to the attacker. Stepwise Processing needs to be done.
Know that tail end of the query is a comparison with the address, let's assume is the name of the field. Constructed SQL: SELECT fieldlist FROM table WHERE field = 'x' AND IS NULL; --'; Not concerned about matching the address, hence the dummy x'. -- marks the start of an SQL comment. (Consumes the final quote provided by application) Why using AND conjunction instead of OR?? Used a proposed field name ( ) in the constructed query to find out if the SQL is valid or not.
Possible Outcomes: “A server error” bad field name. “ unknown" or "password was sent" Guessed the name correctly. Actual Outcome: " address unknown“ So now we know the name of one field in the table In case of any other response we would have tried different names for the field like _address, mail. A lot of guess work is involved here.
Guessing some other obvious names: password, user ID, name etc., one at a time SELECT fieldlist FROM table WHERE = 'x' AND userid IS NULL; --'; At the completion of this test, several field names were determined as: passwd login_id full_name
Consider the query: SELECT COUNT(*) FROM tabname Returns the number of records in that table, and of course fails if the table name is unknown
Constructed SQL: SELECT , passwd, login_id, full_name FROM table WHERE = ' x' AND 1=(SELECT COUNT(*) FROM tabname); -- '; Not concerned about matching the address, hence the dummy x'. Not concerned about how many records are there. Only concerned if the table name is correct or not. After several guesses didn’t get server error for members.
Is members the table used in this query? Can be determined using table.field notation. Constructed SQL: SELECT , passwd, login_id, full_name FROM table WHERE = ' x' AND members. IS NULL; --'; Result: " unknown“ Confirmed that members is the table used in this query.
Only know one address: the random member who got the initial "Here is your password" . Getting some more names to work with, preferably those with access to more data. Start with the company's website to find who is who. The "About us" or "Contact" pages often list some addresses.
Consider a query with the LIKE clause: Allows to do partial matches of names or addresses in the database, each time triggering the "We sent your password" message and . Warning: though this reveals an address each time we run it, it also actually sends that , which may raise suspicions.
Constructed SQL: SELECT , passwd, login_id, full_name FROM members WHERE = ' x' OR full_name LIKE '%Bob%'; Result: “Your login information has been mailed to
Once a valid ID is known, we can attempt to guess passwords at the main login page by an exhaustive search. But there could be logfiles, or account lockouts to detect/prevent this approach. The other relatively safer approach for password guessing is to make use of the non- sanitized inputs.
Constructed SQL: SELECT , passwd, login_id, full_name FROM members WHERE = ' AND passwd = 'hello123'; Outcome: We'll know we found the password when we receive the "your password has been mailed to you" message.
So far, everything has been done through SELECT, which is reading from the table. SQL uses the semicolon for statement termination. Since the input is not sanitized properly, so we can write our own unrelated command at the end of the query.
Constructed SQL: SELECT , passwd, login_id, full_name FROM members WHERE = ' x'; DROP TABLE members; -- '; 1 st query: Not concerned about what this query returns. 2 nd query: attempts to drop table Not required particularly. But shows that not only can we run separate SQL commands, but we can also modify the database.
Given that the partial structure of the members table is known, we can attempt to add a new record to the table. If this works, we'll simply be able to login directly with our newly-inserted credentials.
Constructed SQL: SELECT , passwd, login_id, full_name FROM members WHERE = ' x'; INSERT INTO members (' ','passwd','login_id','full_name') VALUES Friedl');-- ';
Not enough room in the web form to enter this much text directly. The web application user might not have INSERT permission on the members table. There are undoubtedly other fields in the members table, and some may require initial values, causing the INSERT to fail. Even if we manage to insert a new record, the application itself might not behave well due to the auto-inserted NULL fields that we didn't provide values for. A valid "member" might require not only a record in the members table, but associated information in other tables, so adding to one table alone might not be sufficient.
If not able to add a new record to the members database, we still can modify an existing one.
From test no. 6 we know that has an account on system. Constructed SQL to update his database record with our address: SELECT , passwd, login_id, full_name FROM members WHERE = ' x'; UPDATE members SET = WHERE = ';
Used the regular "I lost my password" link - with the updated address - and a minute later received this From: To: Subject: Intranet login This is in response to your request for your Intranet log in information. Your User ID is: bob Your password is: hello
Sanitize the input Escape/Quotesafe the input (Escape Seq opr) Use bound parameters (the PREPARE statement) Limit database permissions and segregate users Use stored procedures for database access Isolate the webserver Configure error reporting MVC (Self Study)