Category Archives: Bad Design

Transport security in online banking, or: “Not my Department”

Lately, I have been trying to improve transport security (read: SSL settings and ciphers) for the online banking sites of the banks I am using. And, before you ask, yes, I enjoy fighting windmills.

Quick refresher on SSL / TLS before we continue: There are three things you can vary when choosing cipher suites:

  • Key Exchange: When connecting via SSL, you have to agree on cryptographic keys to use for encrypting the data. This happens in the key exchange. Example: RSA, DHE, …
  • Encryption Cipher: The actual encryption happens using this cipher. Example: RC4, AES, …
  • Message Authentication: The authenticity of encrypted messages is ensured using the algorithm selected here. Example: SHA1, MD5, …

After the NSA revelations, I started checking the transport security of the websites I was using (the SSL test from SSLLabs / Qualys is a great help for that). I noticed that my bank, which I will keep anonymous to protect the guilty, was using RC4 to provide transport encryption. RC4 is considered somewhere in between “weak” and “completely broken”, with people like Jacob Applebaum claiming that the NSA is decrypting RC4 in real time.

Given that, RC4 seemed like a bad choice for a cipher. I wrote a message to the support team of my bank, and received a reply that they were working on replacing RC4 with something more sensible, which they did a few months later. But, for some reason, they still did not offer sensible key exchange algorithms, insisting on RSA.

There is nothing inherently wrong with RSA. It is very widely used and I know of no practical attacks on the implementation used by OpenSSL. But there is one problem when using RSA for key exchanges in SSL/TLS: The messages are not forward secret.

What is forward secrecy? Well, let’s say you do some online banking, and some jerk intercepts your traffic. He can’t read any of it (it’s encrypted), but he stores it for later, regardless. Then something like Heartbleed comes along, and the same jerk extracts the private SSL key from your bank.

If you were using RSA (or, generally, any algorithm without forward secrecy) for the key exchange he will now be able to retroactively decrypt all the traffic he has previously stored, seeing everything you did, including your passwords.

However, there is a way to get around that: By using key exchange algorithms like Diffie-Hellman, which create temporary encryption keys that are discarded after the connection is closed. These keys never go “over the wire”, meaning that the attacker cannot know them (if he has not compromised the server or your computer, in which case no amount of crypto will help you). This means that even if the attacker compromises the private key of the server, he will not be able to retroactively decrypt all your stuff.

So, why doesn’t everyone use this? Good question. Diffie-Hellman leads to a slightly higher load on the server and makes the connection process slightly slower, so very active sites may choose to use RSA to reduce the load on their servers. But I assume that in nine of ten cases, people use RSA because they either don’t know any better or just don’t care. There may also be the problem that some obscure guideline requires them to use only specific algorithms. And as guidelines update only rarely and generally don’t much care if their algorithms are weak, companies may be left with the uncomfortable choice between compliance to guidelines and providing strong security, with non-compliance sometimes carrying hefty fines.

So, my bank actually referred to the guidelines of a german institution, the “deutsche Kreditwirtschaft”, which is an organisation comprised of a bunch of large german banking institutes. They worked on the standards for online banking in germany, among other things.

So, what do these security guidelines have to say about transport security? Good question. I did some research and came up blank, so I contacted the press relations department and asked them. It took them a month to get back to me, but I finally received an answer. The security guidelines consist of exactly one thing: “Use at least SSLv3“. For non-crypto people, that’s basically like saying “please don’t send your letters in glass envelopes, but we don’t care if you close them with glue, a seal, or a piece of string.”

Worse, in response to my question if they are planning to incorporate algorithms with forward secrecy into their guidelines, they stated that the key management is the responsibility of the banks. This either means that they have no idea what forward secrecy is (the reponse was worded a bit hand-wavy), or that they actually do know what it is, but have no intention of even recommending it to their member banks.

This leaves us with the uncomfortable situation where the banks point to the guidelines when asked about their lacklustre cipher suites, and those who make the guidelines point back at the banks, saying “Not my department!“. In programming, you call that “circular dependencies”.

So, how can this stalemate be broken? Well, I will write another message to my bank, telling them that while the guidelines do not include a recommendation of forward secrecy, they also do not forbid using it, so why would you use a key made of rubber band and rocks if you could just use a proper, steel key?

Don Quixote charging the windmills is licensed CC BY-SA 2.0
Don Quixote charging the windmills by Dave Winer is licensed CC BY-SA 2.0

And, of course, the more people do this, the more likely it is that the banks will actually listen to one of us…

A case study in bad design: PHP Generator for MySQL

Welcome to the second installment of the “case study in bad design”-series, where I talk about generally horrible design in code, security or user experience. Todays subject is the PHP Generator for MySQL software by SQL Maestro (whose website will present you with a self-signed certificate for *.magicshoes.net if you try to access it via SSL, so you at least have to give them credit for creativity in that area).

