Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
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.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
Ferramentas/GitHubGitHub/bazad/ctl_ctloutput-leak
Forensia de MemóriaAnálise de VulnerabilidadesExploraçãoColeta de InformaçõesExploração de Binários
GitHubbazad/ctl_ctloutput-leak

ctl_ctloutput-leak

CVE-2017-13868: Vazamento de informações de dados não inicializados do heap do kernel no XNU.

Ver Repositório
2752há 8 anosRevisado pelo Kitploit

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

ctl_ctloutput-leak

A função ctl_ctloutput no macOS High Sierra 10.13 ignora o valor de retorno de uma chamada a sooptcopyin, o que abre uma janela de corrida para vazar dados não inicializados do heap do kernel para o espaço do usuário. ctl_ctloutput-leak é uma prova de conceito que tenta desencadear esse vazamento de informações. A exploração requer privilégios de root.

Essa exploração foi confirmada para funcionar no macOS High Sierra 10.13.1 Beta 17B25c e no iOS 10.1.1 14B100 (sob mach_portal).

A vulnerabilidade: CVE-2017-13868

Aqui está a parte relevante de ctl_ctloutput no macOS High Sierra 10.13:

root@kitploit:~
if (sopt->sopt_valsize && sopt->sopt_val) {
	MALLOC(data, void *, sopt->sopt_valsize, M_TEMP,	// (a) data is allocated
		M_WAITOK);					//     without M_ZERO.
	if (data == NULL)
		return (ENOMEM);
	/*
	 * 4108337 - copy user data in case the
	 * kernel control needs it
	 */
	error = sooptcopyin(sopt, data,				// (b) sooptcopyin() is
		sopt->sopt_valsize, sopt->sopt_valsize);	//     called to fill the
}								//     buffer; the return
len = sopt->sopt_valsize;					//     value is ignored.
socket_unlock(so, 0);
error = (*kctl->getopt)(kctl->kctlref, kcb->unit,		// (c) The getsockopt()
		kcb->userdata, sopt->sopt_name,			//     implementation is
			data, &len);				//     called to process
if (data != NULL && len > sopt->sopt_valsize)			//     the buffer.
	panic_plain("ctl_ctloutput: ctl %s returned "
		"len (%lu) > sopt_valsize (%lu)\n",
			kcb->kctl->name, len,
			sopt->sopt_valsize);
socket_lock(so, 0);
if (error == 0) {
	if (data != NULL)
		error = sooptcopyout(sopt, data, len);		// (d) If (c) succeeded,
	else							//     then the data buffer
		sopt->sopt_valsize = len;			//     is copied out to
}								//     userspace.

Este código faz o seguinte:

  1. Aloca um buffer do heap do kernel para o parâmetro data da função getsockopt, sem especificar o flag M_ZERO para zerar os bytes alocados.
  2. Copia os dados de getsockopt do espaço do usuário usando sooptcopyin, preenchendo o buffer de dados recém-alocado. Esta cópia deve sobrescrever completamente os dados alocados, razão pela qual o flag M_ZERO não era necessário. No entanto, o valor de retorno de sooptcopyin não é verificado, o que significa que é possível que a cópia tenha falhado, deixando dados não inicializados no buffer. A cópia poderia falhar se, por exemplo, o programa passasse um endereço não mapeado para getsockopt.
  3. O código então chama a implementação real de getsockopt para este socket de controle do kernel. Essa implementação deve processar o buffer de entrada, possivelmente modificando-o e encurtando-o, e retornar um código de resultado. No entanto, a implementação é livre para assumir que o buffer fornecido já foi inicializado (já que teoricamente vem do espaço do usuário) e, portanto, várias implementações não modificam o buffer. A função NECP necp_ctl_getopt, por exemplo, simplesmente retorna 0 sem processar o buffer de dados.

Assim, ao especificar um endereço de dados não mapeado para getsockopt, podemos fazer com que um buffer do heap de tamanho controlado seja alocado, impedir que o conteúdo desse buffer seja inicializado e então alcançar uma chamada a sooptcopyout que tenta escrever esse buffer de volta ao endereço não mapeado. Tudo o que precisamos fazer para que a cópia de saída seja bem-sucedida é remapear esse endereço entre as chamadas a sooptcopyin e sooptcopyout. Se conseguirmos fazer isso, vazaremos dados não inicializados do heap do kernel para o espaço do usuário.

Acontece que essa é uma corrida bastante fácil de vencer. Durante os testes no meu Macbook Pro de 2015, o número médio de tentativas para vencer a corrida nunca foi superior a 600, e a mediana nunca foi superior a 5. No iOS 10.1.1 em um iPhone 7, a corrida foi ainda mais fácil de vencer, normalmente exigindo no máximo 2 tentativas. (Este teste foi realizado com DEBUG desativado, pois os printfs diminuem drasticamente a velocidade da exploração.)

Uso

Para compilar, execute make. Veja o início do Makefile para várias opções de compilação.

Execute a exploração especificando o tamanho alvo do vazamento na linha de comando:

root@kitploit:~
$ sudo ./ctl_ctloutput-leak 128
000000:  ef be ad de ef be ad de  00 00 00 00 00 00 00 00
000010:  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
000020:  00 00 00 00 00 00 00 00  01 00 00 00 40 80 00 00
000030:  de 28 45 00 04 00 00 00  a0 ff 4a 26 80 ff ff ff
000040:  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
000050:  08 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
000060:  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
000070:  00 00 00 00 00 00 00 00  ef be ad de ef be ad de

Cronograma

Relatei este problema à Apple em 7 de outubro de 2017. Foi atribuído o CVE-2017-13868. A Apple corrigiu os problemas no macOS 10.13.2 e no iOS 11.2.

Licença

O código ctl_ctloutput-leak é lançado em domínio público. Como cortesia, peço que, se você referenciar ou usar qualquer parte deste código, atribua-o a mim.

Baixar ferramenta
  • Finalmente, se a implementação real de getsockopt não retornar um erro, ctl_ctloutput chama sooptcopyout para copiar o buffer de dados de volta ao espaço do usuário.