HackThisSite - JavaScript Mission 1

Challenge

Idiot Test. The page is a single password box and a button; the check runs entirely in the browser.

第一关 Idiot Test:页面只有一个密码输入框和一个提交按钮,点按钮时在浏览器里执行页内 JS 校验。

页面结构是 input#pass 加一个 <button onclick="javascript:check(document.getElementById('pass').value)">。按钮不提交任何表单,点击只是把输入框的值交给页内函数 check()

Solution

用带登录态的会话取关卡页源码(HackThisSite 是短期凭据,这里写成占位符):

1
2
$ curl -s -b 'HackThisSite=<mission-cookie>' \
'https://www.hackthissite.org/missions/javascript/1/'

页面里负责校验的函数:

1
2
3
4
5
6
7
8
function check(x) {
if (x == "cookies") {
alert("win!");
window.location += "?lvl_password=" + x;
} else {
alert("Fail D:");
}
}

为什么这段 JS 能被绕过

  • check() 把输入和字面量 "cookies" 直接比较,密码就硬编码在客户端 JavaScript 里。浏览器拿到的源码就是全部逻辑,查看源码或 devtools 即可读出,不需要任何猜测。
  • 真正决定通关的动作是成功分支里的 window.location += "?lvl_password=" + x。它把密码追加到当前 URL 上,再作为一个普通 GET 回跳给服务端。也就是说,客户端 JS 只决定是否发起这次跳转;跳转本身可以手工构造,无需运行页面。
  • 用 Node 把这段逻辑提取出来运行一遍,即可确认比较结果:
1
2
$ node -e 'function check(x){ return x == "cookies"; } console.log(check("cookies"))'
true

Submit

cookies 填进输入框点按钮,等价于对关卡页发起这次请求:

1
2
3
$ curl -s -b 'HackThisSite=<mission-cookie>' \
-e 'https://www.hackthissite.org/missions/javascript/1/' \
'https://www.hackthissite.org/missions/javascript/1/?lvl_password=cookies'

服务端靠 Referer 判断请求来自关卡页:同一 URL 不带 Referer 时不计完成,补上 -e 指向的关卡页地址后即计入完成。提交后 profile 的 Javascript 列表出现本关完成标记,账号积分 6501 → 6669(七关合计)。

cookies