People trying SQL Injection attacks on our servers - sql

I am a developer for a company that has numerous clients. I protect against SQL Injection multiple ways.
By using Parameterized queries
By using Stored procedures for every interaction with the database
By using validation on the server to ensure data is of correct type
Delete/Insert/Update permission is denied at table level for user of the websites (the website user role is only allowed execute permission on the procedures that are ran through the website)
I log all of the injection attacks, with attempted attack info, date, ip address, useragent. Some days there are a lot of them. Today is one of those days. In the last hour I have logged over 10,000 such attacks, and they are still coming in at a rate of about 150 or so per minute. Typically the attacks come in on the few pages where a parameter is passed in the query string. So my validation then sees it is a potential attack and logs it then sends a 400 status to the browser. Today I saw something different and am curious what they are trying to hit this does not look like a Transact SQL in this instance the information after the 778 is the data added to the query string
778";CREATE OR REPLACE FUNCTION SLEEP(int) RETURNS int AS '/lib/libc.so.6','sleep' language 'C' STRICT; SELECT sleep(32) AND "fvtz" LIKE "fvtz
is this a Linux mySQL attack or ??
just curious

Related

How to get information about an SQL Select statement

I am wondering if it is possible to get the real name of the tables/fields from which each field in a select statement comes from.
Lets say you have two tables, Creditors and Debtors both have the fields Code, Name and Phone.
If a user enters the following sql statement:
SELECT Code AS CustomerCode, Name AS CustomerName, Phone AS ContactNumber FROM Debtors.
This will result in SQL server returning field names CustomerCode, CustomerName and ContactNumber.
Is it possible to get from the SQL server some sort of meta data that maps each field to its real name and the table it comes from?
Programmically, given an SQL select statement, I want to be able to determine the real name of each field and the real name of the tables they come from.
I don't want to parse the SQL myself so I thought that there might be away to send the statement to the sql server and get back this information without the row data.
What we are trying to do is implement table/field level security. A user can enter an sql statement to select fields from a table or across multiple tables (using joins) and have the results displayed in a table. The fields get added dynamically to a grid control but only the ones that the user is allowed to see.
If the user joins multiple tables how do we know programmically which fields come from which table? the problem gets worse if they use aliases in the SQL.
Currently this is working on a legacy in house built sql engine (that uses a proprietary database) which can return all of the required table/field information without the row data so part of the applications security model is built around this. However moving this application to something like SQL server might prove difficult if we can't get this to work.
Besides Sql server, do any other sql databases support this type of functionality?
To the best of my knowledge, you cannot get that information.
You can probably handle your problem in many databases, however, by using GRANT / REVOKE security in the database itself. Assuming that users are logging into the database itself (not just your application), many DBMSes allow you to GRANT SELECT privileges on restricted columns from a table. Using that technique, it will not fool the server if the user specifies ALIASes for columns.
A quick google indicates that at least PostgreSQL, SQL Server, and Oracle offer column level GRANT SELECT protection based on userid.
Interesting question, by the way.
No. The whole point is you should only know the name presented to you and not where it came from.
The way to solve your problem is to remove all access from tables and only grant access through views with appropriate access permissions.

SQL Server: is it possible to get data from another SQL server without setting linked server?

I need to do the following query (for example):
SELECT c1.CustomerName FROM Customer as c1
INNER JOIN [ExternalServer].[Database].[dbo].[Customer] as c2
ON c2.RefId = c1.RefId
For some security reason my client doesn't allow me to create a linked server. The user under whom I execute this query has access to both tables. Is it possible to make it work without using linked server? Thanks.
You could use OPENROWSET, which'll require the connection info, username & password...
While I understand that the client believes that having an always-on connection to their data is risky, that's why you lock down the account. OPENROWSET means including the connection info in plain text.
'Linked Server' is a very specific thing -- basically, a permanent connection between servers. I can think of all sorts of reasons not to want that, while at the same time having no problem with folks writing queries that combine data from the two different data sources.
Anyway, depending on your requirement -- if this is just for ad hoc querying, OPENROWSET is good if inside of SQL-Server, or if you want to do this in MS Access, just link to the two tables, and your Access query won't care that one comes from one server, and one comes from another.
Alternatively, with a web or windows front-end, you could indpendently query each table into a data object, and then build a separate query on top of that.
Http Endpoints...
WebServices...
There's a million ways. I wouldn't be so quick to assume, as #Lasse suggests, that any form of 'linking' this data together would make you some kind of rougue data linker.

What is SQL injection? [duplicate]

