
300,000 WordPress hacking attempts and 5 observations - fredsted
http://simonfredsted.com/1260
======
ChrisNorstrom
DO NOT automatically IP blacklist offenders. I ended up with a .htaccess list
of 3,000 banned IPs which took my site down.

Use the highly loved, 5 star rated, 5+ million downloaded "iThemes Security
Plugin" for Wordpress (formerly Better Wordpress Security).
[https://wordpress.org/plugins/better-wp-
security/](https://wordpress.org/plugins/better-wp-security/)

● Use the "Change Admin" feature to change your admin username to anything
other than "admin".

● Hide your backend so that "yoursite.com/wp-admin" doesn't even lead to the
login screen

● Use "Away Mode" so the backend is completely disabled during certain days or
times of day. (10pm - 8am overnight)

● Enable "Brute Force" protection for logins, after 3 bad password attempts
the host should be locked out.

● DO NOT enable "Blacklist Offenders" feature. If you do, this will add the IP
address of offenders to your .htaccess file and eventually take your site
offline when the list reaches thousands of IPs. It doesn't scale and you can
quickly reach thousands of IPs in just a few days depending on the popularity
of your blog.

● Use "Immediately ban host who tries to log in as Admin"

Personally this is what I've found to work for me and my blog. Some days I get
220 hacking attempts and other days it dies down.

~~~
fredsted
That is some really good advice for keeping security tight, I'm going to link
this from my blog post if you don't mind.

Personally, since I basically use WordPress as a static HTML generator, I'm
wondering if there is a solution out there that can just decouple the
administration interface and put it on a while different domain, port, or
server – I really like WordPress for managing my content.

------
d23
> The top 1 IP address that have tried hacking my blog, 54.215.171.123,
> originates from a location you wouldn’t suspect: Amazon.

Really? That's basically exactly what I would expect.

~~~
fredsted
I would expect Amazon to have some automated abuse controls; the rest of their
infrastructure is pretty impressive.

~~~
medecau
What you're talking about requires deep packet inspection. I don't see why AWS
would do that on a platform that has the potencial to generate an enormous
amount of HTTP traffic.

The costs of operating something like this would have to be passed on to the
client making them less competitive. No way AWS would do this.

~~~
fredsted
Good point - I've not been involved in this kind of deep packet inspection
required to do this – in my mind, all it would require is a filter on "wp-
admin.php" and the resulting status code.

------
ChrisGranger
To my mind, that's a shocking number of attacks on a relatively small target.
It makes me wonder what sort of numbers the really famous sites are seeing,
and if they track the data in this way as well.

It's amazing that in nearly-2015, enough people still use passwords like
'123456' and 'password' such that they're still at the top of the guessing
list in hacking attempts. Some of us will never learn, I guess...

~~~
ckuehl
_> It makes me wonder what sort of numbers the really famous sites are seeing_

Not exactly a famous site, but I thought a larger sample size might be
interesting...

We [1] provides shared hosting for about 500 WordPress installations, of
widely varying sizes. The sites are mostly static "blogs" for student groups
or individual students, with about half on a single domain
(www.ocf.berkeley.edu/~something) and others on different subdomains of
berkeley.edu.

In the past week, the webserver handled 3,527,157 requests (about 814 MB of
uncompressed access logs). 111,409 of those were WordPress login attempts [2].

I was going to compare the list of top IPs with the list in the article, but
was surprised to find that there were no shared IPs between the lists. For
context, we had 435 unique IPs, 9 with > 1000 requests, and 32 with > 100
requests.

The top ten requestors in the past week are from (cities from whois data):

    
    
        56742 Kiev, Ukraine
        19302 Novosibirsk, Russia
         7645 Sofia, Bulgaria
         7641 Moscow, Russia
         7190 Kiev, Ukraine
         6748 Kharkov, Ukraine
         2160 Roubaix, France
         1041 Kharkov, Ukraine
          967 Kuala Lumpur, Malaysia
          894 Putian, China
    

[1] [https://www.ocf.berkeley.edu/](https://www.ocf.berkeley.edu/)

[2] POST requests to wp-login.php. I don't have accurate numbers on how many
failed, but to say that less than 250 were legitimate user logins is probably
accurate.

~~~
michaelcampbell
How can Kiev be #1 and #5? Similarly Kharkov.

~~~
ckuehl
Sorry, I should have clarified. That list is the top 10 IPs by number of
requests, not the top 10 cities. I just replaced the actual IPs with the
cities in their whois (since I'm not sure I want to post the IPs publicly).

~~~
michaelcampbell
AH, of course; thanks.

------
anewhnaccount
That IP address should be reported to Amazon so they can either cut off the
owner from AWS or inform them someone has cracked their system.

*Edit: here: [http://portal.aws.amazon.com/gp/aws/html-forms-controller/co...](http://portal.aws.amazon.com/gp/aws/html-forms-controller/contactus/AWSAbuse#other_abuse)

------
jlgaddis
I use the following in my nginx configuration (inside the "server" block) to
restrict access to the WordPress login page from two IP addresses (one is my
static IP at home and the other is the IP address of a VPN endpoint):

    
    
      location = /wp-login.php {
        allow x.x.x.x/32;
        allow y.y.y.y/32;
        deny all;
      }

~~~
iamjason89
Was just about to recommend this. Supporting Wordpress everyday, I find this
is the best way to combat the problem. Another option would be to add an
additional password for the directory. For you apache guys,

    
    
      AuthType Basic
      AuthName "Authentication Required"
      AuthUserFile "/etc/htpasswd/.htpasswd"
      Require valid-user

~~~
porker
Good tip. The other two changes I recommend are:

1\. Disable PHP execution in the uploads directory (hmm, wonder if it'd work
if I disabled it in the entire wp-content folder?).

2\. Run PHP as a different user to the file owner.

Both of these are to minimise damage when an extension is exploited by a
hacker (if it hasn't happened to you yet, it will do) and to reduce the damage
done to the server/site.

------
annnnd
Interesting addition to the plugin: check admin login credentials with the
passwords on the list. If found, notify the admin and disable his account
until he resets the password to something better.

Of course, you would have to accumulate the list across many computers and
distribute it to WP servers... And be careful NOT to include misspelled
passwords (invalid login followed by a valid login). :)

I am also not sure "top X passwords" list would be enough - you should
probably check against the whole list, which could be huge.

------
pan69
When you set up a new WordPress site, or you can do this for an existing site
as well, create a new user and give this new user the Administrator role. Then
log out and log in as the new admin user. Now, don't delete the original
"admin" user but instead change the password to something super strong and
give the user no role. This way, bots will think that the admin user exists
and will try to brute force the super strong password you gave it, which
obviously will be futile.

~~~
regecks
Unfortunately this is of limited helpfulness.

At my job (small web host), many of the WordPress brute force attacks we see
across our shared hosting fleet use the '?author=\d+' trick in WordPress to
find the usernames of admin-like users before starting the actual attack.

Totally idiotic of WordPress to reveal usernames this way.

We have moderate success in slowing/blocking these attacks using a WAF such as
mod_security (after a certain number of HTTP 200 responses on wp-login, aka
login failed, block the IP).

On the bright side, our load averages went down a non-trivial amount once we
introduced these rules (a few customers would get effectively and
inadvertently DoS'd by these brute forces LOL)

~~~
pan69
Hmm. The your ?author=\d+ trick doesn't seem to do anything on any of my
WordPress websites, just get a 404.

~~~
gondo
the \d+ is regular expression that means, use: ?author=1 ?author=2 ?author=3
?author=4 ...

~~~
regecks
Right.

e.g.
[http://en.blog.wordpress.com/?author=1](http://en.blog.wordpress.com/?author=1)
[http://en.blog.wordpress.com/?author=2](http://en.blog.wordpress.com/?author=2)

Pointless information disclosure

------
meigwilym
I'm not sure how effective this is, but I've recently started settin up
wordpress in it's own directory. It's a simple procedure, which defends
against fishing for example.com/wp-admin hits. All my WP sites are in
example.com/example/wp-admin.

Regular users never see the example/ directory.

------
dazc
Adding Two-Factor Authentication to the login doesn't stop the hacking
attempts but ensures they will fail.

------
passfree
Just in case someone wants to check "their own" wordpress deployments, there
is a free, friendly wordpress security scanner here:
[https://suite.websecurify.com/market/wpscanner](https://suite.websecurify.com/market/wpscanner)

------
junto
I use Login Security Solution plugin and IQ geo block plugin. I block all
users from problem countries like China, Russia and Ukraine (to name but a
few). I whitelist my own country and IPs to access the backend. Has worked
well for me so far. I also use Cloudflare.

------
laurencei
Could you also just alter the login page irk? I.e. Are the boys all directly
targeting /wp-admin - if so could you change the url to /secret - and then
they won't even be able to attempt to login in the first place?

~~~
Cthulhu_
Yeah that should be possible. In addition to that, change the default username
to something nonstandard, and if you have SSH run it on a non-standard /
random port too.

------
r109
OP does this plugin also monitor brute forcers that attempts that try to pass
credentials through POST strings? I see this shit often... annoying..

~~~
fredsted
It works by using the WordPress login hook, and that uses POST, so I'd say so.

