1. Intercepting and Modifying Server Responses
1.1. Problem
You want to test your client-side code and see how it handles
spurious responses from the server. The server might not always send
perfect data, so your client-side code needs at least rudimentary error
recovery. Sometimes the request-modification technique in this article is too difficult because the requests are sent
in a binary or opaque format that is hard to modify. If you change the
client’s state by tampering with server responses, you can let the
client-side code generate bad requests for you.
1.2. Solution
We will continue with our WordPress example from this article. Configure your web browser to use WebScarab . Start up
WebScarab and click on the Proxy tab. Choose the Manual Edit pane and
look for the check box labeled Intercept requests. Also check the box labeled
Intercept responses.
When your request appears, just click the Accept
Changes button and let it go. The next window to pop up will be the
response to that request as shown in Figure 1.
As with the intercepted request, you can modify any part of the
response. You can change header names, header values, or the content of
the response.
1.3. Discussion
It is especially handy to enter a careful expression in the
“Include Paths matching” box so that you’re only intercepting requests
and responses related to just the AJAX requests you’re interested in. In an active AJAX
application, you’re going to have lots of requests going back and forth,
and this could cause lots of dialog boxes to pop up from WebScarab. It interferes with the
application’s functionality and it interferes with your ability to do
specific tests if you cannot isolate the requests and responses.
As in the case of an intercepted request, it is useful to change
values to include cross-site scripting values. Another really useful method is to identify values
that cause the client to change its notion of state. For example, the
authors have seen an application that managed records in a database and
the response from the server included both record identifiers (e.g.,
records identified with numbers) and the permissions associated with
each record. By modifying the response from the server, the client-side
code could be tricked into believing that the user had permission to
delete the folder with ID 12345, when in fact they should not have that
permission. Clicking “delete” on the record generated a correctly
formatted AJAX request to delete the record, and it succeeded. In this
particular application, the browser requests were very complicated and
difficult to manipulate. Server responses, however, were in easy-to-read
XML. The interception and modification of server responses was far
easier than formatting a correct request. By changing the XML from the
server, the client was tricked into sending delete requests for records
that it should not delete, and those requests were honored by the
server. Oops!
Notice that both the intercepted request and intercepted response
dialog boxes (Figure 10-5) have
checkboxes at the top labeled Intercept requests and Intercept
responses. Frequently you want to perform a single interception,
observe the results, and then stop intercepting. Uncheck these boxes
before clicking the Accept Changes button and WebScarab will stop
intercepting requests and/or responses. To enable interception again,
go back to the Proxy pane and click the boxes again. |
2. Subverting AJAX with Injected Data
2.1. Problem
If your application uses AJAX, the server will probably deliver
data in a format that client-side JavaScript can parse and use. By
crafting injection strings to break that format, one can inject
arbitrary content onto a page. Worse yet, existing input validation
checking for HTML or JavaScript injection may not detect the same
injection in a new data format. This recipe discusses non-structured
text that might confuse the browser. XREF and XREF discuss injecting
data serialized in XML and JSON, respectively.
2.2. Solution
Several common data formats used for AJAX include raw text, HTML, XML, or JSON. There
are ways to escape and abuse each format. The steps to inject the data
are the same, but the format is somewhat different.
Imagine a web application that uses AJAX to implement an online
chat. Every 10 seconds the browser’s JavaScript calls out to the server
and retrieves whatever chat messages have been posted. The response
comes back in HTML that looks like Example 1.
Example 1. HTML source of AJAX-based chat
<tr><th>jsmith</th><td>are you going to the show?</td></tr>
<tr><th>mjones</th><td>yeah, mike's driving</td></tr>
<tr><th>jsmith</th><td>can I hitch a ride?</td></tr>
<tr><th>mjones</th><td>sure. be at mike's at 6</td></tr>
|
The user IDs (jsmith and
mjones) are values that the users
theoretically can control. When they sign up, or perhaps after they have
signed up, they can set their user ID. Now further imagine that the
application, on the sign-up page, safely displays the user ID, but
allows dangerous characters. That is, if the user types jsmith<hr> as their user ID, the
system will display jsmith%3chr%3e,
which is safe. However, the application stores the value as jsmith<hr> in the database. In this sort
of situation, our test will work well.
The first step of a general test method is to identify data that
is retrieved via an AJAX call, rather than data that is delivered when
the page first loads. To identify the data AJAX retrieves. Typically such data is the result of other
forms of application input—either user input, external RSS feeds, or
data delivered via an external API. The easiest case is when a user can
submit data through a normal form and that data is stored in the
database, then retrieved and delivered via an AJAX call in another place
in the application. In our case, it is the polling request for recent
chat lines.
The next step is to examine the source code of the web page and
see how the returned data is used. In this recipe, we’re discussing
plain text or HTML. In our example, the latest chat messages come to us
formatted in HTML.
You’ll need to identify this input source and submit a string that
breaks your particular data format. Each data format requires a
different form of injection string. You’ll recognize that your injection
test is successful when you see page content in places it shouldn’t be
or entirely new page elements.
Injecting raw text
Raw text is the easiest format into which one can inject
data. It’s also identical to HTML injection and so potentially
already caught by existing input validation, but you should check
anyway. If your AJAX returns raw text and displays it directly on
screen, try inserting any normal HTML tag. The <hr> tag works in a pinch; it’s
short and easily visible. On the other hand, <script>alert('this is an xss
attack');</script> is a slightly more malicious
example.
Injecting HTML
HTML injection is fundamentally equivalent to raw text injection,
with the one exception that your injection string might arrive as
an attribute within an HTML tag. In this case, inspect the AJAX
response to determine where your data arrives, and then include
the appropriate HTML escape characters. For example, if your AJAX
response returns your email address in this HTML: <href="mailto:YOUR_STRING_HERE">Email
Address</href>, then you’ll need to include the
characters "> prior to
normal HTML injection.
2.3. Discussion
Because data serialization can be a ripe area for attack within AJAX
applications, avoid writing your own data serialization code. Whenever
possible, use standard JSON or XML parsing libraries. They are available
for most languages.
A common maxim is that one must make tradeoffs between security
and convenience. With the proper libraries, one doesn’t have to
sacrifice the convenience of the JSON format for security’s sake,
although there’s danger in evaluated JSON code or, returning JSON data without checking for
proper authentication.