This question already has answers here:
How does the SQL injection from the "Bobby Tables" XKCD comic work?
(13 answers)
Closed 3 years ago.
Can someone explain SQL injection? How does it cause vulnerabilities? Where exactly is the point where SQL is injected?
Can someone explain SQL injecton?
SQL injection happens when you interpolate some content into a SQL query string, and the result modifies the syntax of your query in ways you didn't intend.
It doesn't have to be malicious, it can be an accident. But accidental SQL injection is more likely to result in an error than in a vulnerability.
The harmful content doesn't have to come from a user, it could be content that your application gets from any source, or even generates itself in code.
How does it cause vulnerabilities?
It can lead to vulnerabilities because attackers can send values to an application that they know will be interpolated into a SQL string. By being very clever, they can manipulate the result of queries, reading data or even changing data that they shouldn't be allowed to do.
Example in PHP:
$password = $_POST['password'];
$id = $_POST['id'];
$sql = "UPDATE Accounts SET PASSWORD = '$password' WHERE account_id = $id";
Now suppose the attacker sets the POST request parameters to "password=xyzzy" and "id=account_id" resulting in the following SQL:
UPDATE Accounts SET PASSWORD = 'xyzzy' WHERE account_id = account_id
Although I expected $id to be an integer, the attacker chose a string that is the name of the column. Of course now the condition is true on every row, so the attacker has just set the password for every account. Now the attacker can log in to anyone's account -- including privileged users.
Where exactly is the point where SQL is injected?
It isn't SQL that's injected, it's content that's interpolated ("injected") into a SQL string, resulting in a different kind of query than I intended. I trusted the dynamic content without verifying it, and executed the resulting SQL query blindly. That's where the trouble starts.
SQL injection is a fault in the application code, not typically in the database or in the database access library or framework.
Most cases of SQL injection can be avoided by using query parameters. See How can I prevent SQL injection in PHP? for examples.
SQL Injection occurs when the user of an application is able to affect the meaning of database query. This often occurs when arbitary strings from user input are concatenated to create SQL which is fed to the database. For example lets say we had the following code (in PHP, but the same holds true for any language), which might be used to handle a user login.
$sql = "SELECT FROM users WHERE username='".$_GET['username']."' AND password='".$_GET['password']."'";
The harm is done when the user enters something like
administrator'; --
... for the username. Without proper encoding the query becomes:
SELECT * FROM users WHERE username='administrator'; -- AND password=''
The issue here is that the ' in the username closes out the username field then the -- starts a SQL comment causing the database server to ignore the rest of the string. The net result is the user can now log in as the administrator without having to know the password. SQL Inection can also be used to execute UPDATE, DELETE or DROP queries and really damage the database.
SQL Injection can be prevented by using parameterised queries, or applying your language/toolkit's escaping functions (such as mysql_real_escape_string() in PHP).
Once you understand SQL Injection you'll get the joke behind this cartoon.
This question has been answered many times on StackOverflow, but it's an important topic for everyone to know about, so I'm not going to vote to close this question.
Here are links to some of my past answers on this topic:
What is SQL Injection?
How do I protect this function from SQL injection?
Are Parameters really enough to prevent Sql injections?
Is SQL injection a risk today?
I also gave a presentation at the MySQL Conference this month, and my slides are online:
SQL Injection Myths & Fallacies
SQL injection is when things that're supposed to be data are treated as SQL code unwillingly.
For instance, if you were to do
mysql_query("SELECT * FROM posts WHERE postid=$postid");
Normally it'd get you the post with a given id, but assume that $postid is set to the string 10; DROP TABLE posts --; all of a sudden, the actual query you're sending is
mysql_query("SELECT * FROM posts WHERE postid=10; DROP TABLE posts --");
This is quite a problem, as you'd be losing your entire posts table due to a malicious user - oh dear.
The easiest way to prevent this is to use prepared statements, for instance through PDO or MySQLi.
The equivalent example in PDO would then be
$statement = $db->prepare('SELECT * FROM posts WHERE postid = :postid');
$statement->bindValue(':postid', $postid);
$statement->execute();
Doing this ensures that the database system knows that $postid is to be treated as data and not code, and will thus be handled appropriately.
SQL injection is where a malicious user will put SQL into input fields to try and run the SQL on your server.
The #1 advice that I adhere to is to use parameterized stored procedures rather than building raw SQL in code.
Stored Procedure parameters don't get executed, making them safe in most cases.
I found this paper to be an extremely good read about SQL injection techniques (link is to PDF): Advanced SQL Injection In SQL Server Applications.
Despite the title saying "Advanced", it's quite readable even if you don't have much knowledge about SQL injection.
To get some general background check out the Wikipedia article on SQL Injection.
In short SQL injection attacks can leave you vulnerable to all manor of database data theft and destruction. The exact details of what can be done to your system depend on the details of the system itself.
Any time you pass input from your users to your database you have a potential injection point. Web applications are often lacking in the this regard, as new programmers often do not understand the risks of handling input from users, and web applications are attacked by very smart people you never thought would find your program.
You will like this article from code project ; )
Summary
Encrypt sensitive data.
Access the database using an account with the least privileges
necessary.
Install the database using an account with the least privileges
necessary.
Ensure that data is valid.
Do a code review to check for the possibility of second-order
attacks.
Use parameterised queries.
Use stored procedures.
Re-validate data in stored procedures.
Ensure that error messages give nothing away about the internal
architecture of the application or the
database.
The point where SQL is injected is any point that your application accepts input from the user.
Whether this becomes a dangerous vulnerability for your web application depends on whether this input is later used as part of an SQL query without properly checking its type and escaping it if necessary.
Without proper escaping, some SQL code 'injected' by the user could be executed by the SQL engine as SQL code, rather than a simple string or value.

