
Плагин для IDA Pro для поиска на основе запросов внутри бинарного файла, полезный в основном для исследования уязвимостей.
Инструмент VulFi (Vulnerability Finder) представляет собой плагин для IDA Pro, который можно использовать для помощи в поиске уязвимостей в бинарных файлах. Его основная цель — предоставить единое представление со всеми перекрёстными ссылками на наиболее интересные функции (такие как strcpy, sprintf, system и т.д.). В случаях, когда доступен декомпилятор Hexrays, он попытается отсеять вызовы этих функций, которые не представляют интереса с точки зрения исследования уязвимостей (например, strcpy(dst,"Hello World!")). Без декомпилятора правила гораздо проще (чтобы не зависеть от архитектуры), поэтому отсеиваются только самые очевидные случаи.
См. Список изменений для получения дополнительной информации об обновлениях.
Поместите файлы vulfi.py, vulfi_prototypes.json и vulfi_rules.json в папку плагинов IDA (cp vulfi* <IDA_PLUGIN_FOLDER>).
Перед запуском VulFi убедитесь, что вы хорошо понимаете бинарный файл, с которым работаете. Постарайтесь идентифицировать все стандартные функции (strcpy, memcpy и т.д.) и назвать их соответствующим образом. Плагин нечувствителен к регистру, поэтому MEMCPY, Memcpy и memcpy — все являются допустимыми именами. Однако обратите внимание, что поиск функции требует точного совпадения. Это означает, что memcpy? или std_memcpy (или любой другой вариант) не будут распознаны как стандартная функция и, следовательно, не будут учитываться при поиске потенциальных уязвимостей. Если вы работаете с неизвестным бинарным файлом, сначала необходимо установить параметры компилятора: Options > Compiler. После этого VulFi сделает всё возможное, чтобы отфильтровать все очевидные ложные срабатывания (например, вызов printf с константной строкой в качестве первого параметра). Обратите внимание: хотя плагин создан без привязки к конкретной архитектуре, некоторые процессоры не имеют полной поддержки указания типов, и в таких случаях VulFi просто отметит все перекрёстные ссылки на потенциально опасные стандартные функции, чтобы вы могли продолжить ручной анализ. В этих случаях вы можете воспользоваться функциями отслеживания плагина.
Чтобы запустить сканирование, выберите пункт Search > VulFi из верхнего меню. Это либо запустит новое сканирование, либо загрузит предыдущие результаты, сохранённые в файле idb/i64. Данные автоматически сохраняются при сохранении базы данных.
После завершения сканирования или загрузки предыдущих результатов будет представлена таблица со столбцами:
Not Checked. Другие статусы: False Positive, Suspicious и Vulnerable. Их можно задать с помощью контекстного меню (правый клик) на элементе, и они должны отражать результаты ручного просмотра данного вызова функции.High, Medium и Low (также Info для случаев, когда сканеру не удалось корректно определить все параметры). Приоритеты определяются вместе с другими правилами в файле vulfi_rules.json.Если в файле idb/i64 нет данных или пользователь решил выполнить новое сканирование, плагин спросит, следует ли запускать сканирование с использованием включённых по умолчанию правил или использовать собственный файл правил. Обратите внимание: повторное сканирование с уже существующими данными не перезаписывает ранее найденные элементы, идентифицированные правилом с тем же именем, что и правило, с которым сохранены предыдущие результаты. Таким образом, повторное сканирование не удаляет существующие комментарии и обновления статуса.

