Дата и время публикации:
Синопсис
Приводящее к выходу за пределы родительской директории
В процессе ввода пути файла или директории, ограниченными родительской директорией, может произойти несанкционированный доступ к другим объектам файловой системы за её пределы из-за не правильно нейтрализованными специальными символов.
Целостность конфиденциальности доступа (Integrity Confidentiality Availability)
Атакующему может быть доступно, например с использованием устанавливающий права доступа атрибутов файлов "Set-UID" или "Set-GID", создавать или перезаписывать критические файлы, которые используют исполняемый код, таких как программы или библиотеки.
Целостность (Integrity)
Атакующему может быть доступна перезапись или создание критических файлов, содержащие исполняемый код программ, библиотек или иных важных данных. Если в целевой файл используется в механизмах безопасности, тогда атакующей может быть достигнут обход их. Например, добавление новой учетной записи (new account) в конец файла /etc/passwd может позволить атакующему обходить процедуру аутентификации .
Конфиденциальность (Confidentiality)
Атакующему может быть доступно чтение непредвиденных файлов и обращаться к конфиденциальным данным. Если целевой файл используется в механизмах безопасности, тогда атакующий может быть доступен обход данного механизма. Например, чтение файла учетных записей пользователей (файла /etc/passwd) может помочь атакующему взломать аккаунт в системе путем подбора пароля.
Доступность (Availability)
Атакующему может быть доступна перезапись или компрометация непредвиденных файлов , таких как содержащие исполняемый код программ, библиотек или иных важных данных. Что может помещать работе программного обеспечения пользователей, зарегистрированным в системе, из-за потенциальной угрозы блокировки их программного обеспечения.
Описание
Листинг 1.
... 8 char dirname[256]; 9 char filename[256]; ... 13 char pathname[256]; 14 15 snprintf (pathname, sizeof pathname, "%s/%i/%s", dirname, getpid (), filename); 16 ...
В настоящий момент самой распространенной ошибкой считается перезапись данных путем переполнения буфера CWE-120 или возможного выхода за пределы его границ при выполнении операций чтения и записи CWE-119 нарушающие конфиденциальность и предоставляющие несанкционированный доступ к конфиденциальной информации.
Но обрезание формата строки не связано с перезаписью данных. Так почему она является проблемой? Потому что мы имеем дело с последовательностью подаваемых символов, некоторые из которых могут быть непреднамеренно пропущены, что приведет к усечению форматной строки одной из двух общих форм.
В результате первой будет наблюдаться NUL-завершаемая строка, являющейся короче чем сумма длин двух соединяемых строк. В другом случае результирующая последовательность байтов не будет завершена символом конца строки, что приведет к неминуемо неопределенному результату, который фиксируется другой ошибкой CWE-170 .
char charNUL = '\0'; unsigned int integer = 0; char charBinary = '0';
Поэтому в рамках CWE-22 будем рассматривать первый случай, когда будет зафиксировано нарушение целостности вывода данных из-за усечения форматной строки во время составления пути файла,которое влечет нарушение требований функций безопасности объекта оценки согласно общих критериев.
Статическим анализатором исходного кода компилятора GCC предусмотрено две проверки, которые определяют ошибки усечения строки в виде предупреждение Wformat-trunctation , которое фиксируется с помощью опции -Wall и превращается в ошибку при использование опции -Werror .
Оно было введено в GCC-7 и обнаруживает усечения форматной строки в функциях snprintf семейства стандартного ввода/вывода PRINTF(3). Рассмотрим часто приводимый пример такого рода проблемы, который показан в листинге 2
Листинг 2
... 8 char dirname[256]; 9 char filename[256]; 10 11 FILE* open_file (void) 12 { 13 char pathname[256]; 14 15 snprintf (pathname, sizeof pathname, "%s/%i/%s", dirname, getpid (), filename); 16 17 return fopen (pathname, "w"); 18 } ...
Приводимый исходный код приведет к возникновению предупреждающего сообщения об ошибке [-Werrorformat-truncation=], как показано в дампе 3
Дамп 3
... cwe134_truncated_format.c: In function ‘open_file’: cwe134_truncated_format.c:15:44: error: ‘%i’ directive output may be truncated writing between 1 and 11 bytes into a region of size between 0 and 255 [-Werror=format-truncation=] 15 | snprintf (pathname, sizeof pathname, "%s/%i/%s", dirname, getpid (), filename); | ^~ cwe134_truncated_format.c:15:3: note: ‘snprintf’ output between 4 and 524 bytes into a destination of size 256 15 | snprintf (pathname, sizeof pathname, "%s/%i/%s", dirname, getpid (), filename); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ...
Это связано с тем, что конкатенация пяти компонентов в pathname явно не укладывается в выделенный буфер размером 256 байт, а её результат не будет соотнесен с предполагаемым файлом. А все потому что имя директории pathname длинной около 256 символов, заканчивается на PID, который может быть обрезан. Чем и может воспользоваться атакующий для повреждения других файлов, находящиеся в других директориях и содержащие конфиденциальные данные, исполняемый код другого процесса, который возможно управляется атакующим для чтения или манипуляции ими. Для помощи в выявлении указанной проблемы GCC выдает предупреждение Wformat-truncation, показанное в дампе 3
Для формирования указанного предупреждения им, компилятором GCC, используются длинны строк и размерность целочисленных аргументов для определения места форматной строки, где её обрезание будет достигнуто. При этом, когда длинна аргумента строки не может быть определена и аргумент имеет известный размер массива, для формирования предупреждение используется размер массива для оценки наихудшего сценария взамен длинны строки, который в данном случае будет равняться размеру массива dirname плюс значение целочисленного аргумента INT_MAX, которые в сумме дает значительно больший размер чем 256 байт результирующего буфера pathname .
Фраза "output may be truncated" указывает, что именно на целочисленном аргументе строка форматирования будет обрезана. Также следует помнить, что GCC проводит подобную проверку не только на максимальные значения, но и на минимальные.
Казалось бы самым простым способом парировать приводимый пример нарушения CWE-22 определять, что усечение форматной строки произошло и немедленно прекращать работу программы, как показано в листинге 4
Листинг 4
... 15 int n = snprintf (pathname, sizeof pathname, "%s/%i/%s", dirname, getpid (), filename); 16 if ((size_t)n > sizeof pathname ) { 17 abort (); 18 } ...
При этом, самым лучшим способом является выделять памяти столько, сколько нужно, как показано в листинге 5
Листинг 5
... 12 size_t path_sz = sizeof dirname + 64 + sizeof filename ; 13 char pathname [ path_sz ]; 14 15 int n = snprintf (pathname, path_sz, "%s/%i/%s", dirname, getpid (), filename); 16 if ((size_t)n > path_sz ) { 17 return NULL; 18 } ...
В строке 12 листинга 2.4 показано, что до выделение участка памяти в стеке функции в строке 13, производится сначала расчет длинны предполагаемого пути, где целочисленное значение указывает на количество цифр, которые могут быть добавлены INT_MAX в виде символов. При этом видно, что фактически INT_MAX содержит не более 10 символов, а на её нужды выделяется 64 байта, потому что производится выравнивание к соответствующему значению границы стека выделяемого функции open_file фрейма стека .
Библиография
1 GCC-bugs.[Bug c/80354] Poor support to silence -Wformat-truncation=1
2 CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
3 CWE-170: Improper Null Termination
4 Developers.redhat.com. Detecting String Truncation with GCC 8
5 GeeksforGeeks. ASCII NUL, ASCII 0 (‘0’) and Numeric literal 0