PHP Generator for MySQL is a software that allows non-programmers to create web-frontends to their MySQL-Databases. It does a comparatively good job and provides some decent options, although the UI is somewhat cluttered and unintuitive, and the error reporting in places nonexistant. I was required to use it (as opposed to writing something myself) during my last employment with an institute at my university.

The story begins in July 2012, when I noticed that the code generated by PHP Generator had multiple vulnerabilities to Cross-Site scripting, allowing me to steal the login cookie (which, for good measure, contained the password in clear text, even if it was stored as a hash in the database). I cursed, wrote up some proof-of-concept code and reported the vulnerability to the devs.

A few weeks later, a new version of PHP Generator was released, fixing one of the two Cross-Site scripting holes I reported. They never responded to my mail and never fixed the second Cross-Site scripting hole. So, a year almost to the day later, I sent a follow-up mail, reminding them about the holes I reported, reporting another hole and setting a deadline of two weeks, after which I would apply for a CVE and publish the vulnerability. That got their attention and they responded within a day and got a new build out a few days later, fixing the vulnerabilities (and refusing to credit me in the changelog for reporting these issues, but hey, whatever).

A few days ago, I took another pass at the code and found another vulnerability (HTML stored in the database would be evaluated when displayed on the website), complaining that they were now using unsalted hashes of the password for authentication in the cookies (instead of session IDs completely unrelated to the password, which would be a better practice) and, after past experiences, setting a deadline of a week for a reply. Once again, they replied within a day.

Appearently, evaluating HTML from the database was a feature and not a bug. A feature that was on by default and could be disabled on a “per-input” basis. Whoever thought that was a good idea? Every “feature” that opens up the possibility for a security hole as big as stored XSS should either be completely removed or be off by default, to be enabled manually and with a big message box warning about the security implications. To make matters worse, the state of this setting seems to not be saved in the project file, leading to compatibility problems if the default value was changed (and I have no idea how they would make this state persist over restarts of the program if they save the setting nowhere…).

As for the proper session management, they claim to be working on something. They also may add salted hashes, but have not fully committed on that, citing possible compatibility issues.

They closed their mail with a statement that blew my mind:

By the way, we have never received any security related complaints from other PHP Generator users, so probably there is no real threat.

I’m not going to comment further on this statement, as anyone with at least a rudimentary understanding of security should be able to see what is wrong with this.

PHP Generator for MySQL starts at $99 for a single, non-commercial license without upgrades. I would think that you could expect more interest in the security of their customers for that.

A case study in bad design. Todays subject: the Deutsche Bahn

Welcome to the first installment of the new series “a case study in bad design“, which will probably be an ongoing series unless something very surprising happens (namely, people stopping to write horrible code).

Todays subject is the homepage of the german railways corporation, the Deutsche Bahn. (And just setting this link revealed another faux pas, namely that their SSL certificate is only valid for www.bahn.de, not for bahn.de without the leading www).

Everything began with my mother (which is, in a way, not surprising at all, but in that case I am not talking about my birth). She regularily takes the train to Bremen, and had set up a profile for her usual passenger settings (economy or first class, which kind of seat, that sort of thing) in her bahn.de-Account. She noticed her profile repeatedly disappearing, which, at some point, made her so angry she wrote a mail to the people responsible for the website.

They responded with some seemingly senseless information about her browser not allowing cookies. But since no sensible person would store those presets in a cookie if you have a perfectly good user account to store it in, so that was obviously bullshit, right?

Right?

(Checks title of blog post) ah, damn.

A quick check turned up that the travel profile was indeed stored in a cookie. Which would have been bad enough as it was, considering that this profile…

  1. …would be nice to have on more than once PC without setting it up seperately
  2. …is user specific and, subsequently, has no business being in a cookie instead of a database in the first place
  3. …is something that does not change all too often, which makes putting it into a cookie even more stupid than it already is

Well, we now know that this information is stored in a cookie. Then again, this does not explain the random disappearence of it. That is, until you check the cookie information.

Yes, the cookie is valid for a whooping 10 days! This means that every time you don’t visit bahn.de for 10 or more days, you will loose all your preset profiles. Who exactly thought that this was a good idea? Because that person was wrong. As an added bonus, the cookie is not deleted if you log out, so if you, for some reason, create a profile on a public computer, you are leaking your travelling preferences (that’s probably not a big deal, but completely unnecessary).

But, while we’re at it, let’s play around with that cookie. Maybe we can find some Cross-Site scripting (considering all the places I have already found it, it would not surprise me to find it here). Quickly add some quotation marks, just to see what happens, aaaaand…

Obviously.

