Dest0g3 520迎新赛 WEB_WP

308 阅读2分钟

1.phpdest

文件包含漏洞

  • require_once:包含指定文件一次,若出现异常则停止脚本进行

require_once()第一次包含flag.php后,如果再次包含此文件的话不会执行。 很明显flag就是在flag.php里,考虑绕过require_once()函数。 image.png 此处的绕过涉及require_once()拒绝重复匹配的底层原理:

  • 当首次包含某个文件时,会在相应的文件哈希表上进行"注册",当重复包含时会产生hash值的匹配从而拒绝包含。当软连接使用 /proc/self/root 的层数足够多时,可使得hash重新匹配,从而造成重复包含,进而绕过once的限制。

image.png 进行base64解码,得到flag image.png

2.easyphp

代码审计之后可以发现if代码块根本不会执行。

image.png 考虑利用set_error_handler()函数,注意到此处有字符串拼接

于是考虑传入数组触发自定义报错函数从而获取flag

image.png

3.easyrce

代码审计,远程代码执行RCE漏洞,这题几乎把所有的命令执行函数给ban了 image.png

看了下wp,new trick:

hex2bin($string):将十六进制的字符串转化为ASCII字符串,

对system('cat /flag')进行bin2hex,然后在post时使用hex2bin

注意:没有ban的字符就使用原字符,否则无法爆出flag image.png post传参获取flag image.png

4.funny_upload

文件上传漏洞配合一句话木马进行连接

直接上传一句话木马和图片木马,发现均存在过滤

尝试之后发现.htaccess文件可以上传,考虑使用htaccess的相关配置实现绕过

image.png

5.EasySSTI

image.png 发现有回显,结合题目的名字进行注入测试,使用{{..}}可进行SSTI注入攻击

绕过blacklist,获取flag

image.png

6.middle

import os
import config
from flask import Flask, request, session, render_template, url_for,redirect,make_response
import pickle
import io
import sys
import base64


app = Flask(__name__)


class RestrictedUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
        if module in ['config'] and "__" not in name:
            return getattr(sys.modules[module], name)      # 返回module模块中的name属性的值,可以构造出backdoor函数的调用
        raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))


def restricted_loads(s):
    return RestrictedUnpickler(io.BytesIO(s)).load()      # opcode转python语句

@app.route('/')
def show():
    base_dir = os.path.dirname(__file__)
    resp = make_response(open(os.path.join(base_dir, __file__)).read()+open(os.path.join(base_dir, "config/__init__.py")).read())
    resp.headers["Content-type"] = "text/plain;charset=UTF-8"
    return resp

@app.route('/home', methods=['POST', 'GET'])
def home():
    data=request.form['data']
    User = restricted_loads(base64.b64decode(data))      
    return str(User)

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True, port=5000)
import os
def backdoor(cmd):
    # 这里我也改了一下
    if isinstance(cmd,list) :                               # 传入list
        s=''.join(cmd)
        print("!!!!!!!!!!")
        s=eval(s)
        return s
    else:
        print("??????")

Flask框架、pickle反序列化前置知识去找找文档学习下!

代码审计,是python的pickle中的反序列化漏洞。

利用思路:

  • 可利用的任意执行函数为backdoor中的eval()

  • 发现在/home路径下可提交data数据

  • data数据经由restricted_loads()函数进行load()反序列化

  • RestrictedUnpickler中进行了过滤,必须包含'config'字段和不能使用'__',其中的return getattr(),可以配合backdoor()函数进行利用

构造如下exp.py image.png 并生成python opcode(“序列化”),同时注意要进行一次base64编码(查看源代码不难分析): image.png url中使用/home路径,传参获取flag image.png

7.ezip

下载图片,扔进FlexHex进行解析,发现一串base64字符串

image.png

解码获得upload.php和zip的类声明代码:

