Writing

Feed Software, technology, sysadmin war stories, and more.

Sunday, June 9, 2013

Feature plus feature equals security hole

I think some of the most interesting and/or unintentionally funny security holes come from the interaction of unrelated features or bugs. This is where someone starts seeing the "big picture" and comes up with new connections which turns out to be useful in nefarious contexts.

It seems like a lot of holes these days are variants on themes like buffer overflows and SQL injection, but I saw one which was entirely different some time back. It was an effective way to get admin powers or anyone else's account for that matter, and it was all in the name of ease of use for developers.

Someone on the outside, perhaps a client or their security contractors, was doing a black box audit of this software. Part of this process involves sniffing around through the binaries to look for interesting strings or other oddities which might be worthy of further analysis. I've done this myself to discover under-documented features in the absence of source code, for instance.

Anyway, it seems they discovered a string along the lines of "backdoor_mode". You have to admit that's a rather interesting thing to find in a program which is supposed to be a secure gatekeeper for valuable data! This filtered back to the developers as a bug report, and someone on the QA side of the team started tracing it back in the source code. That's when they found it.

It seems the program had a command line flag called "--backdoor_mode", and it was a boolean. If set to true, it would switch on something interesting in the authentication code. There was a section where it took the username and crypto credentials which were passed in and verified them. Well, this flag showed up in there and looked like this:

valid_user = false;
 
if (setting_enabled("backdoor_mode")) {
  if (username.find("_xyzzy_") == 0) {
    username.erase(0, 7);
    valid_user = true;
   }
} else {
  valid_user = user_check(username, crypto_stuff):
}

For those who don't speak C++, I'll explain. It assumes the user isn't valid by default. Then, when the backdoor_mode has been switched on, then it checks to see the username you presented. If it starts with "_xyzzy_", then it chops that off and asserts it's a valid login.

So what's the upshot of this? Well, with this mode enabled, you can effectively become any user you want, and you need not present valid cryptographic data. This sounds mighty useful for developers, right? This way, you can stand up a test instance with the flag set on the command line and then use the "xyzzy trick" to become anyone you want. It's necessary to test scenarios where user A can't see user B's files, or vice-versa.

If this is so useful, then where's the hole? To understand that, you have to know a little about the rest of the program. It's another feature which is provided by way of some network library code. This code allows you to view a bunch of internal variables inside the program, much like how SNMP works. You can poll it any time you like to see what's going on. It's great for monitoring.

This same library code also makes it possible to set values. It runs without authentication, and lets you do things like increasing the debug level. This is useful for run-time troubleshooting.

Unfortunately, it was also possible to set the value of the backdoor_mode flag itself. Yep, even though that was the sort of thing which should only be set from the command line, it was wired all the way through to the insecure network access code.

Someone who possessed all of this knowledge could now do some rather interesting things. First, they would send the server a SET command to flip backdoor_mode to true. Then, they'd try to access it as the target username with "_xyzzy_" in front, and with any old crypto credentials they wanted, since they wouldn't be checked.

The server would let them in, and now they could do anything they wanted as if they were that user. Even the logs would look like it was ordinary accesses by that user. Nobody would know what was going on.

When this came to light, people started freaking out. It had been in the code for several versions, and was present in every single released version which was still in use. There was no way to disable it without replacing the binary in question. This could mean a forced upgrade since there were no patches for old versions. All of that meant it was no small thing to fix this hole, since an upgrade would take a lot of work.

The news had to be distributed to just the minimum set of people: those who could perform the upgrades and patches to their installs. Everyone else at those sites just heard that there was a "required upgrade" being performed by someone, and they couldn't talk about why. It wasn't until later that they could come forth with the details, assuming anyone still cared.

By itself, being able to get and set variables remotely is useful. Likewise, being able to spoof users in a development setting is useful.

It's just the mix of the two which makes life interesting.