Web安全学院
Web安全学院
  • 首页
  • 译序
  • 学习路线
  • 前篇
    • Web应用程序安全测试
    • 动态应用程序安全测试(DAST)
    • 带外应用程序安全测试(OAST)
  • 服务器端主题
    • SQL注入
      • SQL注入
      • SQL注入UNION攻击
      • 在SQL注入攻击中检索数据库
      • SQL盲注
      • SQL注入速查表
    • 认证
      • 认证漏洞
      • 基于密码登录中的漏洞
      • 多因素认证中的漏洞
      • 其他认证机制中的漏洞
      • 如何保护你的认证机制
    • 目录遍历
      • 目录遍历
    • 命令注入
      • OS命令注入
    • 业务逻辑漏洞
      • 业务逻辑漏洞
      • 业务逻辑漏洞示例
    • 信息泄露
      • 信息泄露漏洞
      • 如何发现并利用信息泄露漏洞
    • 访问控制
      • 访问控制漏洞与权限提升
      • 不安全的直接对象引用(IDOR)
      • 访问控制安全模型
    • 文件上传漏洞
      • 文件上传漏洞
    • 条件竞争
      • 条件竞争
    • 服务器端请求伪造(SSRF)
      • 服务器端请求伪造(SSRF)
      • 盲SSRF漏洞
    • XXE注入
      • XML外部实体(XXE)注入
      • XML实体
      • 发现并利用盲XXE漏洞
  • 客户端主题
    • 跨站脚本(XSS)
      • 跨站脚本
      • 反射型XSS
      • 存储型XSS
      • 基于DOM的XSS
      • XSS上下文
        • 跨站脚本上下文
        • 客户端模版注入
      • 利用跨站脚本漏洞
      • 内容安全策略
      • 悬空标记注入
      • 如何防范XSS漏洞
      • 跨站脚本(XSS)速查表
    • 跨站请求伪造(CSRF)
      • 跨站请求伪造(CSRF)
      • XSS与CSRF
      • 绕过CSRF令牌验证
      • 绕过SameSite Cookie限制
      • 绕过基于Referer的CSRF防御
      • 如何防范CSRF漏洞
    • 跨域资源共享(CORS)
      • 跨域资源共享(CORS)
      • 同源策略(SOP)
      • CORS和Access-Control-Allow-Origin响应标头
    • 点击劫持
      • 点击劫持(UI伪装)
    • 基于DOM的漏洞
      • 基于DOM的漏洞
      • 控制Web消息源
      • 基于DOM的开放重定向
      • 基于DOM的Cookie操纵
      • 基于DOM的JavaScript注入
      • 基于DOM的document-domain操纵
      • 基于DOM的WebSocket URL投毒
      • 基于DOM的链接操纵
      • Web消息操纵
      • 基于DOM的Ajax请求标头操纵
      • 基于DOM的本地文件路径操纵
      • 基于DOM的客户端SQL注入
      • 基于DOM的HTML5 Storage操纵
      • 基于DOM的客户端XPath注入
      • 基于DOM的客户端JSON注入
      • DOM-data操纵
      • 基于DOM的拒绝服务
      • DOM破坏
    • WebSocket
      • 测试WebSocket安全漏洞
      • 什么是WebSocket?
      • 跨站WebSocket劫持
  • 进阶主题
    • 不安全的反序列化
      • 不安全的反序列化
      • 利用不安全的反序列化漏洞
    • 测试GraphQL API
      • 测试GraphQL API
      • 什么是GraphQL?
    • 服务器端模板注入
      • 服务器端模板注入
      • 利用服务器端模板注入漏洞
    • Web缓存投毒
      • Web缓存投毒
      • 缓存设计缺陷的利用
      • 缓存实现缺陷的利用
    • HTTP Host标头攻击
      • HTTP Host标头攻击
      • 如何识别和利用HTTP Host头的漏洞
      • 密码重置投毒
    • HTTP请求走私
      • HTTP请求走私
      • 查找HTTP请求走私漏洞
      • 利用HTTP请求走私漏洞
      • 高级请求走私
        • 高级请求走私
        • HTTP/2降级
        • 响应队列投毒
        • HTTP/2专属载体
        • HTTP请求隧道
      • 浏览器驱动的请求伪造
        • 浏览器驱动的请求伪造
        • CL.0请求走私
        • 客户端异步攻击
        • 基于暂停的异步攻击
    • OAuth认证
      • OAuth 2.0认证漏洞
      • OAuth授权类型
      • OpenID Connect
      • 如何防范OAuth认证漏洞
    • JWT攻击
      • JWT攻击
      • 在Burp Suite中使用JWT
      • 算法混淆攻击
    • 原型污染
      • 什么是原型污染?
      • JavaScript原型和继承
      • 客户端
        • 客户端原型污染漏洞
        • 通过浏览器API进行原型污染
      • 服务器端
        • 服务器端原型污染
      • 预防原型污染漏洞
    • 基本技能
      • 基本技能
      • 使用编码混淆攻击
      • 在手动测试中使用Burp Scanner
