I have a forum where users can post comments. When a comment is created its corresponding datetime value is stored in UTC format.
I intend to present the data in local time, say 'ASIA/SINGAPORE';
2 options:
use convert_tz each time querying the database. I dont like the
approach, cause it makes me rewrite the select_expr each time querying.
use SET time_zone = 'ASIA/SINGAPORE';
As for the second option, I want to know what is the validity scope of the command (no super privilege here). more specifically, say if i'm using a php application, does the config gets invalid as i close db connection? should i issue the command each time querying the db?
Tnx.
MySQL variables are scoped in the connection (lowest level, between libmysql <-> mysqld). It means, that if PHP itself or some application library uses any kind of mysql connection pooling, then you could observe this variable disappearing (because of invisible connection switching), and the variable definitely will disappear after disconnecting.
If you are not happy rewriting your query, you probably could select apropriate tz name on the fly -- say, form a users table, as long as you have the id of the logged user, like this:
SELECT convert_tz( ..., ..., (select user_tz from users where user_id = ...))
Related
What I'm trying to do is to convert certain timestamps into the local time of the user.
So what I would do is to ask the user about his timezone (select all the timezones from the corresponding table and then let user select from the list) and then
SELECT CONVERT_TZ('2004-01-01 12:00:00','UTC','MET')
Now the problem. I do not have access to the MySQL timezone tables (command denied to user '' for table 'time_zone' - probably the hosting doesn't allow me). So while I can execute commands as above, I cannot fetch all the timezone names that MySQL knows.
The reason why I want to use timezone names and not the offsets is to do not worry about things like daylight savings time.
So how can I circumvent this problem? I was looking for SQL request to create a duplicate of the table with timezone names but found only the one with GMT offsets, which doesn't work for me, as explained above.
I found this link timezonedb.com where it is possible to download sql tables for the timezones. There is a small drawback of that sql - the table countries doesn't have a numerical index, but this is easy to fix.
Thanks Matt Johnson for the hint!
I'm looking for a stored procedure or something to log user-logins to mysql.
Users will have to be in a positive list.
I need to log user, login time, ip/hostname and query ( query not essential, but a nice-to-have).
My major problem is that I cannot do it via general query log, as is generates +23Gb of log per instance/day (i have 18 instances) and I don't have capacity for it.
I was thinking somewhat in lines of stored procedures, but cannot get my head around it, but not sure if it is the right way to go about it.
Capacity expansion is not an option.
Platform is:
CentOS Linux release 7.3.1611
mysql-community-server-5.6.36-2
Any thoughts on how to solve my issue are welcome.
You may be looking for the mysql init_connect system variable :
A string to be executed by the server for each client that connects. The string consists of one or more SQL statements, separated by semicolon characters.
So basically you want to create a table where logins will be logged, and set the init_connect system variable to something like :
INSERT INTO my_logging_audit
SELECT USER(), NOW()
WHERE USER() IN ('foo', 'bar');
Is it possible to apply some function (user defined / system) to selected columns automatically, may be binding it at schema level.
My scenario is I am saving timestamps of record saving in each table automatically, for which I have used getdate() as default value of those columns, It was working fine till we had our own hosting. But since now we are moving to shared hosting and don't know in which timezone the servers shall be placed in future, I am using GETUTCDATE() to get GMT time.
Since a lot of procedures / functions are already in place, I am looking for something where I don't need to convert this UTC time to my local time explicitly.
So that my Select * from MyTable shall give me time in my fixed timezone using the function I've created.
Let me know if its possible by any way.
Thanks.
It's not exactly clear what you want to do, but there's no way to replace what the SELECT statement asks for with something else: what you ask for in a query is what you get. Unless you replace a table with a view with the same name, but that probably isn't the best approach.
Using a view or function would still mean you have to change your code anyway, so why not just UPDATE all data to UTC time and then do the conversion in your application code? SQL Server has no idea what time zone a client is in anyway, so it isn't possible to do the conversion reliably on the server side. Unless perhaps the client sends the local time zone to the server as a parameter or in CONTEXT_INFO, but there wouldn't be much point because doing it in the client would be simpler anyway.
And of course handling it all in the application will give you a much more flexible, robust solution.
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.
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');