Короче говоря, недостатки форматной строчки

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

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

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

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

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

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

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

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

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

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

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

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

С первого взора все в норме, хотя здесь часто скрывается 1 вправду великая проблема, коль скоро запустить план и правильно использовать в поле ввода %x %x %x, то в консоль выведется решительно не данное, а

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

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

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

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

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

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

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

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

Состояние стека при обычном подходе:

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

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

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

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

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

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

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

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

printf(“%x ”,a);

На Pascal смотрится так:

write(inttostr(a);

Можно взять в толк, что здесь употребляется функция inttost(), и по моему мнению это решение во много раз успешнее.

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

printf(str); С другой стороны заменитьprintf(”%s”,str);

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

SASecurity gr.

Возник вопросец в последствии чтения? Или создатель не обрисовал актуальный эпизод?Есть что заявить на данную тему, а объяснение - данное не твое?

Тогда Go на наш форум .

Общайтя на темы ИТ непринужденно, стремительно развивайся и повествуй свежее иным! Мы станем счастливы принять тебя в нашу фирму

Теги:

Оставить комментарий