Hacker News new | ask | show | jobs
by kbenson 3337 days ago
Next, we reduced the response hash to one hex digit and authentication still worked. Continuing to dig, we used a NULL/empty response hash (response="" in the HTTP Authorization header).

Authentication still worked. We had discovered a complete bypass of the authentication scheme.

What. the. fuck.

This is not the kind of bug you should ship in anything if you have the barest bit of testing in place, much less a large company like Intel, in an enterprise feature which has a lot of security ramifications, and which has apparently existed for a long time (years?).

Edit: Also, this is really good evidence for short and hard disclosure deadlines. What's the chance something as simple as this wasn't known by someone else? All they had to do was decide to look and they found something within minutes. It's not like this is obscure or doesn't get your much, it's about as juicy as they come.

2 comments

Wow. Just Wow.

After reading about this over several days I would have never guessed it was such a gaping hole. This reminds me of a software bug I encountered in the 90s with a version of the Renegade BBS software (a Telegard hack). In one minor revision, you could login to any account by just not bothering to enter a password. Though the "sysop" (admin) account often had a custom name, for convenience, you could login by your user number and the sysop user number was always zero. A good friend of mine had his entire system wiped out by a malicious user with this little problem.

It doesn't sound like this is a matter of leaving the password field blank, but rather sending a request with a tool like cURL and setting the header to an empty/NULL response, but it's about as close to just as bad as you can get. Sheesh.

So what might the coding error have been? I mean, it seems like null password matches any password. Parsing null can be hard, but seriously?
In the case of Intel's AMT, I'm not sure what could have possibly gone wrong, but it sounds like this is something that has happened in other applications that use Digest Authentication.

In the case of Renegade's BBS software, I don't exactly recall the specifics and since it's been several years, I may not have this exactly right but I'm fairly certain this is how it happened because I did a lot of work with the code it was based on[0].

The bug occurred only if the user didn't provide a password. So, effectively, you could login by not providing a password or by providing the correct password. In the original Telegard source, the login prompt did nothing if no password was provided, it simply discarded the provided Enter and waited for a password. This was handled by a global function that was used for accepting input. I'm guessing that function was refactored (I ended up doing this ... it was pretty ugly IIRC) in the Renegade code and it became possible to send a blank password. The login routine was an interesting beast, as well. I remember reviewing it in the original code and scratching my head ... it made positively no sense and so I threw it out and replaced it with a much simpler implementation. Rumors had swirled around the release of the source code that this obfuscation was intentional and that there was a back-door built into the login routine. I'm not sure if that's true or not but the sheer amount of code to do a string comparison was a little ridiculous[1] -- passwords were not hashed, they were stored in plain text in a record (struct-like component) dumped to a file and were even viewable in the sysop control panel's User Editor.

It's entirely possible that they didn't refactor this bit of logic but changed something in that mess that caused an empty string to evaluate true along with a matched string. Or it could be that they refactored that like I did and put an OR where an AND belonged. If they refactored that global ReadLine method to allow empty returns, they may have felt a need to check for an empty value at this prompt, though I'm not sure what the motivation for this would have been. An empty or NIL value wouldn't have caused the application to crash -- there's no null reference exceptions when you're dealing in a non-OOP language -- you're not executing methods attached to the String type because such a thing didn't exist in the language.

The developer should have discovered the problem way before it was ever released in the wild, but I get why it was missed. He probably checked a bad value and a good value but never thought to check no value at all. Hell, it was a mystery why all of these Renegade boards were going down and a bunch of folks assumed it was a back-door, as was suspected about the original Telegard code. It was a few weeks before people figured out that it was such a simple screw-up.

[0] The source code wasn't public, it wasn't open source. In fact, it only existed because an older version of Telegard had its source code leaked, which the Renegade developers used to create their product (there were a number of "Telegard Hacks" in those days, including one I wrote and later rewrote from scratch and served as the entire reason I decided to become a software developer).

[1] Sounds suspicious at first glance but there were so many really poorly performing things about Borland Pascal's core libraries that it was not uncommon to write several hundred lines of inline assembly to do things like "write text to the screen quickly". I had done this, myself, on a few occasions -- the specifics were something around writing to memory reserved for use by the display capabilities of the 8088/80286/80386 (BIOS reserved memory IIRC).

[2] NIL was Borland Pascal's "null", and I believe it supported empty strings. Unlike ISO PASCAL at that time, Borland Pascal had a real string type which was stored in memory as a character array with a length field at the 0th index. It didn't use null terminated character arrays like C/C++ which made working with strings in the language elegant by comparison. Strings, however, were 8-bit ASCII ... this being the 90s with the target being DOS and all.

OK, it's explained in https://arstechnica.com/security/2017/05/the-hijacking-flaw-...

The code compares the correct "hash and the hash response received from the browser, with N set to the length of the response received from the browser". So if the browser returns "", that's compared with the first zero characters in the correct hash, which is also "". Funny.

Well... I agree with you in principle, but in practice I find developers often to forget that code fails the way it is supposed to fail, when it is supposed to fail. In the authentication case, everyone remembers to check that when you're supposed to be logged in, you can access what you should be able to access. But it's really common to not think to test that when you're not logged in you shouldn't be able to access what you should be able to access (when logged in), or that when logged in as user X you shouldn't be able to access user Y's stuff.
I hope that's more unlikely than you say.
The article in question mentions they reported essentially the same bug in IBM solidDB [1], and I recall that the first big break in Nintendo Wii application signing [2] was similar.

[1] http://www.zerodayinitiative.com/advisories/ZDI-11-115/

[2] http://wiibrew.org/wiki/Signing_bug