Throughout years of performing penetration tests, when encountering an Internet facing password reset page, we usually find at least one opportunity for improvement with it. As humans, we generally learn from our mistakes. For that reason, we’ll revisit three examples of how we were able to use and abuse services in the past.
Our first example simply was a login page for a web application that had instructions to type “DOMAINNAMEusername” as your username. The page also included a link to a password-reset page. In this example, we assume it is authenticating against some sort of directory service. With that, we were able to guess a few usernames such as “jsmith” and “bsmith” since the error message changed from “invalid login” to “invalid password”. From here, it was trivial to lock out the user accounts with failed login attempts. The lockout duration was 24 hours with the corporate helpdesk being outsourced. At $16-$18 per ticket to unlock accounts, simple username enumeration via LinkedIn, JigSaw, or other sites using OSINT tools could easily cause a denial of service condition as well as significant financial damage to the organization.
The second example involves Computer Associates’ SiteMinder Identity Management product (http://www.ca.com/us/secure-sso.aspx). The password-reset configuration that we tested took a username and presented a single password question when a correct username was provided. We again guessed predictable usernames such as “jsmith” and “bsmith” which prompted for security question challenges such as “first car”, “mother’s maiden name”, and “city born in”. Since there was only a single security question and we believed we could guess a first car (“mustang” or “camaro” for example) or find a birthplace online, we began to try to guess more usernames. In doing so, we were able to fuzz the username field and received an error that included “DS” in its text. We assumed this stood for “directory service” or similar, which would suggest an LDAP error. Furthermore, we were able to generate such errors using characters commonly used in LDAP filters. We submitted “*admin” into the username field and were greeted with a security question for the user “serveradmin”. We were able to use an asterisk as a wildcard and match a username. Furthermore, using “*admin*” we obtained an error message notifying us that the results matched several accounts, and we must match exactly one account. We call this an “LDAP injection 0-day vulnerability”, whereas CA’s response to our client’s inquiry called it “acceptable functionality”.
From here, we headed over to LinkedIn to look up employees that had unique names so that we could match them using “*uniquename” and other input. From here, we were able to match a user’s name and obtain their “hometown” from their Facebook profile, which allowed us to correctly answer their security question and reset their password. From here, we were able to find an online portal that used AD authentication and login to it. The portal allowed us to obtain plaintext social security numbers. By simply using LDAP injection to match usernames, weak security questions, and public information, plaintext SSN’s were obtained.
Our third example was a “network password reset” page, as the client called it. It was a custom ASP.NET web application used for resetting Active Directory passwords. When guessing a valid username such as “jsmith”, three security questions were presented. All three must be answered correctly in order to proceed with the reset. When inspecting traffic for a valid guess compared to an invalid guess, it was noticed that the ASP.NET ViewState grew very large for valid usernames. The ViewState is Base64 encoded by default so viewing its contents is trivial. We looked at the decoded data and to our surprise, saw the answers to all three security questions! We proceeded to reset the user’s password, login via Citrix, and used a remote desktop shortcut to make our way inside and eventually obtain domain admin rights over the client. Developers have the option to store data in the ViewState, however it is not recommended. The purpose of the ViewState is to keep track of the state of the controls on the page, and is not really intended for the use we observed. The ViewState can be encrypted by setting the “ViewStateEncryptionMode” to “Always” (http://msdn.microsoft.com/en-us/library/system.web.ui.page.viewstateencryptionmode(v=vs.85).aspx) in the page directive or in the Web.config file. A better storage option for the security question answers could have been stored in a database or a server-side session variable where they are not accessible from the client-side.
Anything that is custom developed is prone to error and should undergo rigorous testing. Such testing should include source code review, dynamic testing, and hardening using minimum-security baselines. Hopefully your organization can learn from our clients’ mistakes.
This article was written by Scott White – Principal Security Consultant for TrustedSec.