How to exploit a SQL injection inside "IN" condition? - sql

I am trying to exploit the following sql (in SQL Server 2014):
declare #maliciousSQL nvarchar(max);
set #maliciousSQL = '???'
exec ('SELECT SUM(quantity) from mytable where id in ' + #maliciousSQL );
How can parameter #maliciousSQL be crafted to run any arbitrary sql? Assume the task is to execute command 'truncate table othertable' - is it doable?
Thanks to anyone for help

SQL Injection looks like this:
declare #maliciousSQL nvarchar(max);
set #maliciousSQL = '(1); DELETE test1;'
exec ('SELECT SUM(quantity) from mytable where id in ' + #maliciousSQL );
Terminate the statement with a semicolon then write what you like

You can use this:
set #maliciousSQL = '(1); truncate table XXX;'
The entire point is to do not concatenate SQL statements and preferring to use parameterized queries.
Actually, the question title is misleading: you can't run DDL inside a DML statement, but a malicious caller can run multiple separate commands if you allows unsafe concatenation.

You need to set up the SQL before executing. I also recommend sp_executesql. So:
declare #maliciousSQL nvarchar(max);
declare #sql nvarchar(max);
set #maliciousSQL = '???'
set #sql = 'SELECT SUM(quantity) from mytable where id in ' + #maliciousSQL;
exec sp_executesql #sql;

Related

Scalar variable must be declared in SQL variable

I'm creating a report using sql scripts through management studio and I'm getting the error " Must Declare the scalar variable "#Account". I've been reading other similar questions on this portal but they are related to c#
I'm currently trying to reduce the code on the script so I decided to put a sql script into a variable because depending on a condition the where condition will change. Below is an example of the code
Declare #Account int = 1 , #SQL varchar(max)=''
Select #SQL = N'Select ColumnA,ColumnB, ColumnC from Table1 where ColumnA =1'
if #Account IS NULL
Begin
exec(#SQL)
end
--Here is where the error is hapening
else
begin
--This is the line causing the error
Select #SQL = #SQL + 'AND ColumnB=#Account"
exec(#SQL)
end
If I type manually the value of the variable next to "ColumnB=" it works but the account number will be selected by the user executing the script. I'm thinking on maybe building a temp table to capture the variable value and then do a sub query on the where condition but maybe the solution to this error may be more easier
You want sp_executesql:
select #SQL = #SQL + 'AND ColumnB=#Account';
exec sp_executesql #SQL, N'#Account int', #Account=#Account;
This is how you pass parameters into a dynamic SQL statement in SQL Server. I strongly recommend that you only use sp_executesql to execute SQL statements -- even when you don't have parameters. Using it makes it easy to implement parameters when you need them.
You are passing in '#Account' into the #SQL variable -- the underlying EXEC cannot see that variable.
One way of fixing this would instead be to do this:
Select #SQL = #SQL + 'AND ColumnB=' + CAST(#Account as varchar)

Is it possible to set a part of a select statement in a variable

I have a query of which the select-part is really long. I'd like to split this in several pieces, especially because some parts are in there twice or even more often.
What I'd like is something like the following:
Declare #SQLPart as varchar(1000)
Set #SQLPart = 'Field1,
case ... as Field2,'
Select ..., #SQLPart, ... From .....
Unfortunately this results error messages. I tried something like EXEC(#SQLPart) as well but of course this also didn't work. How would I solve this?
Yes, dynamic sql and sp_executesql:
CREATE TABLE ##Temp (Field1 int, Field2 int)
Declare #SQLPart nvarchar(1000)
Set #SQLPart = N'Field1, Field2 '
DECLARE #SQL nvarchar(1000) = N'SELECT ' + #SQLPart + 'FROM ##Temp'
PRINT #SQL
EXEC sp_executesql #SQL
DROP TABLE ##Temp
Your SQL code must be nvarchar type.
Alse sp_executesql is better than EXECUTE function, when you have many similar queries, sp_executesql caches executaion plans, and it can be better in perfomance.
You can use dynamic sql here,and use a EXECUTE keyword to execute this dynamic query
Declare #SQLPart as varchar(1000)
Set #SQLPart = 'Field1,
case ... as Field2,'
EXECUTE ('SELECT ....,'+#SQLPart+',... FROM ...')
SQL Server does not support Macro-Substitution, so you would have to use Dynamic SQL.
Declare #SQL varchar(max) ='Select ... ' + #SQLPart + '... from ...'
Exec(#SQL)

Get error in string query

I'm a beginner to SQL Server
I wrote this query:
DECLARE #sql nvarchar(1000) = 'UPDATE Work
SET [Name] = Programmer, [ImageAddress] = pic.jpg
WHERE Id = 2'
SELECT #sql
EXEC Sp_executesql #sql
but I get this error
Invalid column name 'Programmer'.
Why do I get this error?
Thank you for your help
You are dealing with SQL in strings. Quoting the strings becomes a challenge. You need for Programmer to be in single quotes when the query is executed. To get this, you need double single quotes in the string:
DECLARE #sql nvarchar(1000)='
UPDATE Work
SET [Name] = ''Programmer'', [ImageAddress] = ''pic.jpg'' WHERE Id=2'
select #sql
EXEC Sp_executesql #sql;
Because you are wise enough to use sp_executesql, you should learn about parameters. You can write the query as:
DECLARE #sql nvarchar(1000)='
UPDATE Work
SET [Name] = #Programmer, [ImageAddress] = #imageaddress WHERE Id=2'
select #sql
EXEC Sp_executesql #sql, N'#programmer nvarchar(255), #imageaddress nvarchar(255)',
#programmer = N'Programmer', #imageaddress = N'pic.jpg';
This has several advantages besides the quoting. It is safer in terms of SQL injection and it allows SQL Server to cache the execution plans if the query is called more than once.
try this:
You need to use '' (Double Quotes for string) Inside Dynamic SQL
DECLARE #sql nvarchar(1000)='
UPDATE Work
SET [Name] = ''Programmer'',[ImageAddress] =''pic.jpg'' WHERE Id=2'
select #sql
EXEC Sp_executesql #sql

Transact SQL result of query used in another

I need to get the table name to query from a table.
var tableName = "select tableName from tableList where type='A';"
Then subsequently use that table name in another query.
"select * from" + tableName
Transact SQL/stored procedures are new to me in general so any help would be appreciated. I didn't design the database and unfortunately can't really change it to be a better design as much as I would love to!
My question is - is this possible from one stored procedure and if so can anyone mock up how I'd do it.
Or if there are any better ways anyone can think of (bar redesigning the database!)
Thanks
Maybe via dynamic SQL
DECLARE #String AS VARCHAR(8000)
DECLARE #TableName AS VARCHAR(50)
DECLARE #Results AS VARCHAR(8000)
SET #TableName = (select top 1 tableName from tableList where type='A')
SET #String = 'Select * from ' + #TableName
SET #Results = #String + #TableName
EXEC #Results
You can either use execas #kevchadders suggested or you can use sp_executesql, read The Curse and Blessings of Dynamic SQL for an excellent explantion on dynamic SQL.
You should use dynamic SQL to achieve that.
Basically, you execute your query using sp_executesql or exec, and store the result to a, kinda, staging table to be processed further:
declare #sql = varchar(8000);
select #sql = 'insert into resulttbl select * from ' + #tableName;
exec sp_executesql(#sql);
-- further process using resulttbl
Or
insert into resulttbl
exec ('select * from ' + #tableName);
-- further process using resulttbl
Anyway, you should read the following article for a better explanation: The Curse and Blessings of Dynamic SQL
You can directly write
select * from (select tableName from tableList where type='A') X

How to use a varying database?

I want to use a database which name is stored in a variable. How do I do this?
I first thought this would work but it doesn't:
exec('use '+#db)
That will not change database context
Suggestions anyone?
Unfortunately I don't know of a direct solution to this one. The nearest working version is:
DECLARE #db nvarchar(MAX)
SET #db = 'use DBname'
Exec sp_executesql #db
but this only changes the context for the length of the procedure call. However, more statements can be included in that call to make use of the context:
DECLARE #sql nvarchar(MAX)
SET #sql = 'use DBName SELECT * FROM Table1'
Exec sp_executesql #sql
If you absolutely have to do this using dynamic SQl, I prefer this:
DECLARE #sql nvarchar(MAX)
declare #databasename varchar (20)
Set #databasename = mydatabase
SET #sql = 'SELECT * FROM ' + #databasename + 'dbo.Table1'
Exec sp_executesql #sql
The reason I prefer it is that you can extend it to use multipe datbases in the same query if need be.
I havea a concern that you don't know the datbase name for each table already without resorting to dynamic means. In other words, why can't you write:
SELECT * FROM mydatabase.dbo.Table1
If you have multiple databases with the same table names, likely you have a design problem.
The use statement is only in scope inside the exec block. Therefore you would have to do everything else in the same exec:
exec('use '+ #db + '
--do other stuff'
)
Presumably you know all the possible database names. One (slightly inelligant) way of doing this would be to use a CASE or multiple IF statements to test the variable and hardcode the USE statement for each case.