Tag Archives: zero-day

Malformed HTML & XSS Character Filtering: A Few Lessons

On a recent web app pen test I ran into the following issue: the application would escape (that is, add backslashes) before single and double quotes but not filter other characters. Upon review of the source it was clear the developer knew that not escaping these quotes would lead to issues (such as SQL injection) but they did not appear the grasp the larger picture.

For those who wish to avoid the technical discussion below, here are the talking points:

  • If you are a developer, filter out as many characters as possible without breaking your web app
  • If you are a pen tester, the fewer characters filtered the more likely the code has vulnerabilities

What I hope to show is how an assumption about syntax could prove untrue since the following two statements are valid:

  • Not enough filtering may allow the attacker to create “enough valid” HTML syntax to allow code injection
  • The browser’s disposition to interpret malformed or “bad html” as valid gives the attacker more surface area to attack

Below is a tutorial on basic malformed HTML in three parts. The first part shows how bad filtering can lead one to create valid (or semi-valid) HTML the developer did not intend. The examples will show that the browser will interpret partially malformed HTML as legitimate despite syntax errors. The second part shows that once the attacker creates “valid” HTML injecting attack code is made much easier by injecting additional malformed HTML. The third part is an exploit created from parts one and two.

The code below is a case of  a developer dynamically building a string to pin/post to pinterest. The code has been rewritten to hide the source of the material but it is a true and formally live case of the  logical errors described above.

My motivation for this basic tutorial is my response from another professional. While I was investigating this issue on-site another infosec professional said to me that if the quotes are escaped then the app can’t be exploited. It turns out this is the same incorrect assumption the developer made. Perhaps this will help explain this issue so that other professionals recognize instances of this issue.

Note: the syntax highlighting is not an accurate representation on how the browser will interpret the HTML. In fact, the syntax highlighting below is more strict.

Part 1 – Bad Filter, Bad HTML

The developer’s assumption was simply that if the attacker could not pass a single or double quote they could not create syntactically meaningful HTML or exploit the application. For example, the following valid HTML

after being run through the filter would be turned into:

which, due to the backslashes, is meaningless to the browser.

Unfortunately simple cases of only filtering double quotes is an assumption since we can sometimes: first, end tags meaningfully despite the escape; and second, do not need double quotes in our HTML in order to get some invalid HTML to be “properly” interpreted as valid.

In this case I found the developer was building strings dynamically from values in the URL. The offending URL looked like this:

So putting “test” in the badparm as so:

resulted in the following dynamic HTML

So you’ll note that we have the ability to get our input — the string ‘test’ — into the middle of the dynamically built string. Given that this code is intended to be “pinned”, there are two forms of attack here. Once we can get our code to be injected via a URL if we can get it pinned on pinterest– either through us manually pinning it or through social engineering the end user — it will be stuck there. Quite interestingly, it’s possible for our reflected XSS injection attack to become a stored injection attack (as long as pinterest does not filter the characters in our URL). Then anyone who clicks on the pinterest link will run the code when it comes back to badsite.com. The other way is to simply leave our attack as a reflected attack and inject our code into badsite.com through a URL on which we get an end user to click. In either attack, to be successful, we will need to end (or close) the tag otherwise our code will remain as part of the URL and not as code to be parsed and interpreted in the next block.

Let’s test out the filter. If we add a double quote to the end of badurl.com as such:

We have the following output (slightly abbreviated from the longer version above):

So far, the string is escaped properly. But what if we put in a > after as such:

All of a sudden we get the following code:

To be more explicit the following snippet from above is “valid” html:

Yes, despite the mangled \”> it is treated as a valid ending to HTML. The escape backslash added by the developer’s filter is not counted!

In all fairness, the two code snippets above is not valid but no matter. Since we’ve successfully closed the tag according to the browser we can now put our code after to be executed as a new tag.

Part 2 – Bad HTML, Bad Filter equals Good Exploit

In the prior section we learned about how escaping can be bypassed if the HTML end tag is seen as valid. In this case we will see how malformed HTML can be interpreted as valid.

Here is a valid image tag:

But did you know the following is also interpreted as valid by the browser?

That’s right. An image tag without double quotes! So, here’s the important point. If the image tag does not need double quotes, when we encounter filters that only filter the quotes we will bypass it. Who needs quotes anyway?

In this simple example I loaded Google’s homepage image via an img tag. I leave it to the reader as an exercise to understand how the img tag may be used to inject javascript and other malicious code. In short, if a researcher can inject the img tag into a dynamic URL displayed on a webpage (as shown above) they can do damage. So, pretend the Google image is really an exploit.

Part 3 – The Exploit!

If we go back to our bad url from Part 1:

and put a “> and then our malformed image tag without double quotes we get the following URL:

If we execute the URL we get the following code as a result:

The browser will now run our mangled/malformed injected img code (without the dquotes) since we’ve closed off the HTML and our injected code is seen as the next tag for the browser to interpret.

