一、报错注入
(一)概念
是一种 SQL 注入攻击方式。当攻击者构造的恶意 SQL 语句在数据库执行过程中发生错误时,数据库会返回包含错误信息的结果。攻击者可以巧妙地利用这些错误信息来获取数据库中的敏感数据,如数据库版本、表名、列名以及数据记录等。
(二)为什么使用报错注入
以mysql为例:在“http header”注入中,没加注入语句 ' or 1=1 时
加了注入语句之后,没看到用户表中的数据,还是未加注入语句的页面。原因是:服务端那边拿到这个数据之后,只是在数据库中查询了一下有没有admin' 这个用户就结束了,没有把整个表里面的查到的数据展示给你看。在页面没有给任何反馈信息的情况下,就可以用到报错注入。
二、报错注入的原理
(一)概念
数据库在执行 SQL 语句时,会按照一定的规则来处理语法错误等情况。以 MySQL 为例,当执行的查询语句出现错误,它会返回详细的错误信息,这些错误信息可能包含查询语句本身的部分内容或者数据库相关的信息。
例如,在某些函数的使用过程中,如果参数不符合要求就会报错。攻击者可以通过控制这些函数的参数来使数据库报错,并在错误信息中包含想要获取的数据。
(二)在Pikachu靶场上演示
以get请求中的vince为例:
正常情况下:
若加一个单引号,拼接的sql语句语法就出现错误,mysql就报错了,服务端拿到这个信息之后没有处理,直接返回给了客户端,会出现报错信息,从报错当中提炼一些信息,是mysql数据库。
三、常见的报错注入函数(以 MySQL 为例)
●报错注入函数有很多,下面介绍三个常见函数
(一)floor () 函数结合 count () 函数和 group by 子句
1.floor()函数的基本概念
在许多编程语言中,floor()
函数的主要作用是向下取整。它返回不大于输入参数的最大整数。例如,如果输入一个实数x
,floor(x)
会将x
向下舍入到最接近的整数。如floor(3.14)
的结果是 3。
2.当和count(*)
以及group by
结合时
以下是关于 floor()
函数结合 count()
函数以及 group by
子句在常见数据库(以 MySQL 为例,其他数据库如 SQL Server、Oracle 等在概念上类似但语法细节可能稍有不同)中的使用说明:
2.1整体作用概述
通常情况下,我们会利用 floor()
函数对某个数值类型的字段进行向下取整操作,然后使用 group by
子句按照取整后的结果进行分组,再通过 count()
函数来统计每组内的记录数量。这样的组合常用于对数据按照一定区间进行归类统计,比如按照时间区间(将时间戳向下取整到某个时间粒度,如按小时、按天等)统计记录个数,或者对数值范围进行分组统计等场景。
2.2.具体示例
假设我们有一个数据表 orders
,其中包含 order_amount
(订单金额,数值类型)字段和 order_time
(订单时间,日期时间类型)字段,现在要按照每 10 元的区间统计订单数量,示例代码如下:
SELECT
FLOOR(order_amount / 10) AS amount_interval,
COUNT(*) AS order_count
FROM
orders
GROUP BY
FLOOR(order_amount / 10);
在上述 SQL 语句中:
首先,FLOOR(order_amount / 10)
这部分对每个订单的金额进行向下取整操作,将其除以 10 后向下取整到对应的整数,这里使用 AS amount_interval
给取整后的结果起了一个别名 amount_interval
,方便后续在结果集中引用和查看。
接着,COUNT(*)
函数用于统计每个分组中的记录数量,也就是每个金额区间内的订单个数,同样使用 AS order_count
给统计结果起了别名 order_count
。
最后,通过 GROUP BY FLOOR(order_amount / 10)
按照取整后的金额区间进行分组,确保相同区间的订单会被归为一组进行数量统计。
如果要按照时间维度,比如按天来统计每天的订单数量,假设 order_time
字段是 datetime
类型,可以这样写:
SELECT
FLOOR(UNIX_TIMESTAMP(order_time) / (24 * 60 * 60)) AS day_interval,
COUNT(*) AS order_count
FROM
orders
GROUP BY
FLOOR(UNIX_TIMESTAMP(order_time) / (24 * 60 * 60));
这里先使用 UNIX_TIMESTAMP()
函数将日期时间类型转换为时间戳(以秒为单位),然后除以一天包含的秒数(24 * 60 * 60
),再通过 floor()
函数向下取整到对应的天数,之后按照取整后的天数进行分组,并用 count()
函数统计每天的订单数量。
2.3结合的好处
可以灵活地对数据按照特定规则进行分组统计,为数据分析提供有力支持,并且可以构造出特殊的报错语句来获取数据。
示例:select count(*),concat((select database()),floor(rand(0)*2))x from information_schema.tables group by x;
原理:rand()
函数会产生一个 0 到 1 之间的随机数,floor(rand(0)*2)
会返回 0 或 1。在group by
子句中,当对一个随机的、不确定的列(这里是x
)进行分组时,由于rand()
函数的特性,会导致数据库在计算过程中出现错误。而concat()
函数用于拼接字符串,在这里拼接了数据库名称和floor(rand(0)*2)
的结果,从而在报错信息中泄露数据库名称。
(二)extractvalue () 函数
1.基本概念
extractvalue()
函数是用于从 XML 文档(或类似的结构化数据格式)中提取值的函数。它的主要功能是根据指定的 XPath 表达式,从 XML 数据中获取相应节点的值。
【XPath(XML Path Language)是一种用于在 XML 文档中定位节点的语言。通过extractvalue()
函数结合 XPath,可以精确地获取 XML 文档中特定元素、属性或文本内容的值。】
●简单来说就是用于从 XML 文档中提取值。它接受两个参数,第一个参数是 XML 文档,第二个参数是 XPath 表达式。
示例:select extractvalue(1,concat(0x7e,(select database()),0x7e));
原理:这里故意将第一个参数设置为非 XML 格式的数据(1),这样会导致报错。而第二个参数通过concat()
函数拼接了特殊字符(0x7e 表示~)和想要获取的数据库名称,当数据库报错时,就会在错误信息中显示拼接后的内容,包括数据库名称。
2.语法结构(以 MySQL 为例)
一般语法为extractvalue(xml_fragment, xpath_expression)
。其中xml_fragment
是包含 XML 数据的字符串或列(存储 XML 数据的列),xpath_expression
是用于定位要提取的值的 XPath 表达式。
例如:SELECT extractvalue('<book><title>My Book</title></book>', '/book/title');
。在这个例子中,第一个参数是一个简单的 XML 片段,第二个参数是 XPath 表达式,它会从 XML 片段中提取<book>
元素下<title>
元素的值,即My Book
。
(三)updatexml () 函数
1.函数概述
与extractvalue()
函数类似,updatexml()
函数用于更新 XML 文档中的值,也就是主要用于更新 XML 文档中的数据。示例:select updatexml(1,concat(0x7e,(select database()),0x7e),1);
原理:同样,将第一个参数设置为非 XML 格式的数据(1)导致报错。在第二个参数中拼接想要获取的信息,通过报错信息来泄露数据。
它允许用户根据指定的 XPath 表达式在 XML 数据中找到相应的节点,并更新其值。在数据库环境(如 MySQL)中非常有用,当存储的 XML 数据需要修改时,可以通过这个函数精准地对 XML 文档的某个部分进行更新。
2.语法结构(以 MySQL 为例)
语法一般是updatexml(xml_fragment, xpath_expression, new_value)
。其中xml_fragment
是包含 XML 数据的字符串或者存储 XML 数据的列,xpath_expression
是用于定位要更新的节点的 XPath 表达式,new_value
是要更新的新值。
例如,假设有一个 XML 数据<?xml version="1.0" encoding="UTF-8"?><book><title>Old Title</title></book>
,如果要更新书籍的标题,可以使用UPDATE books SET xml_column = updatexml(xml_column, '/book/title', 'New Title') WHERE book_id = 1;
(假设数据存储在名为books
的表中的xml_column
列,并且通过book_id
来定位具体的记录)。
2.1正则与 xpath_expression很像
2.1.1目的方面的相似性
正则表达式和 XPath 表达式都用于在文本或结构化数据中定位特定的内容。
①正则表达式主要用于处理纯文本内容,它可以在一段文本(如一个字符串、一个文本文件的内容等)中找到符合特定模式的字符序列。例如,在一个网页的 HTML 源代码文本中,通过正则表达式找到所有的邮箱地址。
②XPath 表达式主要用于在 XML(可扩展标记语言)或 HTML(超文本标记语言)等具有树形结构的文档中定位节点。例如,在一个 XML 文档中,通过 XPath 表达式找到所有<book>
节点下的<title>
节点。
2.1.2语法结构的差异
●正则表达式语法特点
正则表达式由普通字符和特殊字符(元字符)组成。普通字符如字母、数字等按照字面意思进行匹配,而元字符具有特殊的匹配规则。例如,“.” 可以匹配除换行符外的任何单个字符,“” 表示前面的字符可以出现 0 次或多次。例如,正则表达式 “a.b” 可以匹配 “aab”“a1b”“abbb” 等多种形式。
它是基于线性文本的匹配,关注的是字符的顺序和组合模式。例如,在验证一个电话号码格式 “\d {3}-\d {3}-\d {4}”(其中 “\d” 表示数字,“{3}” 表示前面的数字出现 3 次),就是按照电话号码的数字排列和分隔符的顺序来匹配的。
●XPath 语法特点
XPath 使用路径表达式来定位节点。它以文档的根节点为起点,通过节点名称、属性等元素来构建路径。例如,在 XML 文档中,“/bookstore/book/title” 这个 XPath 表达式是从根节点开始,经过 “bookstore” 节点、“book” 节点,最后定位到 “title” 节点。
XPath 可以利用节点的层次结构和属性进行定位。例如,“//book [@category='fiction']/title” 这个表达式可以找到所有属性 “category” 值为 “fiction” 的 “book” 节点下的 “title” 节点。其中 “//” 表示在文档的任意位置开始查找,“[@category='fiction']” 是根据属性值来筛选节点。
2.1.3应用场景的区别与联系
文本处理场景
正则表达式在处理文本内容时更加灵活,特别是对于没有明显结构的纯文本。例如,在处理日志文件内容时,通过正则表达式可以提取出特定格式的日期时间(如 “\d {4}-\d {2}-\d {2} \d {2}:\d {2}:\d {2}” 匹配 “2024 - 01 - 01 12:34:56” 这种格式的日期时间)、错误信息中的关键词等。
XPath 表达式在处理具有层次结构的文本(如 XML 和 HTML)时更具优势。例如,在网页抓取中,使用 XPath 表达式可以更准确地从 HTML 页面中提取出文章标题(在 “<head><title>...</title></head>” 部分)、商品价格(通常在商品详情页面的特定 HTML 标签结构中)等信息。
数据提取与验证场景
正则表达式可以验证文本是否符合某种格式。例如,验证一个身份证号码是否符合格式要求,通过正则表达式可以检查其长度、数字和字母的组合等是否正确。
XPath 表达式可以验证 XML 或 HTML 文档中的节点是否存在以及其结构是否符合预期。例如,在 XML 数据交换中,通过 XPath 表达式可以检查接收到的 XML 文档是否包含特定的业务节点和正确的节点层次结构。
3.替换 XML 数据中节点值的示例
以 MySQL 数据库为例进行讲解(不同数据库对于 XML 相关函数的支持和语法细节可能略有差异)。假设我们有一个名为 employees
的表,表中有一个名为 employee_info_xml
的列,该列存储的 XML 数据格式如下(示例简化情况):
<?xml version="1.0" encoding="UTF-8"?>
<employee>
<name>John Doe</name>
<department>IT</department>
<phone>1234567890</phone>
</employee>
现在我们想要把 department
节点的值从 IT
替换成 Engineering
,就可以使用 UPDATEXML()
函数来实现。
SQL 语句示例
UPDATE employees
SET employee_info_xml = UPDATEXML(employee_info_xml, '/employee/department', 'Engineering')
WHERE some_condition; -- 这里需要根据实际情况添加合适的筛选条件,比如根据员工 ID 等确定要更新的具体记录
在上述 SQL 语句中:UPDATE employees
表示要对名为 employees
的表进行更新操作。
SET employee_info_xml = UPDATEXML(employee_info_xml, '/employee/department', 'Engineering')
这部分是核心。其中,第一个 employee_info_xml
是表中存储 XML 数据的列名,UPDATEXML(employee_info_xml, '/employee/department', 'Engineering')
函数的使用方式如下:
①第一个参数 employee_info_xml
提供了包含 XML 数据的源内容(即要操作的 XML 片段所在的列数据)。
②第二个参数 '/employee/department'
是 XPath 表达式,用于定位到 XML 数据中我们想要更新的节点,也就是 <employee>
元素下的 <department>
元素。
③第三个参数 'Engineering'
则是要替换成的新值,通过这个函数的执行,就能将原本 <department>
节点的值替换掉。
WHERE some_condition
用于指定具体更新哪条记录。例如,如果表中有 employee_id
字段,并且我们只想更新 employee_id
为 101
的员工记录对应的 XML 数据,那么这里就可以写成 WHERE employee_id = 101
。
更复杂的情况示例
如果 XML 数据结构更复杂些,比如有多层嵌套,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<company>
<department>
<employee>
<name>Jane Smith</name>
<phone>0987654321</phone>
<projects>
<project>
<name>Project A</name>
<status>Ongoing</status>
</project>
</projects>
</employee>
</department>
</company>
现在要把 Project A
的 status
节点值从 Ongoing
替换为 Completed
,对应的 SQL 语句可以这样写:
UPDATE employees
SET employee_info_xml = UPDATEXML(employee_info_xml, '/company/department/employee/projects/project[name="Project A"]/status', 'Completed')
WHERE some_condition;
这里的 XPath 表达式 '/company/department/employee/projects/project[name="Project A"]/status'
先是按照 XML 的层级结构逐步定位到 project
节点,并且通过 [name="Project A"]
这个条件筛选出名称为 Project A
的项目节点,最后定位到其下的 status
节点进行值的替换操作。
●需要注意的是,在实际应用中,要确保 XPath 表达式的准确性以及做好防范 SQL 注入的相关措施,因为如果 XPath
表达式来源不可信,恶意构造的表达式可能会引发安全问题。
四、防御措施
(一)输入验证
对用户输入的数据进行严格的验证,确保其符合预期的格式和内容。例如,如果一个输入框应该只接收数字,那么就对输入的数据进行数字验证,拒绝包含 SQL 语句或特殊字符的输入。
(二)参数化查询
使用参数化查询(如在 PHP 中使用 PDO 或 mysqli 的预处理语句)可以有效地防止 SQL 注入。在参数化查询中,SQL 语句的结构是预先定义好的,用户输入的数据作为参数传递,而不是直接嵌入到 SQL 语句中,这样可以避免用户输入的数据被当作 SQL 代码执行。
(三)最小权限原则
为数据库用户分配最小的必要权限。例如,一个只用于读取数据的应用程序应该使用具有只读权限的数据库用户,这样即使存在 SQL 注入漏洞,攻击者也无法执行修改数据库结构、插入或删除数据等危险操作。
标签:XML,XPath,函数,报错,employee,节点,注入 From: https://blog.csdn.net/2402_87815315/article/details/144315356