Bypassing Client-Side Controls
In this blog, I will describe how the core security problem with web applications arises because clients can submit arbitrary input. Despite this fact, a large proportion of web applications, nevertheless, rely on various measures implemented on the client-side to control the data that they submit to the server. In general, this represents a fundamental security flaw: the user has full control over the client and the data it submits and can bypass any controls that are implemented on the client-side and are not replicated on the server.
An application may rely on client-side controls to restrict user input in two broad ways. First, an application may transmit data via the client component using a mechanism that it assumes will prevent the user from modifying that data when the application later reads it. Second, an application may implement measures on the client-side that control the user’s interaction with his or her own client, with the aim of restricting functionality and/or applying controls around user input before it is submitted. This may be achieved using HTML form features, client-side scripts, or browser extension technologies.
This blog looks at examples of each kind of client-side control and describes ways in which they can be bypassed.
It is common to see an application passing data to the client in a form that the end-user cannot directly see or modify, with the expectation that this data will be sent back to the server in a subsequent request. Often, the application’s developers simply assume that the transmission mechanism used will ensure that the data transmitted via the client will not be modified along the way.
Because everything submitted from the client to the server is within the user’s control, the assumption that data transmitted via the client will not be modified is usually false and often leaves the application vulnerable to one or more attacks.
You may reasonably wonder why if the server knows and specifies a particular item of data, the application would ever need to transmit this value to the client and then read it back. In fact, writing applications in this way is often easier for developers for various reasons:
It removes the need to keep track of all kinds of data within the user’s session. Reducing the amount of per-session data being stored on the server can also improve the application’s performance
If the application is deployed on several distinct servers, with users potentially interacting with more than one server to perform a multistep action, it may not be straightforward to share server-side data between the hosts that may handle the same user’s requests. Using the client to transmit data can be a tempting solution to the problem.
If the application employs any third-party components on the server, such as shopping carts, modifying these may be difficult or impossible, so transmitting data via the client may be the easiest way of integrating these.
In some situations, tracking a new piece of data on the server may entail updating a core server-side API, thereby triggering a full-blown formal change-management process and regression testing. Implementing a more piecemeal solution involving client-side data transmission may avoid this, allowing tight deadlines to be met.
However, transmitting sensitive data in this way is usually unsafe and has been the cause of countless vulnerabilities in applications
Hidden Form Fields
Hidden Form Fields Hidden HTML form fields are a common mechanism for transmitting data via the client in a superficially unmodifiable way. If a field is flagged as hidden, it is not displayed on-screen. However, the fi eld’s name and value are stored within the form and are sent back to the application when the user submits the form.
The classic example of this security flaw is a retailing application that stores the prices of products within hidden form fields. In the early days of web applications, this vulnerability was extremely widespread, and by no means has it been eliminated today..
A typical HTML form
The code behind this form is as follows:
<form method=”post” action=”Shop.aspx?prod=1”> Product: iPhone 5 <br/> Price: 449 <br/> Quantity: <input type=”text” name=”quantity”> (Maximum quantity is 50) <br/> <input type=”hidden” name=”price” value=”449”> <input type=”submit” value=”Buy”> </form>
Notice the form field called price, which is flagged as hidden. This field is sent to the server when the user submits the form:
POST /shop/28/Shop.aspx?prod=1 HTTP/1.1 Host: mdsec.net Content-Type: application/x-www-form-urlencoded Content-Length: 20 quantity=1&price=449
Although the price field is not displayed on-screen, and the user cannot edit it, this is sole because the application has instructed the browser to hide the field. Because everything that occurs on the client-side is ultimately within the user’s control, this restriction can be circumvented to edit the price. One way to achieve this is to save the source code for the HTML page, edit the fi eld’s value, reload the source into a browser, and click the Buy button. However, an easier and more elegant method is to use an intercepting proxy to modify the desired data on the fly.
An intercepting proxy is tremendously useful when attacking a web application and is the one truly indispensable tool you need. Numerous such tools are available. We will use Burp Suite, which was written by one of this book’s authors. The proxy sits between your web browser and the target application. It intercepts every request issued to the application, and every response received back, for both HTTP and HTTPS. It can trap any intercepted message for inspection or modification by the user. If you haven’t used an intercepting proxy before, you can read more about how they function, and how to get them configured and working
Once an intercepting proxy has been installed and suitably configured, you can trap the request that submits the form and modify the price field to any value,
If the application processes the transaction based on the price submitted, you can purchase the product for the price of your choice.
TIP If you find an application that is vulnerable in this way, see whether you can submit a negative amount as the price. In some cases, applications have actually accepted transactions using negative prices. The attacker receives a refund to his credit card and also the item he ordered — a win-win situation if ever there was one.
Another common mechanism for transmitting data via the client is HTTP cookies. As with hidden form fields, normally these are not displayed on-screen, and the user cannot modify them directly. They can, of course, be modified using an intercepting proxy, by changing either the server response that sets them or subsequent client requests that issue them. Consider the following variation on the previous example. After the customer has logged in to the application, she receives the following response:
HTTP/1.1 200 OK Set-Cookie: DiscountAgreed=25 Content-Length: 1530
This DiscountAgreed cookie points to a classic case of relying on client-side controls (the fact that cookies normally can’t be modified) to protect data transmitted via the client. If the application trusts the value of the DiscountAgreed cookie when it is submitted back to the server, customers can obtain arbitrary discounts by modifying its value. For example:
POST /shop/92/Shop.aspx?prod=3 HTTP/1.1 Host: mdsec.net Cookie: DiscountAgreed=25 Content-Length: 10 quantity=1
URL Parameters Applications frequently transmit data via the client using preset URL parameters. For example, when a user browses the product catalog, the application may provide him with hyperlinks to URLs like the following:
When a URL containing parameters is displayed in the browser’s location bar, any parameters can be modified easily by any user without the use of tools. However, in many instances, an application may expect that ordinary users cannot view or modify URL parameters.
Where embedded images are loaded using URLs containing parameters
Where URLs containing parameters are used to load a frame’s contents
Where a form uses the POST method and its target URL contains preset parameters
Where an application uses pop-up windows or other techniques to conceal the browser location bar.
Of course, in any such case, the values of any URL parameters can be modified as previously discussed using an intercepting proxy
The Referer Heade
Browsers include the Referer header within most HTTP requests. It is used to indicate the URL of the page from which the current request originated — either because the user clicked a hyperlink or submitted a form, or because the page referenced other resources such as images. Hence, it can be leveraged as a mechanism for transmitting data via the client. Because the URLs processed by the application are within its control, developers may assume that the Referer header can be used to reliably determine which URL generated a particular request.
For example, consider a mechanism that enables users to reset their password if they have forgotten it. The application requires users to proceed through several steps in a defined sequence before they actually reset their password’s value with the following request:
GET /auth/472/CreateUser.ashx HTTP/1.1 Host: mdsec.net Referer: https://mdsec.net/auth/472/Admin.ashx
The application may use the Referer header to verify that this request originated from the correct stage (Admin.ashx). If it did, the user can access the requested functionality.
However, because the user controls every aspect of every request, including the HTTP headers, this control can be easily circumvented by proceeding directly to CreateUser.ashx and using an intercepting proxy to change the value of the Referer header to the value that the application requires.
The Referer header is strictly optional according to w3.org standards. Hence, although most browsers implement it, using it to control application functionality should be regarded as a hack.
COMMON MYTH It is often assumed that HTTP headers are somehow more “tamper-proof” than other parts of the request, such as the URL. This may lead developers to implement functionality that trusts the values submitted in headers such as Cookie and Referer while performing proper validation of other data such as URL parameters. However, this perception is false. Given the multitude of intercepting proxy tools that are freely available, any amateur hacker who targets an application can change all request data with ease. It is rather like supposing that when the teacher comes to search your desk, it is safer to hide your water pistol in the bottom drawer, because she will need to bend down farther to discover it
HACK STEPS 1. Locate all instances within the application where hidden form fields, cookies, and URL parameters are apparently being used to transmit data via the client. 2. Attempt to determine or guess the role that the item plays in the application’s logic, based on the context in which it appears and on clues such as the parameter’s name. 3. Modify the item’s value in ways that are relevant to its purpose in the application. Ascertain whether the application processes arbitrary values submitted in the parameter, and whether this exposes the application to any vulnerabilities
Opaque Data Sometimes, data transmitted via the client is not transparently intelligible because it has been encrypted or obfuscated in some way. For example, instead of seeing a product’s price stored in a hidden field, you may see a cryptic value being transmitted:
<form method=”post” action=”Shop.aspx?prod=4”> Product: Nokia Infinity <br/> Price: 699 <br/> Quantity: <input type=”text” name=”quantity”> (Maximum quantity is 50) <br/> <input type=”hidden” name=”price” value=”699”> <input type=”hidden” name=”pricing_token” value=”E76D213D291B8F216D694A34383150265C989229”> <input type=”submit” value=”Buy”> </form>
When this is observed, you may reasonably infer that when the form is submitted, the server-side application checks the integrity of the opaque string, or even decrypts or deobfuscates it to perform some processing on its plaintext value. This further processing may be vulnerable to any kind of bug. However, to probe for and exploit this, first, you need to wrap up your payload appropriately.
NOTE Opaque data items transmitted via the client are often part of the application’s session-handling mechanism. Session tokens sent in HTTP cookies, anti-CSRF tokens transmitted in hidden fi elds, and one-time URL tokens for accessing application resources, are all potential targets for client-side tampering
HACK STEPS Faced with opaque data being transmitted via the client, several avenues of attack are possible: 1. If you know the value of the plaintext behind the opaque string, you can attempt to decipher the obfuscation algorithm being employed. 2. The application may contain functions elsewhere that you can leverage to return the opaque string resulting from a piece of plaintext you control. In this situation, you may be able to directly obtain the required string to deliver an arbitrary payload to the function you are targeting. 3. Even if the opaque string is impenetrable, it may be possible to replay its value in other contexts to achieve a malicious effect. For example, the pricing_token parameter in the previously shown form may contain an encrypted version of the product’s price. Although it is not possible to produce the encrypted equivalent for an arbitrary price of your choosing, you may be able to copy the encrypted price from a different, cheaper product and submit this in its place. 4. If all else fails, you can attempt to attack the server-side logic that will decrypt or deobfuscate the opaque string by submitting malformed variations of it — for example, containing overlong values, different character sets, and the like