В контекстном меню (правый клик) в представлении VulFi вы также можете удалить элемент из результатов или удалить все элементы. Учтите, что все комментарии и обновления статуса будут потеряны после выполнения этой операции.
Начиная с версии 2.1, VulFi также поддерживает операции, выполняемые сразу над несколькими выбранными элементами. Это позволяет отмечать несколько элементов определённым статусом, удалять их или добавлять одинаковый комментарий к нескольким строкам. Иногда бывает, что операция не обновляется корректно. В таких случаях обновите интерфейс (Ctrl+U) несколько раз, пока не увидите изменения.
Всякий раз, когда вы хотите проверить обнаруженный экземпляр возможной уязвимой функции, просто дважды щёлкните в любом месте нужной строки, и IDA перенесёт вас в то место в памяти, которое было определено как потенциально интересное. Используя правый клик и опцию Set Vulfi Comment, вы можете ввести комментарий для данного экземпляра (например, чтобы обосновать статус).
Плагин также позволяет создавать пользовательские правила. Эти правила могут быть определены в интерфейсе IDA (идеально для отдельных функций) или предоставлены в виде файла пользовательских правил (идеально для правил, охватывающих несколько функций).
Если вы хотите отслеживать пользовательскую функцию, обнаруженную в ходе анализа, щёлкните правой кнопкой мыши в любом месте её тела и выберите Add <name> function to VulFi. Вы также можете выделить и щёлкнуть правой кнопкой мыши имя функции в текущем представлении дизассемблера/декомпилятора, чтобы не переключаться в тело функции.

Также можно загрузить пользовательский файл с набором нескольких правил. Чтобы создать файл пользовательских правил со структурой, приведённой ниже, вы можете использовать прилагаемый файл шаблона здесь.
[ // Массив правил
{
"name": "RULE NAME", // Имя правила
"function_names":[
"function_name_to_look_for" // Список всех имён функций, которые должны быть сопоставлены с условиями, определёнными в этом правиле
],
"wrappers":true, // Также искать обёртки для указанных выше функций (обратите внимание, что обёрнутая функция также должна соответствовать правилу)
"mark_if":{
"High":"True", // Если вычисляется как True, отметить с приоритетом High (см. Правила ниже)
"Medium":"False", // Если вычисляется как True, отметить с приоритетом Medium (см. Правила ниже)
"Low": "False" // Если вычисляется как True, отметить с приоритетом Low (см. Правила ниже)
}
}
]
Пример правила, которое ищет все перекрёстные ссылки на функцию malloc и проверяет, не является ли её параметр константой и проверяется ли возвращаемое значение функции, показан ниже:
{
"name": "Possible Null Pointer Dereference",
"function_names":[
"malloc"
],
"wrappers":false,
"mark_if":{
"High":"not param[0].is_constant() and not function_call.return_value_checked()",
"Medium":"False",
"Low": "False"
}
}
Loop Check — Отмечает все циклы. В этом случае param[0] — это счётчик цикла (если обнаружен), а param[1] — условие, с которым сравнивается счётчик для завершения цикла.Array Access — Отмечает все обращения к массивам. В этом случае param[0] — это массив, а param[1] — индекс.Те же функции можно использовать при создании правил, как и для обычных параметров функций (всё, что можно вызвать для param[<index>]).
param[<index>]: Используется для доступа к параметру вызова функции (индекс начинается с 0)function_call: Используется для доступа к событию вызова функцииparam_count: Содержит количество параметров, переданных функцииparam[<index>].is_constant()param[<index>].number_value()param[<index>].string_value()param[<index>].set_to_null_after_call()function_call.return_value_checked(<constant_to_check>)param[<index>].used_in_call_<before|after>(["function1","function2"])function_call.reachable_from("<function_name>")param[<index>].is_sign_compared()param[<index>].used_as_index()param[2].number_value() > 5"%s" in param[1].string_value()not param[1].is_constant()function_call.return_value_checked(param_count)function_call.return_value_checked()all(not p.is_constant() for p in param[2:])any(p.is_constant() for p in param)Truestrlen: not param[1].is_constant() and not param[1].used_in_call_before(["strlen"])Low. Это способ избежать пропуска перекрёстных ссылок, когда не удалось корректно получить все параметры (в основном это относится к режиму дизассемблера).Ctrl+U, чтобы вручную обновить представление (несколько раз).read: function_call.reachable_from("read")