exponenta event banner

CERT C: Rec. STR02-C

Обеззараживание данных, передаваемых в сложные подсистемы

Описание

Определение правила

Удаление данных, передаваемых в сложные подсистемы. [1 ]

Внедрение Polyspace

Эта проверка проверяет наличие следующих проблем:

  • Выполнение команды внешнего управления.

  • Команда выполняется из пути, управляемого извне.

  • Библиотека загружена из внешнего пути.

Примеры

развернуть все

Проблема

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

Риск

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

Зафиксировать

Проверьте входные данные, чтобы разрешить только предполагаемые входные значения. Например, создайте белый список приемлемых входных данных и сравните входные данные с этим списком.

Пример - Вызов внешней команды
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "unistd.h"
#include "dlfcn.h"
#include "limits.h"
#define MAX 128


void taintedexternalcmd(void)
{
	char* usercmd;
	fgets(usercmd,MAX,stdin);
	char cmd[MAX] = "/usr/bin/cat ";
	strcat(cmd, usercmd);
	system(cmd); 
}

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

Исправление - использование предопределенной команды

Одной из возможных корректировок является использование switch для выполнения предопределенной команды с использованием пользовательского ввода в качестве переменной переключения.

#define _XOPEN_SOURCE
#define _GNU_SOURCE

#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "unistd.h"
#include "dlfcn.h"
#include "limits.h"

enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};
enum { CMD0 = 1, CMD1, CMD2 };

void taintedexternalcmd(void)
{
    int usercmd = strtol(getenv("cmd"),NULL,10);
    char cmd[SIZE128] = "/usr/bin/cat ";

    switch(usercmd) {
        case CMD0:
            strcat(cmd, "*.c");
            break;
        case CMD1:
            strcat(cmd, "*.h");
            break;
        case CMD2:
            strcat(cmd, "*.cpp");
            break;
        default:
            strcat(cmd, "*.c");
    }
    system(cmd); 
}
Проблема

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

Риск

Злоумышленник может:

  • Измените команду, выполняемую программой, возможно, на команду, которой может управлять только атака.

  • Измените среду, в которой выполняется команда, с помощью которой злоумышленник управляет тем, что команда означает и делает.

Зафиксировать

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

Пример - Выполнение пути из переменной среды
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};

void bug_taintedpathcmd() {
    char cmd[SIZE128] = "";
    char* userpath = getenv("MYAPP_PATH");

    strncpy(cmd, userpath, SIZE100);
    strcat(cmd, "/ls *");
    /* Launching command */
    system(cmd); 
}

Этот пример получает путь от переменной среды MYAPP_PATH. system выполняет команду из этого пути без проверки значения пути. Если путь не является намеченным путем, программа выполняется не в том месте.

Исправление - использовать доверенный путь

Одной из возможных корректировок является использование списка разрешенных путей для сопоставления с путем переменной среды.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};

/* Function to sanitize a string */
int sanitize_str(char* s, size_t n) {
    int res = 0;
    /* String is ok if */
    if (s && n>0 && n<SIZE128) {
        /* - string is not null                     */
        /* - string has a positive and limited size */
        s[n-1] = '\0';  /* Add a security \0 char at end of string */
        /* Tainted pointer detected above, used as "firewall" */
        res = 1;
    }
    return res;
}

/* Authorized path ids */
enum { PATH0=1, PATH1, PATH2 };

void taintedpathcmd() {
    char cmd[SIZE128] = "";

    char* userpathid = getenv("MYAPP_PATH_ID");
    if (sanitize_str(userpathid, SIZE100)) {
        int pathid = atoi(userpathid);


        char path[SIZE128] = "";
        switch(pathid) {
            case PATH0:
                strcpy(path, "/usr/local/my_app0");
                break;
            case PATH1:
                strcpy(path, "/usr/local/my_app1");
                break;
            case PATH2:
                strcpy(path, "/usr/local/my_app2");
                break;
            default:
                /* do nothing */
		break;
        }
        if (strlen(path)>0) {
            strncpy(cmd, path, SIZE100);
            strcat(cmd, "/ls *");
            system(cmd);    
        }
    }
}
Проблема

