CERT C: Rec. STR02-C

Санируйте данные, переданные комплексным подсистемам

Описание

Управляйте определением

Санируйте данные, переданные комплексным подсистемам. [1]

Примеры

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

Описание

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

Риск

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

Фиксация

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

Пример - команда параметра вызова

#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
};

void taintedexternalcmd(char* usercmd)
{
    char cmd[SIZE128] = "/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(int usercmd)
{
    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система запускает команду от того пути, не проверяя значение пути. Если путь не является намеченным путем, ваша программа выполняется в неправильном месте.

Коррекция — использует доверяемый путь

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

#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);    
        }
    }
}

Описание

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

Риск

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

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

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

Фиксация

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

Другое решение состоит в том, чтобы использовать функции, которые требуют явных путей. Например, 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 Carnegie Mellon University, веб-сайт SEI CERT-C © 2017 Carnegie Mellon University”, CERT SEI C Кодирование Стандарта – Правил для Разработки безопасных, Надежных и Защищенных систем – 2 016 Выпусков”, © 2016 Carnegie Mellon University, and “CERT SEI Стандарт Кодирования C++ – Правил для Разработки безопасных, Надежных и Защищенных систем на C++ – 2 016 Выпусков” © 2016 Carnegie Mellon University, со специальным разрешением от его Института программной инженерии.

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

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