XML External Entities (XXE) Injection

What is it?

If your web application processes user-submitted XML data, it may be vulnerable to an attack that allows attackers to read arbitrary data on the filesystem.

XML parsers allow the defining of ‘entities’, including references to stuff outside of the XML file, called an ‘external entity’ This can be used to access local or remote content via a URI, not to be confused with a URL. A URI typically looks something like [protocol]://[path]. For example, loading /etc/passwd on a local Linux system would look like:

file:///etc/passwd

Using this to attack

First, we create what is known as a Document Type Definition, or DTD for short. This allows us to define XML elements (the bits that appear like so:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE [DTD-name]
  [<!ELEMENT [element-name] ANY >
   <!ENTITY [entity-name] SYSTEM "[protocol]://[path]" >]>

Where [DTD-name], [element-name], [entity-name], [protocol] and [path] are…the DTD name, XML element name, entity name, protocol and resource path of the thing you’re trying to access. When we want to reference the data in the actual XML, we use the following notation:

&[entity-name];

So our attacking XML, assuming we are trying to read /etc/passwd, would look something like this:

<?xml  version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
   <!ELEMENT foo ANY >
   <!ENTITY xxe SYSTEM  "file:///etc/passwd" >]>
<foo>&xxe;</foo>

Is file access the only thing that can be done with this?

Depending on the server in question, no. If the web server in question has the PHP ‘expect’ module loaded, it is possible to get command execution on the machine like so:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo
  [<!ELEMENT foo ANY >
   <!ENTITY xxe SYSTEM "expect://[command]" >]>
<foo>`&xxe;`</foo>

How do system administrators protect against this?

The main protection sysadmins can use when defending a service that requires XML data is to simply not trust any DTD data enclosed in the XML and instead use a static DTD stored locally. That way, the attacker cannot redefine the DTD, or any elements and therefore cannot define entities.

Cross-Site Scripting (XSS)

What Is It?

Imagine you have the ability to alter the behaviour of a web page to your liking to a small (or large) subset of users. No browser plugin installation necessary, the page and it’s behaviour is yours to mess with as you see fit. You control what the user sees, the information they can send (and who it goes to), potentially including session information.

This is the kind of power an XSS vulnerability has. With JavaScript, it is possible to almost completely alter the contents of a page or even redirect users to your own page for nefarious deeds.

How does it work?

Generally speaking, it relies on a few fundamental things:

1) That the application repeats user-inputted data. Doesn’t have to be immediate, and doesn’t have to be the same user doing the inputting as the one to fall victim.

2) That the application fails to effectively separate the inputted data from the existing HTML or JavaScript code (or that such separation is possible to bypass)

There are three main types of XSS.

Reflected XSS

This is where you put the XSS code into a HTML request and have it immediately execute on the responding page. For GET-based XSS flaws, a direct link can be provided to the victim but for POST-based flaws, you’d have to trick them into inputting the XSS code themselves. You can do this by claiming the code is a secret coupon for infinite nachos or something.

Stored XSS

This is where you send your XSS code to an application in a form where it can be stored and brought up later – think something like a Facebook comment. Once the page with the XSS code, the code will execute immediately.

DOM-Based XSS

This one is a little different in that instead of exploiting bad handling of HTML code in the server’s responses, we’re exploiting bad handling of user input within the legitimate JavaScript code of the application. Imagine you’re typing into a search bar and as you type a bit of JavaScript changes a bit of text to reflect what you type. If you manage to get some Javascript code running in this reflected bit of text, you’ve got yourself a DOM-Based XSS

Testing for XSS

The simplest test one can do for XSS is to enter the following code into an input field or POST/GET request variable:

<script>alert('XSS')</script>

This defines a JavaScript block of code that presents a message box window saying ‘XSS’. Alternatively, if you’re looking to persuade someone that an XSS can do real damage, try the following:

<script>alert(document.cookie)</script>

This instead loads the document cookies (or at least the ones without the flag ‘HttpOnly’) into the message box. If those don’t work, you can try the following:

- javascript:alert('XSS')
- <iframe src='javascript:alert("XSS")' />

Among a long list of other potential XSS bypass strings.

SQL Injection

What is it?

SQL Injection is a popular method of attack against web applications. In terms of what you can do with one, the options are almost limitless. It is almost like if you were trying to get into a nightclub and if the owner asks you for your ID, you instead hand him a crumpled up piece of paper saying ‘I am the owner, please give me all the money from the cash drawers’. It shouldn’t work…except in this case, the bouncer is the most gullible idiot imaginable and hands you the cash with with a big dumb grin on his face.

This would be incredibly stupid in the real world, so why does it work on websites? Well, this goes back to how SQL databases work. Every interaction with a database is essentially a line of text, much like how you interact with the commandline. So if you were on a login page, the interaction might look something a little like this:

SELECT username, password FROM users WHERE username='<username field>' AND password='<password field>' LIMIT 1;

The web application then swaps out <username field> and <password field> with whatever you entered as username and password. So far, so good. But the problem is, traditional SQL queries cannot tell the difference between what is code, and what is user-inputted data, so if you enter “admin” as your username and the following

' or 1=1;-- -

as a password, that SQL command can look like the following:

SELECT username, password FROM users WHERE username='admin' AND password='' or 1=1;-- -' LIMIT 1;