How to determine an Oracle query without access to source code?

We have a system with an Oracle backend to which we have access (though possibly not administrative access) and a front end to which we do not have the source code. The database is quite large and not easily understood - we have no documentation. I'm also not particularly knowledgable about Oracle in general.
One aspect of the front end queries the database for a particular set of data and displays it. We have a need to determine what query is being made so that we can replicate and automate it without the front end (e.g. by generating a csv file periodically).
What methods would you use to determine the SQL required to retrieve this set of data?
Currently I'm leaning towards the use of an EeePC, Wireshark and a hub (installing Wireshark on the client machines may not be possible), but I'm curious to hear any other ideas and whether anyone can think of any pitfalls with this particular approach.
Clearly there are many methods. The one that I find easiest is:
(1) Connect to the database as SYS or SYSTEM
(2) Query V$SESSION to identify the database session you are interested in.
Record the SID and SERIAL# values.
(3) Execute the following commands to activate tracing for the session:
exec sys.dbms_system.set_bool_param_in_session( *sid*, *serial#*, 'timed_statistics', true )
exec sys.dbms_system.set_int_param_in_session( *sid*, *serial#*, 'max_dump_file_size', 2000000000 )
exec sys.dbms_system.set_ev( *sid*, *serial#*, 10046, 5, '' )
(4) Perform some actions in the client app
(5) Either terminate the database session (e.g. by closing the client) or deactivate tracing ( exec sys.dbms_system.set_ev( sid, serial#, 10046, 0, '' ) )
(6) Locate the udump folder on the database server. There will be a trace file for the database session showing the statements executed and the bind values used in each execution.
This method does not require any access to the client machine, which could be a benefit. It does require access to the database server, which may be problematic if you're not the DBA and they don't let you onto the machine. Also, identifying the proper session to trace can be difficult if you have many clients or if the client application opens more than one session.
Start with querying Oracle system views like V$SQL, v$sqlarea and
v$sqltext.
Which version of Oracle? If it is 10+ and if you have administrative access (sysdba), then you can relatively easy find executed queries through Oracle enterprise manager.
For older versions, you'll need access to views that tuinstoel mentioned in his answer.
Same data you can get through TOAD for oracle which is quite capable piece of software, but expensive.
Wireshark is indeed a good idea, it has Oracle support and nicely displays the whole conversation.
A packet sniffer like Wireshark is especially interesting if you don't have admin' access to the database server but you have access to the network (for instance because there is port mirroring on the Ethernet switch).
I have used these instructions successfully several times:
http://www.orafaq.com/wiki/SQL_Trace#Tracing_a_SQL_session
"though possibly not administrative access". Someone should have administrative access, probably whoever is responsible for backups. At the very least, I expect you'd have a user with root/Administrator access to the machine on which the oracle database is running. Administrator should be able to login with a
"SQLPLUS / AS SYSDBA" syntax which will give full access (which can be quite dangerous). root could 'su' to the oracle user and do the same.
If you really can't get admin access then as an alternative to wireshark, if your front-end connects to the database through an Oracle client, look for the file sqlnet.ora. You can set trace_level_client, trace_file_client and trace_directory_client and get it to log the Oracle network traffic between the client and database server.
However it is possible that the client will call a stored procedure and retrieve the data as output parameters or a ref cursor, which means you may not see the query being executed through that mechanism. If so, you will need admin access to the db server, and trace as per Dave Costa's answer
A quick and dirty way to do this, if you can catch the SQL statement(s) in the act, is to run this in SQL*Plus:-
set verify off lines 140 head on pagesize 300
column sql_text format a65
column username format a12
column osuser format a15
break on username on sid on osuser
select S.USERNAME, s.sid, s.osuser,sql_text
from v$sqltext_with_newlines t,V$SESSION s
where t.address =s.sql_address
and t.hash_value = s.sql_hash_value
order by s.sid,t.piece
/
You need access those v$ views for this to work. Generally that means connecting as system.

SQL 2005 Linked Server Query Periodically Failing

We have a database running on SQL 2005. One of the store procedure looks up a user's email address from Active Directory using a linked server. The call to the linked server occurs in a database function.
I'm able to call is successfully from my Asp.Net application the first time, but periodically after that, it fails with the following error:
{"The requested operation could not be performed because OLE DB provider \"ADsDSOObject\" for linked server \"ADSI\" does not support the required transaction interface."}
It appears that the amount of time between calling the function affects whether the linked server query will work correctly. I am not using any transactions. When I try calling the function in a quick make-shift SQL script, it runs fine everytime (even when tested in quick succession).
Is there some sort of transaction being left open that naturally dies if I don't try calling the procedure again? I'm at a loss here.
Here is the simple call in the store procedure:
DECLARE #email varchar(50)
SELECT #email = LEFT(mail, 50)
FROM OPENQUERY (
ADSI,
'SELECT mail, sAMAccountName FROM ''LDAP://DC=Katz,DC=COM'' WHERE objectCategory = ''Person'' AND objectClass = ''User'''
)
WHERE sAMAccountName = CAST(#LoginName AS varchar(35))
RETURN #email
I've worked with SQL Server linkservers often, though rarely LDAP queries... but I got curious and read the Microsoft support page linked to in Ric Tokyo's previous post. Towards the bottom it reads:
It is typical for a directory server
to enforce a server limitation on the
number of objects that will be
returned for a given query. This is to
prevent denial-of-service attacks and
network overloading. To properly query
the directory server, large queries
should be broken up into many smaller
ones. One way to do this is through a
process called paging. While paging is
available through ADSI's OLEDB
provider, there is currently no way
available to perform it from a SQL
distributed query. This means that the
total number of objects that can be
returned for a query is the server
limit. In the Windows 2000 Active
Directory, the default server limit is
1,000 objects.
I'm thinking that the reason it fails on you (or not) depending on whether call it from the app or from a "quick make-shift sql script" (as you put it) might be related to the security context under which the operation is executing. Depending on how the link server connection was set up, the operation could be being executed under a variety of possible credentials depending on how you initiate the query.
I don't know, but that's my best guess. I'd look at the linkserver configuration, in particular the linkserver settings for what set of credentials are used as the security context under which operations executed across the linkserver run.
Rather then query Active Directory through a linked server, you might be better off caching your AD data into a SQL database and then querying that instead. You could use Integration Services by creating a OLE DB connection using "OLE DB PRovider for Microsoft Directory Services" and having a DataReader source with a query like:
SELECT physicalDeliveryOfficeName, department, company, title, displayName, SN,
givenName, sAMAccountName, manager, mail, telephoneNumber, mobile
FROM 'LDAP://DC=SOMECO,DC=COM'
WHERE objectClass='User' and objectCategory = 'Person'
order by mail
Using this method you will still run into the 1000 row limit for results from an AD query (note it is NOT advisable to try and increase this limit in AD, it is there to prevent the domain controller from becoming overloaded). Sometimes its possible to use a combination of queries to return the full data set, e.g. names A - L and M - Z
Alternatively you could use the CSVDE command line utility in Windows Server to export your directory information to a CSV file and then import it into a SQL database (see http://computerperformance.co.uk/Logon/Logon_CSVDE_Export.htm for more info on exporting AD data with CSVDE).
please read the support page from Microsoft
I suspect that it might be the cached query plan due to your statement that "When I try calling the function in a quick make-shift SQL script, it runs fine everytime (even when tested in quick succession)."
Could you try executing your stored procedure like so:
EXEC usp_MyProcedure WITH RECOMPILE
This question appears in the top of the first google page when search for the error string but has not valid answer.
This error happens intermitently when isolation level is not specified on .NET code nor in Store Procedure.
This error also happens in SQL Server 2008.
The fix is force SET TRANSACTION ISOLATION LEVEL READ (UN)COMMITTED because a isolation level any higher is not supported by Active Directory and SQL Server is trying to use SERIALIZABLE.
Now, as this error is intermitent. Why is ADO.NET or SQLServer switching its default isolation to SERIALIZABLE sometimes and sometimes not? What triggers this switching?