Unu, a Romanian hacker (he who may enjoy the challenge of breaking into other computers but does no harm) who we’ve talked about on the site before has been busy with his fifth demonstrated SQL Injection vulnerability on the web site of a well known company in the last 30 days. This time he has again targeted Kaspersky Labs, the anti-virus vendor that he previously demonstrated web site vulnerabilities for back on February 7th of this year. The sites affected this time around are the Kaspersky Lab sites in Malaysia http://www.kaspersky.com.my and Singapore http://www.kaspersky.com.sg. On both sites it is a news section, news.php, that is vulnerable, leading to the same MySQL database backend, and exposing customer and employee access credentials as well as what appear to be activation keys for Kaspersky Internet Security 2010.
As noted, the page news.php on both sites is identical, and subject to the same SQL injection vulnerability. Here is what the page looks like under normal circumstances.
“I do not break, I do not delete, I do not change, and I NEVER save anything.”
Same Server, Same Database
Unu starts out pointing out that he notices that the same SQL injection, enumerating table names, returns the same results on both the Singapore and Malaysia web sites.
“It was not about any kind of attack…my intention. I am not a thief. I’m just a guy who likes to do security testing, penetration. It’s like any other hobby”
Further inspection reveals they return the same IP address as well (18.104.22.168) in Malaysia.
The links in the screenshot Unu next presents represent what appear to be the contents of the mysql.user table which appears to show seven unique users as well as a few entries with different IP’s for root. As Unu notes, the ‘%’ entry for host means that the associated user can connect from any host, although an outside the company connection to the MySQL instance running on the box would usually require port 3306 to be open on the machine.
In the part of the URL we see, he requests: concat(user,0×3a,host,0×3a,password) which would show ‘user:host:password’ when successful (0×3a is hex for ‘:’).
Unu walks us through an experiment where he performs a rainbow table or dictionary password brute forcing technique for the user id beginning ph (the last entry in the screenshot) with a hash in the password field of A1F1CB851D62F002C09A0C9C4A76262473432F55. To verify he is correct, that this is password !QAZ2wsx, we use the same method MySQL uses in its Password() function for its internal user table which is a function that essentially performs two hashes of the password string using SHA1:
>>> import hashlib >>> hashlib.sha1(hashlib.sha1('!QAZ2wsx').digest()).hexdigest().upper() A1F1CB851D62F002C09A0C9C4A76262473432F55
Or we could also just do this using MySQL’s built in function:
mysql> SELECT PASSWORD('!QAZ2wsx'); +-------------------------------------------+ | PASSWORD('!QAZ2wsx') | +-------------------------------------------+ | *A1F1CB851D62F002C09A0C9C4A76262473432F55 | +-------------------------------------------+ 1 row in set (0.00 sec)
And Unu is correct, as the output is the A1F1CB851D62F002C09A0C9C4A76262473432F55 hash. Of course Unu broke the password having only the hash, for that we outsource to http://www.passcracking.com a Russian site that “uses combined technique (classic rainbow tables, hybrid rainbow tables, dictionary) for md5 hashes and simple dictionary search for other hashes.“. We input our string A1F1CB851D62F002C09A0C9C4A76262473432F55 and get this result:
Unu then presents a screenshot that appears to be a table of user ids for the Kaspersky web site access (my.kaspersky.com?).
From the parts of the query we can see in the URL, we note a request for fields: lastname:email:address:postcode:city:state:country:memberpwd. The nature of this data seems to be related to data filled in during the installation process:
Unu doesn’t give us a full entry that is not obfuscated, but at 32 characters the passwords are likely MD5 hashes.
His next screenshot appears to pull data from a table of probable employee id’s for web application access for Kaspersky employees. At least two have privileged access based on the first table entry being for a generic user name “ADMINISTRATOR” with a role ’1′, which is present also in the last id on the screen (the others show role ’2′).
These password fields are 32 characters long, and thus likely MD5 hashes. Unu notes that four of the hashes are the same (e99a18c428cb38d5f260853678922e03), and cracks them to reveal a password of ‘abc123′. As four passwords are the same, this is likely a default password or a standard set up password rather than one that four employees uniquely selected. (if it was 123456 I may think differently)
We verified Unu’s claim in python to prove it correct:
>>> import hashlib >>> hashlib.md5('abc123').hexdigest() 'e99a18c428cb38d5f260853678922e03'
And we also tried it out using the Coder utility from bindshell.net, just to demonstrate another tool:
And finally we have to do it the reverse way the same way Unu did. So we took the hash e99a18c428cb38d5f260853678922e03, and this time we’ll try www.md5decrypter.com, and we also get abc123.
A more correct way to store user passwords in a custom web application database to avoid attackers being able to exercise simple cracking of the MD5 hashes? Use a salt value in the encryption: md5($salt . $password). Note that this doesn’t perform miracles, just makes it more difficult.
mysql> select md5(concat("TWFuIGlzIGRpc3Rpbmd1aXNoZWQsI", "123abc")); +--------------------------------------------------------+ | md5(concat("TWFuIGlzIGRpc3Rpbmd1aXNoZWQsI", "123abc")) | +--------------------------------------------------------+ | c4462dfd359bf907bcf0aeb330892f91 | +--------------------------------------------------------+ 1 row in set (0.00 sec)
Example of salting a hash in python:
>>> import hashlib >>> salthash = hashlib.md5() >>> salthash.update("TWFuIGlzIGRpc3Rpbmd1aXNoZWQsI") >>> salthash.update("123abc") >>> salthash.hexdigest() 'c4462dfd359bf907bcf0aeb330892f91'
Kaspersky Access Keys?
The last screenshot Unu presents as showing serial numbers and/or activation codes for Kaspersky products, and notes the query returned 12,900 results. His query, what we can see of it, requested fields called rkeyid, rkey, rkeymd5, productid, and createddatetime. Looking at the screenshot, we see that rkeyid is an autonumber type field, just a key that increments one with each entry. The rkey field does not match an activation code for a Kaspersky product (only twenty characters), and we can see from the productid field that the rkey is matched to Kaspersky Internet Security 2010, the combined anti-virus, anti-spyware, anti-spam, and parental controls software package.
When you purchase a Kaspersky product, you get an activation code in the format of XXXXX-XXXXX-XXXXX-XXXXX. This code is inputted into the Kaspersky product during installation, which connects to the Internet in order to receive a key file back from Kaspersky that activates the product. We’re guessing rkey and its related hash file rkeymd5 are key files for the Kaspersky product. If that’s true, then the visible third entry which Unu did not block out in the screenshot is a Kaspersky Internet Security 2010 product key.
The Youtube video below from IWEB Productions demonstrates how this works (however they are showing how to use a key file you already have, entering a bad activation code and skipping the download of the key, a subversion of the Kaspersky licensing process).
Our friends from Romania who comment on the blog get annoyed when we speculate, but a popular tool for performing SQL Injection attacks on web applications with MySQL database backends, that typically starts by checking load_file, and requests data using the ordering concat(user,0x3a,host,0x3a,password) (whereas a SELECT * in MySQL would output host, user, password as the order) is rsauron’s schemafuzz.py. If Unu tells us differently, we’ll post an update.
Previous SQL Injection on Kaspersky USA
On February 7th, 2009 Unu had found a SQL vulnerability in the U.S. version of the Kaspersky web site. Kaspersky posted a press release describing their response to the incident, including bringing in database security expert David Litchfield to provide analysis. Perhaps unfortunately, they included the following language back in February:
Kaspersky Lab recognizes the fact that this attack could have had much more serious consequences. The company is conducting a thorough security audit of all official Kaspersky Lab sites and developing additional internal review procedures to ensure corporate resources are protected from similar attacks in the future.
Unu has been picking on security companies of late, in addition to the two successful attacks on Kaspersky web properties he has demonstrated SQL injection attacks on the web sites of both nProtect and fellow anti-virus vendor Symantec.
Kaspersky Lab is a privately held company headquartered in Moscow, Russia with about 1200 employees spread throughout the world. It was founded in 1997 by the now divorced Natalya and Eugene Kaspersky. The Kaspersky anti-virus products generally score well in comparative analysis of anti-virus products by independent test labs. Their Chief Operating Officer, Eugene Buyakin, was projecting revenues of $480 million for 2009 back in the beginning of the year.
Who’s Unu? (from a previous post)
Unu, apparently from Bucuresti Romania, says that for him penetration testing and finding vulnerabilities is a hobby and a passion. His blog, a testament to the results of his hobby, is a compilation of the results of successful SQL Injection attacks against web sites like BNP Paribas, Credit Agricole in France, Royal Bank of Scotland’s WordPay, Poste Italiane (the Italian Postal Service) and others as well as examples of successful parameter manipulation and other web application vulnerabilities. He appears to practice a version of responsible disclosure in that he has notified the organizations mentioned on the blog and explained the problems. His blog, and its disclosures, are interesting reading for the security professional and thus we encourage you to have a look.
The problems appear to be corrected, we assume David Litchfield is catching a plane as we speak. Kaspersky may want to tone down the next press release unless they are sure all of their global web properties are and will remain unassailable. In our estimation it would be easier to reword the press release, as achieving perfect resistance to web application vulnerabilities is not a reasonable goal. Regular testing of new web site changes in a testbed environment before production release, and regular scans of the production web properties with a web application vulnerability scanner along with hand testing by a quality security professional would be reasonable approaches.
- Black Day to Kaspersky, vulnerable again, again exposes users and serial data
- From back in February: Kaspersky Lab Confirms Website Attack; Verifies No Data Was Compromised
- How Rainbow Tables work
Filed Under: SQL Injection