Project 3  HINTS

My solutions work and use XmlHttpRequests, but the autograder is unhappy. What gives?

The autograder uses a testing framework called Selenium, which has limitations regarding asynchronous XmlHttpRequests. One student has reported that, in some cases, asynchronous XmlHttpRequests appear to cause problems for the autograder that can be fixed by changing them to a synchronous XmlHttpRequests. If you are using asynchronous XmlHttpRequests but find that the autograder isn't giving you points when you think it should, you might try making them synchronous to see if that helps. (This involves changing a single boolean parameter when you issue the request. See Mozilla's page on XmlHttpRequest for more information on how to do this.)

Note: This is not a subtle suggestion that you should use XmlHttpRequests. You can solve all of the parts without using XmlHttpRequests, and we are not trying to suggest that you should or should not use XmlHttpRequests; merely that if you do use XmlHttpRequests, you might want to be aware of this apparent limitation of the autograder. If you don't use XmlHttpRequests, you can ignore this comment. If you do use asynchronous XmlHttpRequests and got full credit with the autograder, great, you too can ignore this comment.

Comment: We're aware that, in many cases, asynchronous XmlHttpRequests may be the right tool for the job. We realize this is an imperfection of the autograder, but there it is. Sorry about that.

Is magic_quotes_gpc enabled on the web server?

Yes, it's enabled. The optional magic_quotes_gpc PHP feature escapes single quotes, double quotes, and backslashes in GET and POST data by prepending a backslash. This feature makes it slightly harder to write websites that are vulnerable to cross-site scripting and SQL injection attacks. However, as you will see in this assignment, sites with magic_quotes_gpc are not magically bug-free. There are many ways that sites can turn off magic_quotes_gpc, such as .htaccess files, php.ini files, and by calling stripslashes on the escaped data. Note that magic_quotes_gpc doesn't do anything to angle brackets (<>). For that, you want htmlspecialchars.

Is register_globals enabled on the web server?

No, it is off. The login page is vulnerable to an attack if register_globals is on, which you are welcome to fix if you want in the second part. 

Resources

JavaScript, PHP, CSS : How do I learn these?

The definitive resource on PHP is php.net. You can find some introductory tutorials there. You can find a lot of references on Google. There's a decent one at W3Schools. Pay particular attention the DOM examples.

How do I figure out why my Javascript isn't working?

Two extremely useful tools for debugging in Mozilla Firefox are the JavaScript console and the DOM Inspector. Both can be accessed from the Tools menu. The JavaScript console lets you see which exceptions are being thrown and why. The DOM Inspector lets you peek at the structure of the page and the properties and methods of each node it contains. (If the DOM Inspector isn't installed, make sure it's selected when you install Mozilla Firefox.) You might also want to try Firebug.

What do I need to know about CSS?

You only need to know enough to make your attacks disappear. You should know what basic syntax like <style>.profilecontainer{display:none}</style> means, and you should feel free to use stealthy attributes like style="display: none; visibility: hidden; height: 0; width: 0; position: absolute" in the HTML of your attacks. Beware that frames and images may behave strangely with display: none, so you might want to use visibility: hidden instead.

How can I see cookies and form data that the browser sends?

Try the LiveHTTPHeaders browser extension.

Attack A.


How do I start? This seems hard.
You should start by thinking about sanitization of untrusted user input. The server echoes back user data without properly sanitizing it. See how the example works.

The example attack doesn't seem to do anything. What did I miss ?

You need to be logged in before the attack will work. When you click the link, you should get a browser alert with the contents of document.cookie.

How do I put code into a URL? And yes, I want to have weird characters like newlines in my code?

Try to URL-encode it.

What is this random query parameter?

It is to bypass your browser cache. If you try your attack more than once, the browser might think that it already has the page in its cache, and so it wouldn't send a second HTTP GET request. Adding a random number ensures that the browser will treat the new URL as different, and won't use the cache. The log script ignores this parameter.

Why are the characters reflected back different from the ones in the URL?

Your query parameter is URL decoded by the server before being reflected back at the user. You'll need to made sure that your attack code is URL encoded. For example, use + instead of space and %2b instead of +. Here is a URL encoding reference and a handy conversion tool.

My attack is working. How should I make it invisible to the user?

The text box should be its usual size and in the normal place. No warning text or characters that are normally part of the page should be visible. From the point of view of the visitor, it should appear as if they just visited to users.php and didn't put in a username yet (with the possible exception of the address bar). It's ok if the page briefly looks weird before correcting itself. 
My attack works. But, I had to switch the character-set encoding. Can we assume the grader can be fooled into changing his setting?

        No. You can assume that the character set remains the same. 

      

