Injection attack by sql query in php - mysql

Can anyone explain me meaning of this query?
-999.9 and(select 1 from(select count(*),
concat((select (select concat(0x7e,0x27,unhex(Hex(cast(database() as char))),0x27,0x7e))
from `information_schema`.tables limit 0,1),floor(rand(0)*2))x
from `information_schema`.tables group by x)a)--
I found that required fields in form are filled by 1 and email id was field by this particular query. In form, I have sequence like name, mobile nu, email id and other details. After email id whatever fields are there, were filled by blank or 'null' and before email id all fields were filled by '1'.

It is a blind SQL injection. It is used when the site is not vulnerable to normal SQL injection. Your site validates the input data, probably not correctly but well enough to not let information leak through SQL injection.
Blind SQL injection does not attempt to get information directly; if a leak is found then there is no need for blind injection in the first place.
How it works: it injects strange embedded queries like the one mentioned in the question and it checks the behaviour of the page. A page that checks the result of its queries produces a different content when a query fails. It displays an error message or redirects to some page or, sometimes, it doesn't produce any output (when the "handling" of the query failures is like "or die()").
The blind SQL injection makes an assumption then produces and injects a query that either runs correctly or fails. It checks the page content to know if the injected part made the query succeed or fail. Depending on the result (success or failure), the injection script knows if its assumption was true or false then it takes a decision and tries again with a different assumption.
I cannot tell what is testing this injection fragment. It makes the query fail on the MySQL version I am using because of the group by x part. Maybe it succeeds on other versions (MySQL 4?); in this case it is used only to detect the version of the MySQL. It's not about the exact version but the major version. There are small things changed here and there on major MySQL versions and it's important for the attacker script to know what version is running. This way it knows what language features it can use. If it does not use the correct syntax then all its queries fails and its goal cannot be accomplished. :-)
One of the legacy websites I am maintaining was attacked a couple of months ago in a similar fashion. We thought all the input data was correctly checked and there is no way to inject something into it. It happened that a small hole still existed, somebody decided to attack the site (to extract email addresses probably) and the tool they used found the hole and started injecting queries through it.
The inject query was something like 2 RLIKE (SELECT ...) where ... stands for a complicated query that selects the name of the Nth object (table or column) from information_schema (using LIMIT), uses function MID(name, K, 1) to extract the Kth character from the selected name then compares that character with a specified character (using IF() or CASE) to eventually produce 2 or something that was not a valid regular expression.
Each request is checking a single character of a single table or field name against a certain character from the ASCII set. If the checked character is smaller than the one provided by the injector then the injected part evaluates to 2 RLIKE 2 and the query run normally. Otherwise it evaluates to something 2 RLIKE ( and the query fails. This way, the injector script divides in half the range of potential values for the character it is testing. The next queries shrinks it again and again until it founds the exact character. It requires up to 7 injected requests to find a single character of a single name of table of field.
Then it starts over with the character at position K+1 and so on. Using the same technique but with a different query, the script finds first how long is the name it wants to find.
The process is tedious but that's why the computers were invented in the first place: to do tedious work for humans.

Related

What pattern to check on an SQL query for possible injection?

I want to detect possible SQL injection atack by checking the SQL query. I am using PDO and prepared statement, so hopefully I am not in the danger of getting attacked by someone. However, what I want to detect is the possibility of input/resulting query string that may become a dangerous query. For example, my app--properly--will never generate "1=1" query, so I may check the generated query string for that, and flag the user/IP producing that query. Same thing with "drop table", but maybe I can check only by looping the input array; or maybe I should just check to the generated query all over again. I am using MySQL, but pattern for other drivers are also appreciated.
I have read RegEx to Detect SQL Injection and some of the comments are heading in this direction. To my help, I'm developing for users that rarely use English as input, so a simple /drop/ match on the query may be enough to log the user/query for further inspection. Some of the pattern I found while researching SQL injection are:
semicolon in the middle of sentence -- although this may be common
double dash/pound sign for commenting the rest of the query
using quote in the beginning & ending of value
using hex (my target users have small to low chance for inputting 0x in their form)
declare/exec/drop/1=1 (my app should not generate these values)
html tag (low probability coming from intended user/use case)
etc.
All of the above are easier to detect by looping the input values before the query string is generated because they haven't been escaped. But how much did I miss? (a lot, I guess) Any other obscure pattern I should check? What about checking the generated query? Any pattern that may emerge?
tl;dr: What pattern to match an SQL query (MySQL) to check for possible injection? I am using PDO with prepared statement and value binding, so the check is for logging/alert purposes.
In my shop we have two rules.
Always use parameters in SQL queries.
If for some reason you can't follow rule one, then every piece of data put into a query must be sanitized, either with intval() for integer parameters or an appropriate function to sanitize a string variable according to its application data type. For example, a personal name might be Jones or O'Brien or St. John-Smythe but will never have special characters other than apostrophe ', hyphen -, space, or dot. A product number probably contains only letters or numbers. And so forth.
If 2 is too hard follow rule 1.
We inspect code to make sure we're doing these things.
But how much did I miss?
You guess right. Creating a huge blacklist wouldn't make your code immune. This approach is history. The other questions follow the same idea.
Your best bets are:
Validating input data (input doesn't necessarily come from an external party)
Using prepared statements.
Few steps but bulletproof.
Not possible.
You will spend the rest of your life in an armament race -- you build a defense, they build a better weapon, then you build a defense against that, etc, etc.
It is probably possible to write a 'simple' SELECT that will take 24 hours to run.
Unless you lock down the tables, they can look, for example, at the encrypted passwords and re-attack with a root login.
If you allow any type of string, it will be a challenge to handle the various combinations of quoting.
There are nasty things that can be done with semi-valid utf8 strings.
And what about SET statements.
And LOAD DATA.
And Stored procs.
Instead, decide on the minimal set of queries you allow, then parameterize that so you can check, or escape, the pieces individually. Then build the query.

Should I sanitize inputs to a parametrized query?

I have a couple of basic questions on parametrized queries
Consider this code:
$id = (int)$_GET['id'];
mysql_query("UPDATE table SET field=1 WHERE id=".$id);
Now the same thing using a parametrized query
$sql = "UPDATE table SET field=1 WHERE id=?";
$q = $db->prepare($sql);
$q->execute(array($_GET['id']));
My questions are:
is there any situation where the first code (i.e. with the (int) cast) is unsafe?
is the second piece of code OK or should I also cast $_GET['id'] to int?
is there any known vulnerability of the second piece of code? That is, is there any way an SQL attack can be made if I am using the second query?
is there any situation where the first code (i.e. with the (int) cast) is unsafe?
I'm not a PHP expert, but I think there shouldn't be. That's not to say that PHP doesn't have bugs (either known or yet to be discovered) that could be exploited here.
is the second piece of code OK or should I also cast $_GET['id'] to int?
Likewise, the second piece of code should be absolutely fine - even if the data type was a string, MySQL would know not to evaluate it for SQL as it's a parameter and therefore only to be treated as a literal value. However, there's certainly no harm in also performing the cast (which would avoid any flaws in MySQL's handling of parameters) - I'd recommend doing both.
EDIT - #Tomalak makes a very good point about cast potentially resulting in incorrect data and suggests first verifying your inputs with sanity checks such as is_numeric(); I agree wholeheartedly.
is there any known vulnerability of the second piece of code? That is, is there any way an SQL attack can be made if I am using the second query?
Not to my knowledge.
(int) will yield 0 when the conversion fails. This could lead to updating the wrong record. Besides, it's sloppy and an open invitation to "forget" proper type casting when the query gets more complex later-on.
It's safe in its current form (against SQL injection, not against updating the wrong record) but I'd still not recommend it. Once the query gets more complex you're bound to use prepared statements anyway, so just do it right from the start - also for the sake of consistency.
That's sloppy, too. The parameter will be transferred to the DB as a string and the DB will try to cast it. It's safe (against SQL injection), but unless you know exactly how the DB server reacts when you pass invalid data, you should sanitize the value up-front (is_numeric() and casting).
No. (Unless there is a bug in PDO, that is.)
As a rule of thumb:
Don't pass unchecked data to the database and expect the right thing to happen.
Don't knowingly pass invalid data and trust that the other system reacts in a certain way. Do sanity checks and error handling yourself.
Don't make "Oh, that converts to 0 and I don't have a record with ID 0 anyway so that's okay." part of your thought process.

MySQL escaped_strings VS. Parameterised Queries

Just reading up on Parameterised queries, which seem to be the last word in database defence, and was wondering the following:
I have an existing PHP/MySQL self-built CMS where ALL inputs (bar checkboxes and radio buttons) are subject to real_escape_string. There is an admin section accessible via a sha1 encrypted password and a matching username where a small (3) group of trusted people can update content (tinyMCE), upload photos, etc. Strictly smalltime. None of my queries are parameterised, but are only executed after escaping.
There are no inputs taken from the general public, but I do want to open it up to user-submitted forms later.
My host is a private one, with a very good record.
All else being equal, how secure am I?
mysql_real_escape_string does not immediately protect you from SQL injection attacks. I recently helped the developer of a small site who thought he was safe my calling mysql_real_escape_string on all of the inputs, but still got pwn'd. In his case, he was expecting a variable (via GET string) to be an integer, but was not verifying it as such. The attackers then utilized that ID field to craft custom queries and gain access to his entire database.
The moral of the story? Validate, validate, validate. You need to assume every possible piece of data coming from the outside (even if it's an <input type="hidden"> that you populate) is an attempt to bypass security measures. This is where using frameworks like Codeigniter, etc. are helpful, because they have validation components built right in. If you want to do everything yourself, just be careful, and check all input variables.
I'd rather use parametrized / prepared statements. Compared to just escaping input, they let you specify type which is handy (you don't have, for instance, to convert datetime values to server-specific format), and it also resolves ambiguity in handling conversion errors by different RDMS. For example, query SELECT * FROM table1 WHERE int_field='aaa' (int_field is integer) returns records with int_field equals 0 in Mysql, raises error in Oracle and SQLServer, and returns empty set in SQlite

implementing a blacklist of usernames

I have a block list of names/words, has about 500,000+ entries. The use of the data is to prevent people from entering these words as their username or name. The table structure is simple: word_id, word, create_date.
When the user clicks submit, I want the system to lookup whether the entered name is an exact match or a word% match.
Is this the only way to implement a block or is there a better way? I don't like the idea of doing lookups of this many rows on a submit as it slows down the submit process.
Consider a few points:
Keep your blacklist (business logic) checking in your application, and perform the comparison in your application. That's where it most belongs, and you'll likely have richer programming languages to implement that logic.
Load your half million records into your application, and store it in a cache of some kind. On each signup, perform your check against the cache. This will avoid hitting your table on each signup. It'll be all in-memory in your application, and will be much more performant.
Ensure myEnteredUserName doesn't have a blacklisted word at the beginning, end, and anywhere in between. Your question specifically had a begins-with check, but ensure that you don't miss out on 123_BadWord999.
Caching bring its own set of new challenges; consider reloading from the database everyday n minutes, or at a certain time or event. This will allow new blacklisted words to be loaded, and old ones to be thrown out.
You can't do where 'loginName' = word%. % can only be used in the literal string, not as part of the column data.
You would need to say where 'logi' = word or 'login' = word or ... where you compare substrings of the login name with the bad words. You'll need to test each substring whose length is between the shortest and longest bad word, inclusive.
Make sure you have an index on the word column of your table, and see what performance is like.
Other ways to do this would be:
Use Lucene, it's good at quickly searching text, espacially if you just need to know whether or not your substring exists. Of course Lucene might not fit technically in your environment -- it's a Java library.
Take a hash of each bad word, and record them in a bitset in memory -- this will be small and fast to look up, and you'll only need to go to the database to make sure that a positive isn't false.

Using Access 2003 VBA functions through JET

Hallo all.
I need to run the 'replace([column], [new], [old])' in a query executing on n Access 2003 DB. I know of all the equivalent stuff i could use in SQL, and believe me I would love to, but i don't have this option now. I'm trying to do a query where all the alpha chars are stripped out of a column ie. '(111) 111-1111' simply becomes '1111111111'. I can also write an awsum custom VBA function and execute the query using this, but once again, can't use these functions through JET. Any ideas?
Thanx for the replies guys. Ok let me clarify the situation. I'm running an .NET web application. This app uses an Access 2003 db. Im trying to do an upgrade where I incorporate a type of search page. This page executes a query like: SELECT * FROM [table] WHERE replace([telnumber], '-', '') LIKE '1234567890'. The problem is that there are many records in the [telnumber] column that has alpha chars in, for instance '(123) 123-1234'. This i need to filter out before i do the comparison. So the query using a built in VBA function executes fine when i run the query in a testing environment IN ACCESS, but when i run the query from my web app, it throws an exception stating something like "Replace function not found". Any ideas?
Based on the sample query from your comment, I wonder if it could be "good enough" to rewrite your match pattern using wildcards to account for the possible non-digit characters?
SELECT * FROM [table] WHERE telnumber LIKE '*123*456*7890'
Your question is a little unclear, but Access does allow you to use VBA functions in Queries. It is perfectly legal in Access to do this:
SELECT replace(mycolumn,'x','y') FROM myTable
It may not perform as well as a query without such functions embedded, but it will work.
Also, if it is a one off query and you don't have concerns about locking a bunch of rows from other users who are working in the system, you can also get away with just opening the table and doing a find and replace with Control-H.
As JohnFx already said, using VBA functions (no matter if built in or written by yourself) should work.
If you can't get it to work with the VBA function in the query (for whatever reason), maybe doing it all per code would be an option?
If it's a one-time action and/or not performance critical, you could just load the whole table in a Recordset, loop through it and do your replacing separately for each row.
EDIT:
Okay, it's a completely different thing when you query an Access database from a .net application.
In this case it's not possible to use any built-in or self-written VBA functions, because .net doesn't know them. No way.
So, what other options do we have?
If I understood you correctly, this is not a one-time action...you need to do this replacing stuff every time someone uses your search page, correct?
In this case I would do something completely different.
Even if doing the replace in the query would work, performance wise it's not the best option because it will likely slow down your database.
If you don't write that often to your database, but do a lot of reads (which seems to be the case according to your description), I would do the following:
Add a column "TelNumberSearch" to your table
Every time when you save a record, you save the phone number in the "TelNumber" column, and you do the replacing on the phone number and save the stripped number in the "TelNumberSearch" column
--> When you do a search, you already have the TelNumberSearch column with all the stripped numbers...no need to strip them again for every single search. And you still have the column with the original number (with alpha chars) for displaying purposes.
Of course you need to fill the new column once, but this is a one-time action, so looping through the records and doing a separate replace for each one would be okay in this case.