The words you are searching are inside this book. To get more targeted content, please make full-text search by clicking here.
Discover the best professional documents and content resources in AnyFlip Document Base.
Search
Published by , 2017-02-23 10:15:38

Secure_Coding

Secure_Coding

6.4. Рандомизация стека 1 315

0 9 a l ready_wri t ten %= O x l O O O O ;
10
1 1 width_field = { w r i te_word- a l ready_w r i t ten ) % O x l O O O O ;
1 2 if ( width_field < 1 0 ) width_field += Oxl O O O O ;
1 3 sprint f ( conver t_spec , 11 % % %du % % n " , width_fiel d ) ;
1 4 s t rcat ( format_s t r , conve rt_spec ) ;
15
1 6 / / Последнее слово
17 a l ready_wri tten += width field;
18 write word = Ох0 8 0 4 ;
1 9 a l ready_wri t ten %= O x l O O O O ;
20
2 1 width__field = ( w r i t e_wo rd- a l ready_w r i t ten ) % Ox l O O O O ;
2 2 i f ( w i dth_ f i e l d < 1 0 ) width__field += Ox l O O O O ;
2 3 sprin t f ( conve r t_spe c , 11 % % % du % % n " , width_field) ;
2 4 s t rcat ( format_s t r , conve rt_spec ) ;

Непосредственный доступ к аргументу

POSIX [ 1 1 5 ] разрешает применение преобразования к п-му после формата аргументу
в списке аргументов, а не к очередному неиспользованному аргументу. 1 1 В данном слу­
чае символ спецификатора преобразования % заменяется последовательностью %n$, где n
представляет собой десятичное число в диапазоне [ 1 , { NL_ARGМAX } ] , которое указывает
позицию аргумента.

Формат может содержать как нумерованные (например, %n$ и *m$) , так и ненумерован­
ные (например, % и * ) спецификации преобразования аргументов, но не оба одновременно
(исключением является одновременное использование % % и % n $ ) . Одновременное исполь­
зованное в строке формата нумерованных и ненумерованных спецификаций аргументов
имеет неопределенные результаты. При использовании нумерованных спецификаций ар­
гументов указание n-ro аргумента требует, чтобы в строке формата были указаны все пре­
дыдущие аргументы, от первого до п - 1 -го.

В строке формата, содержащей спецификацию преобразования вида %n$, обращаться
к нумерованным аргументам в списке аргументов из строки формата можно любое коли­
чество раз.

В примере 6. 1 1 показано, как спецификация преобразования вида %n$ может использо­
ваться для эксплойта строки формата. Строка формата в строке 4 выглядит сложной, пока
не разобрана по частям. Первая спецификация преобразования, % 4 $ 5u, берет четвертый
аргумент ( константу 5 ) и форматирует вывод как десятичное число шириной 5. Вторая
спецификация преобразования, % 3 $ n, записывает текущее значение счетчика вывода (5)
по адресу) указанному в качестве третьего аргумента ( & i) . Затем этот шаблон повторяется
дважды. В итоге вызов p r int f ( ) в строках 3-6 приводит к выводу чисел 5, 6 и 7 в столб­
цах шириной по 5 символов. Вызов p rint f ( ) в строке 8 выводит значения, присвоенные
переменным i, j и k, которые представляют собой увеличивающиеся значения счетчика
вывода из предыдущего вызова функции printf ( ) .

1 1 Строки преобразования в стиле % n $ поддерживаются в Linux, но не в Visual С++. Это не удиви­
тельно, поскольку стандарт С не включает непосредственный доступ к аргументам.

1316 Форматированный вывод

Пример 6.1 1 . Непосредствен ный доступ к параметру

О1 int i , j , k = О ;
02
03 printf (
0 4 " % 4 $ 5u%3$n% 5 $ 5u%2 $n% 6 $ 5u % 1 $ n\n" ,
05 &k, &j , &i, 5, 6, 7
06 ) ;
07
08 printf ( " i %d, j %d, k %d\n" , i, j , k) ;
09
1 0 Вывод :
11 5 6 7
12 i = 5, j = 10, k = 15

Номер аргумента n в спецификации преобразования % n $ должен быть целым числом
между 1 и максимальным номером аргумента, предоставленного вызову функции. Некото­
рые реализации предоставляют верхнюю границу этого значения, например, в виде конс­
танты NL ARGМAX. В GCC фактическое значение времени выполнения может быть получе­
но с помощью вызова sysconf ( ) .

int rnax_va lue = s ys con f ( _SC_NL_ARGМAX ) ;

Некоторые системы (например, System V) имеют малую верхнюю границу, такую как 9.
Библиотека GNU С реальной границы не имеет. Максимальное значение в Red H at 9 Linux
равно 4 096.

Эксплойт, показанный в примерах 6 . 1 0 и 6. 1 1 , можно легко изменить для применения
непосредственного доступа к аргументам. Строки 1 7- 1 9 из примера 6.9 можно удалить.
Новый код для вычисления з аписанной части строки формата показан в примере 6. 12.
Изменения внесены только в строки 13 и 23 (замена спецификаций формата используе­
мыми при непосредственном доступе к аргументам ) и в строку 5 (удаление спецификаций
преобразования %х изменяет количество байтов, записанных в выходной поток) .

П ример 6. 1 2. Запись памяти с использованием непосредствен ного доступа к а ргументам

01 s tatic unsigned int a l ready_wri t ten , width f i e l d ;

02 static uns igned int write_word;

03 s tatic char conve rt_spec [ 2 5 6 ] ;

04

05 already_written = 1 6 ;
06

0 7 / / Первое слово

08 write wo rd = О х 9 0 2 0 ;

0 9 a l ready_wr i t ten % = O x l O O O O ;

10

1 1 width_field = ( wr i te word- al ready_wri t ten ) % O x l O O O O ;

1 2 i f ( width_f ield < 1 0 ) width_f ie l d += O x l O O O O ;

1 3 sprint f ( conve rt_spec , " % % 4 $ % du% % 5 $n " , width_ f i e l d ) ;

1 4 s t rcat ( forrna t_s tr , conve r t_spec ) ;

15

1 6 / / Последнее слово

1 7 a l ready_wr i t ten += wi dth field;

18 write word = Ох0 8 0 4 ;

1 9 already_wr itten %= O x l O O O O ;

20

6.5. Стратегии противодействия 1 317

2 1 w i dth_f i e l d = ( wr i te_wo rd-al ready_wri t ten ) % Oxl O O O O ;
2 2 i f ( wi dth_f ield < 1 0 ) w i dth_f i e l d += O x l O O O O ;
2 3 sprint f ( convert__s pec , " % % 6 $ % du % % 7 $ n " , width_field ) ;
2 4 s t rcat ( forma t_s t r , conve r t_spe c )

• 6.5. Стратегии противодействия

Многие разработчики, узнавая об опасности спецификатора преобразования %n, спра­
шивают: "А не могут ли они (разработчики библиотек ввода-вывода) попросту от него изба­
виться?" Некоторые реализации, такие как Microsoft Visual Studio, по умолчанию отключают
спецификатор преобразования %n, предоставляя функцию set_printf_count_output ( )
для его включения при необходимости. К сожалению, поскольку спецификатор преобра­
зования %n давно и хорошо известен, его удаление приведет к неработоспособности боль­
шого количества существующего кода. Однако для предотвращения уязвимостей строки
формата можно прибегнуть к ряду стратегий противодействия.

Исключение пользовательского ввода из строк формата

Просто следуйте рекомендации "FIOЗO-C. Исключите пользовательский ввод из строк
формата" ( The CERT С Secure Coding Standard [ 1 86 ] ) .

Динамическое применение статического содержимого

Еще одно общее предложение для устранения уязвимости строк формата - запрет ис­
пользования динамических строк формата. Если все строки формата статические, уязви­
мость строки формата невозможна (за исключением тех случаев переполнения буфера, ког­
да целевой массив символов недостаточно ограничен) . Однако такое решение невозможно,
поскольку динамические строки формата широко используются в существующем коде.

Альтернативой стратегии динамического формата является динамическое использова­
ние статического содержимого. В примере 6. 1 3 показана простая программа, которая умно­
жает первый аргумент на второй. Программа также принимает третий аргумент, который
указывает, как отформатировать результат при выводе. Если третий аргумент является
строкой hex, произведение отображается в шестнадцатеричном формате с использованием
спецификатора преобразования % х; в противном случае оно отображается как десятичное
число с помощью спецификатора преобразования %d.

П ример 6.1 3. Динамические строки формата

0 1 # include <stdio . h>
0 2 # i ncl ude < s t r i ng . h>
03
0 4 i n t rnai n ( i nt a rgc , char * a rgv [ ] )
05 int х, у;
О б s t a t i c cha r forma t [ 2 5 6 ] = " % d * % d = " ;
07
0 8 х = atoi ( a rgv [ l ] ) ;
0 9 у = atoi ( argv [ 2 ] ) ;
10
1 1 i f ( s t r cmp ( a rgv [ 3 ] , " hex" ) == 0 ) {
1 2 s t rcat ( fo rma t , " 0 x%x \ n " ) ;
13
14 else {

1318 Форматированный вывод

1 5 s t rcat ( fo rmat , " %d\ n " ) ;
16
1 7 p�intf ( format , х , у , х * у ) ;
18

1 9 exit ( 0 ) ;
20

Если не обращать внимание н а очевидное и явно опасное отсутствие любой проверки
входных данных, эта программа безопасна в смысле эксплойтов строки формата. Програм­
мисты также должны предпочитать функцию strtol ( ) функции atoi ( ) (см. рекоменда­
цию The CERT С Secure Coding Standard [ 1 86] , "INT06-C. Используйте функцию s trtol ( )
или родственные ей для преобразования строкового токена в целое число") . Хотя поль­
зователи могут влиять на содержимое строки формата, им не предоставляется полный
контроль над ней. Такое динамическое использование статического содержимого является
хорошим подходом к решению проблемы динамических строк формата.

Хотя это и неправильное решение, этот пример программы можно легко переписать с
использованием статических строк формата. Это облегчит состояние аудиторов по безо­
пасности, которым иначе будет требоваться определить, является ли безопасным исполь­
зование динамических строк формата.

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

Ограничение количества записанных байтов

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

Количество байтов, записываемых функциями, можно ограничить с помощью поля
точности, являющегося ч астью спецификации преобразования % s . Например, вместо

sprint f ( bu ffe r , "Wrong com.rnand : % s \ n " , u s er ) ;

попробуйте написать

sprint f (bu ffe r , "Wrong com.rnand : % . 4 9 5 s \ n " , user ) ;

Поле точности указывает максимальное количество байтов, записываемое специфика­
тором преобразования % s. В данном примере статическая строка требует 1 7 байтов (вклю­
чая завершающий нулевой байт) , и точность 495 гарантирует, что получающаяся строка
разместится в 5 1 2-байтном буфере.

Другой подход заключается в использовании более безопасных версий функций библи­
отеки форматированного вывода, которые менее подвержены переполнениям буфера (на­
пример, snprint f ( ) и vsnp r i n t f ( ) как альтернативы spr i nt f ( ) и vspri n t f ( ) ). Эти
функции указывают максимальное количество выводимых байтов, включая завершающий
нулевой байт.

Всегда важно знать, какие функции и какие версии функций используется во время вы­
полнения. Например, библиотека Linux libc4. [45 ] не имеет функции snpr i nt f ( ) . Однако
дистрибутив Linux содержит библиотеку l ibbsd, в которой имеется функция snprint f ( ) ,
игнорирующая аргумент размера. Следовательно, использование s np r i nt f ( ) с ранней
библиотекой libc4 может привести к серьезным проблемам безопасности. Если вы не счи­
таете это проблемой, прочтите врезку ''Сокращения программирования'>.








































































Click to View FlipBook Version