What is this SQL injection doing? - mysql

Long story short, through an old asp site I run someone found an unfiltered URL parameter and was able to run this query. I'm trying to figure out what it DOES though...
The query should read:
select * from reserve where id = 345
the one that was ran was:
select * from reserve where id = 345 and ascii(substring((select concat(user,0x3a,password,0x3a,host) from mysql.user limit 0,1),17,1))=53
I'm really not sure what this obtains. Any Input?

It might be probing whether or not the web application is accessing the database as root. Removing the ascii(substring()) portions returns the following when run as root:
mysql> select concat(user,0x3a,password,0x3a,host) from mysql.user limit 0,1;
+--------------------------------------+
| concat(user,0x3a,password,0x3a,host) |
+--------------------------------------+
| root:<rootpw-hash>:localhost |
+--------------------------------------+
Following a successful probe, they may then attempt to retrieve the contents of mysql.user from which they can start cracking passwords against rainbow tables.

The second part of where condition is really strange: it looks for a mysql credentials and process them as follows:
concat(user,0x3a,password,0x3a,host) will be something like 'someUser:hisPass:localhost'
the above string will be splitted in a smaller one
the above string is converted to ascii code (you might know it from legacy languages as ord())
the result of the conversion is compared to 53 integer
I suppose that the first part of WHERE statement (id = 345) will always return true while the second one is too specific, so the entire query will probably return an empty result all the time.

the query is seemingly one from the a set of them:
by changing the charcode and substring start position and you can find out all usernames and the corresponding password hashes (when the page renders as expected you have a char match)
it allows to find out that the current user has access to the mysql schema.

An sql injection exploit does not necessarily immediately output the query result to the attackers screen, often the result is only either an error, or no error, or maybe the injection causes a measurable (to the attacker) delay. in that way the attacker can obtain 1 bit of information per request.
By sending lots of requests, iterating over string positions, doing a binary search on the characters - or as in this case a linear search ( which may indicate that the attacker does not really understand what he is doing, but he will get there eventually ), he will be able to find all the characters in the mysql root user passwordhash. ( Which can possibly be bruteforced offline ).

The SQL is trying to read user data from the My-Sql user table which typically contains a list of users and hosts that are allowed to access a given my-sql server.
It looks to me like the perp is trying to trick mysql into dumping the contents of the user table so they can then record the password hashes offline and dcrypt them to find valid logins.
If your web application is using a login that will allow access to the mysql users table, then this is a serious security flaw, if it's using a login that is only granted permission to the tables required for the app then no information will be obtainable.
Security tip: When setting up ANY kind of database it's vitally important that the application using does so with a login/access role that grants it ONLY what it needs.
If your application only ever needs to read data and never modify it, then it should never have any permissions other than to read. You always need to double check this, because most database systems will by default create user roles for a given database with full read, create, modify privileges.
Always create a specific user, just for that db and or collection of tables, and always give that user the absolute minimum that's required, if your app does then get hacked with a cross site scripting attack, the most their going to get access too is that one specific database.

Related

MySql grant permissions only to read something not whole table

I want to protect my database better, because, if someone decompiles my program, he will have my sql uid and password and can use them to steal my data. How can I grant permissions to the sql user, that I use for my program, to SELECT and UPDATE only when there is a WHERE or a LIKE in the sql statement? Because if someone finds out the user, he can steal my whole table. Thanks.
This is allowed :
SELECT * FROM table WHERE username = 'username'
This is not allowed:
SELECT * FROM table
One of the advantages of using a Database View is that A database view helps limit data access to specific users. You may not want a subset of sensitive data can be queryable by all users. You can use a database view to expose only non-sensitive data to a specific group of users.
So, in theory, you might try something like
CREATE VIEW user_username AS SELECT * FROM table WHERE username = 'username'
in order to create separate views for every user of your application.
That being said, it is a very bad idea to do so. Also, if by decompiling, a user has access to a database containing ALL the users, the I am pretty sure there must be something wrong with the design of the application.
But, as very few details are given about the application in question, it is hard to advise as to how it should be done.

Can a mysql user be restricted to a max number of rows per select query?