A quick trip to the source code (a mere 3000 lines of horribly indented HTML and Javascript) reveals a bunch of JavaScript imports. A glance at the *.min.js-files, followed by a curse, followed by the awesomeness that is http://jsbeautifier.org/, revealed somewhat readable Javascript code, containing gems like “b && (a = b)” (a shorthand for “if (b) a = b;”, as it seems) and wonderful “for”-statements like the following:
for (var f = c, c = d, e = void 0, e = void 0, g = [], f = f.substring(4); 0 < f.length && 0 != f.indexOf("]#");)
Appearently, separating statements in a conditional with commata makes them evaluate one after another, and the last statements result is used to check if the conditions of the conditional are fulfilled. I especially love the double assignment of e = void 0.

I will not torture you (or me) with the whole >12 000 lines of Code, but rest assured that it does not get better. In the end, I gave up on finding the cause for the lifelock that occured after my modifications to the cookie, seeing as I am not likely to be paid for this crap and my pain resistance is not high enough for this single-letter variable bullshit. I’ll notify them about it anyway, although I am not sure what (if anything) will come of it.

Review: The UNIX-HATERS handbook

Note: I have stopped releasing my book reviews on this blog, as I want to put it on a more technical track. But since this is a technical book, I’ll post this review anyway.

The UNIX-Haters HandbookThe UNIX-Haters Handbook by Simson Garfinkel

My rating: 4 of 5 stars

This book was, among other things, a good history lesson. I learned more about the history of UNIX and computers / computer science from this book than in the past three years of studying computer science. It also made me aware of some rather horrible design choices in both the old UNIXes and the modern Linux, to some extent.

The hating on UNIX going on in this book is written in a highly amusing way, and I found myself chuckling about finding the things that annoy me today in this book from 1994, almost 20 years ago. Appearently, no one was interested in fixing inconsistencies between programs, yet another proof of the theory that, by releasing a program, you make a temporary design choice into a standard (although this still does not explain the discrepancies between git commit -S and git tag -s, if you know what I mean).

All in all, I would recommend this book to people interested in the history of UNIX and bad design choices.

View all my reviews

Adventures in base64, or: How not to design your confirmation links

I recently applied for a room at a student housing complex. After finishing up my online application, I got a confirmation link. I clicked it, checked that everything was fine, and closed it. I then reopened it because the URL had caught my eye. Slightly modified for privacy:

https://[...]/xyz.html?ID=MTIzNHxEb2V8Sm9obnwxOTkwLTAxLTAxCg==

Now, if you’ve been playing around with “dd if=/dev/urandom | base64” like I have, you will see the patterns that imply a base64 encoded string in this URL. So, I quickly copied the ID and decoded it (as I said, I changed the ID around a bit to avoid disclosing personal information).

$ echo MTIzNHxEb2V8Sm9obnwxOTkwLTAxLTAxCg== | base64 -d
1234|Doe|John|1990-01-01

Sooo. Well, that’s not very secure, is it? Give me a confirmation link which I know how to build and only have to guess one part of, which is probably automatically incrementing. I can work with that. But then again, why would I want to fake registrations to a student housing complex? Let’s keep digging.

$ echo "1235|Doe|John|1990-01-01" | base64
MTIzNXxEb2V8Sm9obnwxOTkwLTAxLTAxCg==

Let’s enter that changed ID into the URL, and…

Your Application could not be confirmed: The application was not found in the database (Applicant_ID:1235, Surname:Doe, Name:John, DateOfBirth:1990-01-01)

Oh well. Okay, let’s at least check for Cross-Site scripting, maybe we can find something…

$ echo "<script type="text/javascript">alert('xss');</script>|Herp|De Derp|1337-42-42" | base64
PHNjcmlwdCB0eXBlPSd0ZXh0L2phdmFzY3JpcHQnPmFsZXJ0KCd4c3MnKTs8L3NjcmlwdD58SGVycHxEZSBEZXJwfDEzMzctNDItNDIK

Enter this into the URL, and…

Your Application could not be confirmed: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'text/javascript'>alert('xss');' and Surname='Herp' and DateOfBirth='1337-' at line 1

Yikes. At this point, I backed the hell off, because we have some pretty strict laws about this stuff in Germany. SQL injections are not to be taken lightly, so I quickly whipped up an eMail to the organization and explained the problem to them. I received a lot of silence, and after a few days, I called them up and asked if they had received my mail. They had, and were working on it.

Almost two weeks passed, and the hole was still there, so I called again and asked for the person in charge of the homepage. A brief talk revealed that they had passed the issue on to their vendor, who was, appearently, not very good with providing delivery dates. I asked if I could release this blog entry, and they asked for more time, which I agreed to.

Today, I received an eMail stating that the hole had been fixed. I double checked it, and appearently, it was indeed fixed. I also received permission to release this blog entry. Appearently, the system was in use not only at this specific institution, but also in some other institutions (who have been notified about the need to update, I hope).

All in all, except for the long periods of waiting, it was a pleasent experience. The people at the institution were friendly and understood the dangers of the issue. If everyone would react as quickly and professionally as they did, the web would probably be a more secure place. The reaction time of the vendor could be improved though, taking almost a month to deliver a fix for a critical security issue that could be fixed by changing approximately one line of code is not acceptable.