Análise do concurso IDS Bypass no Positive Hack Days 9

O fórum internacional do Positive Hack Days 2019 sediou o primeiro concurso IDS Bypass. Os participantes tiveram que examinar um segmento de rede de cinco nós, explorar a vulnerabilidade do serviço ou cumprir a condição especificada (por exemplo, enviar uma resposta HTTP específica) e, assim, obter o sinalizador. Encontrar uma exploração foi fácil, mas o IDS complicou a tarefa: o sistema ficou entre participantes e nós e verificou todos os pacotes de rede. Os invasores viram no painel se a assinatura bloqueou a conexão. Abaixo, mostrarei detalhadamente as tarefas em si e analisarei sua solução.



100.64.0.11 - Struts


O primeiro nó no número daqueles que resolveram a tarefa foi Struts. Após a varredura das portas do Nmap, encontramos o serviço Apache Struts na porta 8080.

# nmap -Pn -sV -p1-10000 100.64.0.11 631/tcp open ipp CUPS 2.1 8005/tcp open mxi? 8009/tcp open ajp13 Apache Jserv (Protocol v1.3) 8080/tcp open http Apache Tomcat/Coyote JSP engine 1.1 



A vulnerabilidade do Apache Struts desapareceu em 2017: usando a injeção de OGNL, um invasor pode executar qualquer código no Struts sem autorização. Há uma exploração, por exemplo, no GitHub , mas o IDS é capturado:

[Drop] [**] [1:1001:1] Apache Struts2 OGNL inj in header (CVE-2017-5638) [**]