Powered by GitBook
On this page
  • 确定SQL注入UNION攻击所需的列数
  • 在SQL注入UNION攻击中查找具有有用数据类型的列
  • 使用SQL注入UNION攻击检索感兴趣的数据
  • 在单列中检索多个值
  1. 服务器端主题
  2. SQL注入

SQL注入UNION攻击

当一个应用程序存在SQL注入漏洞,并且查询结果在应用程序的响应中返回时,可以使用UNION关键字从数据库的其他表中检索数据。这就是SQL注入UNION攻击。

UNION关键字允许你执行一个或多个额外的SELECT查询,并将结果追加到原始查询中。例如:

SELECT a, b FROM table1 UNION SELECT c, d FROM table2

此SQL查询将返回一个包含两列的单结果集,其中包含table1中a和b列的值以及table2中c和d列的值。

要使UNION查询起作用,必须满足两个关键要求:

  • 各个查询必须返回相同数量的列。

  • 每列中的数据类型在各个查询之间必须兼容。

要实施SQL注入UNION攻击,需要确保你的攻击满足这两个要求。通常涉及弄清楚:

  • 原始查询返回了多少列?

  • 从原始查询返回的哪些列适合容纳注入查询的结果?

确定SQL注入UNION攻击所需的列数

在进行SQL注入UNION攻击时,有两种有效的方法可以确定原始查询返回了多少列。

第一种方法是注入一系列ORDER BY子句,并递增指定的列索引,直到发生错误。例如,假设注入点是原始查询的WHERE子句中的带引号字符串,你可以提交:

' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--
etc.

这一系列的有效载荷修改了原始查询,按结果集中的不同列对结果进行排序。ORDER BY子句中的列可以由其索引指定,因此你不需要知道任何列的名称。当指定的列索引超过结果集中的实际列数时,数据库会返回错误,例如:

The ORDER BY position number 3 is out of range of the number of items in the select list.

应用程序实际上可能会在其HTTP响应中返回数据库错误,或者可能返回一个通用错误,或者根本不返回结果。只要你能检测到应用程序响应中的某些差异,就可以推断出查询返回多少列。

第二种方法是提交一系列UNION SELECT有效载荷,指定不同数量的空值:

' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT NULL,NULL,NULL--
etc.

如果空值的数量与列数不匹配,数据库会返回一个错误,例如:

All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.

同样,应用程序实际上可能会返回此错误消息,或者可能只返回一个通用错误或没有结果。当空值的数量与列数匹配时,数据库将在结果集中返回一个额外的行,其中每列都包含空值。对产生的HTTP响应的影响取决于应用程序的代码。如果运气好的话,你将在响应中看到一些额外的内容,比如HTML表上的额外行。否则,空值可能会触发其他错误,例如NullPointerException。最糟糕的情况是,响应可能与由不正确的空值数引起的响应没有区别,使得这种确定列数的方法无效。

LAB

注意

  • 使用NULL作为注入的SELECT查询返回的值的原因是,原始查询和注入查询之间的每个列的数据类型必须兼容。由于NULL可以转换为常用的每种数据类型,使用NULL可以最大程度地提高在列数正确时有效载荷成功的机会。

  • 在Oracle上,每个SELECT查询必须使用FROM关键字并指定一个有效的表。在Oracle上有一个名为dual的内置表,可以用于此目的。因此,在Oracle上注入的查询将需要如下所示:

    ' UNION SELECT NULL FROM DUAL--

  • 所描述的有效载荷使用双破折号注释序列--来注释掉注入点后的原始查询的其余部分。在MySQL上,双破折号序列必须跟随一个空格。或者,哈希字符#可用于标识注释。

在SQL注入UNION攻击中查找具有有用数据类型的列

进行SQL注入UNION攻击的原因是能够从注入的查询中检索结果。通常,希望检索的感兴趣的数据是以字符串形式存在,因此需要在原始查询结果中找到一个或多个数据类型为字符串数据或与之兼容的列。

在已确定所需列数后,你可以通过提交一系列UNION SELECT有效载荷,依次将字符串值放入每一列中,来测试它是否可以容纳字符串数据。例如,如果查询返回四列,你将提交:

' UNION SELECT 'a',NULL,NULL,NULL--
' UNION SELECT NULL,'a',NULL,NULL--
' UNION SELECT NULL,NULL,'a',NULL--
' UNION SELECT NULL,NULL,NULL,'a'--

如果某列的数据类型与字符串数据不兼容,注入的查询将导致数据库错误,例如:

Conversion failed when converting the varchar value 'a' to data type int.

如果没有发生错误,并且应用程序的响应包含一些额外的内容,包括注入的字符串值,则相关列适合检索字符串数据。

LAB

使用SQL注入UNION攻击检索感兴趣的数据

当确定了原始查询返回的列数,并找到可以容纳字符串数据的列时,你就可以检索感兴趣的数据。

假设:

  • 原始查询返回两列,两列都可以容纳字符串数据。

  • 注入点是原始查询WHERE子句中的引号字符串。

  • 数据库中包含一个名为users的表,具有username和password列。

在这种情况下,你可以通过提交以下输入来检索users表的内容:

' UNION SELECT username, password FROM users--

当然,实施此攻击所需的关键信息是存在一个名为users的表,该表具有名为username和password的两列。如果没有这些信息,你将尝试猜测表和列的名称。实际上,所有现代数据库都提供了检查数据库结构的方法,以确定其中包含的表和列。

LAB

阅读更多

在单列中检索多个值

在前面的示例中,假设查询仅返回单个列。

你可以通过将多个值拼接在单个列中,来轻松检索这些值,最好包括一个适当的分隔符,以便可以区分组合值。例如,在Oracle上,可以提交以下输入:

' UNION SELECT username || '~' || password FROM users--

这里使用了双管道序列||,它是Oracle上的字符串拼接运算符。注入的查询将username和password字段的值用~字符分隔合并在一起。

查询的结果将让你读取所有的用户名和密码,例如:

...
administrator~s3cure
wiener~peter
carlos~montoya
...

LAB

PreviousSQL注入Next在SQL注入攻击中检索数据库

Last updated 1 year ago

有关数据库特定语法的更多详细信息,请参阅。

请注意,不同的数据库使用不同的语法来进行字符串拼接。有关详细信息,请参阅。

SQL注入UNION攻击,确定查询返回的列数
SQL注入速查表
SQL注入UNION攻击,查找包含文本的列
SQL注入UNION攻击,从其他表中检索数据
在SQL注入攻击中检查数据库
SQL注入速查表
SQL注入UNION攻击,在单个列中检索多个值