漏洞重温之sql注入(五)
漏洞重温之sql注入(五)
sqli-labs通关之旅
填坑来了!
Less-17
首先,17关,我们先查看一下页面,发现网页正中间是一个登录框。
显然,该关卡的注入应该为post型。
直接查看源码。
首先,我们看到网页封装了一个check_input函数,在函数中,使用了mysql_real_escape_string函数对我们输入的内容进行转义,一般来说,在这么操作之后,sql注入基本无法完成。
然后我们看一下,网页对我们的哪些输入使用到了check_input函数。
查看下方代码:
$uname = check_input($_POST['uname']);
$passwd = $_POST['passwd'];
从上面代码中,我们可以看到,网页对我们输入的uname值进行了转义,对passwd没有,也就是说,我们可以将注入代码通过passwd参数完成注入攻击。
随后,我们关注下方代码:
@$sql="SELECT username, password FROM users WHERE username= $uname LIMIT 0,1";
这条代码是网页向服务器发起的第一条请求。该请求是网页利用我们输入的uname参数从user表中查询username和password两条数据。
因为uname参数是无法用来进行sql注入的,所以这条语句我们无法利用。
接着往下看:
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
这两条是执行刚才的那条查询语句,并且将结果返回到$row参数中。
当然,如果我们是要进行注入的话,这两条也没用。
接着看:
if($row)
{
//echo '<font color= "#0000ff">';
$row1 = $row['username'];
//echo 'Your Login name:'. $row1;
$update="UPDATE users SET password = '$passwd' WHERE username='$row1'";
mysql_query($update);
echo "<br>";
这是当uname查询成功之后,所执行的代码块,在这个代码块中,我们总算看到了自己能够利用的passwd参数。
但是由于这条语句使用的是UPDATE语句,所以我们没有办法直接利用这条语句查询出我们想要的内容。
重点在下面,我们看下面这个代码块:
if (mysql_error())
{
echo '<font color= "#FFFF00" font size = 3 >';
print_r(mysql_error());
echo "</br></br>";
echo "</font>";
}
这个代码块的意思就是,如果代码出现了错误,那么就使用print_r参数将报错信息打印到网页上。
也就是说,虽然我们没法利用update语句进行查询,但是我们却可以通过构造语句,使得数据库报错,然后通过上方的代码块,将我们想查询的数据返回到页面上。
这里,我使用的是updatexml函数进行报错注入。
pyload如下:
uname=admin&passwd=1' or updatexml(1,concat(0x7e,(select database()),0x7e),1) -- &sumbit=Sumbit
updatexml函数的报错注入,其实是有一种固定格式的,如果不想了解太深的话,只需要记住下面的格式,就可以使用了。
updatexml(1,concat(0x7e,(执行语句),0x7e),1)
而如果要理解的话,其实也很简单,updatexml函数是一个改变文档中符合条件的节点值的函数。而这个函数后面是有三个值的。
其实,第一个值简单来理解就是我们要查找内容的名称,第二个值是查找的内容,第三个是替换内容。
但是,第二个值是有固定格式的,如果格式不正确,就会导致报错。这也是可以使用updatexml函数进行报错注入的原理。
concat函数的目的是返回结果为连接参数产生的字符串,就是将我们代码执行成功之后的结果返回回来。
0x7e就是符号“~”。
当然,这里要注意的一点是,updatexml函数只能截取32位的数据,如果我们想要查询所有数据库名称的话,直接按照之前的方法是不行的。
例如:
那这样在实际情况中是不够的,因为数据不可能只有32位,所以,为了能查看到所有数据,我们可以使用limit函数来切割结果,一个一个的放出来,这样位置就够用了。
payload如下:
uname=admin&passwd=1' and updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 0,1),0x7e),1) -- &sumbit=Sumbit
第十七关,通关。
当然,报错注入还是有其他的一些常用函数的,而且我的解释是从我的视角出发,针对对报错注入没有了解,想要了解更多的人而做的。如果想要更深入的了解,可以看下这位keefe大佬的这篇文章。
http://aiyuanzhen.com/index.php/archives/34/
Less-18
单从网页上看的话,第十八关似乎跟第十七关的区别不大,只是页面上多了一条ip address的显示。
我们直接查看源码,看这一关设置了什么难题。
这一关,是对于我们输入的uname参数和passwd参数同时使用check_input函数进行了转义,导致我们无法利用这两个参数进行sql注入攻击。
乍一看,似乎无懈可击,但不着急,接着往下看。
首先是最上面一条的sql语句,网页是判断了用户名和密码,都正确之后才会进入下面的If判断。
而我们可以利用的代码,就在这个里面。
首先我们先查看这段代码,他获取了我们的ua属性,所以在我们访问的时候,才会在网页上给出那段提示。注意,这个参数的获取,是没有被check_input函数转移的,也就是说,我们可以在这个参数里面插入sql语句进行注入攻击。
然后,我们看这个函数被利用到的语句。
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";
是insert语句,所以我们同样无法直接利用这条语句返回我们希望看到的结果。
不过,在这条语句下方,依然有print_r(mysql_error())这条语句。这条语句的功能是打印数据库报错信息,也就是说,我们依然可以选择使用报错注入获取我们希望得到的数据。
当然,因为我们需要在请求包的UA中插入代码,所以我们需要使用Burp进行抓包,来修改UA属性。
payload如下:
' or updatexml(1,concat(0x7e,(select databese()),0x7e),1) or '
这里要注意的一点是,因为网页是验证了用户名和密码之后才会执行我们插入代码的语句,所以想要利用这个注入点,就需要有系统的账户名和密码。
想要读取多条数据的方式,和十七关一样,使用limit函数将结果切割之后挨个输出就可以了。
第十八关,通关。
Less-19
直接看十九关的页面,发现跟十八关几乎一模一样,所以猜测过滤方式应该相同,直接看源码。
过滤果然一样,唯一不同的点是,之前的$uagent参数是从请求包中的ua属性中获取,而这19关是从referer获取。
也就是说,上一次我们需要在ua属性里面插入代码,这一次,我们需要在referer属性里面插入。
pyload一致,我就不写了,直接放图。
第十九关,通关。
Less-24
24关,看页面就能明显感觉跟之前的几个post型注入有区别,而且,可以看到在页面上多了忘记密码和新建用户两个选项。
很明显,这是一个二阶注入。
二阶注入呢,简单来理解是,我们没办法直接在页面插入sql语句,并且使其执行返回我们需要的结果。所以我们可以先把带有sql代码的语句插入到数据库里,当我们再次调取之前插入的数据的时候,就可以完成注入。
这关应该怎么破,我们直接看源码。
这关的文件很多,但是有用的就两个地方。
这段代码,就是我们新建用户的时候所调用的代码,首先我们可以看到,网页在接受我们输入的数据的时候,使用了mysql_escape_string函数将我们的输入进行了转义,然后将我们输入的用户名先在数据库中进行了一次查询。
这次查询的目的是看我们的用户名在数据库中是否重复,如果重复,提示我们更换用户名,如果不重复,就将我们的注册的用户名和密码写入到数据库中。
而这正是我们想要利用的地方。
然后,我们去看修改密码页面,因为我们无法通过该注入直接查询到我们希望查询到的数据,那就可以将某个用户的密码修改成我们已知的密码,这样也可以完成注入攻击。
这是修改密码位置的sql语句,可以看到,语句是使用单引号进行闭合的。
所以,如果我们想利用这条语句修改掉用户密码的话,我们在注册账户的时候,就需要使用单引号去闭合。
具体操作步骤如下,用户名我选择使用 admin1' or 1=1 -- 使用or连接符的话,就可以将系统中所有用户的密码在执行该命令的时候全部修改掉。
密码我选择123456.
出现这个页面,说明我们的用户创建成功,然后使用该账户进行登录。
登录成功后,发现网页的修改密码位置。
输入我们的用户名,使用密码12345.
点击修改之后,网页会出现如下页面。
这个时候,我们去数据库查看一下我们修改所有用户密码为12345的操作是否完成。
可以看到,密码已经都被修改为了12345。
第二十四关,通关。
Less-25
打开页面,网页提示输入id,确认该位置注入属于get型注入。
随后我们看到页面提示or和and不能使用了。
查看源码。
可以发现,该位置的确封装了一个函数将and和or过滤为空,但是因为是单词,而且这个过滤只进行了一次,所以我们只需要利用双写便可以成功的进行注入。
从上面的sql语句我们可以确定该位置闭合需要使用单引号。
pyload如下:
1' anandd 1=2 union select 1,version(),database() --
第二十五关,通关。
25a关,过滤跟25关一致。细微的差别在下图。
这里的id参数没有被任何符号包裹,所以想要构造攻击payload,只需要将上一关使用的payload的单引号和过滤符号删除就可以。
第25a关,通关。