I've found that it's possible to grant user access to only specific tables in a DB. The next part of the puzzle is restricting the scope of select queries.
Should my frontend server ever be compromised by someone able to script, they may attempt to use mysql credentials from the server to dump the database.
If everything is limited to only select, update, and insert queries via mysql privileges, the supposed malicious user could still select * on the tables the mysql user has access to. Perhaps I'm overly paranoid, but I'm wondering if anything can be done to restrict that too.
The assumption here is that if the server is compromised, the mysql user can be used via a script on the server to get a copy of everything in the DB. I'm trying to find the options to protect my (and my users' data).
By design, the frontend application that will use this mysql user will never need to return more than 20 rows (mostly due to hardcoded . I'm therefore happy to restrict the mysql user from ever getting more than 20 rows from a select query.
Can this be done using mysql privileges for that mysql user?
You could create view as select ... limit 20, remove select privilege from the table and grant it only for the view instead.

My way around sql injection

I'm not an expert but I do have a web front processing orders that have data needing to be input for further logins. Instead of using that database, I created another one with an extra column called status. Initially when orders are processed, they are set to 0. The cron job runs every 3 minutes polling this database for all users with status 0. When run, the cron sets the status of all currently processed users to status 1 (so if there are any that do get input during runtime of the script, it will be processed next time which is only 3 minutes).
After the status of all new users is set to 1, just the password and email fields are dumped to a file and then loaded via "LOAD DATA INFILE" back into the real database that users need to log in with their client. there is no web log in form. It is for emails, just using the IMAP client. However, I do use the root account for the cron since I realized I needed to grant all privs to a user for the dumping of data and if that is going to be it, I might as well just use root to update the status column first, then dump the new data to a file, then load it into the new db and go back and delete all users with status 1. It is a simple 4 line script running mysql from the command line.
Is this a safe bet or am I risking something running a root cron every 3 min? I don't see how I can possibly have an issue since I never use root to process the web stuff. I use a separate mysql user with only INSERT privs for the web front to process new orders. Any comments? I feel like this way I can avoid sql injection even though my mysql user still has limited privs, there always might be something I don't know about.
Is this a safe bet or am I risking something
As long as it's simple LOAD DATA INFILE query - no. However,
Instead of using that database, I created another one with an extra column called status.
Such a flying circus is absolutely unnecessary.
It doesn't protect you from injection anyway.
Instead, you have to use prepared statements for ALL the queries in your application.

MySQL - mysql database priviledges and root user

so..
I'm watching a Tutorial Video courtesy of Lynda.com on the basics of MySQL (cool Stuff),
The instructor is instructing us on setting up Root User Password via Console (which i've actually already Done).
He stated the following :
MySQL Stores it Users,Root Users and Permission for those users in a table called user, located in a datbase called mysql
Then a little lightbulb appeared above my head and i typed this in
{SHOW DATABASES;}
{USE mysql;}
{SHOW TABLES;}
{SELECT * FROM user;)
Then a bunch of stuff appeared that was obviously all the user info
so HERE'S MY QUESTION (actually 2 if i may)
1.Am i correct in assuming that if i (hypothetically) modify they "Y"'s or the "N"'s , i then effectively alter the permissions and/or access grants to those corresponding users.
LASTLY, i have set my password, and next to my name in the list, under the password column, there is a really long string of what appears to be a Hexadecimal string
Just for fun How would i convert that back so that it shows my password
(FYI I'm familiar with conversion of Binary to hex and to decimal and so on, but i'm guessing there's some sort of encryption at work here, perhaps AES or 3DES or something)
it's starts with a Star , followed by 40 Hex Characters, my password is only 12 Characters Long
so..to finish up, in doing all this, i now think i understand what the purpose of the mysql schema is in MYSQL
and needless to say i shouldn't delete it... right LOL
all input on this subject is greatly appreciated ahead of time
thanks guys
Am i correct in assuming that if i (hypothetically) modify they "Y"'s or the "N"'s , i then effectively alter the permissions and/or access grants to those corresponding users.
Yes - however the data is cached independently of the query cache - hence updating the table won't immediately give you this access - you need to reload the privileges or restart the database before the changes take effect.
How would i convert that back so that it shows my password
You can't. It's a cryptographic hash of your password. However given enough time and enough computing resource you can find a string which results in the same hash (which might be the same as the pasword) - this could then be used to log in as that user. But we're talking about millions of CPU hours here.
Yes, you can set 'Y' or 'N' in those rows, but after modifying system security tables you will have to execute FLUSH PRIVILEGES; command. I'd suggest you to use GRANT or REVOKE command instead of editing system tables directly.
No, it is not possible to decrypt MySQL user's password.

MySQL Injection - Use SELECT query to UPDATE/DELETE

I've got one easy question: say there is a site with a query like:
SELECT id, name, message FROM messages WHERE id = $_GET['q'].
Is there any way to get something updated/deleted in the database (MySQL)? Until now I've never seen an injection that was able to delete/update using a SELECT query, so, is it even possible?
Before directly answering the question, it's worth noting that even if all an attacker can do is read data that he shouldn't be able to, that's usually still really bad. Consider that by using JOINs and SELECTing from system tables (like mysql.innodb_table_stats), an attacker who starts with a SELECT injection and no other knowledge of your database can map your schema and then exfiltrate the entirety of the data that you have in MySQL. For the vast majority of databases and applications, that already represents a catastrophic security hole.
But to answer the question directly: there are a few ways that I know of by which injection into a MySQL SELECT can be used to modify data. Fortunately, they all require reasonably unusual circumstances to be possible. All example injections below are given relative to the example injectable query from the question:
SELECT id, name, message FROM messages WHERE id = $_GET['q']
1. "Stacked" or "batched" queries.
The classic injection technique of just putting an entire other statement after the one being injected into. As suggested in another answer here, you could set $_GET['q'] to 1; DELETE FROM users; -- so that the query forms two statements which get executed consecutively, the second of which deletes everything in the users table.
In mitigation
Most MySQL connectors - notably including PHP's (deprecated) mysql_* and (non-deprecated) mysqli_* functions - don't support stacked or batched queries at all, so this kind of attack just plain doesn't work. However, some do - notably including PHP's PDO connector (although the support can be disabled to increase security).
2. Exploiting user-defined functions
Functions can be called from a SELECT, and can alter data. If a data-altering function has been created in the database, you could make the SELECT call it, for instance by passing 0 OR SOME_FUNCTION_NAME() as the value of $_GET['q'].
In mitigation
Most databases don't contain any user-defined functions - let alone data-altering ones - and so offer no opportunity at all to perform this sort of exploit.
3. Writing to files
As described in Muhaimin Dzulfakar's (somewhat presumptuously named) paper Advanced MySQL Exploitation, you can use INTO OUTFILE or INTO DUMPFILE clauses on a MySQL select to dump the result into a file. Since, by using a UNION, any arbitrary result can be SELECTed, this allows writing new files with arbitrary content at any location that the user running mysqld can access. Conceivably this can be exploited not merely to modify data in the MySQL database, but to get shell access to the server on which it is running - for instance, by writing a PHP script to the webroot and then making a request to it, if the MySQL server is co-hosted with a PHP server.
In mitigation
Lots of factors reduce the practical exploitability of this otherwise impressive-sounding attack:
MySQL will never let you use INTO OUTFILE or INTO DUMPFILE to overwrite an existing file, nor write to a folder that doesn't exist. This prevents attacks like creating a .ssh folder with a private key in the mysql user's home directory and then SSHing in, or overwriting the mysqld binary itself with a malicious version and waiting for a server restart.
Any halfway decent installation package will set up a special user (typically named mysql) to run mysqld, and give that user only very limited permissions. As such, it shouldn't be able to write to most locations on the file system - and certainly shouldn't ordinarily be able to do things like write to a web application's webroot.
Modern installations of MySQL come with --secure-file-priv set by default, preventing MySQL from writing to anywhere other than a designated data import/export directory and thereby rendering this attack almost completely impotent... unless the owner of the server has deliberately disabled it. Fortunately, nobody would ever just completely disable a security feature like that since that would obviously be - oh wait never mind.
4. Calling the sys_exec() function from lib_mysqludf_sys to run arbitrary shell commands
There's a MySQL extension called lib_mysqludf_sys that - judging from its stars on GitHub and a quick Stack Overflow search - has at least a few hundred users. It adds a function called sys_exec that runs shell commands. As noted in #2, functions can be called from within a SELECT; the implications are hopefully obvious. To quote from the source, this function "can be a security hazard".
In mitigation
Most systems don't have this extension installed.
If you say you use mysql_query that doesn't support multiple queries, you cannot directly add DELETE/UPDATE/INSERT, but it's possible to modify data under some circumstances. For example, let's say you have the following function
DELIMITER //
CREATE DEFINER=`root`#`localhost` FUNCTION `testP`()
RETURNS int(11)
LANGUAGE SQL
NOT DETERMINISTIC
MODIFIES SQL DATA
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DELETE FROM test2;
return 1;
END //
Now you can call this function in SELECT :
SELECT id, name, message FROM messages WHERE id = NULL OR testP()
(id = NULL - always NULL(FALSE), so testP() always gets executed.
It depends on the DBMS connector you are using. Most of the time your scenario should not be possible, but under certain circumstances it could work. For further details you should take a look at chapter 4 and 5 from the Blackhat-Paper Advanced MySQL Exploitation.
Yes it's possible.
$_GET['q'] would hold 1; DELETE FROM users; --
SELECT id, name, message FROM messages WHERE id = 1; DELETE FROM users; -- whatever here');