SANS Penetration Testing

Pass-the-Hash Web Style

[Editor's Note: My goodness, there are a lot of ways to get authentication wrong in the web application world. In this article, my esteemed pants-wearing colleague, Tim Medin, describes a couple of problems we frequently find in web application penetration testing, and how to operationalize attacking them in your pen test projects. -Ed.]

We all know about the Pass-the-Hash technique as it relates to Windows systems, but what about on the web? No, I don't mean Windows web apps either. I'm talking about a different kind of pass-the-hash, one where the web app developer congratulated himself with an ingenious security feature, but almost completely missed the goal in securing the application's authentication.

Let's start off by looking at the normal flow for web app authentication:

  1. Present authentication form to user
  2. User enters credentials, for example: timmedin/l0ngPassw0rd!
  3. User submits credentials
  4. Server receives credentials - timmedin/l0ngPassw0rd!
  5. Server hashes password - d4b7e94d08729a3ebfac1e54406f7a00
  6. Server compares username (timmedin) and hash (d4b7e94d08729a3ebfac1e54406f7a00) with stored versions

Step 5 is important here, as the password that the user entered is not stored in the database. If an attacker is able to dump the database, he would not have clear text credentials for each user (cracking is the next step). To make things even more difficult to crack, the developer could utilize a salt in steps 5 and 6. Of course, if step 3 happens over a non-encrypted transport mechanism, then an attacker can see the credentials and reuse them. This reuse allows the attacker to effectively become the victim and access portions of the web application that he was not supposed to access.

Of course, the answer to protect the credentials (step 3) is to use transport encryption (TLS/SSL) to make sure that an attacker can't see the credentials. We have all heard the arguments against TLS and certs (cpu hit, management pain, etc.) so some developers come up with a (seemingly) brilliant idea to hide the password and thereby fix the problem without needing TLS. Check it out:

Non-TLS, supposedly "safe" (but not really) authentication process:

  1. Present authentication form to user
  2. User enters credentials - timmedin/l0ngPassw0rd!
  3. User submits credentials
  4. Browser intercepts submission, hashes password - timmedin/d4b7e94d08729a3ebfac1e54406f7a00
  5. Server receives credentials - timmedin/d4b7e94d08729a3ebfac1e54406f7a00
  6. Server compares username (timmedin) and hash (d4b7e94d08729a3ebfac1e54406f7a00) with stored versions

Do you see the problems (plural) here? If not, give it a moment. If you still don't, do not worry, most people miss these issues, but they are a severe security problem.

Problem 1:
The biggest difference between these two processes is that the developer moved the hashing from the server to the client. This means that the password (l0ngPass0rd!) is not sent across the wire in clear text (yeah!). The problem is, this hash is now the clear text authentication mechanism (boo!). We don't need the original password for anything. All we need to do is reuse this hash (our new password) to authenticate to the site. It's pass-the-hash alright, but entirely on the web. If your authentication mechanism can be satisfied with only the hash (and not the password from which the hash is derived), the hash is effectively a password for your system.

Problem 2:
The second issue stems from the first. The "new password" (a.k.a., the hash) is stored directly in the database. Some web app developers think: "Why would you need to hash a hash? It is already secure, right?" Wrong. If an attacker can dump the database, he has a clear text authentication mechanism for every user on your application. Oops! The only (slightly) good news here is that the attacker who compromises your database to snag the hashes will still have to crack the passwords to access all of the other applications your users have foolishly manually sync'ed their passwords with.

Remember, the hash can be used in its unaltered form to authenticate us to the web app, effectively behaving as a password. That means this new value needs to be protected. To properly secure the "new password" (a.k.a., the hash), it needs to be salted and hashed (again). The hash protects it from being extracted in the clear and then passed, and the salt neuters rainbow tables and drives up the complexity of a cracking attack against multiple accounts with different salts.

Problem 3:
Some people think they are secure because they believe they have solved the password security issues of transmitting and storing a password in the clear. Instead, they are merely transmitting and storing a hash... in the clear. They may argue (quite vehemently) that they no longer need TLS. This false sense of security can be quite painful, or deadly, in the case of medical apps (where I've seen this issue most recently).

Solution:
The right (and realistic) way to do this properly is to implement TLS and HTTP Strict Transport Security (HSTS), along with salted password representations stored at the server or back-end database. TLS will protect the credentials on the wire. HSTS tells the client to use TLS on all subsequent visits to the site. Of course, there is a window of vulnerability for SSL Stripping on the first visit, but that makes the attack window smaller.

Integrating the Attack into your Penetration Tests:
This attack is pretty straight forward. There are multiple ways to do it, but IMHO this way is the easiest. To get started, you need a valid hash (from the database or sniffing), an interception proxy (such as Burp or ZAP), and your favorite browser. Setup your browser to use the proxy, then browse to the site. Enter the username and any old password. Hit the submit button and let JavaScript do its magic. Your proxy should catch the authentication form, allowing you to replace the hash and send the credentials on their merry way. After that, you should have access to the web app as the user whose username and hash you've supplied. Enjoy!

One word of warning: if you find this kind of issue in a pen test, prepare for a battle when you report on it to target system personnel and web application developers. Every time I've found it, the developers were quite vehement that this hash mechanism safely protected the password and didn't require TLS or other protections. You need to carefully explain the concerns, and might want to rely on the steps listed above to describe them. Good luck!

Join me for SEC560: Network Penetration Testing and Ethical Hacking at SANS Boston 2013! Boston, MA Monday, Aug 5 - Saturday, Aug 10, 2013

-Tim Medin
Counter Hack

Post a Comment






Captcha


* Indicates a required field.