Monthly Archives: January 2018

Cross-Site Scripting attacks are tremendously prevalent, which I find surprising because it is an easy problem to detect and to remediate. There are even a lot of decent mitigation alternatives out there as well.

What is Cross-Site Scripting (or XSS, if you prefer)?

Cross-Site Scripting occurs whenever someone else is able to run JavaScript within your site. This could, of course, happen if someone can upload HTML files (containing scripts), but the dominating attack vector is regular input fields.

For example, a web application might have a search feature:

/search.php?search=test

The resulting page might then contain:

<h1>Search results for: test</h1>

From this basic example we can assert that the user is in control of two things regarding the content:
1. What search results are present on the search page
2. A section of the body is directly correlated to the search term (parameter search)

So searching for “asdkhafohgsoudghs” would possibly yield zero results. Searching for “e” might match every single entry. That makes sense, but is not that useful to us at the very moment.

The fact that whatever we supply as the search parameter is directly reflected is very interesting. The intended behaviour is to reflect the search query, but what if we enter HTML?

search.php?search=test<img src=test/>

It would probably look something like:

So we managed to inject a broken image by entering the corresponding HTML. Nice. Now, what about that Cross-Site Scripting?

search.php?search=test<img src=test onerror=”alert(‘:)’)”/>

At this point, we have the ability to inject and run JavaScript.

So why is this a bad thing?

> … After all, it’s just alert boxes!

Everyone likes to bash JavaScript for being horrible. While some (most?) criticism is legitimate, keep in mind that it’s possible to do pretty much anything once you can run it.

There are some restrictions in place, one of them being that some stuff can only be performed within the current domain. That’s why we need to inject the scripts on the victim site. Otherwise it would be REALLY easy wreak havoc on the internet.

Because when you have access to inject JavaScript, you can:
1. Steal the cookies, nom nom
2. Hijack the current session (either cookies or other tokens)
3. Modify the cookies, if that is useful
4. Modify or completely replace the current page
5. Steal credentials, keystrokes, and so on
6. Redirect the users

What flavour do you want?

XSS comes in different varieties, as is to be expected.

Reflected Cross-Site Scripting
So the example we had above was a reflected cross-site scripting. You input something, the site reflects it, and the attack triggers. If you do this attack, then you XSS yourself. Not that effective.

Usually, you would want to forge some URL that you can send to a victim, preferably disguise it as well. In some cases (e.g. POST-request) you need to leverage a CSRF-attack in order to get the script in there.

Persistent Cross-Site Scripting
While there is no difference for what you can do, persistence makes further attacks easier. Depending on where the script is presented, it might also make exploitation easier.

For a Persistent Cross-Site Scripting to occur, a script that is injected once must be stored and then consistently be presented by the web application. For example, a user might change their display name to “Derp<script>…</script>”

Semi-Persistent Cross-Site Scripting
Reflected and Persistent pretty much had a baby. Important to note here is the scope of the attack, for how long is the attack persistent? X page loads? X minutes? Per session? Day? Until something else happens?

So what happens if you swap 57 to something else? 58? Or perhaps 56 because, you reason, it is probably guaranteed to exist a user with the previous ID if it’s an incrementing counter.

If the application allows you to view profiles of other users (perhaps including their bank details and balances), the application has an issue with A4, as it exposes a direct reference to an object, and does not properly check if whoever queries it is authorised to get access to the data.

What to look out for

Again, this is a set of authorisation-problems. Exposing references and identifiers is never a good thing to do, but it’s not a vulnerability in itself as long as proper access control is in place.

Now, you could go through the following mental checklist in order to check for A4:

A. Does this page always look the same, for all people and under all circumstances?
If not, chances are the application presents different pages depending on some user input.

B. How are the unique/dynamic pages identified?
Look at the HTTP request. Are you sending some kind of token or identifier to indicate what page you want? Is it tied to the session/login?
Make sure to look at:
– GET-parameters, e.g. “?id=57&section=all”
– POST-parameters (request body)
– Cookies (delete one of them at a time, and see if the page changes)
– Common headers (do you get the mobile site if you pretend to be on iOS?)
– Other headers (custom headers?)

