首先是php的SSRF。
可以用进制绕过。
格式化字符串。用%1$s
绕过
之后就是探测开放端口
得到5000端口有个应用
告诉我们flag在/fl4g/flag
使用方法是/query?path=
存在任意文件读取。读取源码进行分析
main.py
from flask import Flask, request
from file import File
from readfile import FileReader
app = Flask(__name__)
@app.route('/query')
def query():
path = request.args.get('path')
if not path:
return '请输入路径'
file = FileReader(File(path))
return str(file)
@app.route('/')
def index():
return 'Use /query?path= to query what you want. And what you want is at /fl4g/flag'
if __name__ == '__main__':
app.run(port=8890)
file.py
import os
import os.path
class File:
"The file class"
def __init__(self, path):
self.path = path
self.name = os.path.basename(self.path)
self.dir = os.path.dirname(self.path)
def listDir(self):
return os.listdir(os.path.dirname(self.dir))
readfile.py
class FileReader:
def __init__(self, file):
self.file = file
def __str__(self):
if 'fl4g' in self.file.path:
return 'nonono,it is a secret!!!'
else:
output = 'The file you read is:\n'
filepath = (self.file.dir + '/{file.name}').format(file=self.file)
output += filepath
output += '\n\nThe content is:\n'
try:
f = open(filepath,'r')
content = f.read()
f.close()
except:
content = 'can\'t read'
output += content
output += '\n\nOther files under the same folder:\n'
output += '\n'.join(self.file.listDir())
return output.replace('\n','')
从main.py开始分析
接受path的值。然后传入File类中
File.path=path
File.name= os.path.basename(path)
File.dir=os.path.dirname(path)
再把File类当作参数。传入FileReader类中
判断。File.path不能有fl4g
filepath = (self.file.dir + '/{file.name}').format(file=self.file)
简化下就是
filepath = (File.dir + '/{File.name}').format(file=File)
当我们传入/etc/passwd时
File类各个属性值如下
path=/etc/passwd
name=passwd
dir=/etc
我们现在要绕过/f14g这个限制
这里可以利用format这个点
输入/fl4{file.name[3]}/flag
此时的属性如下
path=/fl4{file.name[3]}/flag
name=flag
dir=/fl4{file.name[3]}
进行format格式化时
'/fl4{file.name[3]}'+'/{file.name}'.format(file)
这个file是Fille类。所以format是调用File类的name的第四个字符
也就是g
然后file.name返回flag
就变成了
'/fl4g'+'/flag'
然后读取。成功绕过限制