Этот текст является подробным комментарием к статье «Я использовал 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 проектах. Но мы не называем эти баги уязвимостями — это было бы преувеличением.

Вот еще несколько полезных ссылок: