Post

Lab - Reflected XSS with some SVG markup allowed

This writeup delves into the 16th XSS lab in port swigger.

Lab - Reflected XSS with some SVG markup allowed

Introduction

This lab delves into reflected XSS but using SVG markup? I have no idea how this is going to go; I’m literally writing this and solving at the same time.

Investigation

We have the usual PortSwigger vulnerable web app: a blog post with a search bar.

ImageOne

Vulnerability Discovery

Let’s try to fuzz the search bar again and see if some HTML is allowed or not.

Fuzzing

Interesting, the tag itself is not allowed, but from what I read from the description, SVG is allowed, so let’s try it.

not allowed

not allowed

And SVG is actually accepted. This can be a great payload actually.

svgAccepted

Payload Crafting

So SVG is accepted. Let’s try to make this simple payload <svg onload=alert(1)></svg>. It turns out that the event is not allowed, so maybe we need to brute-force events.

svgAccepted

svgAccepted

Even onclick is not allowed. So let’s try to brute-force to find an allowed event.

Brute Forcing Using BurpSuite

For brute forcing, we are going to use our usual tool, Burp Suite.

So we intercept the search traffic and send it to Intruder.

BruteForcing

Then, in the URL, we change the event and make it the placeholder for brute forcing. For event brute forcing, you can check PortSwigger’s cheat sheet.

Then we load the list of tags.

listTags

Then we start the attack and try to investigate which event returns a response other than 400.

investigateEvents

We found an event that returns a 200 response, which is onbegin.

svgAccepted

But what is onbegin exactly?

Research

After some research, I found that onbegin is an event trigger that is linked to a process like an animation or an AJAX request, and it starts right before a process or animation starts.

I discovered that this event can only be linked to SVG child elements that are responsible for animations, like the following:

1
2
3
4
5
<animate>
<animateTransform>
<animateMotion>
<set>
<mpath>

and maybe much more. The problem is that these elements may be blocked by the WAF.

So let’s fuzz them by hand; they aren’t that many.

Fuzzing

I found out that <animateTransform> is actually accepted by the website, but we need an SVG element that can be animated. However, SVG elements are actually filtered, so let’s try to see possible SVG elements and maybe brute-force them.

So after fuzzing different elements by hand—ChatGPT gave them to me—I found out that <text> is accepted, so now we can craft the payload, inshallah.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<svg width="400" height="200">
  <!-- Text element -->
  <text x="50" y="100" font-size="30" fill="blue" id="myText">
    Hello SVG!
    <!-- Animate the text with rotation -->
    <animateTransform
      attributeName="transform"
      type="rotate"
      from="0 100 100"
      to="360 100 100"
      dur="3s"
      begin="0s"
      id="rotateAnim"
      onbegin="alert(1)"
      repeatCount="indefinite"
    />
  </text>
</svg>

We insert it into the input, we get the alert, and the lab is solved.

InsertPayload

InsertPayload

Another Payload

Soooo it turns out that animateTransform can work without a shape to animate, so literally:

1
2
3
<svg>
	<animatetransform onbegin="alert(1)"/>
</svg>

This one works perfectly fine—no need for parkour, but still… nice one.

Conclusion

It was a nice lab that taught us how even SVG can be exploited in XSS, and this is one of those forgotten payloads that we should not overlook.

This post is licensed under CC BY 4.0 by the author.