
LINKSYS AC1900 EA7500v3 IGD UPnP Stack Buffer Overflow Remote Code Execution Vulnerability
Esta vulnerabilidade permite que atacantes adjacentes à rede executem código arbitrário em instalações afetadas de roteadores LINKSYS EA7500. Não é necessária autenticação para explorar esta vulnerabilidade.
A falha específica existe no tratamento dos dados de requisições HTTP para o serviço IGD UPnP. Ao analisar o conteúdo de uma variável fornecida pelo usuário em uma determinada Solicitação de Ação SOAP UPnP, o processo não valida adequadamente o comprimento dos dados fornecidos pelo usuário antes de copiá-los para um buffer de pilha de tamanho fixo. Um atacante pode explorar esta vulnerabilidade para executar código no contexto de root.
Produto/Firmware: Linksys EA7500 Firmware TODAS AS VERSÕES incluindo Ver. 3.0.1.207964 - Outros modelos de roteadores e versões de firmware que usam este binário também são afetados
O binário do serviço UPnP IGD está localizado em /usr/sbin/IGD e é executado por padrão na porta 49152. Este serviço fornece o arquivo de descrição UPnP XML IGDdevicedesc.xml que detalha várias funções que podem ser invocadas usando requisições HTTP com um corpo XML.
Uma dessas funções é SetDefaultConnectionService. Esta função requer uma variável do tipo string. Quando a função SetDefaultConnectionService é invocada e executada, o programa não valida o comprimento da variável fornecida pelo usuário antes de
realizar uma chamada strncpy envolvendo este buffer. Tanto o endereço de origem quanto as variáveis de tamanho de cópia da chamada strncpy são controlados pelo usuário, sendo o tamanho da cópia o comprimento da variável fornecida pelo usuário.
Os dados são então copiados para um buffer fixo de 184 bytes, levando a uma vulnerabilidade de estouro de buffer de pilha.
A função SetDefaultConnectionService é rotulada como _set_connection_type. A função começa inicializando um buffer de 184 bytes e então obtém um ponteiro para o buffer que contém a variável string fornecida pelo usuário incluída na requisição, se não for NULL. Isso é feito chamando PAL_xml_node_GetFirstbyName e depois PAL_xml_node_get_value. Veja o código abaixo:
int _set_connection_type(int **param_1)
{
int iVar1;
char *var_value;
size_t var_value_length;
undefined uVar2;
undefined1 *puVar3;
char **ppcVar4;
undefined4 *puVar5;
char *pcVar6;
int *piVar7;
char acStack_d4 [184]; -----> /* Inicializando buffer de 184 bytes */
memset(acStack_d4,0,0xb4);
iVar1 = PAL_xml_node_GetFirstbyName((*param_1)[0xf0],"NewConnectionType",0); -----> /* iVar1 agora aponta para o valor fornecido pelo usuário */
if ((iVar1 != 0) && (var_value = (char *)PAL_xml_node_get_value(), var_value != (char *)0x0)) { -----> /* Garante que o valor fornecido pelo usuário não está vazio e obtém um ponteiro para ele */
...
Mais adiante na mesma função, uma chamada strlen é realizada para obter o tamanho da string fornecida pelo usuário mais um deslocamento estático de 0x174. A condição vulnerável é acionada na chamada strncpy subsequente, onde o argumento de destino é o endereço do buffer de 184 bytes recém-inicializado, a origem é o ponteiro para a string fornecida pelo usuário, e o tamanho da operação de cópia é o tamanho da string fornecida pelo usuário retornado pela chamada strlen mais um deslocamento estático de 0x174. Isso leva a uma vulnerabilidade de estouro de buffer, pois tanto o endereço de origem quanto as variáveis de tamanho são controlados pelo usuário e nenhuma verificação de validação de tamanho é realizada. Veja o código abaixo:
int _set_connection_type(int **param_1)
{
...
var_value_length = strlen((char *)(iVar1 + 0x174)); ----> /* iVar1 é um ponteiro para a string fornecida pelo usuário */
strncpy(acStack_d4,(char *)(iVar1 + 0x174),var_value_length + 1); ----> /* Chamada strncpy vulnerável */
...
O deslocamento para sobrescrever um endereço de retorno de função na pilha é de 276 bytes. Os próximos 4 bytes podem ser utilizados para redirecionar a execução para um endereço arbitrário e, assim, sequestrar o fluxo de controle do programa.
Use uma função de cópia de string mais segura: Em vez de usar strncpy, que não garante a terminação nula do buffer de destino, uma função de cópia de string mais segura pode ser usada, como strncpy_s ou memcpy_s. Essas funções garantem que o buffer de destino seja sempre terminado em nulo e não permitem a cópia de mais dados do que o buffer pode suportar.
Validação de entrada: Valide a entrada do usuário para garantir que ela não exceda o tamanho do buffer de destino. Se a entrada for maior que o tamanho do buffer, rejeite-a ou trunque-a para caber dentro do buffer.
Use um buffer alocado dinamicamente: Aloque memória para o buffer de destino dinamicamente em vez de usar um buffer de pilha de tamanho fixo. Esta abordagem permite que o tamanho do buffer seja ajustado de acordo com o tamanho dos dados de entrada. (Não recomendado para um sistema com recursos limitados)
Execução do PoC: python poc.py 192.168.1.1 49152
Link para Download do Software: https://support.linksys.com/kb/article/559-en/ (Versão de firmware Ver. 3.0.1.207964)
gdbserver-7.7.1-armel-eabi5-v1-sysv disponível aqui: https://github.com/stayliv3/gdb-static-cross/tree/master/prebuilt).pkill IGD para encerrar o binário e depois relance-o usando ./gdbserver :1337 /usr/sbin/IGD. O seguinte arquivo .gdbinit pode ser usado para iniciar uma sessão de depuração estável:> set follow-fork-mode child
> set detach-on-fork off
> target remote 192.168.1.1:1337
> c