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

Как работать с вебом по HTTPS ?

omar_hayat

CD-диск
Пользователь
Регистрация
26.08.2024
Сообщения
15
Реакции
14
Всем привет!

Штудирую интернет на предмет исходников и теоретических материалов по вопросу написания простого клиента HTTPS на плюсах. Вопрос оказался сложный и интересный. Информация разрозненная и многоплатформенная.

Для ускорения процесса основенния теоритичекой части решил поинтересоваться, может у кого есть инфа где где более-менее подробно изложено как вся эта технология работает под капотом (книжки, статьи) в приложении на Винде?

Интернеты (стоковерфлоу и подобные форумы) рекомендуют юзать библиотеки типа асио и либкурл. Исходники конечно под такое есть. Только билдятся они нормально под линукс. Так как на винде нужен спец.бубен чтобы установить библиотеку openssl (в виде какого то хитрого интерпритатора perl`a).

Кто как кодирует трафик при передаче данных?

На сейчас стало понятно что всё сводится к отправке зашифрованного пакета обычными стедствами (сокет или GET запрос). Осталось самая малость, понять как шифровать пакет:)
 
Wininet - тоже готовое решение так-то. Может быть и не нужно, но вопрос в понимании того, что ты делаешь и зачем. Вот затащил ты себе в экзешник готовых библиотек, слинковал статически экзешник в 10мб, а потом он куда-то не прокачался, тк канал был херовый, или где-то он не заработал потому, что библиотека слишком модная и молодежная, чтобы на старой системе работать. Если самоцель выйти в продакшн быстрее, и ты готов какими-то такими моментами пренебречь, ну окей, тебе - не нужно. Потом можно будет уверено писать, что у твоего стиллера в живой природе никогда не встречалась семерка, и смеяться на "старечками", которые о ней зачем-то думают, глупенькие.
Давай так, насчет wininet соглашусь, решение готовое, но мне непонятно утверждение, что если ты кодишь малравь, то обязан использовать только его. Альтернатив масса, на любой вкус и цвет, причем более удобных.
Насчет понимания что ты делаешь и зачем. Я тоже писал в бородатые времена на ассемблере, болел этими болячками с размером стаба, вырезаним всего что только можно, онли винапи, что бы не дай бог попало что-то лишнее в код, сосед же засмеет. А потом как-то переболел. Я понимаю как работают под капотом те библиотеки, которые использую, и уже не вижу смысла изобреать то, что было сделано до меня, тщательно оттестировано и проверено компетентными людьми.
10 мб с точки зрения скорости канала возможно уже перебор, но я не видел ни разу таких цифр, разве что если это раст или го, на плюсах мы не выходили из 2мб, и это при условии что там было реально много библиотек, чаще получается 700-800 кб. 10мб и 20кб это крайности, достаточно находиться в комфортной середине.
Я не понимаю гонки за 20-100 кб. Что можно уместить вообще в этот размер ? Люди лишают себя базовых удобств, передают параметры в строках вида x|y|z, когда можно использовать json, лепят кучу костылей, отчего код нечитаем и поддерживать его трудно. А если кодер сменился, то ему попробуй еще объясни как все работает.
Насчет поддержки старых осей ты зря так обо мне подумал. Я собираю все используемые библиотеки с поддержкой XP, в большинстве либ уже есть готовые дефайны для выбора версии SDK, остальные настраиваются через стандартные виндовые дефайны и иногда небольшие изменения в коде библиотеки.
#define WINVER 0x0501 // Windows XP
#define _WIN32_WINNT 0x0501 // Windows XP
И работатет на всей нужной линейке без нареканий.
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Давай так, насчет wininet соглашусь, решение готовое, но мне непонятно утверждение, что если ты кодишь малравь, то обязан использовать только его
Кто говорил, что ты обязан использовать только его?

когда можно использовать json
XML ридер и райтер доступны через COM и даже в совсем старых дотнетах, если что.
 
Кто говорил, что ты обязан использовать только его?
Как кто, наш уважаемый квейк, без иронии есчо
Зависит, что ты пишешь. Если малварь - даже не смотри в сторону этого, учи вининет/винхттп. Если не малварь - вариантов дофига, лично мне нравится curl.
Отсюда и пошла дискуссия, а почему это не смотреть, лишая себя множества удобств.

XML ридер и райтер доступны через COM и даже в совсем старых дотнетах, если что.
Да, но это всего лишь один малый пример, гонщики за малым стабом намеренно "упрощают" все настолько, что потом ебутся еще больше.
-Может оставим crt ? Удобно же.
-Не, надо убрать, все так делают, не знаю почему, но значит мы тоже уберем.
-Может сделаем нормальную сериализацию ?
-Не, бро, посылай строкой, разделяй запятыми или слешем, у всех так, а у кого не так дурачки наверное.
-Давай сетевуху на asio или netlib сделаем ?
-Не братан, ты че, делаем на чистом winapi, так же все делают, наверное это круто, потом напишем в описании, что мы тоже крутые.
...
Глаза красные, мозг кипит, заебались как марафонцы, зато у нас вес меньше чем у вас и сделали все сами. Ух, какая гордость. А главное, сколько пользы.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Отсюда и пошла дискуссия, а почему это не смотреть, лишая себя множества удобств
Ну ты слишком сагрился на это. И опять же нужно понимать, что и для чего ты делаешь. Например, шеллкод ты из CRT и сторонних библиотек не сделаешь. Морфить код со сторонними библиотеками куда сложнее. Проливать огромные экзешники в какую-то особо нужную тебе залупу с плохим или же вообще с отсутствием интернета куда сложнее. Сторонние библиотеки могут не поддерживать какие-то старые системы и тд. Если тебе это не нужно, то какие проблемы?
 
Например, шеллкод ты из CRT и сторонних библиотек не сделаешь.
Почему же, линкуешь crt и сторонние либы полностью статично, запаковываешь это все в шелл с loadpe, и он загрузит тебе всю эту шляпу на любой винде, особенно если собрано было все с SDK минимальной версии, допустимой на той же xp. Другой вопрос, что шеллкод размером несколько мб не комильфо, никто так не делает, но возможность как таковая есть.


Проливать огромные экзешники в какую-то особо нужную тебе залупу с плохим или же вообще с отсутствием интернета куда сложнее.
Это уже таргетированные атаки, конечно тут стоит запариться, и выбрать оптимальную стратегию. Я не отрицаю, что некоторые конкретные случаи требуют особого подхода. Но их меньшинство.


Сторонние библиотеки могут не поддерживать какие-то старые системы и тд. Если тебе это не нужно, то какие проблемы?
Мы в 2к24 живем, библиотек сейчас столько, что ты не ограничен в выборе, подбери то, что будет удовлетворять условиям поставленной задачи, а именно работа на нужных ОС, удобство разработки и дальнейшей поддержки кода. Какие проблемы ?
 
Почему же, линкуешь crt и сторонние либы полностью статично, запаковываешь это все в шелл с loadpe, и он загрузит тебе всю эту шляпу на любой винде, особенно если собрано было все с SDK минимальной версии, допустимой на той же xp. Другой вопрос, что шеллкод размером несколько мб не комильфо, никто так не делает, но возможность как таковая есть.



Это уже таргетированные атаки, конечно тут стоит запариться, и выбрать оптимальную стратегию. Я не отрицаю, что некоторые конкретные случаи требуют особого подхода. Но их меньшинство.



Мы в 2к24 живем, библиотек сейчас столько, что ты не ограничен в выборе, подбери то, что будет удовлетворять условиям поставленной задачи, а именно работа на нужных ОС, удобство разработки и дальнейшей поддержки кода. Какие проблемы ?
Собирать пе с crt и затем конвертировать его в шеллкод с лоадпе... зачем это надо?

"Мы живем в 2к24", сударь вы видимо застряли в "2к17"

Библиотек в наше время очень много, согласен, но зачем тебе тащить целую библиотеку с ее подводными камнями? Всё можно реализовать при помощи встроенных функций винды, и это не так сложно
Ну и как верно подчеркнул DildoFagins - морфить такой чудо код будет гораздо проблемней


C:
DWORD PostRequest(LPCWSTR host, BOOL isSsl, LPCWSTR path, LPWSTR req, PBYTE& pServerResponse)
{
    DWORD dwDataSize = 0;
    DWORD dwDownloaded = 0;
    DWORD dwLast = 0;
    PBYTE pOutBuffer = NULL;
    BOOL  bResults = FALSE;

    HINTERNET  hSession = NULL,
        hConnect = NULL,
        hRequest = NULL;

    hSession = pWinHttpOpen(_WSTR(L"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36"),
        WINHTTP_ACCESS_TYPE_NO_PROXY,
        WINHTTP_NO_PROXY_NAME,
        WINHTTP_NO_PROXY_BYPASS, 0);

    if (hSession)
        hConnect = pWinHttpConnect(hSession, host,
            isSsl ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT, 0);
    else
        debug_printf("WinHttpOpen Error");
    hRequest = pWinHttpOpenRequest(hConnect, _WSTR(L"POST"), path,
        NULL, WINHTTP_NO_REFERER,
        WINHTTP_DEFAULT_ACCEPT_TYPES,
        isSsl ? WINHTTP_FLAG_SECURE : 0);


    const wchar_t* headers = _WSTR(L"Content-Type: application/x-www-form-urlencoded");// не получается использовать с []
    DWORD headersLen = m_wcslen(headers);
    PCHAR request = f_stralloc(m_wcslen(req));
    UnicodeToASCII(req, request);
    free_s(req);
    DWORD requestLen = m_lstrlen(request);
    if (hRequest)
        bResults = pWinHttpSendRequest(hRequest,
            headers, headersLen,
            request, requestLen, requestLen,
            0);
    else
        debug_printf("WinHttpOpenRequest Error Code %d", pGetLastError());
    if (bResults)
        bResults = pWinHttpReceiveResponse(hRequest, NULL);
    else debug_printf("WinHttpSendRequest Error Code %d", pGetLastError());

    DWORD dwStatusCode = 0;
    DWORD dwSize = sizeof(DWORD);
    if (!pWinHttpQueryHeaders(hRequest,
        WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
        WINHTTP_NO_OUTPUT_BUFFER,
        &dwStatusCode, &dwSize, WINHTTP_NO_HEADER_INDEX) || dwStatusCode != 200) {
        debug_printf("WinHttpQueryHeaders Error Code %d, Status Code %d. Trying to send request again...", pGetLastError(), dwStatusCode);
        pWinHttpCloseHandle(hRequest);
        pWinHttpCloseHandle(hConnect);
        pWinHttpCloseHandle(hSession);
        return 0;
    }

    if (bResults)
    {
        do
        {
            dwDataSize = 0;
            if (!pWinHttpQueryDataAvailable(hRequest, &dwDataSize))
            {
                debug_printf("Cannot get data avaible");
                break;
            }
            BOOL Second = FALSE;
            if (dwLast != 0) {
                pServerResponse = (PBYTE)f_zalloc(dwLast + dwDataSize + 1);
                f_memset(pServerResponse, 0, dwLast + dwDataSize + 1);
                f_memcpy(pServerResponse, pOutBuffer, dwLast);
                free_s(pOutBuffer);
                pOutBuffer = pServerResponse;
                dwLast += dwDataSize;
                Second = TRUE;
            }
            else {
                pServerResponse = (PBYTE)f_zalloc(dwDataSize + 1);
                pOutBuffer = pServerResponse;
                dwLast = dwDataSize;

            }
            if (!pOutBuffer)
            {
                dwDataSize = 0;
                break;
            }
            else
            {

                BOOL Flag;
                if (Second) {

                    Flag = pWinHttpReadData(hRequest, (LPVOID)(pOutBuffer + dwLast - dwDataSize),
                        dwDataSize, &dwDownloaded);
                }
                else {
                    f_memset(pOutBuffer, 0, dwDataSize + 1);
                    Flag = pWinHttpReadData(hRequest, (LPVOID)(pOutBuffer),
                        dwDataSize, &dwDownloaded);
                }
                if (!Flag)
                    break;



            }
        } while (dwDataSize > 0);
    }
    else debug_printf("WinHttpReceiveResponse Error Code %d", pGetLastError());


    debug_printf("Response size is %d", dwLast);

    if (hRequest) pWinHttpCloseHandle(hRequest);
    if (hConnect) pWinHttpCloseHandle(hConnect);
    if (hSession) pWinHttpCloseHandle(hSession);

    return dwLast;
}


Жалкая сотня строк кода для отправки Post запроса на сервер по HTTP / HTTPS с использованием винапи
 
Последнее редактирование:
Собирать пе с crt и затем конвертировать его в шеллкод с лоадпе... зачем это надо?
Читай внимательно, я в своем сообщении наверху сказал что "никто так не делает", но в принципе сделать реально, если захотелось, когда Дилдо утверждает, что нет, нельзя. На этом и все.

но зачем тебе тащить целую библиотеку с ее подводными камнями? Всё можно реализовать при помощи встроенных функций винды, и это не так сложно
А зачем целую ? Современные линкеры не пихают код всей либы в бинарь, а вставляют только используемый код и данные, если ты об этом.
Про подводные камни тоже не понял, если ты давно работаешь с определенным набором библиотек, и в целом имеешь за плечами хороший опыт разработки, для тебя не будет никаких неожиданностей. А если джуна посадить бота писать на бусте, который впервые его увидел, так он повесится раньше, чем закончит. Очевидные вещи.
Библиотеки созданы в первую очередь, что бы не изобретать велосипеды и сделать кодинг более приятным и эффективным. Да, в некоторых библиотеках есть порог вхождения, и новичкам это только усложняет работу. Другие из коробки доступны для неопытных. Главное преимущество использования библиотек (для того, что бы не цеплялись к словам, сразу уточню, популярных и известных библиотек) в том, что их код уже отлажен, протестирован, содержит минимум потенциальных ошибок, которые могут подосрать на продакшне. Ты можешь концентрироваться на более важных для бизнеса вещах, чем собственные реализации велосипедов на любой вкус и цвет.
Кто хочет терять время, пусть его теряет, возможно его собственный код получится ничем не хуже библиотечного, но это нерационально на интенсивном потоке разработки.
В дикой природе малварь написанная что с библиотеками, что на чистом винапи будет функционировать идентично, если не брать в рассчет глупые ошибки кодеров. Но с библиотеками процесс разработки будет быстрее, а поддержка кода легче.

морфить такой чудо код будет гораздо проблемней
Ну если ты морфишь на уровне исходников, возможно для тебя это проблема, есть такая штука как IR, там плевать что морфить, свой код или библиотечный, все через одну мясорубку проходит. На такие решения уже перешла добрая половина форума, которая хоть как-то связана с разработкой малвари и морфингом кода.
 
Последнее редактирование:
Зачем ты задаешь бессмысленные вопросы ?
Это риторический вопрос

Читай внимательно, я в своем сообщении наверху сказал что "никто так не делает", но в принципе сделать реально, если захотелось, когда Дилдо утверждает, что нет, нельзя. На этом и все.
Сделать конкретно шеллкод с crt нельзя, он все сказал верно, обертка с лоадпе над пе файлом это уже не шеллкод


Но с библиотеками процесс разработки будет быстрее, а поддержка кода легче
Очень сомнительно)
 
Сделать конкретно шеллкод с crt нельзя, он все сказал верно, обертка с лоадпе над пе файлом это уже не шеллкод
Технически мы правы оба, я понял твою мысль, ты имеешь ввиду, что шеллкод должен быть просто набором байт, которые составляют инструкции кода, как привычные шеллкоды из metasploit, например. Там нет никаких признаков PE файла, есть только код, и данные на стеке или в памяти, которую шелл сам себе и подготовил. Это шеллкод по всем канонам.
А я имею ввиду, что шеллкодом можно назвать последовательность байт, которую можно расположить в любой исполняемой памяти, по любому адресу, и передать туда управление. А дальше закрутятся все шестеренки, и цель будет достигнута. И запакованный PE внутри шеллкода с loadpe подходит под это определение.
 
Технически мы правы оба, я понял твою мысль, ты имеешь ввиду, что шеллкод должен быть просто набором байт, которые составляют инструкции кода, как привычные шеллкоды из metasploit, например. Там нет никаких признаков PE файла, есть только код, и данные на стеке или в памяти, которую шелл сам себе и подготовил. Это шеллкод по всем канонам.
А я имею ввиду, что шеллкодом можно назвать последовательность байт, которую можно расположить в любой исполняемой памяти, по любому адресу, и передать туда управление. А дальше закрутятся все шестеренки, и цель будет достигнута. И запакованный PE внутри шеллкода с loadpe подходит под это определение.
Чисто технически да, но тогда можно любой пешник обернуть, и называть шелом
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
есть такая штука как IR
Много ты видел либ, которые в виде IR распространяются? Даже, если такая либа есть, это по сути тоже самой, что пересобирать ее из исходников, разница только в доли секунды для каждого юнита трансляции.

ты не ограничен в выборе
Да, ты не ограничен в возможности гуглить и с должным упорством находить, например, старые версии компилятора golang, который еще поддерживал венду младше десятки. Но сколько сторонних библиотек хорошо документируют, какие системы они поддерживают в каких версиях?

запаковываешь это все в шелл с loadpe, и он загрузит тебе всю эту шляпу на любой винде
Только это не шеллкод, это шеллкод обертка над pe-файлами, и в памяти у тебя будет и обертка и сам твой исходный pe-файл.

в том, что их код уже отлажен
Код ни одной сторонней библиотеки не будет настолько отлажен, как код библиотеки, встроенной в операционную систему.
 
Много ты видел либ, которые в виде IR распространяются? Даже, если такая либа есть, это по сути тоже самой, что пересобирать ее из исходников, разница только в доли секунды для каждого юнита трансляции.
Зачем в виде IR распространять? Дилдо, ты же вроде давно на форуме, должен знать, что есть такой замечательный компилятор как clang, и на его базе строят компиль-тайм морферы/мутаторы. Прямо во время сборки весь код перемалывают с костями и шкурой, и твой собственный, и библиотечный (при условии сборки из исходников).


Но сколько сторонних библиотек хорошо документируют, какие системы они поддерживают в каких версиях?
Для меня их достаточно, я в деве давно, успел перепробовать и протестировать на разных версиях ОС очень много кода. Могие библиотеки предоставляют специальные дефайны, что бы выбрать минимальный SDK нужной версии. Я писал об этом выше, ты перепрыгиваешь глазами важные участки, и смотришь непонятно куда.


Только это не шеллкод, это шеллкод обертка над pe-файлами, и в памяти у тебя будет и обертка и сам твой исходный pe-файл.
Какая разница если это запускается как шеллкод и выглядит как шеллкод ? Технически это нечестный шеллкод, если придираться, но он так же способен запустить полезную нагрузку в любом участке исполняемой памяти. То что там потроха в виде PE файла это уже детали, по прежнему если есть RCE в которую можно впихнуть такого франкенштейна, оно сработает как обычный шеллкод на удаленной тачке и выполнит нагрузку.


Код ни одной сторонней библиотеки не будет настолько отлажен, как код библиотеки, встроенной в операционную систему.
Бесспорно, но мне например не нравится реализация работы с проксями в wininet/winhttp, можно только http/s проксирование прикрутить через хидеры запроса или настройки IE, носков 4/5 нет, да и много других плюшек там не поковыряешь, специфичные протоколы связи там не реализованы. Очень много расширенного функционала приходится брать на стороне.
Если тебе хватает пары get-post запросов простенького содержания, можешь остановиться на вининет. Но есть задачи, с которыми он не справляется, или приходится городить костыли к нему.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Дилдо, ты же вроде давно на форуме, должен знать, что есть такой замечательный компилятор как clang
Я достаточно давно на форуме, чтобы понимать, что ты не знаешь, о чем говоришь, и я за свою жизнь написал много морферов. Так вот, слушай, библиотека распространяется в виде уже собранных юнитов трансляции, в .obj файлах и в .o файлах, если мы говорим о MinGW лежит собранный код, там не лежит IR. Только нативный код, данные и метаданные, к нему, которые нужны линкеру. Никакой плагин к компилятору тебе не даст модифицировать объектники. Морфить и пересобирать IR - это тоже самое, что и пересобирать сорсы, так как очень много оптимизаций реализуются на уровне IR, а не на уровне AST. Может быть, чуть быстрее из-за всратых парсеров и препроцессоров, но этим можно пренебречь.

Я писал об этом выше, ты перепрыгиваешь глазами важные участки, и смотришь непонятно куда
Так может и не стоит портянки тебе текста писать, которые никто не читает, а только прыгает по ними глазами?

Какая разница если это запускается как шеллкод и выглядит как шеллкод ?
Огромная.
 
Какая разница если это запускается как шеллкод и выглядит как шеллкод ? Технически это нечестный шеллкод, если придираться, но он так же способен запустить полезную нагрузку в любом участке исполняемой памяти. То что там потроха в виде PE файла это уже детали, по прежнему если есть RCE в которую можно впихнуть такого франкенштейна, оно сработает как обычный шеллкод на удаленной тачке и выполнит нагрузку.
Приведу простой пример...

В магазине на полках лежит сыр, внешне одинаковый, разница лишь в размере

Один сыр сделан из молока, а второй из какой то хрени

Вот ты кушаешь его, тебе по барабану - сыр это сыр, вкус и там там одинаковый, но ты не задумываешься над тем, какой сыр пагубно влияет на твой организм

А потом: ой у меня живот болит...

Хз как еще проще объяснить
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Ладно что то я отвлекся, вернемся к библиотекам. Не вижу ничего плохого в использовании готовых решений в малвари, это сокращает время разработки, отладки, тестирования, малварь это такое же ПО как и любой другой софт.
Пишите на чем угодно, линкуйте свою малварь с опенссл, бустом, хоть с едром линукс.
Только не надо новичков ерунде учить.

Почему - да потому что закриптовать потом хрен получится , вот почему. Потому что крипторы такие же "а зачем разбираться в винапи, ассемблере, 2024 год же".

На экспе был чел, продавал свою софтину за 25к (приват версию за 50). Напортачил с црт так, что никто не смог криптовать, в итоге улетел в блеки. Бегал под конец как обосраный олень по всем, чтобы подебажили и нашли ошибку, толи в крипторе, толи где.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
обосраный олень
94wz8r.jpg

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

Напортачил с црт так, что никто не смог криптовать, в итоге улетел в блеки.
Отсюда логичный вопрос, это проблема конкретно этого кодера, который где-то ошибся, что-то неправильно сделал, или исходя только из этого случая будем считать, что всех ждет такая же участь?
 
Использование Wininet WINAPI это палка о двух концах. С одной стороны это очень удобно, компактно, является "родным" для винды, можно провнерять серты, а с другой стороны что всякая эвристика и эмуляторы АВ давно уже эту фишку проверяют.
На счет крипта - да никто не мешает морфить код на уровне сорцев.
Лучшим решением было бы свой самописный протокол связи использовать. Взять тот же Crypto API (там есть от RSA до эллиптики чисто для обмена ключами) и к примеру чачу (занимает 1-2кб) и интегрировать с чистыми сокетами.
 


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