Attack B.

Why is this not a cross site scripting attack?

It is a cross site request forgery attack because you are exploiting the fact that StockBank uses only a cookie to authenticate requests, even requests with side effects.

Can I use the vulnerability in user.php from Attack A?

No. Since this not a cross site scripting attack, you do not need to use the vulnerability in users.php.

How can I make this work with no user interaction?

It might be helpful to know that JavaScript can interact with page elements and can tell the browser to initiate actions as though they came from the user. For every button, text field, form, etc., the browser creates a special object that is accessible from JavaScript. For instance, each form has a submit method; if script calls this method, it will cause the form to be submitted. As another example, the "Send" button on the transfer form has a click method; if JavaScript calls that method, it will cause the browser to behave as if the user had clicked on that button, and submit the form.

Attack C.

Why is the site using JavaScript to focus the username field?

It's a convenience for the user, so they don't have to select the username field manually when they first come to the page. You may find it useful as well.

How do I get my injected code in?

Defeat the sanitization. Because your code is sanitized with htmlspecialchars, you won't be able to inject a simple <script> tag like you did in Attack A. Trick the browser into running your code another way.

Does it have something to do with character set selection bugs?

No, that's not it.

I think I figured it out, but when I call alert to test my attack, nothing happens.

It turns out that calling alert would lead to an infinite loop of dialog boxes, so Firefox is trying to be helpful by preventing it. Try using something like document.loginform.login_username.value=42 to test whether your attack is working.

How am I supposed to invoke the log script from my script without using any characters that will get escaped?

There are numerous static methods of String that you might find usable. Also, don't forget about escape, unescape, and eval.

Encoding by hand is incredibly tedious. Help?

You can save yourself some headaches if you write out your attack as a string in your attack page and then encode it programmatically, using those static String methods.

What do I need to do to make my attack invisible to the user?

You'll have to get a handle on the relevant DOM nodes and make the extraneous text disappear, either by deleting the text or setting the style.display property.

How can I get a handle on the warning message? It doesn't have an id attribute.

It does have other distinguishing characteristics. You may find getElementsByTagName useful. Depending on how your attack works, you may not see a warning message anyway.

I'm sending data to the log script when the form is submitted, but it isn't working. What's wrong?

There's a race condition here where the form may be getting submitted before the request is made to the log script. Once the form submit starts, the thread that's downloading the image is killed. So, to ensure that your attack always works, you should delay the form submission a little bit. You can use addEventListener with an event handler such as function(evt) { evt.preventDefault(); ... }. In this way, you can prevent the form submission until you're ready to trigger it yourself.

What should I do after the username and password are logged?

You can trigger the submission manually using the login button's click() method. Use removeEventListener() to avoid infinite loops.

Attack D.

Why am I not getting points for my clever worm?

Do not try to conceal the effect of your worm or hide the worm from the profile area. The autograder checks whether your worm has propagated by simulating the effect of a user visiting an infected page, and then checking the profile textarea on that user's web page to see whether it contains the worm.

How does the site sanitize profiles?

It uses strip_tags() to restrict the tags that can be used, and it uses a regular expression to replace certain dangerous words like "onmouseover" with a space character. Note that strip_tags() will remove all tags that are more than 1024 characters. If your solution occurs inside a tag, you will have to make sure it fits inside this limit, or it won't render to the user.

What tags does it allow or disallow in profiles?

Check the sources.

How do I transfer the money?

Many ways: (1) Create an <iframe> pointing to transfer.php, set the appropriate form fields inside it, and post the form.
(2) You can create a form on the current page with transfer.php as its target, and then post it with the target pointing at an <iframe>.
(3) Another option is to use XMLHttpRequest, since you're actually making a same-site request this time. 

How do I create an <iframe>?

You can use the DOM methods document.createElement and document.body.appendChild.

How do I get a handle on form fields inside the <iframe>?

It differs by browser, and only works when the frame's domain matches the parent page (that's the Same Origin Principle). Here's the Firefox way of doing it: iframe.contentDocument.forms[0].dollars.value = 1;

Are there any alternatives to target, which is blacklisted?

You can use string concatenation to express "target" without actually saying it. The following are equivalent in JavaScript: x.target, x["target"], x["tar"+"get"].

Is there an easy way to get a copy of the current profile?

You can use document.getElementById('profile').innerHTML, but it may mangle quotes in your profile, so be sure to check that the replicated profile is still functional. Also, note that only display:inline tags can be nested inside a <p>.