upload.php:
<?php
error_reporting(0);
include("zip.php");
if(isset($_FILES['file']['name'])){
    // 过滤文件名和拓展名
    if(strstr($_FILES['file']['name'],"..")||strstr($_FILES['file']['name'],"/")){
        echo "hacker!!";
        exit;
    }
    if(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION)!="zip"){
        echo "only zip!!";
        exit;
    }

    $Myzip = new zip($_FILES['file']['name']);
    // 创建目录
    mkdir($Myzip->path);
    // 文件存放位置的移动       
    move_uploaded_file($_FILES['file']['tmp_name'], './'.$Myzip->path.'/' . $_FILES['file']['name']);
    echo "Try to unzip your zip to /".$Myzip->path."<br>";
    // 调用解压函数
    if($Myzip->unzip()){echo "Success";}else{echo "failed";}
}
?>

zip.php:
<?php
class zip
{
    public $zip_name;
    public $path;
    public $zip_manager;

    public function __construct($zip_name){
        $this->zip_manager = new ZipArchive();
        $this->path = $this->gen_path();
        $this->zip_name = $zip_name;
    }
    public function gen_path(){
        $chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $newchars=str_split($chars);                                                                    // 将字符串转化成数组
        shuffle($newchars);                                                                      // 打乱数组中的元素位置
        $chars_key=array_rand($newchars,15);
        $fnstr = "";
        for($i=0;$i<15;$i++){
            $fnstr.=$newchars[$chars_key[$i]];
        }
        return md5($fnstr.time().microtime()*100000);
    }

    public function deldir($dir) {
        //先删除目录下的文件:
        $dh = opendir($dir);
        while ($file = readdir($dh)) {
            if($file != "." && $file!="..") {
                $fullpath = $dir."/".$file;
                if(!is_dir($fullpath)) {
                    unlink($fullpath);
                } else {
                    $this->deldir($fullpath);
                }
            }
        }
        closedir($dh);
    }
    function dir_list($directory)               // 字段转化成数组
    {
        $array = [];

        $dir = dir($directory);
        while ($file = $dir->read()) {
            if ($file !== '.' && $file !== '..') {
                $array[] = $file;
            }
        }
        return $array;
    }
    public function unzip()                                                                 // 解压
    {
        $fullpath = "/var/www/html/".$this->path."/".$this->zip_name;
        $white_list = ['jpg','png','gif','bmp'];                                            // 列出白名单
        $this->zip_manager->open($fullpath);                                                // 打开zip文件
        for ($i = 0;$i < $this->zip_manager->count();$i ++) {
            if (strstr($this->zip_manager->getNameIndex($i),"../")){                // 索引中过滤../
                echo "you bad bad";
                return false;
            }
        }
        if(!$this->zip_manager->extractTo($this->path)){                    // extractTo() 将文件解压到指定文件
            echo "Unzip to /".$this->path."/ failed";
            exit;
        }
        // 触发extractTo的失败  exit避免文件删除


        // unlink()删除文件
        @unlink($fullpath);
        //
        $file_list = $this->dir_list("/var/www/html/".$this->path."/");
        for($i=0;$i<sizeof($file_list);$i++){
            // is_dir() 判断给定文件名是否为一个目录
            if(is_dir($this->path."/".$file_list[$i])){
                echo "dir? I deleted all things in it"."<br>";@$this->deldir("/var/www/html/".$this->path."/".$file_list[$i]);@rmdir("/var/www/html/".$this->path."/".$file_list[$i]);
            }
            else{
                if(!in_array(pathinfo($file_list[$i], PATHINFO_EXTENSION),$white_list)) {echo "only image!!! I deleted it for you"."<br>";@unlink("/var/www/html/".$this->path."/".$file_list[$i]);}
            }
        }
        return true;

    }


}

发现在zip类中的unzip函数中存在

rmdir 删除目录

unlink 删除文件

发现在此之前有exit(),考虑利用exit进行绕过

这里涉及php的ZipArchive类中的函数:extractTo()函数

extractTo(string $path,mixed $entries):bool

功能:传入绝对路径,将经ZipArchive类实体open的zip文件进行压缩到绝对路径位置 $entries参数指明了要解压zip文件中的哪些文件

利用:当在zip文件中设置两个file_name一致的文件时,会造成解析错误,解压继续执行但是返回布尔值false

本题只要在zip文件中部署一句话木马hack.php及其相同的文件名,即可绕过rmdir和unlink

image.png

image.png 最后中国蚁剑连接,查询/flag目录即可