int main(int argc, char* argv[])

{

  printf(argv[1]);

}

Запуск такой программы с параметром %s%s%s%s%s может привести к ее сбою.

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

Целочисленное переполнение.

Для представления целочисленных переменных используется фиксированный объем памяти (для современных систем обычно это 32 или 64 бита). Соответственно диапазон значений, которые может принимать целочисленная переменная, ограничен. При попытке инкрементировать переменную, достигшую своего максимального значения, она будет сброшена т. е. приравнена к нулю.

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

Ошибки с целочисленными знаковыми.

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

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

НЕ нашли? Не то? Что вы ищете?
Ошибки завышения или занижения на единицу.

Подобная ошибка обычно возникает, когда размер записанных в буфер данных на единицу превышает его емкость. Для некоторых архитектур (в их числе наиболее распространенная Intel x86) это может привести к выполнению произвольного кода в случае, когда буфер расположен в памяти непосредственно перед указателем кадра или указателем на функцию. Уязвимый код:

void func(char* s)

{

  char buffer[100];

  memset(buffer, 0, sizeof(buffer));

  strncat(buffer, s, sizeof(buffer));

}

В данном случае не учитывается тот факт, что фактический размер строки в Си превышает количество символов (каждая строка содержит нулевой байт в конце).

Переполнение кучи.

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

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

Использование после освобождения.

Рассмотрим следующий код:

void func()

{

  int* n = new int;

  delete n;

  *n = 123;

}

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

Состояние гонки.

Состояние гонки – это ошибка проектирования приложения в многозадачной среде, при которой работа программы зависит от порядка и времени выполнения частей кода. Пример:

if (!access(tempfile, W_OK)) {

  fp = fopen(tempfile, “a+”);

  …

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

Отказ в обслуживании.

Отказ в обслуживании (denial of service, DoS), так же как и распределенный отказ в обслуживании (DDoS), это действие, направленное на перегрузку системы или службы до такой степени, когда она будет не в состоянии обрабатывать поступающие запросы. Наиболее известным примером такой атаки является SYN flood – отправка большого количества пакетов на установление TCP соединения, что вызывает потребление всех доступных ресурсов системы.

Отказ в обслуживании возможен также и на прикладном уровне. Злоумышленник, обнаруживший в коде веб-сервера переполнение буфера, которое невозможно эксплуатировать для выполнения произвольного кода, может использовать его для аварийного завершения процесса. Однако, такой подход будет несколько нерациональным.

Уязвимости веб-приложений.

В связи с непрерывным развитием сети Интернет все большую значимость приобретает вопрос безопасности веб-приложений. Атаки происходят повсеместно, им подвергаются и системы интернет-банкинга, и корпоративные ресурсы, и просто популярные сайты с целью распространения с их помощью вредоносного ПО. Поэтому специалисты в данной области широко востребованы.[4]

Рассмотрим наиболее известные классы уязвимостей, которым подвержены веб-приложения.

PHP-инъекция.

PHP - один из наиболее популярных языков программирования, используемых для создания динамических веб-страниц. РНР-инъекции позволяют атакующему выполнить произвольный код на уязвимом веб-сервере. Пример:

include($page. ‘somefile. php’);

Если злоумышленник выполнит запрос вида:

http:///index. php? page=http:///

То произойдет загрузка и исполнение веб-сервером файла, содержание которого контролируется атакующим.

SQL-инъекция.

Большинство приложений для получения информации из базы данных использует запросы на языке SQL. В случае, когда проверка корректности входных данных реализована неверно либо отсутствует, и эти данные используются в качестве параметра в SQL-запросе, атакующий может получить несанкционированный доступ к информации либо нарушить процесс аутентификации. В определенных конфигурациях SQL-инъекция может привести к выполнению произвольного кода на удаленной системе. Рассмотрим код:

$query = “SELECT * FROM users WHERE name = ‘” + $user + “’”;

Если злоумышленник в качестве параметра $user передаст следующую строку:

‘ or ‘a’=’a

В результате запрос, обработанный СУБД, будет выглядеть как

SELECT * FROM users WHERE name = ‘’ or ‘a’=’a’

что позволит обойти аутентификацию так как второе условие всегда истинно.

Межсайтовое выполнение скриптов.

Самый распространенный метод, который применяют злоумышленники для получения прав другого пользователя на определенном веб?ресурсе, - это использование межсайтового выполнения скриптов (cross site scripting, XSS). Данный вид уязвимостей так же, как и предыдущие, связан с недостаточной фильтрацией входных данных, в данном случае элементов языка HTML и кода JavaScript.

Существует два основных класса подобных уязвимостей: отраженные и хранимые. Отраженные представляют собой выполнение в контексте атакованного приложения кода, включенного в текст запроса (например, в одном из параметров URL?адреса). Для успешного выполнения атаки жертва должна перейти по специально сформированной ссылке. В случае, если ошибка относится ко второму, наиболее опасному классу, внедряемый злоумышленником код хранится на сервере и исполняется браузером каждого пользователя, который зашел на уязвимую страницу.

Методы обнаружения уязвимостей.

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

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

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

Далее каждый тип будет рассмотрен более подробно.

Принцип «белого ящика». Аудит исходного кода.

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

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

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

Инструменты автоматизации.

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

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5