O código de assinatura em si não está disponível para os participantes, mas a partir da mensagem nos logs você pode entender o mecanismo de sua operação. Nesse caso, a assinatura detectou uma injeção de OGNL no HTTP:

 GET /showcase.action HTTP/1.1 Accept-Encoding: identity Host: 100.64.0.11:8080 Content-Type: %{(#_='multipart/form-data')... 

Se examinarmos o comportamento do IDS, ficará óbvio que ele captura a combinação% {no início do cabeçalho Content-Type. Existem várias soluções:

  1. O participante @empty_jack tentou quebrar a combinação de caracteres% {com seu próprio dicionário de fuzzing e, assim, chegou a uma solução com a linha Content-Type:% $ {.
  2. Confunda a própria solicitação HTTP. O membro @ c00lhax0r descobriu que o caractere nulo no início do cabeçalho também ignoraria o IDS: Content-Type: \ 0 $ {.
  3. A maioria das explorações do CVE-2017-5638 faz uma injeção com um símbolo de porcentagem. Mas alguns pesquisadores desta e das vulnerabilidades anteriores do Apache Struts escrevem que a injeção pode começar com% e $. Portanto, a combinação de $ {ignorará a assinatura do IDS e executará o código no sistema. Essa decisão foi concebida inicialmente.

Essa tarefa foi a mais fácil, foi decidida por oito participantes.

100.64.0.10 - Solr


Na porta 8983 estava o servidor Apache Solr, escrito em Java.

 $ nmap -Pn -sV -p1-10000 100.64.0.10 22/tcp open ssh (protocol 2.0) 8983/tcp open http Jetty 



É fácil encontrar uma exploração do Apache Solr 5.3.0 - CVE-2019-0192 . Um invasor pode falsificar o endereço de um servidor RMI em uma coleção. A operação requer a estrutura ysoserial, que gera cadeias de objetos Java (gadgets) e as entrega de várias maneiras. Por exemplo, de um servidor JRMP.

Obviamente, usando a exploração da testa na testa, os participantes verão as assinaturas do IDS disparando:

[Drop] [**] [1:10002700:3001] ATTACK [PTsecurity] Java Object Deserialization RCE POP Chain (ysoserial Jdk7u21) [**]

O Jdk7u21 é apenas uma das trinta cargas e sua escolha depende das bibliotecas usadas no serviço vulnerável. A cadeia de dispositivos Jdk7u21 usa apenas as classes padrão do Java Development Kit versão 7u21, e a cadeia CommonsCollections1 contém classes das amplamente usadas Apache Common Collections 3.1.

O invasor substitui o endereço do servidor RMI na coleção Solr pelo seu próprio e, em seguida, inicia o servidor JRMP. Solr solicita um objeto em um endereço e recebe um objeto Java malicioso. Após sua desserialização, o código é executado no servidor.

A assinatura é acionada em uma sequência de classes em um objeto Java serializado. É transmitido da máquina do atacante e no tráfego começa assim:



A solução para esse problema era simples. A assinatura refere-se explicitamente a Jdk7u21. Para contornar isso, você tinha que tentar outras cadeias de gadgets. Por exemplo, uma das CommonsCollections. Não havia assinaturas para outras cadeias no IDS. O participante receberá um shell no sistema e lerá a bandeira. Cinco participantes completaram a tarefa.

100.64.0.12 - SAMR


Uma das tarefas mais difíceis e interessantes da competição. Esta é uma máquina Windows com uma 445ª porta aberta. O sinalizador é dividido nos nomes de dois usuários do sistema e, para concluir a tarefa, era necessário obter uma lista de todos os usuários no nó do Windows.

Obviamente, o MS17-010 e outras explorações não funcionaram nesta máquina. Os usuários enumerados podem, por exemplo, scripts do Nmap ou da estrutura do impacket :

 $ python samrdump.py 100.64.0.12 Impacket v0.9.15 - Copyright 2002-2016 Core Security Technologies [*] Retrieving endpoint list from 100.64.0.12 [*] Trying protocol 445/SMB… Found domain(s): . SAMR . Builtin [*] Looking up users in domain SAMR [-] The NETBIOS connection with the remote host timed out. [*] No entries received. 

Ambos os cenários fazem solicitações de DCERPC para a máquina na porta 445. Mas nem tudo é tão simples: alguns pacotes são bloqueados pelo IDS e, desta vez, duas assinaturas são acionadas:

[**] [1:2001:2] SAMR DCERPC Bind [**]
[Drop] [**] [1:2002:2] SAMR EnumDomainUsers Request [**]

O primeiro detecta uma conexão com o serviço SAMR e sinaliza apenas a conexão TCP com um sinalizador. E o segundo é acionado pela solicitação EnumDomainUsers para o serviço SAMR. Este serviço tem outras maneiras de obter usuários: QueryDisplayInfo, QueryDisplayInfo2, QueryDisplayInfo3. Todos eles também foram bloqueados por assinaturas.

O protocolo DCERPC e os serviços do Windows oferecem enormes oportunidades para o gerenciamento remoto de sites. Este protocolo é usado pela maioria das ferramentas conhecidas, como PsExec ou BloodHound. O serviço SAMR, ou seja, SAM Remote Protocol, permite trabalhar com contas no host, incluindo a lista de usuários.

Para solicitar o EnumDomainUsers Impacket, faça o seguinte:



Uma conexão DCERPC ao serviço SAMR é estabelecida pelo SMB e todas as solicitações adicionais entram no contexto deste serviço. As assinaturas funcionam no primeiro e no último pacote da captura de tela.

Dei duas pistas para a tarefa:

  • Suas tentativas fazem com que o IDS gere 2 alertas. Olhe atentamente para o primeiro.
  • Quais comandos de conexão para este protocolo você conhece?

É sobre o protocolo DCERPC e como estabelecer conexões. Na lista de PDUs disponíveis, os comandos Vincular e Alterar Contexto são responsáveis ​​por conectar e alterar o contexto, e o segundo permite alterar o contexto atual sem interromper a conexão.

Para resolvê-lo, foi necessário reescrever a lógica do script samrdump:

  1. Torne Vincular a outro serviço, por exemplo, com UUID 3919286a-b10c-11d0-9ba8-00c04fd92ef5.
  2. Use Alterar contexto para alternar para o SAMR.
  3. Enviar solicitação para EnumDomainUsers.

As alterações se encaixam em três linhas:

 < dce.bind(samr.MSRPC_UUID_SAMR) --- > dce.bind(uuid.uuidtup_to_bin(("3919286a-b10c-11d0-9ba8-00c04fd92ef5", "0.0"))) > dce.alter_ctx(samr.MSRPC_UUID_SAMR) > dce._ctx = 1 

Uma solução alternativa foi proposta pelo vencedor do concurso @ psih1337. A consulta EnumDomainUsers retornou uma lista de usuários não por nome, mas por SID (ID de segurança). SID não é um número aleatório. Por exemplo, a conta LocalSystem possui o SID S-1-5-18 e, para usuários criados manualmente, inicia em 1000.

Assim, classificando manualmente as sementes de 1000 a 2000, é muito provável que encontre as contas desejadas no sistema. Eles foram encontrados sob os sids 1008 e 1009.

A solução para esta tarefa exigiu um entendimento do protocolo DCERPC e experiência na pesquisa de infra-estruturas do Windows. @ psih1337 foi o único que decidiu.

100.64.0.13 - DNSCAT


Na porta 80, há uma página da web com um formulário para um endereço IP.



Se você especificar seu IP, o UDP chegará à porta 53:

 17:40:45.501553 IP 100.64.0.13.38730 > 100.64.0.187: 61936+ CNAME? dnscat.d2bc039ce800000000d6eae8eae3bf81fd84d1695f5888aba8dcec06d071.a73b3f0561ca4906d268214f4b70da1bdb50f75739ae0577139096732bf8.0d0a987ce23408bac15426a22e. (173) 17:40:45.501639 IP 100.64.0.187 > 100.64.0.13: ICMP 100.64.0.187 udp port domain unreachable, length 209 17:40:46.520457 IP 100.64.0.13.38730 > 100.64.0.187: 21842+ TXT? dnscat.7f4e039ce800000000d6eae8eae3bf81fd84d1695f5888aba8dcec06d071.a73b3f0561ca4906d268214f4b70da1bdb50f75739ae0577139096732bf8.0d0a987ce23408bac15426a22e. (173) 17:40:46.520546 IP 100.64.0.187 > 100.64.0.13: ICMP 100.64.0.187 udp port domain unreachable, length 209 


Claramente, este é DNSCAT, uma ferramenta para túneis DNS. Depois de especificar o endereço IP no formulário, um cliente DNSCAT tenta estabelecer uma conexão com ele. Se isso der certo, o servidor (ou seja, o participante) receberá um shell na máquina competitiva e puxará a bandeira.

Obviamente, se apenas aumentarmos o servidor DNSCAT e tentarmos aceitar a conexão, falharemos:

[Drop] [**] [1:4001:1] 'dnscat' string found in DNS response [**]

A assinatura do IDS é acionada na linha dnscat no tráfego do nosso servidor - isso está claramente indicado na mensagem. Ofuscar ou criptografar o tráfego também não funcionará.

Observando o código do cliente, descobrimos que as verificações nele não são suficientemente rígidas. Ou seja, a linha dnscat pode não aparecer na resposta! Resta apenas removê-lo do código ou substituí-lo rapidamente com o utilitário NetSED. Substituir imediatamente é muito mais fácil, mas ainda darei um patch para o código do servidor:

 diff -r dnscat2/server/libs/dnser.rb dnscat2_bypass/server/libs/dnser.rb < segments << unpack("a#{len}") > segments << [unpack("a#{len}")[0].upcase] < name.split(/\./).each do |segment| > name.upcase.split(/\./).each do |segment| diff -r dnscat2/server/tunnel_drivers/driver_dns.rb dnscat2_bypass/server/tunnel_drivers/driver_dns.rb < response = (response == "" ? "dnscat" : ("dnscat." + response)) > response = (response == "" ? "dnsCat" : ("dnsCat." + response)) 

Havia cinco soluções para esta tarefa na competição.

100.64.0.14 - POST


A bandeira deste veículo do concurso não foi recebida por ninguém.



Vemos um formulário familiar com um endereço IP. Alguém nos oferece a participação no teste de um novo malware. Entre suas inovações, está contornando o IDS de maneira desconhecida. Para o sinalizador, você só precisa enviar o cabeçalho HTTP "Server: ng1nx" em resposta. Vai fazer calor.

Como esperado: recebemos uma solicitação GET em nosso IP e enviamos uma resposta bloqueada pelo IDS.

[Drop] [**] [1:5002:1] 'ng1nx' Server header found. Malware shall not pass [**]

Há uma dica:

Às vezes, as tarefas que parecem difíceis são as mais simples. Se nada parece vulnerável, talvez você esteja perdendo algo bem debaixo do seu nariz?

Algo vulnerável diante do nosso nariz é o IDS. Na página de resposta, você pode descobrir que temos um IDS Suricata aberto.



O primeiro link na consulta "Suricata IDS Bypass" leva ao CVE-2018-6794 . Essa vulnerabilidade permite ignorar a inspeção de pacotes se o curso normal da comunicação TCP (handshake TCP) for violado e os dados forem enviados antes da conclusão do processo. É assim:

 Client -> [SYN] [Seq=0 Ack=0] -> Evil Server # 1/2 Client <- [SYN, ACK] [Seq=0 Ack=1] <- Evil Server # 2/2 Client <- [PSH, ACK] [Seq=1 Ack=1] <- Evil Server # Data here Client <- [FIN, ACK] [Seq=83 Ack=1] <- Evil Server Client -> [ACK] [Seq=1 Ack=84] -> Evil Server # 3/2 Client -> [PSH, ACK] [Seq=1 Ack= 4] -> Evil Server 

Faça o download da exploração, altere a linha para "ng1nx", desative os pacotes RST do kernel e execute.

Como já mencionado, ninguém recebeu as bandeiras desta máquina, embora alguns participantes estivessem perto de uma solução.

Conclusão


49 participantes inscritos na competição, 12 passaram pelo menos uma bandeira. É interessante que tarefas competitivas possam ter várias soluções ao mesmo tempo, especialmente tarefas com o protocolo SMB e DCERPC. Talvez você tenha suas próprias idéias para concluir algumas tarefas?

Prémios:

  • 1º lugar: @ psih1337
  • 2º lugar: @ webr0ck
  • 3º lugar: @empty_jack

Estatísticas de resposta de assinatura:



Obrigado a todos os participantes! No próximo ano, haverá ainda mais tarefas de diferentes níveis de dificuldade.

Postado por Kirill Shipulin, Positive Technologies

Source: https://habr.com/ru/post/pt457932/


All Articles