Библиотека, загруженная из внешнего управляемого пути, ищет библиотеки, загруженные из фиксированного или управляемого пути. Если непреднамеренные субъекты могут управлять одним или несколькими местоположениями на этом фиксированном пути, то Bug Finder вызывает дефект.

Риск

Если злоумышленник знает или управляет путем, используемым для загрузки библиотеки, он может изменить:

  • Библиотека, загружаемая программой, заменяющая требуемую библиотеку и команды.

  • Среда, в которой выполняется библиотека, предоставляющая злоумышленнику непреднамеренные разрешения и возможности.

Зафиксировать

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

Другим решением является использование функций, требующих явных путей. Например, system() не требует полного пути, поскольку он может использовать PATH переменная среды. Однако execl() и execv() требуется полный путь.

Пример - Вызов пользовательской библиотеки
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <limits.h>

enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};

void* taintedpathlib() {
    void* libhandle = NULL;
    char lib[SIZE128] = "";
    char* userpath = getenv("LD_LIBRARY_PATH");
    strncpy(lib, userpath, SIZE128);
    strcat(lib, "/libX.so");
    libhandle = dlopen(lib, 0x00001);
    return libhandle;
}

В этом примере загружается библиотека libX.so из переменной среды LD_LIBRARY_PATH. Злоумышленник может изменить путь к библиотеке в этой переменной среды. Фактическая загружаемая библиотека может отличаться от той, которую вы планируете.

Коррекция - изменение и проверка пути

Одной из возможных корректировок является изменение способа получения пути к библиотеке и проверка пути к библиотеке перед открытием библиотеки. В этом примере путь принимается в качестве входного аргумента. Затем проверяется путь, чтобы убедиться, что библиотека не находится под /usr/.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <limits.h>

enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};

/* Function to sanitize a string */
int sanitize_str(char* s, size_t n) {
    /* strlen is used here as a kind of firewall for tainted string errors */
    int res = (strlen(s) > 0 && strlen(s) < n);
    return res;
}
void* taintedpathlib(char* userpath) {
    void* libhandle = NULL;
    if (sanitize_str(userpath, SIZE128)) {
        char lib[SIZE128] = "";

        if (strncmp(userpath, "/usr", 4)!=0) {
            strncpy(lib, userpath, SIZE128);
            strcat(lib, "/libX.so");
            libhandle = dlopen(lib, RTLD_LAZY);    
        }
    }
    return libhandle;
}

Проверить информацию

Группа: Rec. 07. Символы и строки (STR)
Представлен в R2019a

[1] Данное программное обеспечение было создано компанией MathWorks и включает в себя следующие компоненты: «Веб-сайт SEI CERT-C», © 2017 Университет Карнеги-Меллон, веб-сайт SEI CERT-C + + © 2017 Университет Карнеги-Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги-Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги-Меллон, со специальным разрешением от его Института программного обеспечения.

ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ МЕЛЛОНА И/ИЛИ ЕГО ПРОГРАММНОГО ИНЖЕНЕРНОГО ИНСТИТУТА, СОДЕРЖАЩИЙСЯ В НАСТОЯЩЕМ ДОКУМЕНТЕ, ПОСТАВЛЯЕТСЯ КАК ЕСТЬ. УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ, ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, В ОТНОШЕНИИ ЛЮБЫХ ВОПРОСОВ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ГАРАНТИИ ПРИГОДНОСТИ ДЛЯ ЦЕЛЕЙ ИЛИ ТОВАРНОЙ ПРИГОДНОСТИ, ИСКЛЮЧИТЕЛЬНОСТИ ИЛИ РЕЗУЛЬТАТОВ, ПОЛУЧЕННЫХ ОТ ИСПОЛЬЗОВАНИЯ УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ В ОТНОШЕНИИ СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКИХ ПРАВ.

Данное программное обеспечение и связанная с ним документация не были рассмотрены и не одобрены Университетом Карнеги-Меллона или его Институтом разработки программного обеспечения.