To be more explicit, the following snippet parsed from the code quoted just above will be treated as valid HTML:

Lesson: filter out those extra characters!

Publicly Disclosed Vulnerabilities & Exploits between 2000-2006

Here is a list of my publicly disclosed vulnerabilities from 2000 through 2006. I figure these should be added to my public OSVDB profile. (I actually have two!) It’s 2013. These were found a long time ago. Still, I did the work; why not receive the credit?

It should be emphasized that these are vulnerabilities that were publicly disclosed and not the totality of those that I’ve discovered between 2000-2006.  If I can find additional ones I will update this as necessary. This page is more for historical accuracy and record keeping than anything else.

Date CVE / CAN / BID Vuln Name and Link
08/25/00 CVE-2000-0777 MS00-061 : Microsoft Money Password Vulnerability
11/01/01  CAN-2001-0721 MS01-054: Microsoft UPnP Denial of Service Vulnerability
11/08/01 BID: 3518 IBM HTTP Server Source Code Disclosure Vulnerability
02/07/02 BID: 4059 OS/400 User Account Name Disclosure Vulnerability
02/18/02 CVE-2002-0291 Dino’s Webserver Denial of Service Vulnerability
02/21/02 CVE-2002-0298 Nombas ScriptEase:WebServer Edition GET Request Denial of Service Vulnerability
03/22/02 CVE-2002-0479 Gravity Storm Service Pack Manager 2000 Directory Permissions Vulnerability
06/25/02 BID: 5094 Microsoft Internet Explorer CLASSID Denial of Service Vulnerability
06/30/02 BID: 5357 Microsoft Windows mplay32 Buffer Overflow
10/08/02 CVE-2002-1529 SurfControl SuperScout Email Admin Server XSS
10/08/02 CVE-2002-1530 SurfControl SuperScout Email Admin Server Data Integrity
10/09/02 CVE-2002-1531 SurfControl SuperScout Email Admin Server Content-Length: DoS
10/09/02 CVE-2002-1532 SurfControl SuperScout Email Admin Server Incomplete Get Request DoS
08/29/05 CVE-2005-2787 Vulnerability and Perl Exploit: SimplePHPBlog
05/17/06 CVE-2006-2531 Ipswitch WhatsUp Professional 2006 Authentication Bypass Vulnerability

Vulnerability: OrangeHRM 2.7.1 Vacancy Name Persistent XSS

OrangeHRM 2.7.1 — the latest stable release as of this writing — suffers from a persistent XSS in the vacancy name variable. Steps:

  1. Navigate to following URL:
  2. Add or Edit a Vacancy
  3. In the Vacancy Name parameter put XSS script
  4. Save
  5. Navigate back to top Vacancy page (click back button)
  6. Witness XSS

Screen prints in the gallery below. The images should be self-explanatory.The direct URL to the list of vacancy page is below.

I contacted OrangeHRM but did not receive a reply.

Analysis: 0-Day NYC Transit System “Free Ride” Bug

I found this bug by accident on my way home from work tonight. The reason I am writing this even though it’s a 0-day:

  1. I do not think it’s widely exploitable.
  2. And if it is, NYC isn’t losing any money over it as far as I could tell.
  3. It will help the MTA/NYC Transit find and fix the problem
  4. I’m not sure it’s reproducible since I wasn’t about to spend my own time and money to test it

Technically what I describe below is a security issue because it denies legitimate users entry/access and could allow a non-legitimate user a “free ride” if they happen to be in the right place at the right time. It might also cost a legitimate user an extra fare since they might swipe again at a different turnstile since they will assume they just swiped at a broken one.

Here’s the scenario that happened to me coming home from work tonight at around 7PM. Imagine three turnstiles lined up in a row.

  1. I swiped my unlimited metrocard at right most turnstile to enter subway system. I was denied access. It said ‘Go’ on the green readout but the turnstile wheel was locked. I swipe again and received the ‘Just Used’ message.
  2. Woman behind me swipes and turn style denies her access in the same way. (She then “hops the turnstile” and enters subway system.)
  3. As I try to swipe my card again and on the other turnstiles I continue to receive the “Just Used” Message. The left most turnstile readout says, “Just Usedd” with two Ds. I probably try around 5 times in the next few minutes. (I know I need to wait 15 min for the ‘Just Used’ flag to clear but I worked late and thought I might get lucky!)
  4.  Legitimate users enter and leave the subway system through turnstiles. I don’t recall how many or which one’s they used. Although tired I don’t recall this watching and step 3 combined being more than 5 minutes.
  5. A legitimate user swipes card in middle turnstile to enter the subway and the right turnstile — without prompting or a card swipe (no one is in proximity) — lights up ‘Go’ on the green readout and allows access.

If NYC transit wants to contact me I’ll give them the location of the turnstile for them to investigate.