Challenge
Javascript Mission 5: Uhm, faith spelled runescape wrong?
索引名为
Escape!,难度 easy。页面上只有一个密码框和Check Password按钮,密码被一层百分号编码包着,用unescape()在浏览器里解出来。
Solution
- 页面没有任何把密码送去服务端校验的请求:比对全在客户端的
check()里完成,命中后用window.location = "../../../missions/javascript/5/?lvl_password="+x回跳。
拉取页面源码:
$ curl -s -b "$HTS_COOKIE" \ -H "Referer: https://www.hackthissite.org/missions/javascript/5/" \ "https://www.hackthissite.org/missions/javascript/5/" -o lvl5.html页面内联脚本(业务部分全文):
moo = unescape("%69%6C%6F%76%65%6D%6F%6F");function check(x) { if (x == moo) { alert("Ahh.. so that's what she means"); window.location = "../../../missions/javascript/5/?lvl_password=" + x; } else { alert("Nope... try again!"); }}moo 直接由 unescape(...) 得到,check(x) 只做一次相等比较,相等就带着 x 回跳。
unescape() 是早期的百分号解码器,%XX 中的 XX 是字符的十六进制 ASCII 码。逐个翻译:
%69= 0x69 = 105 =i%6C= 0x6C = 108 =l%6F= 0x6F = 111 =o%76= 0x76 = 118 =v%65= 0x65 = 101 =e%6D= 0x6D = 109 =m%6F= 0x6F = 111 =o%6F= 0x6F = 111 =o
#!/usr/bin/env python3"""Recover the JavaScript Mission 5 password from the fetched page source.
The page assigns the expected value at load time:
moo = unescape('%69%6C%6F%76%65%6D%6F%6F');
`unescape()` is the legacy percent-decoder, so the password is just thatliteral decoded once. urllib.parse.unquote is the modern equivalent."""import reimport urllib.parse
def main(): src = open("lvl5.html", encoding="utf-8", errors="replace").read() match = re.search(r"unescape\('([^']*)'\)", src) if match is None: raise SystemExit("could not find an unescape() literal in lvl5.html") encoded = match.group(1) password = urllib.parse.unquote(encoded) print("encoded :", encoded) print("decoded :", repr(password))
if __name__ == "__main__": main()$ uv run python decode5.pyencoded : %69%6C%6F%76%65%6D%6F%6Fdecoded : 'ilovemoo'$ curl -s -o /dev/null -w '%{http_code}\n' -b "$HTS_COOKIE" \ -H "Referer: https://www.hackthissite.org/missions/javascript/5/" \ "https://www.hackthissite.org/missions/javascript/5/?lvl_password=ilovemoo"200