随意输入个号上去,发现存在upload功能,点击后提示:Permission denied!

掏出bp,在登录的时候抓包,可以看到可疑的session:

在login页面看到了源码提示:

<!--
404 not found
-->

随便访问个不存在的目录,在响应头看到了hint:

Swpuctf_csrf_token: U0VDUkVUX0tFWTprZXlxcXF3d3dlZWUhQCMkJV4mKg==

base64解码得:SECRET_KEY:keyqqqwwweee!@#$%^&*

根据网页标题的flask,结合session不难看出是flask session伪造。已经有key了。这里我用了flask-session-cookie-manager工具,首先解个码查看格式,然后照葫芦画瓢生产一个伪造的session。

成功获取到了权限。源代码发现注释:

@app.route('/upload',methods=['GET','POST'])
def upload():
    if session['id'] != b'1':
        return render_template_string(temp)
    if request.method=='POST':
        m = hashlib.md5()
        name = session['password']
        name = name+'qweqweqwe'
        name = name.encode(encoding='utf-8')
        m.update(name)
        md5_one= m.hexdigest()
        n = hashlib.md5()
        ip = request.remote_addr
        ip = ip.encode(encoding='utf-8')
        n.update(ip)
        md5_ip = n.hexdigest()
        f=request.files['file']
        basepath=os.path.dirname(os.path.realpath(__file__))
        path = basepath+'/upload/'+md5_ip+'/'+md5_one+'/'+session['username']+"/"
        path_base = basepath+'/upload/'+md5_ip+'/'
        filename = f.filename
        pathname = path+filename
        if "zip" != filename.split('.')[-1]:
            return 'zip only allowed'
        if not os.path.exists(path_base):
            try:
                os.makedirs(path_base)
            except Exception as e:
                return 'error'
        if not os.path.exists(path):
            try:
                os.makedirs(path)
            except Exception as e:
                return 'error'
        if not os.path.exists(pathname):
            try:
                f.save(pathname)
            except Exception as e:
                return 'error'
        try:
            cmd = "unzip -n -d "+path+" "+ pathname
            if cmd.find('|') != -1 or cmd.find(';') != -1:
				waf()
                return 'error'
            os.system(cmd)
        except Exception as e:
            return 'error'
        unzip_file = zipfile.ZipFile(pathname,'r')
        unzip_filename = unzip_file.namelist()[0]
        if session['is_login'] != True:
            return 'not login'
        try:
            if unzip_filename.find('/') != -1:
                shutil.rmtree(path_base)
                os.mkdir(path_base)
                return 'error'
            image = open(path+unzip_filename, "rb").read()
            resp = make_response(image)
            resp.headers['Content-Type'] = 'image/png'
            return resp
        except Exception as e:
            shutil.rmtree(path_base)
            os.mkdir(path_base)
            return 'error'
    return render_template('upload.html')


@app.route('/showflag')
def showflag():
    if True == False:
        image = open(os.path.join('./flag/flag.jpg'), "rb").read()
        resp = make_response(image)
        resp.headers['Content-Type'] = 'image/png'
        return resp
    else:
        return "can't give you"

真的又臭又长,不过搜索flag能找到它的位置在./flag/flag.jpg,但是不知道其绝对路径。涉及几个知识点:

  • 在 linux 中,/proc/self/cwd/会指向进程的当前目录,在不知道 flask 工作目录时,我们可以用/proc/self/cwd/flag/flag.jpg来访问 flag.jpg。
  • ln -s是Linux的软连接命令,其类似与windows的快捷方式。比如ln -s /etc/passwd shawroot 这会出现一个名为shawroot的文件,其内容为/etc/passwd的内容。

所以最后思路是利用ln -s命令,软连接到/proc/self/cwd/flag/flag.jpg

  • ln -s /proc/self/cwd/flag/flag.jpg shaw
  • zip -ry root.zip shaw

其中zip命令的参数含义如下:

-r:将指定的目录下的所有子目录以及文件一起处理

-y:直接保存符号连接,而非该连接所指向的文件,本参数仅在UNIX之类的系统下有效。

抓包上传root.zip,换下session得到flag。

⚪参考:

https://blog.csdn.net/mochu7777777/article/details/105666388