Most of the vulnerabilities I uncover fit neatly into a particular category like XSS, SQLi, or buffer overflow. Sometimes, though, looking outside the box can yield interesting finds. In this post I’ll discuss one such vulnerability I discovered in the community edition of Integria IMS server, a PHP-based IT helpdesk management system. The vulnerability resided in the password reset process and allowed an attacker to takeover any user account provided he or she knew the username. No authentication or user interaction were required.
During the password reset process, Integria generated an MD5 hash and emailed it to the user. The user would enter the hash into the password reset window and if the hash matched the copy the server had on record then the user was allowed to change their password.
There were two issues that combined to allow account hijacking:
– The generated MD5 hash was limited to just 100 possible values for any given user on any given Integria installation.
– The hash submission page lacked brute force protection.
The snippet of code that generated the hash looked something like this:
$resethash = md5($config["sitename"].rand(0,100).$recover)
The hash accepted 3 inputs – a value called $config[“sitename”], a random number between 0 and 100, and the variable “$recover” which turned out to be the username. An internal attacker with an account of their own would most likely know their organization’s username scheme and could enumerate usernames of fellow users. An external attacker could also enumerate usernames, but as it turned out the Integria server shipped with a default admin account enabled, with username ‘admin’, providing a common target across Integria deployments. Thus, the username did not add much randomness to the hash.
The random number afforded little protection since generating 100 MD5 hashes requires very little time or computing power. Only the $config[“sitename”] value was left providing any protection against brute force. At first I was unsure what this value represented but after trial and error I discovered it surfaced as the HTML title of the login page presented to unauthenticated users. Anyone could reach the login page so the $config[“sitename”] value didn’t help guard against attacks either.
The final roadblock was account lockout protection if the sever blocked hash submissions after a certain number of failed attempts. I wrote a script to generate the 100 password reset hashes for a test account and automatically submit them to the server. I ran it and the server did not block attempts to submit the password reset hash after any number of incorrect submissions. At this point we could initiate a password reset for a user, generate all 100 possible hashes, and submit each hash code until we found the one that worked. Or put another way, it was game over…
As of this writing it’s been over a year since a patch was released and updated Integria deployments should be immune. However, if you have an outdated Internet accessible Integria server with the default admin account enabled, please be advised your server is quite vulnerable to takeover. I plan to publish proof of concept code soon and provide a link here.
Shoutout and special thanks to the Integria team for their quick response and working to issue a patch! Thank you for reading, until next time, happy hunting…