C. What is the scope of this identifier?
Let’s say you find “?id=57”. What is the scope? For user profiles… Probably site-wide. An id represents a user globally throughout the application.

Though what if you see “transactions.php?acc=2”? Perhaps that displays the transactions for account number two. Since there are probably thousands of bank accounts in the system, the scope of this identifier is probably bound to your account.

It’s terribly important to recognise that identifiers have a scope in which they are valid. Something that is not unique can only be successfully used in certain contexts, i.e. I could have 100 accounts, but you may only have 3.

From this, you can start to guess (and draft) how the application handles the identifier for the object. Perhaps something is used to set the context, which can be exploited. Perhaps you can change context somehow.

D. Is it possible to access other objects from this control? Should that be allowed?
Swap one reference for another. What happens in the following cases:
1. Use the reference given by the application. This is the default request and should work.
2. Swap to another reference “owned”/associated with your current user account. Most of the time this works as well. If it doesn’t, then we learn something about in which context/scope we can use it… Perhaps there is something else that needs to match up?
3. Refer to an object owned by another user account (might require you to have another account). This will work a lot of the time, you’d be surprised (or not, since it’s on the OWASP top 10 list…)
4. Refer to an object that does not exist. Most of the time this will yield a generic error, though verbose stack traces are also possible.

Some users should be able to view the data of others, keep that in mind when testing. Users should not be able to read private messages belonging to others, but perhaps administrators should be allowed to do so.

Remediation

For existing applications, make sure to implement access restrictions for all objects. User A should only be able to fetch resources that user A is allowed to view, and so on. Identify all references within the application, implement the necessary checks, and make sure to test it.

For new applications, consider avoiding these references altogether. Do you need to pass the user ID, if the user is already logged in? Do you need to have global references, or could they be references to the specific objects belonging to the current user only? Would you be able to present dummy references and then re-map them to the internal references later on?

Final thoughts

Make sure to double-check that the user is permitted to access whatever they’re trying to access. If not, it might be possible to access other users data by directly modifying the exposed references.

You know, keeping things up to date is something you pretty much have to do, but the web doesn’t really make it easy. There’s a plethora of things to remember to patch: the proxies, the web server, the web application, any dependencies, and even the front-end libraries themselves! How often do you update your version of jQuery?

There are two distinctly different types of using vulnerable components:
1. Using something that is vulnerable
2. Using something that is end of life

Deceased software

While something that is “end of life” doesn’t mean that it actually is vulnerable – it usually does – though you’ll be out in the cold in case something happens. Some kid discovers the next big vulnerability against Framework Buzzword, and you have no patch coming.

End of life simply means that the company, vendor, or developer who makes the software will no longer maintain it with security updates.

A note on open source projects
Larger projects will most likely keep an up-to-date list with whatever versions and branches they’re supporting, smaller ones might not. Projects on for example GitHub might not have an active community, a low level of support, and no guarantee when it comes to maintenance. For these types of projects, declaring the end of life is hard. In the end, you will have to accept responsibility for applying patches yourself or having a contingency plan in case something happens.

Danger ahead – vulnerable software in use

Though, obviously, software doesn’t have to be end of life to be vulnerable. Sometimes running an out of date version can be dangerous, depending on the associated vulnerabilities.

So what does that mean? Well, simply put, the community keeps track of and share knowledge on software vulnerabilities. Sometimes the specifics are disclosed (perhaps together with a demo), meaning that anyone with some technical know-how could go ahead and exploit anything running that software. Though sometimes only the fact that there is *something* wrong is disclosed.

How to disclose vulnerabilities is a completely different topic.

So what, no one knows if we’re running this and this version!

Wrong. The internet knows.

There are huge searchable databases that can be used to find services and applications running this and this version of that and that software. You could even use Google (with some limitations)!

Okay. Fair enough. But who would attack us?

Probably someone with nothing better to do, depending on the vulnerability. As time goes on, the likelihood of someone building a utility to automatically exploit the vulnerability increases. And when there is a tool for it, anyone (even a twelve-year-old) could use it – no skill required.

> Damn script kiddies.

So to summarise, the final thoughts:
A. Update your software, dependencies, components, whatever
B. Plan to migrate or upgrade from soon-to-be abandoned software