HackThisSite - JavaScript Mission 6

Challenge

Fiftysixer decided to try his hand at javascript! All was going well until he realized that he forgot to remove the unused code, which resulted in a confusing mess. He didn't mind, in fact, he did his best to make it even MORE confusing!

Find the password:

索引名 go go away .js,难度 Weird。主页面只留一段自相矛盾的误导脚本,真正的比较藏在外部文件 checkpass.js 里。

Solution

  • 关卡页 https://www.hackthissite.org/missions/javascript/6/ 通过 <script src="/missions/javascript/6/checkpass.js"></script> 引入外部脚本。
  • 页面内联脚本故意留下大量未使用且自相矛盾的代码:check() 里出现 "hack_this_site" 字面量和跳向 about:blank 的分支,这些都被真链路旁置。
  • 表单真正调用的是内联的 checkpassw(this.value),它把输入写进 RawrRawr 再调用外部脚本里的 checkpass()

拉取主页面与外部脚本:

1
2
3
4
5
6
$ curl -s -b "$HTS_COOKIE" \
-H "Referer: https://www.hackthissite.org/missions/javascript/6/" \
"https://www.hackthissite.org/missions/javascript/6/" -o lvl6.html
$ curl -s -b "$HTS_COOKIE" \
-H "Referer: https://www.hackthissite.org/missions/javascript/6/" \
"https://www.hackthissite.org/missions/javascript/6/checkpass.js" -o checkpass.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
RawrRawr = "moo";
function check(x) {
"+RawrRawr+" == "hack_this_site";
if (x == "" + RawrRawr + "") {
alert("Rawr! win!");
window.location = "about:blank";
} else {
alert("Rawr, nope, try again!");
}
}

function checkpassw(moo) {
RawrRawr = moo;
checkpass(RawrRawr);
}

check() 里那条 "+RawrRawr+" == "hack_this_site" 是一条无副作用的裸表达式语句,about:blank 分支也永远不会给站点送出密码:表单并不调用 check()。真正的入口是 checkpassw(moo)checkpass(RawrRawr),而 checkpass 定义在外部文件里。这正是题面说的忘了删掉没用的代码。

1
2
3
4
5
6
7
8
9
10
11
12
dairycow = "moo";
moo = "pwns";
rawr = "moo";

function checkpass(pass) {
if (pass == rawr + " " + moo) {
alert("How did you do that??? Good job!");
window.location = "../../../missions/javascript/6/?lvl_password=" + pass;
} else {
alert("Nope, try again");
}
}

决定性的比较是 pass == rawr+" "+moorawr="moo"moo="pwns",中间夹一个空格字面量 " "dairycow="moo" 在本文件里没被使用

从抓下来的 checkpass.js 里把变量逐个读出来再按比较式拼接:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/env python3
"""Recover the JavaScript Mission 6 password from the external script.

index.php loads /missions/javascript/6/checkpass.js; the winning comparison
there is pass == rawr+" "+moo with dairycow="moo", rawr="moo", moo="pwns".

The inline check() (RawrRawr / "hack_this_site" / about:blank) is dead code;
the form calls checkpassw() which forwards to the external checkpass().
The password is exactly "rawr + ' ' + moo" -- the single space included.
"""
import re
import urllib.parse


def main():
js = open("checkpass.js", encoding="utf-8", errors="replace").read()
vals = dict(re.findall(r'(\w+)\s*=\s*"([^"]*)"', js))
missing = {name for name in ("rawr", "moo") if name not in vals}
if missing:
raise SystemExit("missing required assignment(s): " + ", ".join(sorted(missing)))
password = "%s %s" % (vals["rawr"], vals["moo"])
print("rawr :", vals["rawr"])
print("moo :", vals["moo"])
print("password :", repr(password))
print("query : lvl_password=" + urllib.parse.quote(password))


if __name__ == "__main__":
main()
1
2
3
4
5
$ uv run python decode6.py
rawr : moo
moo : pwns
password : 'moo pwns'
query : lvl_password=moo%20pwns