其实这是一道很简单的题,题目中也给了提示:
提示的意思是验证码不会变,结合网上的一些解析也是对此直接默认了,但是这个验证码是怎么不变的,没有看到有人细说,也许这些思考对于一些人来说已经微不足道了,但是结合一些搭建网站前后端的知识,我想从一个初学者的角度更深层次的解释一下这个问题。
——————————————————————————————
爆破是基于上一题对于用户名密码的简单爆破,这题关键在于有了验证码。
初步的试探一下,如果输错了验证码,不管用户名密码是什么,都会显示“验证码输入错误哦!”,然后验证码会刷新。
而把验证码输入正确,用户名密码不正确,就会显示“username or password is not exists~”,然后验证码也会刷新。
所以总结一下网站的展现的表象,这个验证码在两种情况下会变,第一种情况是刷新页面的时候,第二种情况是点击验证码图片的时候。
然后打开burpsuite按照正常顺序,打开代理,输入用户名、密码、验证码,点击“Login”,然后发的请求就会被burpsuite捕获到。
发现这个请求是POST,然后一共有四个参数分别是 username password vcode submit
其中submit是前端代码中在“Login”按钮里写死的
<input class="submit" name="submit" type="submit" value="Login">
而username与password是需要爆破的,所以想着这个vcode先不让他变,把这个请求送到Repeater里面去,先改变用户名和密码看一看响应的回来代码的变化,尤其是“Login”按钮下面那一行小字,看看是返回的文字是验证码不对还是用户名密码不对。
于是在Repeater中如下操作:
在左面的请求中,用户名、密码改成222,验证码(vcode)是正确的,只不过刷新了页面不是原来的验证码了。
在右面的响应中,在html代码中找到那个“Login”按钮,下面显示的是用户名密码不对。
如是再更改几次用户名密码,验证码vcode不改变,结果还是显示用户名密码不对,说明验证码一直是对的。
由此就知道了,在burpsuite里面操作这期间,没有碰浏览器,验证码一直是没有变的。
所以此时把请求发送到intruder来进行爆破,由于是用户名和密码两个参数的爆破,需要选择pitchfork模式,将username和password添加进参数。
分别为用户名和密码选择爆破字典,然后进行爆破。
这里字典简单了些,就是为了做题。
结果如下:
然后发现admin和123456组合的响应报文长度不一样,点进去看发现他是“login success”字样,所以比别的“username or password is not exists~”字样会少一点字。
到此这道题就做完了。
那为啥这个验证码当时在burpsuite里就不变呢?单单的试一试发现他不变有点瞎猫碰死耗子的侥幸,感觉这道题和闹着玩一样。但其实仔细深究的话,这里面知识还是不少的。
这个pikachu平台我是搭建在自己电脑上的,随时可以看源代码,这个问题的答案就是藏在源代码里,所以就先细细的分析一下代码。
首先要知道一个事情,这个网站由php、html、js等代码写成的,php属于后端代码,由服务器来解析运行;html、js是前端代码,在浏览器(客户端)来解析运行。所以在网页中右键,再点击查看网页源代码之后,能看见的只有html和js代码,以及php代码运行过之后对html代码的一些更改、添加等效果。要是想看后端的php代码就要去本地文件夹中去看。
查看浏览器中的验证码图片这个区域的源代码(对应的后端文件是bf_server.php),观察到img标签中的src指向showvcode.php;后面的onclick事件是对于showvcode.php的重新请求,后面用get方法传日期那个没有用,后面代码可以看出来。
在本地文件中找到这个文件,这是pikachu作者的源文件:
showvcode.php
session_start();
include_once 'function.php';
//$_SESSION['vcode']=vcode(100,40,30,4);
$_SESSION['vcode']=vcodex();
//验证码绕过 on server 这里其实还是有一个问题,就是服务端将验证码字符串以明文COOKIE的方式给了前端,那验证码还有什么鸟意义。。。
setcookie('bf[vcode]',$_SESSION['vcode']);
?>
发现这个showvcode.php调用了function.php中的vcodex函数,然后执行vcode()函数的返回值赋值给session会话中的’vcode’参数,而onclick事件里面用get方法新传入的参数在这里没用到,效果和直接请求showvcode.php一样。
再去看源代码:
function.php
function vcodex(){
$string = "abcdefghijklmnopqrstuvwxyz0123456789";
$str = "";
for($i=0;$i<6;$i++){
$pos = rand(0,35);
$str .= $string{$pos};
}
//session_start();
//$_SESSION['img_number'] = $str;
$img_handle = Imagecreate(80, 20); //图片大小80X20
$back_color = ImageColorAllocate($img_handle, 255, 255, 255); //背景颜色(白色)
$txt_color = ImageColorAllocate($img_handle, 0,0, 0); //文本颜色(黑色)
//加入干扰线
for($i=0;$i<3;$i++)
{
$line = ImageColorAllocate($img_handle,rand(0,255),rand(0,255),rand(0,255));
Imageline($img_handle, rand(0,15), rand(0,15), rand(100,150),rand(10,50), $line);
}
//加入干扰象素
for($i=0;$i<200;$i++)
{
$randcolor = ImageColorallocate($img_handle,rand(0,255),rand(0,255),rand(0,255));
Imagesetpixel($img_handle, rand()%100 , rand()%50 , $randcolor);
}
Imagefill($img_handle, 0, 0, $back_color); //填充图片背景色
ImageString($img_handle, 28, 10, 0, $str, $txt_color);//水平填充一行字符串
ob_clean(); // ob_clean()清空输出缓存区
header("Content-type: image/png"); //生成验证码图片
Imagepng($img_handle);//显示图片
return $str;
}
这一段代码主要功能很简单,先从26个字母以及10个数字中随机产生6个字符,然后开始画图,加一些干扰线和干扰像素,再把这6个字符画进去,最后把图片显示出来。
至此搞明白了这个img标签的运行方式,重新刷新页面的时候会请求一次随机的验证码;点击一下图片也会重新请求一下验证码。
但是到这还是不能解决在burpsuite里,验证码为什么不变的问题。
刚才是在前端看的bf_server.php只有html和js,还没看到后端php代码,所以得去分析一下后端php。
/**
* Created by runner.han
* There is nothing new under the sun
*/
······ //不是重点的代码省略掉了
//下面是重点代码
$html="";
if(isset($_POST['submit'])) {
if (empty($_POST['username'])) {
$html .= "用户名不能为空
";
} else {
if (empty($_POST['password'])) {
$html .= "密码不能为空
";
} else {
if (empty($_POST['vcode'])) {
$html .= "验证码不能为空哦!
";
} else {
// 验证验证码是否正确
if (strtolower($_POST['vcode']) != strtolower($_SESSION['vcode'])) {
$html .= "验证码输入错误哦!
";
//应该在验证完成后,销毁该$_SESSION['vcode']
}else{
$username = $_POST['username'];
$password = $_POST['password'];
$vcode = $_POST['vcode'];
$sql = "select * from users where username=? and password=md5(?)";
$line_pre = $link->prepare($sql);
$line_pre->bind_param('ss',$username,$password);
if($line_pre->execute()){
$line_pre->store_result();
//虽然前面做了为空判断,但最后,却没有验证验证码!!!
if($line_pre->num_rows()==1){
$html.=' login success
';
}else{
$html.= ' username or password is not exists~
';
}
}else{
$html.= '执行错误:'
.$line_pre->errno.'错误信息:'.$line_pre->error.'';
}
}
}
}
}
}
这一段重点代码从上到下分析,首先接收了POST表单,三个连续判断username、password、验证码都不能为空,然后判断验证码是否正确:
如果错误,就将返回“输入验证码错误哦!”,但是并没有对验证码进行销毁或更改,作者自己在注释里面也写到了;
如果验证码正确,将进行后续的调取数据库,验证用户名密码等操作,最后成功与否都是用户名密码的正确与否问题,都与验证码无关了。
到此为止bf_server.php中的php代码执行完毕,经过了一系列判断,发现只要验证码通过了第一次判断,后面用户名密码是否正确都不会对验证码进行更改。
但是为什么我们在做题页面,输入正确验证码,填上用户名密码,点击“Login”之后,页面一刷新验证码就变了呢?
别忘了bf_server.php中,紧接着php代码的下面还有html代码和js代码,一旦这些代码作为响应response回传到浏览器,浏览器就会解析,相应的那个验证码的img标签就会又一次对后端的showvcode.php发起请求,从而返回一个新的验证码,也改变了该用户session会话中的’vcode’参数,也就是说此是前后端验证码都改变了。
我按我的理解画了张图:
正是因为所有在burpsuite里面测试后得到的响应报文都没有发回到客户端那里,也就没有解析html和js代码,所以验证码一直没有变。我们就可以在burpsuite里随意的更改用户名密码来爆破,因为有这么一个代理的墙挡着,报文发不过去,客户端一直在loading转圈圈。
以上就是我对这道题的理解,知识很基础,不过我感觉是一个容易被忽略的点,希望对xdm有帮助。