
Plugin do IDA Pro para pesquisa baseada em consultas dentro do binário, útil principalmente para pesquisa de vulnerabilidades.
A ferramenta VulFi (Vulnerability Finder) é um plugin para o IDA Pro que pode ser usado para auxiliar na caça de bugs em binários. Seu principal objetivo é fornecer uma visão única com todas as referências cruzadas para as funções mais interessantes (como strcpy, sprintf, system, etc.). Para casos onde um decompilador Hexrays pode ser usado, ele tentará descartar chamadas a essas funções que não são interessantes do ponto de vista de pesquisa de vulnerabilidades (pense em algo como strcpy(dst,"Hello World!")). Sem o decompilador, as regras são muito mais simples (para não depender de arquitetura) e, portanto, descartam apenas os casos mais óbvios.
Veja Changelog para mais informações sobre atualizações.
Coloque os arquivos vulfi.py, vulfi_prototypes.json e vulfi_rules.json na pasta de plugins do IDA (cp vulfi* <IDA_PLUGIN_FOLDER>).
Antes de executar o VulFi, certifique-se de que você tenha um bom entendimento do binário com o qual está trabalhando. Tente identificar todas as funções padrão (strcpy, memcpy, etc.) e nomeie-as adequadamente. O plugin não diferencia maiúsculas de minúsculas e, portanto, MEMCPY, Memcpy e memcpy são nomes válidos. No entanto, observe que a busca pela função requer correspondência exata. Isso significa que memcpy? ou std_memcpy (ou qualquer outra variante) não serão detectados como uma função padrão e, portanto, não serão considerados ao procurar por vulnerabilidades potenciais. Se você estiver trabalhando com um binário desconhecido, você precisa primeiro definir as opções do compilador em Options > Compiler. Depois disso, o VulFi fará o possível para filtrar todos os falsos positivos óbvios (como chamadas para printf com uma string constante como primeiro parâmetro). Observe que, embora o plugin seja feito sem vínculos com uma arquitetura específica, alguns processadores não têm suporte completo para especificar tipos e, nesse caso, o VulFi simplesmente marcará todas as referências cruzadas para funções padrão potencialmente perigosas, permitindo que você prossiga com a análise manual. Nesses casos, você pode se beneficiar dos recursos de rastreamento do plugin.
Para iniciar a varredura, selecione a opção Search > VulFi no menu da barra superior. Isso iniciará uma nova varredura ou lerá resultados anteriores armazenados no arquivo idb/i64. Os dados são salvos automaticamente sempre que você salva o banco de dados.
Assim que a varredura for concluída ou os resultados anteriores forem carregados, uma tabela será apresentada com uma visão contendo as seguintes colunas:
Not Checked é atribuído a cada novo item. Os outros status são False Positive, Suspicious e Vulnerable. Eles podem ser definidos usando o menu de clique direito em um determinado item e devem refletir os resultados da revisão manual da chamada de função em questão.High, Medium e Low (também Info para casos em que o scanner não conseguiu identificar todos os parâmetros corretamente). As prioridades são definidas juntamente com outras regras no arquivo vulfi_rules.json.Caso não haja dados dentro do arquivo idb/i64 ou o usuário decida realizar uma nova varredura. O plugin perguntará se deve executar a varredura usando as regras padrão incluídas ou se deve usar um arquivo de regras personalizado. Observe que executar uma nova varredura com dados já existentes não sobrescreve os itens encontrados anteriormente identificados pela regra com o mesmo nome daqueles com resultados armazenados anteriormente. Portanto, executar a varredura novamente não exclui comentários existentes e atualizações de status.

No menu de contexto de clique direito dentro da visão do VulFi, você também pode remover o item dos resultados ou remover todos os itens. Observe que quaisquer comentários ou atualizações de status serão perdidos após realizar esta operação.
A partir da versão 2.1, o VulFi também suporta operações realizadas em múltiplos itens selecionados de uma só vez. Isso permite que vários itens sejam marcados com um determinado status, excluídos ou o mesmo comentário adicionado a várias linhas. Às vezes acontece que a operação não atualiza corretamente. Quando isso ocorrer, atualize a interface do usuário (Ctrl+U) algumas vezes até que as alterações sejam refletidas.
Sempre que você quiser inspecionar a instância detectada de uma possível função vulnerável, basta clicar duas vezes em qualquer lugar da linha desejada e o IDA o levará ao local de memória que foi identificado como potencialmente interessante. Usando o clique direito e a opção Set Vulfi Comment, você pode inserir um comentário para a instância (para justificar o status, por exemplo).
O plugin também permite criar regras personalizadas. Essas regras podem ser definidas na interface do IDA (ideal para funções únicas) ou fornecidas como um arquivo de regras personalizado (ideal para regras que visam cobrir múltiplas funções).
Quando você quiser rastrear uma função personalizada, identificada durante a análise, clique com o botão direito em qualquer lugar dentro do corpo dela e selecione Add <name> function to VulFi. Você também pode destacar e clicar com o botão direito em um nome de função na visão atual de desmontagem/decompilador para evitar mudar para o corpo da função.

Também é possível carregar um arquivo personalizado com um conjunto de múltiplas regras. Para criar um arquivo de regras personalizado com a estrutura abaixo, você pode usar o arquivo de modelo incluído aqui.
[ // An array of rules
{
"name": "RULE NAME", // The name of the rule
"function_names":[
"function_name_to_look_for" // List of all function names that should be matched against the conditions defined in this rule
],
"wrappers":true, // Look for wrappers of the above functions as well (note that the wrapped function has to also match the rule)
"mark_if":{
"High":"True", // If evaluates to True, mark with priority High (see Rules below)
"Medium":"False", // If evaluates to True, mark with priority Medium (see Rules below)
"Low": "False" // If evaluates to True, mark with priority Low (see Rules below)
}
}
]
Um exemplo de regra que procura todas as referências cruzadas para a função malloc e verifica se seu parâmetro não é constante e se o valor de retorno da função é verificado é mostrado abaixo:
{
"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 - Marca todos os loops. Nesse caso, param[0] é o contador do loop (se detectado) e param[1] é a condição contra a qual o contador é verificado para terminar o loop.Array Access - Marca todos os acessos a arrays. Nesse caso, param[0] é o array e param[1] é o índice.As mesmas funções podem ser usadas ao criar regras como para parâmetros normais de função (qualquer coisa que possa ser chamada em param[<index>]).
param[<index>]: Usado para acessar o parâmetro de uma chamada de função (índice começa em 0)function_call: Usado para acessar o evento de chamada de funçãoparam_count: Contém a contagem de parâmetros que foram passados para uma funçãoparam[<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: Low. Esta é uma forma de evitar perder referências cruzadas onde não foi possível obter todos os parâmetros corretamente (isso se aplica principalmente ao modo de desmontagem).Ctrl+U para atualizar manualmente a visão (algumas vezes).not param[1].is_constant() and not param[1].used_in_call_before(["strlen"])read: function_call.reachable_from("read")