ANTICHAT.XYZ    VIDEO.ANTICHAT.XYZ    НОВЫЕ СООБЩЕНИЯ    ФОРУМ  
Баннер 1   Баннер 2
Antichat снова доступен.
Форум Antichat (Античат) возвращается и снова открыт для пользователей. Здесь обсуждаются безопасность, программирование, технологии и многое другое. Сообщество снова собирается вместе.
Новый адрес: forum.antichat.xyz
Вернуться   Форум АНТИЧАТ > ИНФО > Статьи > Авторские статьи
   
 
 
Опции темы Поиск в этой теме Опции просмотра

Недостатки форматной строки.
  #1  
Старый 19.11.2009, 14:43
Kerny
Познающий
Регистрация: 18.11.2009
Сообщений: 30
Провел на форуме:
86200

Репутация: 17
Отправить сообщение для Kerny с помощью ICQ
По умолчанию Недостатки форматной строки.

Недостатки форматной строки.

Строка форматирования в языке С++, и ему подобных используется множеством программистов, по всему миру, вообще это одно из самых удобных средств форматирования выводимых данных, но и за удобство приходится платить, как и все остальное это решение придумано и реализовано человеком, а посему не лишено недостатков (как сказали в одном фильме: «Наше совершенство в нашем несовершенстве»)

http://ru.wikipedia.org/wiki/Printf

printf - обобщённое название семейства функций или методов стандартных или широкоизвестных коммерческих библиотек, или встроенных операторов некоторых языков программирования, используемых для форматного вывода — вывода в различные потоки
значений разных типов, отформатированных согласно заданному шаблону. Этот шаблон определяется составленной по специальным правилам строкой (форматной строкой).



Немного о вводе.

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

char user[13];
char pass[13];
gets(&user[0]);
gets(&pass[0]);


Фрагмент кода кажется безопасным и правильным, но на самом деле его выполнение может привести к критическим последствиям, как минимум отказ в обслуживание, как максимум захват контроля на ПК, который использует уязвимое приложение(если оно сетевое, и выше приведенный фрагмент кода , есть ничто иное как просьба авторизоваться), все дело тут в том что функция Gets, никак не проверяет количество символов введенных пользователем, для переменных выделяется по 13 байт, а если пользователь вводит больше символов, чем запланировано, то они выходят за границы буфера и затирают находящиеся за ним значения (Другие переменные, иногда даже участки кода, если user и pass, объявлены локально, то они хранятся в стеке, а как следствие, можно затереть и адрес возврата из функции, что позволяет, выполнить атаку Срыв стека). Ошибка тут вовсе не программиста, а непосредственно разработчиков функции (не сделали проверки).


Вот аналог выше приведенного кода на Delphi (Object Pascal)

var
user:string[13];
pass:string[13];
begin
readln(user);
readln(pass);
end;

Этот код полностью безопасен в отличие от своего собрата на языке С++, функция которая читает введенные пользователем данные(readln) получает в регистре ecx значение размера буфера, затем сохраняет его и сравнивает с количеством введенным пользователем символов, и берет только первые символы пока не кончится буфер. Что - бы защититься от данной «проблемы» достаточно использовать безопасный аналог функции gets, а именно fgets.


char user[13];
char pass[13];
fgets(&user[0],13,stdin);
fgets(&pass[0],13,stdin);


Защита от переполнения функции Read/Readln в Delphi



Читаем стек.

Теперь перейдем непосредственно к форматной строке:

#include "stdafx.h"
int main()
{
char str[17];
fgets(&str[0],17,stdin);
printf(&str[0]);
}

С первого взгляда все в порядке, но тут кроется одна большая неприятность, если запустить
проект и ввести в поле ввода %x %x %x, то в консоль выведется вовсе не это, а 241fe4 12f7bc 7ffdd000


(У вас результат может отличаться и даже должен, это как повезет)



Обратим внимание на текст, который мы вводим, вообще — то он эквивалентен записи:

printf(“%x %x %x”);

Откомпилируйте проект и снова увидите нечто подобное первому результату, получается что мы как — бы «обманываем программу» (не находите, очень похоже на sql – инъекцию)

%x — говорит о том, что нужно достать значение из стека, и записать в буфер, а из буфера вывести на экран (ну а вообще-то переводит переменную типа int в строку).

Нормальный расклад таков:

printf(“%x %x %x”,a,b,c);

Где а,b,c – некоторые переменные, тогда на экран будут выведены значения этих переменных.

Состояние стека при нормальном раскладе:



Погрузившись в отладчике в printf, мы понимаем, что произошло, когда мы не передали ни каких аргументов, но передали три спецификатора, это значит ей нужно распечатать три аргумента, она «не знает», что аргументов ей не дали и поэтому достает их с того места где по ее мнению они должны быть.






Состояние стека, когда аргументы не были переданы:


На месте Случайных данных, должны быть переменные, но мы их не передали, следовательно, там «валяется» разная информация - значение других переменных, адреса возврата, и т.д. Таким образом, мы получаем возможность читать значения в стеке, где при чрезмерном везение оказываются пароли и всякая полезная для взломщика информация.

Читаем код программы.

Помимо %x, у printf существует еще огромная куча спецификаторов, один из них %s, спецификатор %s указывает на строку, то есть в переменной хранится адрес, нате данные, которые нужно вывести, запустите предыдущий пример и введите %s. Посмотрим, что произошло.


Мы считали данные по адресу 7C910208, потому что функция «подумала» - это аргумент. А теперь задумаемся, что если — бы мы могли заменить этот аргумент, на свой собственный, например на адрес точки входа в программу? Да мы получили бы код программы до первого попавшегося ноля, т.к ноль завершает строку, но это не всегда возможно, как повезет.

Перезапись ячейки памяти.

Спецификатор %n, для этого как раз и предназначен, запускайте и вводите, 2222%%x%x%x%x%n, %x - «возьмут на себя» те ячейки, в которые запись запрещена, если все же попытаться записать туда, то произойдет исключение и программа «упадет», мы же записываем по адресу 12ff50, а туда запись разрешена...


Спецификаторы очень опасная вещь, хотя и очень удобна в использование, в Object Pascal ничего подобного нет и от этого программирование на нем уже более безопасно, вместо спецификаторов там используются функции, например строка

printf(“%x ”,a);

На Delphi выглядит так:

write(inttostr(a));

Можно понять, что тут используется функция inttost(), и по-моему такое решение гораздо удачливее. Как же защититься? Можно, например, фильтровать вводимые пользователем данные, как это делается в случае с sql-инъекцией, но это было - бы полным идиотизмом, лучше

printf(str);

Заменить на

printf(”%s”,str);

И все будет ок...

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

sa-sec.org
(с)Kerny

Жду ваших отзывов.

p.s Здесь я не сравнивал Delphi и C так, что базар по этому поводу не разводить.
 
Ответить с цитированием
 



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как убицца ап стену. Инструкция. .::f-duck::. Болталка 2 16.06.2009 23:25
Процесс создания программного обеспечения для распределенных вычислений (С++). c0n Difesa Авторские статьи 9 09.06.2009 16:33
Assembler FAQ GlobalRave С/С++, C#, Delphi, .NET, Asm 2 15.02.2009 18:59
конец строки Mastermind PHP, PERL, MySQL, JavaScript 15 18.08.2005 00:28



Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT.XYZ