Являются ли неинициализированные ценности когда-либо угрозой безопасности?
Во время обучения C я допустил некоторые ошибки и напечатанные элементы массива символов, которые были неинициализированы.
Если я увеличиваю размер массива достаточно большим, скажем, 1 миллион элементов в размере, а затем распечатать содержимое, то, что выходит, не всегда не читается пользователем, но, похоже, содержит некоторую информацию о времени выполнения.
Рассмотрим следующий код:
#include <stdio.h>
main() {
char s[1000000];
int c, i;
printf("Enter input string:\n");
for (i = 0; ( c = getchar()) != '\n'; i++) {
s[i] = c;
}
printf("Contents of input string:\n");
for (i = 0; i < 999999; i++) {
putchar(s[i]);
}
printf("\n");
return 0;
}
Просто прокручивая вывод, я нахожу такие вещи, как:
??? л???????? _ dyldVersionNumber_dyldVersionString_dyld_all_image_infos_dyld_fatal_error_dyld_shared_cache_ranges_error_string__mh_dylinker_header_stub_binding_helper_dyld_func_lookup_offset_to_dyld_all_image_infos__dyld_start__ZN13dyldbootstrapL30randomizeExecutableLoadAddressEPK12macho_headerPPKcPm__ZN13dyldbootstrap5startEPK12macho_headeriPPKcl__ZN4dyldL17setNewProgramVarsERK11ProgramVars__ZN4dyld17getExecutablePathEv__ZN4dyld22mainExecutablePreboundEv__ZN4dyld14mainExecutableEv__ZN4dyld21findImageByMachHeaderEPK11mach_header__ZN4dyld26findImageContainingAddressEPKv
а также
Apple Inc.1 & 0 $U? 0? *? H?? ot CA0? "0учетный центр сертификации10U? 䑩?? GP?? ^ y? -? 6? WLU???? Kl??" 0? > ? P? A????? f? $KУ???? z ? G? [? 73?? М? Я?? г?] _??? d5 # К.Ю.????? Р?? XPG?? ˬ, (& alpha;) & le; & lambda;?? Т.Б.
?!. Т < & Alpha; 3 & bull; 0 & times; 2 & bull; h & le; g & le; & le; v & le; 3 & alpha; w & le; - & le; z0 & le; v0U & le; 0U & le; 0 & le;. @?? GM ^ 0U # 0? +? IG? V?? k?. @?? GM ^ 0? U 0? 0?? H?? cd0?? 0+ https://www.apple.com/appleca/0?+0????Reliance on этот сертификат любой стороной предполагает принятие тогда применимые стандартные условия использования, сертификат poli?\6? Lx? 팛? w? v? w0O???? = G7? @?, Ա? ؾ? s? d? yO4 آ > ? x? k??} 9? S? 8i?? вывода 01 Н?? [d c3w:??!?????, V?? ں Так?? 6 U7?? 2B??? д ~ R?? B $*?? М ^ С К Р???????? 7? уу! 0? 0?? 0
Я считаю, что однажды моя переменная среды $PATH
была даже распечатана.
Может ли содержимое неинициализированной переменной представлять угрозу безопасности?
Обновление 1
Обновление 2
Таким образом, из ответов видно, что это действительно угроза безопасности. Это меня удивляет.
Нет ли способа, чтобы программа объявляла свой контент памяти защищенным, чтобы позволить ОС ограничивать любой доступ к ней, кроме программы, которая инициализировала эту память?
Ответы
Ответ 1
В большинстве программ C
для выделения памяти используется malloc
. Общее недоразумение заключается в том, что malloc
возвращает нулевую память. На самом деле это не так.
В результате из-за того, что фрагменты памяти "переработаны", вполне возможно получить информацию с "значением".
Примером этой уязвимости была программа tar
на Solaris, которая испускала содержимое /etc/passwd
. Основная причина заключалась в том, что память, выделенная для tar
для чтения блока с диска, не была инициализирована, и до получения этого фрагмента памяти утилита tar
сделала системный вызов ОС для чтения /etc/passwd
. Из-за утилизации памяти и того факта, что tar
не инициализировал фрагменты фрагмента /etc/passwd
, были напечатаны в журналах. Это было решено путем замены malloc
на calloc
.
Это фактический пример влияния безопасности, если вы явно не правильно и правильно инициализируете память.
Так что да, правильно инициализируйте свою память.
Обновление:
Нет ли способа, чтобы программа объявляла свой контент памяти защищенным чтобы ОС ограничивала доступ к ней, кроме программы который инициализировал эту память?
Ответ: да (см. в конце) и нет.
Думаю, вы здесь неправильно это понимаете. Более подходящий вопрос будет, например, почему не malloc
инициализирует память по запросу или очищает память при выпуске, но вместо этого перерабатывает ее?
Ответ заключается в том, что разработчики API явно решили не инициализировать (или очистить память), как это делают для больших блоков памяти 1) повлияют на производительность, а 2) не всегда необходимы (например, вы не можете заниматься в своей заявке или несколько частей вашего приложения с данными, которые вам действительно нравятся, если они открыты). Поэтому дизайнеры решили не делать этого, так как это непреднамеренно повлияло бы на производительность и бросить мяч программисту, чтобы принять решение об этом.
Таким образом, перенося это также в ОС, почему ответственность за очистку страниц должна зависеть от ОС? Вы ожидаете, что ваша ОС своевременно передает вам память, но безопасность зависит от программиста.
Сказав, что существует некоторый механизм, который можно использовать, чтобы убедиться, что конфиденциальные данные не хранятся в свопе, используя mlock в Linux.
mlock() и mlockall() соответственно блокируют часть или все вызывающие обрабатывать виртуальное адресное пространство в ОЗУ, предотвращая эту память от подкачки к области подкачки. munlock() и munlockall() выполнить обратную операцию, соответственно разблокирующую часть или все виртуального адресного пространства вызывающего процесса, так что страницы в указанный диапазон виртуальных адресов может снова быть заменен, если требуемый диспетчером памяти ядра. Блокировка и разблокировка памяти выполняются в единицах целых страниц.
Ответ 2
Да, по крайней мере, в системах, где данные могут передаваться внешним пользователям.
Произошла целая серия атак на веб-серверы (и даже на iPod), где вы можете сбрасывать содержимое памяти из другого процесса - и поэтому получите подробную информацию о типе и версии ОС, данных в других приложениях и даже такие вещи, как таблицы паролей
Ответ 3
Вполне возможно выполнить некоторую чувствительную работу в области памяти и не очистить этот буфер.
Затем будущий вызов может извлечь эту неочищенную работу с помощью вызова malloc()
или путем проверки кучи (через объявление unitiaised buffer/array). Он может проверить его (злонамеренно) или непреднамеренно скопировать. Если вы делаете что-то чувствительное, поэтому имеет смысл очистить эту память до ее бинирования (memset()
или аналогичного) и, возможно, перед использованием/копированием.
Ответ 4
Из стандарта C:
6.7.8 Инициализация
"Если объект, который имеет автоматическую продолжительность хранения, не инициализируется явно, его значение неопределенно."
неопределенное значение определяется как:
either an unspecified value or a trap representation.
Представление Trap определяется как:
Определенные представления объектов не обязательно должны представлять значение тип объекта. Если хранимое значение объекта имеет такое значение представления и считывается выражением lvalue, которое не имеет характер, поведение не определено. Если такое представление созданный побочным эффектом, который модифицирует всю или любую часть объекта выражением lvalue, которое не имеет типа символа, поведение не определено .41) Такое представление называется ловушкой представление.
Доступ к таким значениям приводит к поведению undefined и может представлять угрозы безопасности.
Эта статья Атаки на неинициализированные переменные может дать некоторое представление о том, как они могут использоваться для использования системы.
Ответ 5
Если вы обеспокоены безопасностью, самым безопасным способом является всегда инициализировать каждую переменную, которую вы собираетесь использовать. Это может даже помочь вам найти некоторые ошибки.
Могут быть некоторые веские причины не инициализировать память, но в большинстве случаев инициализация каждой переменной/памяти будет хорошей.