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 оператор для запуска предопределенной команды с использованием входа в качестве переменной 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); 
}
Проблема

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

Риск

Атакующий может:

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

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

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

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

Пример - Выполнение пути из переменного окружения
#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;
}

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

Группа: Рек. 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 Университет Карнеги Меллон, с специального разрешения от его Института программной инженерии.

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

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