Tag Archives: security

Plain-text password storage is good

…or at least, not as bad as it’s sometimes made out to be.

Please note that I am not discussing any password system used by any employer, past or present. This is based on general industry knowledge only, and is meant to explain why so much software suggests or requires plaintext passwords to be stored.

When I first came across a professional application that used plaintext password storage (about six years ago now) – I thought, “Ugh, why would anyone store passwords cleartext?”. There are a huge number of really valid reasons why not to – the easiest one being simply “what happens if/when that database gets stolen?”. You may or may not be concerned by “Can the server admins and developers see my password?”. I found out why the hard way when I tried to do something similar, maybe a year or so later.

So, why would a sysadmin or software developer choose to use cleartext password storage, with the risks that it inherently has? The same reason as with most security issues – it’s overridden by convenience and usability. Password security has two main aspects; protection when stored, and protection when in transit.

In-transit seems pretty easy, but has quite a few pitfalls. A horribly common mechanism is just to pass it cleartext. Eww! Another is to pass it reversibly encrypted over SSL. Better – man-in-the-middle snooping is stopped – but still not really great. What about only sending an MD5 across the wire? Challenge-response systems are yet another solution – the server sends you a secret string, you combine it with your password in a way predictable to the server and send a munged ‘response’ back to the server. Great, right?

No. Your average challenge-response system uses a function along the lines of MD5(challenge+MD5(password)). So for both of the last two options, all the server needs to store is the MD5 of the password, instead of the password itself. Win. Except for the fail that you’ve just made your MD5 of your password valuable, because that’s all the attacker needs now – and that’s exactly what the server is storing!

Moving back to storage – what sort of authentication systems does your software use, and what do you need to store to support it? CRAM-MD5? Plaintext over the wire? APOP? Something custom? MD5? CHAP? What happens when CRAM-SHA256 displaces CRAM-MD5, and you’re only storing an MD5? You can only use the authentication methods compatible with what you originally planned for. Maybe you can work around it by storing ten different types of hashes, but it still isn’t really future-proof. You certainly aren’t protected against requests you could never foresee (Can we auth IMAP users against this forum user database?).

However, if you’re storing the password in cleartext, the answer becomes “So what? Can-do, boss!”. You can generate whatever sort of hash you need on the fly, you can use any password authentication scheme that you want. You can integrate with any password-based authentication scheme. Any. Not just the one you’re using today, or tomorrow, but the one you’ll be using five years from now. No matter how it passes over the wire, you can use it.

I’ve simplified this quite a bit, and there are a bajillion other ways to work around it – but nothing that is as compatible or usable as just storing the passwords in cleartext.

If you do want to work around it… Be inconvenienced! Some options might be:

  • Make a stand and decide what protocols you support
  • Don’t use just passwords, use two-factor authentication (passwords plus tokens, SMS codes, biometrics, etc)
  • Accept the cost of forcing the user to visit the “change password” page to generate new hash formats when needed

Even as a user, you have a great option for keeping your own security:

  • Use unique passwords for every account, so a compromised password can only affect the one account

It’s universally sound advice, but often ignored.

Remember finally that we (as developers and sysadmins) can make systems that are incredibly secure – just look at banks. It’s just inconvenient. Technical security, DMZs, firewalls, physical security policies, segregated backups, employee access policies. All that work! But it can be done.

UTF-8 issues in MSN Messenger

Please note that the following was written some time ago, when the described flaw was only freshly fixed. I found the document recently, and have cleaned up the text in minor places; other than that it is as written in early 2004

MSN Messenger inconsistent UTF-8 handling
(Or, How I Learned To Start Worrying and Hate UTF-8)

UTF-8 is a godsend. It allows encoding of foreign (including non-Latin)
characters into a file that’s still compatible with US-ASCII for all
English-only use. Editors that don’t understand it just show garbage
where there’s a foreign character, and handle the “normal” A-Z as they

