O código fonte do .NET está em constante evolução e sua equipe de desenvolvimento está atenta as questões de Cyber Security, no entanto, classes legadas como o BinaryFormatter continuam a apresentar vulnerabilidades exploráveis por atacantes. Nesta análise, discutiremos a vulnerabilidade crítica associada ao BinaryFormatter registrada pelos códigos CVE-2023-32737, CWE-502, e CA2300 (você pode ler mais nos links), destacando o que são esses problemas, como eles impactam a segurança, e as melhores práticas para mitigá-los.
O BinaryFormatter é uma classe do .NET Framework utilizada para serializar e desserializar objetos em formato binário, facilitando o armazenamento ou a transferência de dados complexos. No entanto, devido à forma como o BinaryFormatter trata dados durante a desserialização, ele pode ser suscetível a ataques de desserialização inseguros, onde entradas maliciosas podem executar códigos arbitrários e comprometer a segurança da aplicação.
O CVE-2023-32737 é um identificador específico para uma vulnerabilidade do tipo “desserialização insegura” encontrada no BinaryFormatter. Ele indica que a manipulação de dados serializados possibilita a exploração da classe, permitindo que códigos realizem ações inesperadas e potencialmente maliciosas no ambiente de execução da aplicação.
O CWE-502 refere-se à categoria “Desserialização de Dados Não Confiáveis”. Essa classificação indica que uma vulnerabilidade ocorre quando dados maliciosos são desserializados, o que pode desencadear execuções de código indesejadas. Em outras palavras, o processamento de dados de entrada potencialmente perigosos pode ameaçar a segurança do sistema e comprometer sua integridade.
O CA2300 recomenda evitar o processamento direto de dados não confiáveis, garantindo maior segurança no sistema. Esse aviso serve para alertar desenvolvedores durante o processo de construção do software, sinalizando o uso de práticas inseguras, como a desserialização direta de dados de fontes desconhecidas.
Ao utilizar o BinaryFormatter, aplicações correm o risco de receber objetos binários maliciosos que, durante a desserialização, podem executar código indesejado. Essa vulnerabilidade representa uma séria ameaça, pois permite a elevação de privilégios ou a execução de comandos remotamente, comprometendo a integridade do sistema.
Por ser uma biblioteca amplamente utilizada e inclusa no .NET Framework (não confundir com .NET Core, onde o uso do BinaryFormatter já é desaconselhado e possui suporte limitado), muitos sistemas podem ser alvos potenciais, especialmente os que interagem com dados de fontes externas.
Como parte das melhores práticas, os desenvolvedores podem considerar o uso de serializadores seguros e específicos para os dados e cenários em questão. Algumas das alternativas recomendadas incluem:
Imagine o cenário onde recebemos via API, dados formatados usando o BinaryFormatter, ou seja, não temos domínio sobre o client mas apenas da API que deserializa esses dados tambem usando o BinaryFormatter.
Este caso categoriza o problema de segurança pois podemos receber um código malicioso entre esses dados. Como podemos resolver nosso lado sem quebrar o contrato com os consumidores de nossas APIs?
Uma opção é usar o NrbfDecoder, uma biblioteca disponível no NuGet. Na data de escrita deste artigo, ela ainda permanece em Release Candidate, embora a Microsoft já a considere em “produção”. Isso ocorre porque sua API ainda deve passar por uma grande atualização.
Vamos explorar abaixo uma solução de desserialização com o NrbfDecoder mencionado anteriormente.
Considere que a classe abaixo foi serializada com BinaryFormatter e recebemos uma MemoryStream contendo esta classe.
public class Employee
{
public int Id { get; set; }
public List<string> Roles { get; set; }
}
Vamos ao codigo que desserializa:
...
// Valida se a MemoryStream pode ser desserializada
if (NrbfDecoder.StartsWithPayloadHeader(memoryStream))
{
memoryStream.Position = 0;
// Decodifica a instancia de uma classe que não seja um Array ou tipo primitivo
ClassRecord decodedClass = NrbfDecoder.DecodeClassRecord(memoryStream);
// Iterando sobre as propriedades para fazer bind pelo nome
foreach (var memberName in decodedClass.MemberNames)
{
if (memberName.Equals(nameof(employee.Id))
{
// Lidando com tipos primitivos
employee.Id = decodedClass.GetInt32(memberName);
}
if (memberName.Equals(nameof(employee.Roles))
{
var complexDecoded = decodedClass.GetClassRecord(memberName);
// Identifico o tipo para trata-lo corretamente
if (complexDecoded.TypeName.FullName.Contains("List[[System.String]]"))
{
var listDecoded = complexDecoded.GetArrayRecord("_items")
.GetArray(expectedArrayType: typeof(string));
foreach (var item in listDecoded)
{
// Se for tipo primitivo
if (item is not ClassRecord)
{
employee.Roles.Add(item);
}
// Caso não seja tipo primitivo aqui seguimos decodificando as
// classes ou arrays conforme fizemos anteriormente.
}
}
}
}
// Ao final temos uma instancia da classe Employee desserializada
Embora o BinaryFormatter seja uma ferramenta poderosa no .NET, ele se tornou uma fonte de risco devido à sua suscetibilidade à desserialização insegura, dessa forma a vulnerabilidade identificada pelo CVE-2023-32737 e categorizada em CWE-502 destaca a necessidade de adotar práticas seguras de serialização e controle de dados. Por isso, a Microsoft e a comunidade .NET recomendam substituir o BinaryFormatter por métodos de serialização mais seguros, protegendo assim as aplicações e prevenindo que explorações comprometam a integridade do sistema.
Um Novo Começo para um Programador experiente em linguagens Orientadas a Objeto Após programar em…
Este blog utiliza cookies. Se você continuar assumiremos que você está satisfeito com ele.
Leia Mais...