Этот текст является подробным комментарием к статье «Я использовал GPT-3, чтобы найти 213 уязвимостей безопасности в одной кодовой базе».
Для лучшего понимания обсуждаемой темы было бы желательно, если бы вы сначала прочитали статью Криса Коха: Я использовал GPT-3, чтобы найти 213 уязвимостей безопасности в одной кодовой базе. Я уже написал к нему длинный комментарий. Потом решил написать еще один. На этот раз я решил изложить свои мысли в виде полного поста.
Не разделяю энтузиазма автора. Наши испытания с ChatGPT дали гораздо более скромные и сомнительные результаты, о которых вы можете прочитать в статье: Достаточно ли хорош ChatGPT для обнаружения ошибок в коде?.
GPT-3, похоже, очаровал автора статьи, поскольку автор считает ответы бота правильными, даже если они неверны. Это может объяснить, почему автор утверждает, что GPT-3 почти не давал ложных срабатываний. Конечно, это не даст нам ложных срабатываний, если мы не хотим их замечать :)
Что делает меня таким скептиком? Думаю, в статье показаны лучшие примеры того, как работает GPT-3. На самом деле автор вряд ли выбрал слабые примеры :). Однако даже в этих тщательно отобранных образцах, демонстрирующих возможности GPT-3, есть несколько незамеченных ложных срабатываний.
Давайте посмотрим на первый пример.
int main(int argc, char **argv) { printf(argv[1]);
Со вторым сообщением согласен:
Уязвимость строки формата: программа не проверяет формат вводимых пользователем данных, что может привести к атаке с использованием строки формата.
Здесь можно поспорить с формулировкой. Нет необходимости проверять ввод пользователя. В качестве альтернативы мы можем просто использовать printf по-другому. Предупреждение GPT-3 отстает от документации традиционных статических анализаторов, вот пример для сравнения: V618. Что ж, давайте посмотрим на первое предупреждение, которое немного интереснее.
Непроверенный пользовательский ввод: программа не проверяет длину пользовательского ввода, что может привести к атаке переполнения буфера.
На мой взгляд, это ложное срабатывание. Количество аргументов (переменной argc) не проверяется. Вот ошибка: массив argv может выйти за пределы. Пока GPT-3 начинает рассуждать о переполнении буфера. Конечно, можно было бы сказать, что это одно и то же… Ну, тогда бот мог бы просто сказать: «Произошла ошибка». Если есть реальная ошибка, то вам повезло. Если его нет, ну это жизнь :) Когда программисты говорят о переполнении буфера? Когда они работают со строкой, заканчивающейся нулем, учитывают неправильное использование функций strcat, memcpy и других.
Ладно, может быть, эти ложные срабатывания были недостаточно убедительны. Давайте теперь рассмотрим третий фрагмент кода и сообщение, которое он вызывает:
fp = fopen(filename,"r"); if(fp == NULL) { printf("\nCan't open file or file doesn't exist."); exit(0); }
Непроверенное возвращаемое значение. Возвращаемое значение функции fopen() не проверяется, что может привести к разыменованию нулевого указателя.
В первой версии статьи автор написал, что права была ГПТ-3. Затем был постскриптум, показывающий, что этот конкретный случай был ложным срабатыванием. Спасибо внимательным читателям, отметившим неисправность. На самом деле, если присмотреться, вся магия полезных сообщений GPT-3 пропадает. Хочу еще больше испортить впечатление :).
Снова обратимся к третьему примеру:
char OOBR_stack = buff3[size3+100]; char OOBR_heap = buff4[100];
Неинициализированный доступ к памяти. Доступ к переменным OOBR_stack и OOBR_heap осуществляется без инициализации, что может привести к неопределенному поведению.
Какая ерунда. Вот инициализация. Эти переменные ни в коем случае нельзя считать неинициализированными. Другое дело, что массив выходит за границы из-за инициализации, но в GPT-3 об этом ничего не сказано. GPT-3 также ошибается, когда сообщает о доступе к неинициализированным переменным OOBR_stack и OOBR_heap. Эти переменные нигде не используются.
Хотя это предупреждение кажется умным и полезным, на самом деле оно не имеет смысла. То же самое, скорее всего, справедливо и для других ошибок, не упомянутых в статье.
Кстати, GPT-3 молчит как минимум о двух других неисправностях в том же примере.
free(buff1); // <= if (size1/2==0){ free(buff1); // <= } else{ if(size1 == 123456){ buff1[0]='a'; // <= } }
Во-первых, память может снова освободиться. Во-вторых, возможна запись в уже освобожденный буфер. На самом деле, чем больше мы смотрим на код, тем больше недостатков мы можем найти в предупреждениях, выдаваемых GPT-3.
P.S. С моей точки зрения, называть все уязвимостью слишком претенциозно. Те, что обсуждаются в статье, являются простыми ошибками. Некоторые из них могут быть потенциальными уязвимостями, но не более того. Если обнаруженную уязвимость можно использовать, то да, уязвимость существует. В противном случае это просто ошибка, а их тысячи в любом приложении :). Я точно знаю, что эти баги есть везде. С помощью PVS-Studio мы нашли более 15 000 ошибок в open source проектах. Но мы не называем эти баги уязвимостями — это было бы преувеличением.
Вот еще несколько полезных ссылок: