I’ve been getting a lot of e-mail, lately, from one of my websites.
I mean that quite literally: I’m not receiving e-mail through one of my websites, I’m receiving it from one of my websites.
It seems someone is attempting a brute-force password attack on the site. After a certain number of attempts, the website generates an e-mail and sends it to me, warning of a brute-force attack. At first, I got one or two e-mails a day. Now, it’s up to five or six e-mails per hour.
Time to take some action, and then blog about it. (Used to be you’d take action, then brag about it, usually at the local pub — we do live in an isolated world.)
I’m not really worried about a successful hack. I use reasonably “strong” passwords — random jumbles of letters, numbers, and punctuation. These brute-force hacks go after dictionary words and obvious guesses, like ‘password’ and ‘1234’. They aren’t getting in with a brute force attack.
But the e-mails are annoying. I could just turn them off, but the hack attempts are also using up bandwidth. I’d like to discourage them.
Turns out that they’ve been using something called the system.multicall exploit. Someone back in 2001 proposed a method of getting around website round-trip latency by packaging multiple requests, and the system.multicall PHP object on the server would field the package and execute all of the requests. If the requests required login to the site, each such request would have a login name and a password — and there’s the exploit. You package up a thousand requests in a single blob, containing a thousand different login names and brute force password guesses, fire it off at the site, and let it work.
Normally, password interfaces get twitchy if you fail too many login requests in a row, and lock you out for anywhere from several minutes to several hours. Since you have to get through billions of guesses before you hit gold, even a small delay of ten seconds is enough to frustrate the brute force hackers. But with this system.multicall exploit, there’s only one request with a thousand attempts in it, and it doesn’t even go through the login prompt (which is where all the lockout delays are placed). So these attempts get executed as quickly as the server can process them.
The notice I got from one of the security services said that the system.multicall service has almost no legitimate uses in the real world. So they suggested that we “disable” system.multicall. But their method, to the extent that they describe it at all, involves signing up for their web proxy service and paying them $9.95 per month. I decided to take a more direct approach.
I got into my own site via ssh — that’s the way I get onto the site for deep maintenance and code development — and ran a search for the system.multicall function in the WordPress code. It turned up in:
public_html/{mysitename}/wp-includes/class-IXR.php
which is more-or-less where I would have expected it to be. Here’s the relevant snippet from that file.
function setCallbacks() { $this->callbacks['system.getCapabilities'] = 'this:getCapabilities'; $this->callbacks['system.listMethods'] = 'this:listMethods'; $this->callbacks['system.multicall'] = 'this:multiCall'; } function listMethods($args) { // Returns a list of methods - uses array_reverse to ensure user defined // methods are listed before server defined methods return array_reverse(array_keys($this->callbacks)); } function multiCall($methodcalls) { // JCN - disabling this return array(); // See http://www.xmlrpc.com/discuss/msgReader$1208 $return = array(); foreach ($methodcalls as $call) { ... build up $return array items ... } return $return; }
Now, the nice way to fix this would be to remove the line that assigns ‘this:multiCall’ to the callbacks array. That means the method won’t even show up in the listMethods() call, so anyone trying to use system.multicall would be politely informed that system.multicall isn’t supported on this WordPress site.
I wasn’t in a nice mood.
So instead, I left system.multicall in the callbacks list, but I broke it, using the inserted line commented with JCN.
As explained here, the $methodcalls argument is an array of requests that ask for something that requires a login, and each request provides the login name and password to be used, which are the hack attempts. The response is supposed to be an array with one response for every request, and they look like this:
{‘faultCode': 403, ‘faultString': ‘Incorrect username or password.‘}, {‘faultCode': 403, ‘faultString': ‘Incorrect username or password.‘}, {‘faultCode': 403, ‘faultString': ‘Incorrect username or password.‘}, ... {‘url': ‘http://site.com/wordpress/’, ‘isAdmin': True, ‘blogid': ‘1’, ‘xmlrpc': ‘http://site.com/wordpress/xmlrpc.php’, ‘blogName': ‘wpxxx’}, ...
The line that isn’t a fault code indicates they successfully hacked the site. The response doesn’t have the user and password in it, so that means they have to match up the responses with the requests to find out which user/password combination actually worked. I thought it might be interesting to fake up a response like this:
{'url': 'http://www.fbi.us.gov/cyberterrorism_task_force/backtrace_ip.php', ..., 'blogName': 'you_are_fucked'}
Not that there is such a site. The idea is just to make the hacker’s blood run cold, since my guess is that whoever is using this hacking software probably doesn’t know much about how it works — a lot of hackers just used canned software they pick up on hacker sites, and have no idea what the code actually does.
So when this popped up in their results, they’d pee themselves and spend the next month looking over their shoulders, not knowing if their hacking software (which they don’t understand) actually called the URL and activated a trap that backtraced their real IP address, right through the IP anonymizer they’re using. After all, it’s the FBI, right? They can do that sort of thing, right?
Yes, I have a mean streak. I don’t let it out to play very often.
I didn’t let it out this time. Instead, I decided to just return an empty array, in the hopes that it might actually break their hacking code. I don’t know how fault-tolerant their code is, but since they have to match requests with responses, and there aren’t enough responses for the requests, it could crash poorly-written code.
If it’s kids getting into mischief, they’ll have to work pretty hard to learn enough about their hacking code to get it to run at all against my site without crashing. It’s a challenge and some good training for them. Eventually, they’ll give up, and go away.
If it’s some amateur hacker ring in Russia or China, it’s going to piss them off: they’re probably hacking hundreds or thousands of sites, simultaneously, and selling the cracked passwords to some broker, who then sells the information for a substantial markup to people who want to take over domains that can’t be traced back to them. Crashing their code means they’re losing money. They’ll have to spend time trying to figure out which site tripped them up. In the meantime, they’re down — every time they start their code, as soon as it hits my site, they go down again. Boo-hoo. They’ll eventually find that my site is messing them up, and stop poking at it.
If it’s a more professional ring, with more competent software (and developers who know what they’re doing), they’ll just scrub my site from their list and move on. In fact, it’s probably automatic: that’s how I’d design it. First sign of trouble, and you drop the attacks. Every attack they make on an aware site carries an exposure risk for them, and there’s no point in that. Plus, an aware site means strong passwords, so the brute-force attack is a waste of time. They’ll move on.
Regardless of which scenario (if any of these) is true, the system.multicall door is closed, and whoever was doing this will move on, like any parasite when the feeding is poor.
But I’d like to think that somewhere in the world, some hacking code is, at this very moment, choking to death on (literally) nothing.
You must be logged in to post a comment.