You just have to remember when you’re using it and when you’re not.

I’d like to point out that this write-up is about vulnerabilities
eliminated almost a year ago, and is thusly entirely uncheckable now.

UTF-8 in Messenger
UTF-8 is used in most places in Messenger, which is great. What you
have to remember is what you consider UTF-8 text and what you don’t,
and to remember to treat UTF-8 text consistently. The problem with
Messenger’s UTF-8 support was in its handing of Display Names. MSN 4.x
(and probably 5.x) were never affected, since they didn’t seem to
support UTF-8 display names (only messages). MSN 6 was another issue

MSN 6 supported UTF-8 display names. In a couple of functions, it even
checked that the display name was valid. One of those functions was the
callback for when a “RNG” is received. RNGs are sent by the server to
the client as an invitation to a chat. If MSN6 thought the display name
was empty, the “ring” was never answered, and so the client never
joined the chat. With the advent of UTF-8, this left open a small
loophole – the two-byte display name “300200″ is a piece of invalid
UTF-8 representing the “NUL” character that Microsoft’s software -
against the UTF-8 specification – translates to “NUL”. Invalid UTF-8 is
supposed to be rejected, and for good reason.

Server-side, when an empty display name was set, the server would not
accept it. However, the server wasn’t using a UTF-8-understanding
string comparison function, so when it saw “300200″ it thought that
the name was non-empty, and allowed it. This has now been partially
fixed, resolving the problem this document describes.

When MSN6 sees “300200″ as the display name, it gets decoded from
UTF-8 into standard ASCII and compared to “” (a blank string). It is
considered a “match”, despite the fact that they are technically
different. Thus, “300200″ as a display name would stop MSN6 from
answering a RNG.

The mis-handling of a small piece of UTF-8 text, fixed to one line
long, seems unimportant. However, due to MSN6′s erroneous assertion
that the name is empty – something that is supposed to be impossible,
due to the assumption that the server would filter out empty names -
there is suddenly a serious problem.

The problem is that the RNG is never answered. Any method to force a
client to ignore a RNG is very dangerous, because it exposes a flaw in
another part of the MSN spec – the CKI challenges.

In order to join a chat, the client must supply two things – an email
address, and a “CKI” key, which is an automatically generated
“password” to allow entry into the switchboard session. The CKI is
(currently) just the current time in unix-epoch-style format, and what
appears to be a random unsigned 15-bit number. Because the time is easy
to guess, the only real “security” to stop one user joining a room as
another user is the random number.

15-bits cannot be brute-forced in the time it normally takes a client
to respond to a RNG, however if the client can be stopped from joining,
the invite lasts a lot longer than the usual 2-3 seconds. (I tested it
up to around five minutes). All it would take to join a chat as another
online user is to set the display name to “200300″, invite the user
into a switchboard, then connect yourself and authenticate as that
user, brute-forcing the random part of the CKI.

Microsoft already solved enough of the problem so that this exact
attack is no longer possible – the server now rejects UTF-8 that
resolves to an empty string. However, more could still be done. First,
the CKIs – which are considered opaque strings by clients – should be
changed or extended so that it is not feasible to brute-force it even
with days of use.

Anything else?
The idea of using invalid UTF-8 wasn’t mine; when looking at MSN security
I found some old Windows Messenger-era clients that could be “invisible” in a
groupchat by using invalid names. Although no longer functional, further
experimentation with the idea brought this problem to light. I also found that
at least some MSN versions would log out if they saw a user come online with
an invalid UTF-8 string as their display name.

The level of simplicity with which one could masquerade as another user
in this case brings to light trust issues with Microsoft’s
implementation of instant messaging. The time that this exploit would have been available is also concerning
- it could have affected users from the release of MSN 6.0 to its
resolution over six months later. What else is possible, and how long
will people be unknowingly at risk before that is fixed? Can you trust a
homogeneous environment that you can’t see into?