尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

sql二次注入攻击原理

sql二次注入攻击原理 免责声明本文全部实验操作均在本人完全可控的自建本地靶场环境完成文章仅用于网络安全原理学习与技术研究。根据《中华人民共和国网络安全法》未经授权对任何第三方系统进行探测、命令执行、文件写入等操作属于违法行为。严禁复制、使用本文中的 Payload、代码应用到未获得授权的设备上。若读者将文中内容用于非法用途一切法律责任由行为人本人承担与本文作者无关。个人认知有限文中难免存在疏漏与冗余如有不妥之处欢迎大家交流指正还望海涵。————————————————SQL 二次注入Second-Order SQL Injection一、什么是二次注入二次注入又称二阶 SQL 注入Second-Order SQL Injection是一种特殊的 SQL 注入形式。它和传统的一阶SQL 注入最大的区别在于一阶注入攻击者提交的恶意数据在当前请求中就被直接拼接到 SQL 语句并执行攻击效果立即显现。二次注入攻击者提交的恶意数据在写入时被正确地转义、过滤或使用参数化处理安全地存储进数据库但当这些数据在后续的某个请求中被读取出来并再次被拼接进新的 SQL 语句执行时由于未做二次过滤注入漏洞才真正被触发。通俗地说第一次存储是安全的第二次使用时是危险的。二次注入的关键在于攻击载荷经过了存储 → 读取 → 拼接执行这一完整链条攻击效果具有延迟性和隐蔽性因而往往能绕过仅针对输入进行过滤的常规防御。二、产生原理二次注入产生的根本原因可以概括为一句话应用程序对写入数据库的数据做了过滤/转义但对从数据库读取出来的数据却盲目信任直接拼接到 SQL 语句中。其完整流程如下为什么常见防御会失效以对单引号进行转义为例如使用addslashes()或反斜杠转义攻击者提交用户名admin --应用层使用addslashes()转义后变为admin\ --此时拼接进 INSERT 语句是安全的。但数据库实际存储的字符串是admin --转义字符只在拼接 SQL 时起作用并不写入库。后续某功能如修改密码、查询资料执行UPDATE users SET password新密码 WHERE usernameadmin --此时从库里读出的admin --被原样拼接闭合了前面的引号--注释掉了后续内容注入由此触发。关键认知转义/过滤只能保证这一次拼接安全并不能改变数据本身的危险内容。一旦这些内容被再次使用就必须重新处理。三、利用条件要成功实施二次注入通常需要满足以下条件存在先存储后使用的数据流某功能将用户可控的数据写入数据库另一功能又从数据库读取该数据。写入时经过处理可选但常见写入端可能做了转义/过滤/参数化导致一阶注入不可行攻击者被迫走二次注入路径。读取后的数据被拼接进 SQL后续使用该数据时没有使用参数化查询或再次过滤而是直接拼接字符串。攻击者可构造并观察到差异通常需要借助布尔盲注、时间盲注或回显差异来判断注入结果。四、利用过程示例4.1 场景假设一个网站有两个功能注册功能用户填写用户名、密码注册账号写入数据库。修改密码功能登录后输入新密码系统根据当前登录用户名更新密码读取用户名并拼接 SQL。4.2 攻击步骤第一步注册一个恶意用户名攻击者注册用户名admin #假设注册时后端使用了转义处理该用户名被安全地写入数据库注册成功。数据库users表此时存储idusernamepassword1admin #123456第二步触发二次注入攻击者以admin #身份登录进入修改密码功能提交新密码hacked。后端修改密码的核心 SQL 大致为UPDATE users SET password hacked WHERE username $username;其中$username是从数据库读出的当前登录用户名即admin #拼接后变成UPDATE users SET password hacked WHERE username admin #;由于#或--将其后内容注释实际执行的语句等价于UPDATE users SET password hacked WHERE username admin;结果攻击者成功将真正管理员账号admin的密码修改为hacked从而接管管理员账号。4.3 常见攻击目标垂直越权普通用户通过注入影响高权限用户的数据如上例。获取敏感数据借助布尔盲注/时间盲注逐字符读取其他表数据。删除/篡改数据构造DELETE、UPDATE等破坏性载荷。五、常见应用场景二次注入多发于以下功能点注册/登录 个人资料修改恶意用户名在修改资料、改密时被再次拼接。评论/留言 后台管理评论内容被存储后在后台的搜索、删除、筛选等 SQL 中被再次使用。收货地址/联系人信息存储的地址、姓名在订单查询、统计功能中被拼接。用户昵称 论坛引用/回复昵称在展示或引用他人帖子时被再次拼入查询。导入的数据文件批量导入的数据CSV 等在后续报表、检索中被拼接。配置项/自定义字段用户可配置的字段值在系统内部 SQL 中复用。六、练习一道恒学练习的ctf题目在靶场发表一篇文章总共有5个字段拼接语句再次查看文章注入语句在页面回显尝试查看当前数据库成功得到当前数据库获取数据库列名1,2,(select group_concat(table_name) from information_schema.tables where table_schemaphp_test),4,NOW())--获取数据库字段名1,2,(select group_concat(column_name) from information_schema.columns where table_schemaphp_test and table_namearticles),4,NOW())--获取flag1,2,(select group_concat(password) from php_test.users),4,NOW())--sqli第24关注册账户admin#使用注册的账户登录,登录后可以修改密码修改密码的逻辑UPDATE users SET password新密码 WHERE usernameadmin# AND password旧密码#注释后面的信息从而变成修改管理员的账户admin密码为1234最终生效语句UPDATE users SET password新密码 WHERE usernameadmin使用修改后的密码成功登录admin账户七、防御措施二次注入的防御核心是不信任任何进入 SQL 的数据无论它来自用户输入还是数据库读取。7.1 使用参数化查询预编译语句——最根本手段无论数据来自哪里一律使用占位符绑定参数从根本上杜绝拼接// Java JDBC PreparedStatement String sql UPDATE users SET password ? WHERE username ?; PreparedStatement ps conn.prepareStatement(sql); ps.setString(1, newPassword); ps.setString(2, username); ps.executeUpdate();# Python cursor.execute( UPDATE users SET password %s WHERE username %s, (new_password, username) )参数化查询将数据与代码分离任何来自数据库的字符串都只被当作数据不可能被解析为 SQL 语法。7.2 使用 ORM 框架主流 ORM如 Hibernate、MyBatis 的#{}、SQLAlchemy、Eloquent 等默认对参数进行绑定。注意MyBatis 中务必使用#{}而非${}${}是字符串拼接仍存在注入风险。7.3 对输出侧同样进行过滤/转义若因历史原因必须拼接 SQL那么在从数据库读出数据并再次使用时同样执行与输入侧一致的过滤、转义而不是默认库里的数据是干净的。7.4 最小权限原则为应用配置最小化的数据库账号权限限制 SQL 语句的破坏能力不同功能使用不同权限的数据库账号。严格限制DELETE、UPDATE、DROP等高危操作权限。7.5 白名单校验与输入约束对用户名、昵称等字段在写入时就限制字符集例如只允许字母、数字、下划线直接拒绝含特殊字符、、#、--、;等的输入。从源头减少危险数据入库的可能性。7.6 使用 Web 应用防火墙WAF与安全审计部署 WAF 可在一定程度上检测并拦截明显注入载荷。配合代码审计工具、静态扫描工具在开发阶段发现数据二次使用但未过滤的隐患点。7.7 其他辅助措施安全编码培训与规范建立统一的数据库访问层强制使用参数化接口禁止业务代码拼接 SQL。代码评审重点审查从数据库读取 → 拼接 SQL的链路。定期渗透测试二次注入隐蔽性强需通过专业测试发现。八、总结维度一阶注入二次注入触发时机当前请求立即触发后续请求延迟触发载荷存放直接进入 SQL先入库再取出进入 SQL写入侧处理通常未过滤通常已过滤/转义防御盲点输入过滤缺失对库内数据盲目信任检测难度较低较高隐蔽、延迟核心结论二次注入的根源是对数据库中读出的数据盲目信任而本质上它仍是 SQL 注入。防御的关键不是在输入时过滤一次而是彻底使用参数化查询让所有数据——无论来源——都无法被当作 SQL 代码执行。只要坚持数据与代码分离这一原则无论一阶还是二阶注入都能被有效防范。
返回列表