HackThisSite - Extended Basic Mission 4
Challenge
A program written in a made-up language called
F.ake; work out its output when the user types6,7.第四关给出一段用自造语言
F.ake写的程序,要求算出用户输入6,7时它的输出。
关卡页把程序正文放在 <pre> 里,上面一行注明
{user types 6,7}:
1 | {user types 6,7} |
Solution
用带登录态的会话取关卡页(HackThisSite
是短期凭据,这里写成占位符):
1 | $ curl -s -b 'HackThisSite=<mission-cookie>' \ |
页面里的提交表单:
1 | <form action="/missions/extbasic/template.php" method="post"> |
formkey 每次加载关卡页都会变(实测连续几次分别拿到
J1vgO9lFLqnaYvHFPQZkoeoDg7ru1brsf4o2QPVWUG、8pLDPkPxWkPr5yGy1IzLZS6uw6IFfa9YD1UvthG、X93f0aA1lmFy7IuEU5uKG1eWJpZbDez1lG7AZb4T),所以要先抓页面再立刻提交。
四行程序逐行读:
BEGIN F.ake:程序入口,对应其它语言的main;F.ake就是这门语言的名字。var int as in:从标准输入读一个值,声明成名为var、类型为int的变量。第一次输入是6,所以var = 6。as in是取自输入。int var as in:同一套写法的第二次读入,这次名字是int、类型 token 是var(一个动态/未定类型,含义类似 JavaScript 的var)。第二次输入是7,所以int = 7。out var int:按书写顺序输出后面列出的变量。
关键是把每行的两个 token
按名字在前、类型在后的次序读:var int 是叫 var
的 int,int var 是叫 int
的动态变量。var 和 int
在这里都只是变量名,跟它们像不像类型关键字无关,这也是这门语言故意制造的混淆。
var = 6,int = 7,out var int
依次打印两个变量 → 67。
out var int
是把两个变量的值分别输出再拼接,不是把 6
和 7 做算术相加(那才是 13)。
POST 到 /missions/extbasic/template.php,三个字段
formkey、lvl、pass。第一次不带
Referer 直接提交,服务端拒绝:
1 | <strong> |
和 JavaScript 系列一样,服务端要求 Referer
指向关卡页。补上 -e(curl 的
Referer)后提交被接受,响应里给出指向下一关的
go on 链接:
1 | <a href='/missions/playit/extbasic/5'><img src='http://hackthissite.org/missions/GoOn.gif' alt='go on' title='go on' border='0' /></a> |
提交后 profile 的 Extbasic: 列表由
(1) (2) (3) (5) 变为 (1) (2) (3) (4) (5)。
完整求解脚本(先取 formkey,再带 Referer
提交,最后检查下一关链接):
1 | #!/usr/bin/env python3 |
运行输出:
1 | $ cd <hts-workspace> && uv run python challenges/hts-playit/extbasic-4/solve.py |
Key points
- F.ake 的声明形式是
name type as in(名字在前、类型在后),不能按关键字直觉读;var/int是变量名,不是类型名。 out var int只是依次输出两个变量,输出是字符串67,不是算术和13。formkey是每次加载生成的,必须抓页面 → 立即提交,不能复用旧值。- 提交必须带
Referer: /missions/playit/extbasic/4/,否则返回Invalid Referer且不计完成。