Bypassing Client-Side Controls

Transmitting Data via the Client

It is very common to see an application passing data to the client in a form that is not directly visible or modifiable by the end user, in 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 full 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 a particular item of data is known and specified by the server, 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 an easier task for developers, because 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. Further, if an application is deployed on several load-balanced servers, with users potentially interacting with more than one server to perform a multi-step action, then 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 present a tempting solution to the problem. However, transmitting sensitive data in this way is usually unsafe and has been the cause of countless vulnerabilities in applications.

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 hid- den, it is not displayed on-screen. However, the field’s name and value are stored within the form and 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 it by no means has been eliminated today. Figure -1 shows a typical form.

Screenshot from 2020-04-23 21:31:58

Figure -1: A typical HTML form

The code behind this form is as follows:

<form action=”order.asp” method=”post”>
<p>Product: Sony VAIO A217S</p>
<p>Quantity: <input size=”2” name=”quantity”>
<input name=”price” type=”hidden” value=”1224.95”>
<input type=”submit” value=”Buy!”></p>

Notice the form field called price , which is flagged as hidden. This field will be sent to the server when the user submits the form:

POST /order.asp HTTP/1.1
Content-Length: 23

Now, although the price field is not displayed on-screen, and it is not editable by the user, this is solely 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 in order to edit the price.

One way to achieve this is to save the source code for the HTML page, edit the value of the field, reload the source into a browser, and click the Buy button. However, a more elegant and easier 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 that you need in your arsenal. There are numerous such tools available, but the most functional and popular are:

■ Burp Proxy (part of Burp Suite)
■ WebScarab
■ Paros

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. The proxies listed also have numerous advanced functions to make your job easier, including:

■ Fine-grained rules to control which messages are trapped.
■ Regex-based replacement of message content.

■ Automatic updating of the Content-Length header when messages are modified.
■ Browsing history and message cache.
■ Ability to replay and remodify individual requests.
■ Integration with other tools such as spiders and fuzzers.

HTTP Cookies

Another common mechanism for transmitting data via the client is HTTP cookies. As with hidden form fields, these are not normally displayed on-screen or directly modifiable by the user. They can, of course, be modified using an intercepting proxy, either by changing the server response that sets them, or subsequent client requests that issue them.

Consider the following variation on the previous example. When a customer logs in to the application, she receives the following response:

HTTP/1.1 302 Found
Location: /home.asp
Set-Cookie: SessId=191041-1042
Set-Cookie: UID=1042
Set-Cookie: DiscountAgreed=25

This response sets three cookies, all of which are interesting. The first appears to be a session token, which may be vulnerable to sequencing or other attacks. The second appears to be a user identifier, which can potentially be leveraged to exploit access control weaknesses. The third appears to represent a discount rate that the customer will receive on purchases.

This third cookie points towards a classic case of relying on client-side controls (the fact that cookies are normally unmodifiable) 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, then customers can obtain arbitrary discounts by modifying its value. For example:

POST /order.asp HTTP/1.1
Cookie: SessId=191041-1042; UID=1042; DiscountAgreed=99
Content-Length: 23

URL Parameters

Applications frequently transmit data via the client using preset URL parameters. For example, when a user browses the product catalogue, the application may provide them with hyperlinks to URLs like the following:

When a URL containing parameters is displayed in the browser’s location bar, any parameters can be trivially modified by any user without the use of tools. However, there are many instances in which an application may expect
that ordinary users cannot view or modify URL parameters. For example:

■ Where embedded images are loaded using URLs containing parameters.
■ Where URLs containing parameters are used to load the contents of aframe.
■ 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 using an intercepting proxy.

The Referer Header

Browsers include the Referer header within most HTTP requests. This 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:

POST /customer/ResetForgotPassword.asp HTTP/1.1
Content-Length: 44


The application may use the Referer header to verify that this request originated from the correct stage ( ForgotPassword.asp ), and if so allow the user to reset their password.

However, because the user controls every aspect of every request, including the HTTP headers, this control can be trivially circumvented by proceeding directly to ResetForgotPassword.asp , and using an intercepting proxy to fix the value of the Referer header to the value that the application requires.

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 some cryptic value being transmitted:

<form action=”order.asp” method=”post”>
<p>Product: Sony VAIO A217S</p>
<p>Quantity: <input size=”2” name=”quantity”>
<input name=”enc” type=”hidden” value=”262a4844206559224f456864206668643
<input type=”submit” value=”Buy!”></p>

When this is observed, you may reasonably infer that when the form is submitted, the server-side application will decrypt or deobfuscate the opaque string and perform some processing on its plaintext value. This further processing may be vulnerable to any kind of bug; however, in order to probe for and exploit this, you will first need to wrap up your payload in the appropriate way.

The ASP.NET ViewState

One commonly encountered mechanism for transmitting opaque data via the client is the ASP.NET ViewState. This is a hidden field that is created by default in all ASP.NET web applications, and contains serialized information about
the state of the current page. The ASP.NET platform employs the ViewState to enhance server performance — it enables the server to preserve elements within the user interface across successive requests without needing to maintain all of the relevant state information on the server side. For example, the server may populate a drop-down list on the basis of parameters submitted by the user. When the user makes subsequent requests, the browser does not submit the contents of the list back to the server. However, the browser does submit the hidden ViewState field, which contains a serialized form of the list. The server deserializes the ViewState and recreates the same list that is presented back to the user again.

In addition to this core purpose of the ViewState, developers can use it to store arbitrary information across successive requests. For example, instead of saving the product’s price in a hidden form field, an application may save it in the ViewState as follows:

string price = getPrice(prodno);
ViewState.Add(“price”, price);

The form returned to the user will now look something like this:

<form method=”post” action=”order.aspx”>
<input type=”hidden” name=”__VIEWSTATE” id=”__VIEWSTATE”
<p>Product: Sony VAIO A217S</p>
<p>Quantity: <input name=”quantity” id=”quantity” />
<input type=”submit” name=”buy” value=”Buy!” />

and when the user submits the form, their browser will send the following:

POST /order.aspx HTTP/1.1
Content-Length: 95


The request apparently does not contain the product price — only the quantity ordered and the opaque ViewState parameter. Changing that parameter at random results in an error message, and the purchase is not processed.

The ViewState parameter is actually a Base64-encoded string, which can be easily decoded:

FF 01 0F 0F 05 0D 0A 31 32 31 34 32 32 39 33 34 ; ÿ……121422934
32 0F 16 02 1E 05 70 72 69 63 65 05 07 31 32 32 ; 2…..price..122
34 2E 39 35 64 64                                                ; 4.95dd

NEXT is..Capturing User Data: HTML Forms……,,.,,,,,