Вирусом называется самовоспроизводящаяся часть кода (подпрограмма), которая встраивается в носители (другие программы) для своего исполнения и распространения. Вирус не может исполняться и передаваться без своего носителя.
Червём называется самовоспроизводящаяся отдельная (под-)программа, которая может исполняться и распространяться самостоятельно, не используя программу-носитель.
Первой вехой в изучении компьютерных вирусов можно назвать 1949 год, когда Джон фон Нейман прочёл курс лекций в Университете Иллинойса под названием «Теория самовоспроизводящихся машин» (изданы в 1966[80], переведены на русский язык издательством «Мир» в 1971 году[129]), в котором ввёл понятие самовоспроизводящихся механических машин. Первым сетевым вирусом считается вирус Creeper 1971 г., распространявшийся в сети ARPANET, предшественнице Интернета. Для его уничтожения был создан первый антивирус Reaper, который находил и уничтожал Creeper.
Первый червь для Интернета, червь Морриса, 1988 г., уже использовал смешанные атаки для заражения UNIX машин[34, 99]. Сначала программа получала доступ к удалённому запуску команд, эксплуатируя уязвимости в сервисах sendmail, finger (с использованием атаки на переполнение буфера) или rsh. Далее, с помощью механизма подбора паролей червь получал доступ к локальным аккаунтам пользователей:
получение доступа к учётным записям с простыми паролями:
без пароля вообще;
имя аккаунта в качестве пароля;
имя аккаунта в качестве пароля, повторённое дважды;
использование «ника» (англ. nickname);
фамилия (англ. last name, family name);
фамилия, записанная задом наперёд;
перебор паролей на основе встроенного словаря из 432 слов;
перебор на основе системного словаря /usr/dict/words.
Программной уязвимостью называется свойство программы, позволяющее нарушить её работу. Программные уязвимости могут приводить к отказу в обслуживании (Denial of Service, DoS-атака), утечке и изменению данных, появлению и распространению вирусов и червей.
Одной из распространённых атак для заражения персональных компьютеров является переполнение буфера в стеке. В интернет-сервисах наиболее распространённой программной уязвимостью в настоящее время является межсайтовый скриптинг (Cross-Site Scripting, XSS-атака).
Наиболее распространённые программные уязвимости можно разделить на классы:
Переполнение буфера – копирование в буфер данных большего размера, чем длина выделенного буфера. Буфером может быть контейнер текстовой строки, массив, динамически выделяемая память ит. д. Переполнение становится возможным вследствие либо отсутствия контроля над длиной копируемых данных, либо из-за ошибок в коде. Типичная ошибка – разница в 1 байт между размерами буфера и данных при сравнении.
Некорректная обработка (парсинг) данных, введённых пользователем, является причиной большинства программных уязвимостей в веб-приложениях. Под обработкой понимаются:
проверка на допустимые значения и тип (числовые поля не должны содержать строки ит. д.);
фильтрация и экранирование специальных символов, имеющих значения в скриптовых языках или применяющихся для перекодирования из одной текстовой кодировки в другую. Примеры символов: , , , , ", ';
фильтрация ключевых слов языков разметки и скриптов. Примеры: script, JavaScript;
перекодирование различными кодировками при парсинге. Распространённый способ обхода системы контроля парсинга данных состоит в однократном или множественном последовательном кодировании текстовых данных в шестнадцатеричные кодировки NN ASCII и UTF-8. Например, браузер или веб-приложения производят $n$-кратное перекодирование, в то время как система контроля делает $k$-кратное перекодирование, $0 \leq k < n$, и, следовательно, пропускает закодированные запрещённые символы и слова.
Некорректное использование функций. Например, printf(s) может привести к уязвимости записи в память по указанному адресу. Если злоумышленник вместо обычной текстовой строки введёт в качестве s "текст некоторой длиныn", то функция printf, ожидающая первым аргументом строку формата fmt, обнаружив n, возьмёт значение из ячеек памяти, находящихся перед ячейками с указателем на текстовую строку (устройство стека описано далее), и запишет в память по адресу, равному считанному значению, количество выведенных символов на печать функцией printf.