Curiosity is the motivation behind many attacks, and semantic URL attacks are a perfect example. This type of attack involves the user modifying the URL in order to discover what interesting things can be done. For example, if the user chris clicks a link in your application and arrives at http://example.org/private.php?user=chris, it is reasonable to assume that he will try to see what happens when the value for user is changed. For example, he might visit http://example.org/private.php?user=rasmus to see if he can access someone else’s information. While GET data is only slightly more convenient to manipulate than POST data, its increased exposure makes it a more frequent target, particularly for novice attackers.
Most vulnerabilities exist because of oversight, not because of any particular complexity associated with the exploits. Any experienced developer can easily recognize the danger in trusting a URL in the way just described, but this isn’t always clear until someone points it out.
To better illustrate a semantic URL attack and how a vulnerability can go unnoticed, consider a web-based email application where users can log in and check their example.org email accounts. Any application that requires its users to log in needs to provide a password reminder mechanism. A common technique for this is to ask the user a question that a random attacker is unlikely to know (the mother’s maiden name is a common query, but allowing the user to specify a unique question and its answer is better) and email a new password to the email address already stored in the user’s account.
With a web-based email application, an email address may not already be stored, so a user who answers the verification question may be asked to provide one (the purpose being not only to send the new password to this address, but also to collect an alternative address for future use). The following form asks a user for an alternative email address, and the account name is identified in a hidden form variable:
The receiving script, reset.php, has all of the information it needs to reset the password and send the emailthe name of the account that needs to have its password reset and the email address where the new password is to be sent.
If a user arrives at this form (after answering the verification question correctly), you are reasonably assured that the user is not an imposter but rather the legitimate owner of the chris account. If this user then provides firstname.lastname@example.org as the alternative email address, he arrives at the following URL after submitting the form:
This URL is what appears in the location bar of the browser, so a user who goes through this process can easily identify the purpose of the variables user and email. After recognizing this, the user may decide that email@example.com would be a really cool email address to have, so this same user might visit the following URL as an experiment:
If reset.php trusts these values provided by the user, it is vulnerable to a semantic URL attack. A new password will be generated for the php account, and it will be sent to firstname.lastname@example.org, effectively allowing chris to steal the php account.
If sessions are being used to keep track of things, this can be avoided easily:
if (preg_match($email_pattern, $_POST[’email’]))
$clean[’email’] = $_POST[’email’];
$user = $_SESSION[’user’];
$new_password = md5(uniqid(rand(), TRUE));
/* Update Password */
mail($clean[’email’], ‘Your New Password’, $new_password);
Although this example omits some realistic details (such as a more complete email message or a more reasonable password), it demonstrates a lack of trust given to the email address provided by the user and, more importantly, session variables that keep up with whether the current user has already answered the verification question correctly ($_SESSION[’verified’]) and the name of the account for which the verification question was answered ($_SESSION[’user’]). It is this lack of trust given to input that is the key to preventing such gaping holes in your applications