Banyan

A community-garden app strips event handlers after a space. Only after a space.

Room Description

Banyan — figure 1

https://dashboard.webverselabs-pro.com/challenges/banyan

Scenario

Banyan coordinates community-garden plots. The search endpoint strips any space-prefixed on* attribute. The developer assumed all attribute boundaries are whitespace. HTML does not agree.

Objective

A community-garden app strips event handlers after a space. Only after a space

Initial Analysis

This web application looks so CUTE. It's a farmland reservation kind of thing, where you can reserve a plot and decide what you want to plant.

Banyan — figure 2

There are little endpoints to work with, so the vulnerability should be in plain sight.

  <nav class="by-footer-nav">
    <a href="/">Garden map</a>
    <a href="/reserve">Reserve a plot</a>
    <a href="/plots">Plot directory</a>
    <a href="/crops">What to grow</a>
    <a href="/events">Workdays</a>
  </nav>

The /plots endpoint isn't available through the UI as far as I can see, but there's nothing significant there honestly.

Banyan — figure 3

Finding the bug

/crops

Banyan — figure 4

This is just a static list of crops.

/events

Banyan — figure 5

Saturday is a workday :O? No way! Eitherway, nothing here.

/reserve

And then we have our faithful endpoint that is the main functionality of the web app, reserving a plot:

Banyan — figure 6

If we just submit dummy data then we see how our request is processed:

Banyan — figure 7

Our input is now rendered as such:

<section class="by-page">
  <p class="by-kicker">Request #BY-F1279D</p>
  <h1 class="by-display">Request received.</h1>
  <p class="by-lede">Review on Thursday. We'll email you with the gate code (or your waitlist rank) by Friday morning.</p>
  <article class="by-receipt">
    <div class="by-receipt-row">
      <span class="by-receipt-k">Gardener</span>
      <span class="by-receipt-v">test</span>
    </div>
    <div class="by-receipt-row">
      <span class="by-receipt-k">Plot</span>
      <span class="by-receipt-v">3C · Union Lot · S row</span>
    </div>
    <div class="by-receipt-row by-receipt-row-notes">
      <span class="by-receipt-k">Plans shared with coordinator</span>
      <blockquote class="by-notes">test</blockquote>
    </div>
  </article>
  <a class="by-btn by-btn-ghost" href="/reserve">Submit another →</a>
</section>

Exploitation

Let's start off with a basic payload.

<script>alert(0)</script>
Banyan — figure 8
Banyan — figure 9

We see that input is sanitized in one field, but in another there's a filter, it's taking away the <script part of our payload.

There are possible obfuscation techniques to do to stay with <script>, but the best way is to just find a different payload, like <img src=x onerror=alert(1)>, or <svg onload=alert(1)>.

Now, we can try those payloads, and I did, but they result in failure, and that's because of the challenge description.

A community-garden app strips event handlers after a space. Only after a space.
Banyan — figure 10

As we can see, everything after the space got removed.

The <img src=x onerror=alert(1)> payload worked, but no flag, since I can see the errored out image.

Banyan — figure 11

and as we can see, our input after x gets stripped away:

Banyan — figure 12

<img src>

If we go to Burp Suite's cheat sheet for XSS.

https://portswigger.net/web-security/cross-site-scripting/cheat-sheet

We see event handlers, let's select one we are familiar with and select the image tag:

Banyan — figure 13
Banyan — figure 14

We copy paste the payload in the name field and plan field and we get an alert popup.

<image src/onerror=alert(1)>

(keep in mind <img> and <image> are interchangeable)

Banyan — figure 15
Banyan — figure 16

From the frontend we can see that nothing gets stripped and we don't need a space for the attributes :)

Banyan — figure 17

<svg>

Another payload that works is with <svg> tag, same tactic, no space needed.

<svg/onload=alert(1)>
Banyan — figure 18

The reason these two work is because "/" is treated as a separator.

<iframe>

Now there is a third type of payload that also bypasses this filter, because it doesn't even need a space for the attribute, and it's not even an event handler.

<iframe src=javascript:alert(1)>

We just call an iframe and it src is treated as a URL so it just calls javascript:alert(1) in the iframe which executes the alert pop up.

Banyan — figure 19
Banyan — figure 20

Fun challenge, hope the different ways to solve it are nice enough ^^.