In other words, instead of checking both the username and password as it should, it is checking for the username and checking the password, but because 1 will always equal 1, it will disregard the lack of a correct password and let it through anyway. ‘– -‘ is a comment delimiter, meaning that anything past that point is disregarded by the SQL server as ‘human garbage’

What Can We Do With It?

There’s a lot of things you can potentially do with a SQL Injection. The obvious ones include pulling data or dropping tables, but with the right configuration, shells can be obtained on these boxes as well. This would effectively allow someone to execute any commands they like against the box.

The UNION SELECT Shuffle

If the web application uses the injectable SQL data to populate rows on a table, it can be possible to use this to obtain large amounts of data in one sitting. In these cases, first of all we need to ascertain how many columns it is filling up. To do this, we start our payload with something like this (for MySQL backends):

' UNION SELECT 1;-- -

Now, there’s a good chance that the application will either error out or just show a blank screen. This is because the command above only returns one column, but the web application is probably expecting more and doesn’t know what to do. So we continue the shuffle, as so:

' UNION SELECT 1, 2;-- -

And we keep adding numbers in this way until we get something back that isn’t an error or a blank screen. It may, however, look like a Baby’s First Counting Toy, because the numbers are being printed verbatim. Once we have the required amount of columns (I’m going to give an example of 6 columns here), we can run something more interesting:

' UNION SELECT username, password, 3, 4, 5, 6 FROM users;-- -

I’ve skipped ahead past the recon stage of this attack just to demonstrate an injection with some real teeth. In a real pentest/CTF, you’ll want to find out what databases and tables actually exist so you aren’t just hoping there’s a table called ‘users’ with the columns ‘username’ and ‘password’. More on that later.

Injecting what you can’t see

Just because an application fails seemingly gracefully without giving you any output, doesn’t mean that the field cannot be injected into. Indeed, it can still be very much possible to inject code from the application and even extract data from it, by way of inferential injections.

Inferential SQL injections, also known as Blind SQL injections, work a little bit differently from traditional injections. Instead of calling the data out directly, you are instead asking the server to ‘blink’ if the data is matching what you are expecting. This blink can take one of two forms: a Boolean value or a time-based delay. Using this, we can write a bit of code to develop something that works much like Partner-Assisted Scanning in care settings, as seen in the movie The Diving Bell and The Butterfly, in order to tease out strings of data.

Testing for an Inferential SQL Injection

First, we start off with a SQL query that returns a valid response. Once we have that, we tack on an ‘AND 1=1‘ command to see if it returns the same information. If it doesn’t, try experimenting with ending the SQL statement with a semi-colon and comment denominator. Once you have the desired result, try changing the tacked on command to ‘AND 1=2‘. If all goes well, you should get an empty result or an error. Note down any strings you may come across that only happen in cases of such failure. To do this with a time-based delay, simply swap out ‘AND 1=1‘ with ‘AND sleep(10)‘, noting the response time of the page (it should be over 10 seconds in this case. Note that ‘sleep(10)‘ works only with MySQL, and for other SQL server backends, you will need to use a different command to get the same results.

Getting data from an Inferential SQL Injection

For a Boolean inferential, the command to, for example, obtain the list of databases available (again, MySQL only) looks something like this:

<valid data>' AND (ascii(substr((SELECT schema_name FROM information_schema.schemata LIMIT 0,1),1,1))) = <ascii decimal value>;-- -

Sounds like a mess? Let’s break it down:

  • ascii(<character>)‘ turns a given single character into its numerical ASCII value
  • substr(<string data>, <startpoint>, <length>)' returns a part of a string, from the start point until <length> is reached. In our case, we only ever want a <length> of 1. The beginning of the string is always denoted by a <startpoint> of 1
  • SELECT schema_name FROM information_schema.schemata‘ is simply the command we use to obtain the list of SQL databases. You can swap this out for any SQL injection payload.
  • LIMIT <start>,<number of rows>‘ limits us to the the number of rows, starting from the row of our choosing. Unlike with substr, the first row is always 0, not 1
  • = <ascii decimal value>‘ compares the whole statement to a given ascii value. If they match, the SQL code proceeds as normal, but if not, the page returns no data.

It should be noted that the above code doesn’t give you the data right away. What it does is tell you if a specific character in a specific row matches a specific ASCII value or not. In order to make this effective, we will need to write a script in order to send the many hundreds of requests, determine whether the page has returned valid data or not (our ‘tell’ in this scenario), and collate the data into a string. I highly recommend using Python and the ‘requests’ library to get this done.

For delay-based inferentials, it looks more like this:

' AND IF(((ascii(substr((SELECT schema_name FROM information_schema.schemata LIMIT 0,1),1,1)))) = <ascii decimal value>,sleep(10),NULL);-- -

Where the ‘if’ syntax goes as such:

  • IF(<condition>,<operation if true>,<operation if false>)

Cheating a little bit

To truly get the most out of SQL injections, I recommend bookmarking (or even better, creating your own) cheatsheets to make a note of likely commands you will need to use. I recommend the cheatsheets by ‘pentestmonkey’, however, the ones featured in ‘PayloadsAllTheThings’ are worth a look too

  • http://pentestmonkey.net/category/cheat-sheet/sql-injection
  • https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection