Dealing with a RAT

 

Depuis quelques temps j’accordais une grande attention à l’idée de faire un blog, et les sujets ne me manquent pas…

Je dois avouer que je ne suis pas très à l’aise lorsqu’il s’agit de faire de la rédaction, et certains sujets sont visiblement censurés par notre chère démocratie (cf. Condamné en justice pour un tuto Aircrack).

Et, une obsession en chasse une autre …

Alors, en rangeant un peu de contenu numérique, je suis tombé par hasard sur une version de « Bozok-RAT ». Quoi ? un rat ? …

Commençons par le commencement …

 

Remote Administration Tool (RAT) – Bozok v1.5.1


Un RAT est comme son acronyme l’indique, un outil d’administration à distance.

Mais contrairement à certains outils du marché (Teamviewer, …) un RAT dispose d’un panel d’options généralement plus atractif.

  • L’enregistrement des touches saisies sur le clavier (keylogger),
  • L’accès à une invite de commandes à distance,
  • L’accès à la base de registre Windows,
  • L’accès à un explorateur de fichier,
  • Une multitude d’autres fonctionnalitées …

Parmi ces autres fonctionnalités dans son édition « Ultimate » le logiciel dispose de l’option  « Form Grabbing ». Une capacité qui permet l’extraction de données de formulaires Web avant que ceux-ci soient transmis à un serveur sécurisé.

Si l’on ajoute les fonctionnalités de « keylogger », « Password recovery », « Rootkit », … pour ma part (cela n’engage que moi) ce n’est plus un simple outil d’administration à distance, mais un « malware ».

Pour essayer de satisfaire ma curiosité, j’ai téléchargé une version plus récente du logiciel et visiblement, le développement c’est arrêté à la version 1.5.1, marketing oblige ! C’est une version d’évaluation que j’ai obtenu en glanant sur Internet.

Business is business, le developpeur de l’application proposait l’édition « ultimate » de son logiciel pour 480€ annuel.

Par défaut, le port d’écoute sur le C2C (Centre de Contrôle) est tcp/1515 et le mot de passe de connexion est « mypass ».

La génération d’un agent se déroule comme la plupart des autres outils de ce type.

 

Ci-dessous, une simulation d’un accès en « Remote Shell » avec Bozok-RAT.

Notez au passage que pour ne pas « m’infecter » inutilement, je travaille en environnement complètement cloisoné (sur une machine virtuelle dédiée pour ce type de travail).

 

Analyse statique

J’ai pris l’habitude de commencer mes analyses par des opérations très basiques. Par exemple, en utilisant des outils comme « PEiD » et « PE Studio ».

Le logiciel « PEiD » m’indique que l’agent généré par le centre de contrôle, « serveur.exe », est un fichier binaire pour les systèmes Microsoft Windows 32-bits (codé en Delphi).

Ici, je cherche à savoir si le programme est protégé par un « packer ». Me rappelant, lors d’une précédente analyse que j’avais sans doute commencé avec trop de hâte en voyant la chaîne « UPX » dans le debugger.

J’utilise également le plugin « KANAL » pour rechercher de la cryptographie (sait on jamais) mais rien.

Aussi, « PE Studio » me fourni des données facilement interprétables afin d’obtenir un aperçu général de ce fichier PE (Portable Executable).

Ci-dessous, les différents indicateurs parlent d’eux-même.

Je regarde dans les entêtes et dans la table d’importation.

Dans « optional-header » j’obtiens, entre autre, des informations sur les options utilisées lors de la compilation (SEH, ASLR, DEP, …)

Dans la table d’importation j’observe les APIs Microsoft Windows appelées par ce programme.

    

La liste des sections laisse apparaitre une section nommée « .rsrc ».

Des données de toutes sortes peuvent être stockées dans un fichier PE, une façon de réaliser ceci, est d’utiliser les ressources comme espace de stockage.

Ci-dessous, la liste des ressources. L’une d’elle s’appelle « CFG ».

Liste des chaines de caractères ANSII et Unicode « codée en dur » dans le programme.

Donc pour résumer, à première vue le code ne semble pas être « obfuscé », ce qui me laisse penser ceci ; tout simplement, des appels à certaines API sensibles de Windows sont vus dans la table d’importation.

Certaines informations suggèrent un accès en lecture/écriture dans la base de registre de Windows :

  • RegSetValueExW,
  • RegCreateKeyW,
  • RegDeleteKeyW
  • RegOpenKeyExW

La chaine de caractères Unicode « Software\Microsoft\Windows\CurrentVersion\Run\ » est également présente. C’est un « PATH » de la base de registre Windows bien connu pour la persistance (basique) d’un programme au « démarrage de l’ordinateur ».

** Généralement, il est préférable de ne pas laisser fuiter ces informations aussi simplement. D’autres RAT sont bien plus subtiles ou … évolués.

Le programme semble contenir des ressources (rcdata), l’une de ces ressources s’appelle « CFG ». S’agirait-il de la configuration du RAT ?

La chaine de caractères ASCII « BILGE:TONYUKUK:BEN:M:TABGAC:ILINGE:KILINDIM: TRK:BODUNU:TABGACKA:KK:ERTI » est plutôt suspecte, je décide de la « googeler » et … oh surprise.

En bref, si on demande à son interprete Turc favori (Google), on obtient la traduction approximative suivante :

« Le sage Tonyukuk était la solution au problème, et le buddog turc était aveugle. » (cf. Wikipédia)

Il y a également une référence au « Khan » dans les écrits, ce qui laisse penser que cette histoire ne doit pas dater d’hier :

« Les inscriptions Orhun concernent aussi Tonyukuk, une personne politique qui, contrairement à Bilge Kagan et Ash Tigin, devrait, en fait, être généralement écrite pour le Khan. »

Comment dire … je me suis laissé distraire là !

Je jette un petit coup d’oeil aux ressources du programme, j’utilise « Resource Hacker » comme explorateur.

What The Fuck! Je m’attendais à rencontrer un algorithme de chiffrement ou à minima une substitution monoalphabétique (rot-13, …). Mais, il n’en est rien.

La configuration de l’agent est accessible, en clair, dans les ressources.

Je trouve également d’autres éléments dans les ressources, sans doute liés aux commandes du RAT.

Au passage, j’en profite pour coder un outil en Python capable d’extraire des données contenues dans les ressources d’un PE.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def read_pe_rsrc(file_in, rsrc_name) :
  from pefile import PE
  
  try :
    pe   = PE(file_in)
  except Exception, error :
    print("warning: pe_fail (with exception from pefile module) on file: %s" % (file_in))
    return(None, "(Exception):, %s" % (str(error)))
  
  offset = 0x0
  size   = 0x0
  for rsrc in pe.DIRECTORY_ENTRY_RESOURCE.entries :
    for entry in rsrc.directory.entries :
      if(entry.name is not None) :
        if(entry.name.__str__() == rsrc_name) :
          offset = entry.directory.entries[0].data.struct.OffsetToData
          size   = entry.directory.entries[0].data.struct.Size

  return((pe.get_memory_mapped_image()[offset : offset + size]), None)

def main() :
  import sys
  from argparse import ArgumentParser

  parser = ArgumentParser(prog=sys.argv[0])
  parser.add_argument('-f', '--filename', type=unicode, help='Specify target filename.')
  parser.add_argument('-r', '--rsrcname', type=str, help='specify resource name.')
  args   = parser.parse_args()

  print read_pe_rsrc(args.filename, args.rsrcname)[0]

if(__name__ == '__main__') :
  main()

En jouant avec le « builder » j’arrive assez vite à me faire une idée sur la structure de la configuration.

Je poursuis mon analyse statique à l’aide d’un désassembleur (IDA), mon objectif est d’analyser le comportement (focus sur le chargement de la configuration) du RAT.

L’agent « Bozok » n’a pas été compilé avec l’option ASLR, l’analyse sera d’autant plus simple.

Ci-dessous, le point d’entrée du programme (l’agent) à l’adresse mémoire « 0x004071f0 ».

Le premier appel « call nullsub_1 » fait référence à une fonction qui ne sert à rien.

Je décide alors de suivre le second appel « call sub_404514 ».

Dans cette fonction, j’observe (encore une fois) cette référence à « Tonyukuk ». Je suppose, avec le recul, que cette « string » sert de point de repère au developpeur du logiciel pour des besoins de « débugage ».

Le quatrieme appel de cette fonction « call sub_4040f0 » sert vraisemblablement à l’initialisation du processus de l’agent :

  • On remarque, SetProcessDEPPolicy, NtSetInformationProcess, …
  • Se termine par un appel à GetCurrentProcess().

Je poursuis sur le cinquième appel « call sub_401f9c » et j’observe des références sur la configuration du RAT.

J’observe également la version de l’agent (1.5.1) sans doute en « dur » dans le binaire.

Dans le premier appel de cette fonction « call sub_402300 » je trouve des références aux fonctions permettant de charger des ressources contenues dans un PE (FindRessourceA, LoadResource, …).

Le chargement de la configuration est donc réalisé dans cette fonction.

Si je continu à dérouler, la création d’un Mutex.

Un « Thread » est créé si l’option « Visible Mode » est activée pour afficher une boîte de dialogue avec le texte suivant : « Server is running in visible mode, click OK to uninstall ».

Puis, le troisième appel de la fonction principale commence par initialiser le protocole de communication.

Je dois dire … que je suis encore surpris par le manque de protection concernant la configuration.

Je décide alors de laisser tomber le désassembleur pour une analyse réseau avec Wireshark. Toujours avec l’idée d’avoir un aperçu global avant de rentrer dans les détails si besoin.

 

Analyse dynamique

Ca commence fort … sur la même VM (de sandbox) j’exécute le client et le serveur. Ma première difficulté est d’obtenir une analyse de trames.

Visiblement, dans ces conditions je n’observe rien dans l’analyseur, pourtant, le RAT fonctionne correctement, lui.

Pour éliminer tout malentendu, je positionne une seconde VM. Toujours en étant cloisonné (mais les deux VM peuvent communiquer entre-elles).

Je me sers de l’une des VM pour héberger le C2C et, sur la seconde j’exécute l’agent. Je fini par obtenir une analyse de trames, enfin.

En résumé, j’ai procédé de la facon suivante. J’ai mis en écoute Wireshark sur une des deux VM et j’ai ouvert le centre de contrôle du RAT sur la première, puis, j’ai exécuté l’agent sur la seconde … Je suis parti boire un café.

Un instant plus tard, constatant que le dialogue ne s’est limité qu’à une « pseudo » authentification et le « push » de quelques informations concernant l’hôte cible. Je décide alors d’ouvrir un « shell » à distance et de réaliser un simple « dir ».

J’obtiens ainsi timidement quelques informations qu’il faut désormais étudier.

Ci-dessous, l’authentification entre le C2C et l’agent (nan mais … c’est quoi cette merde ???). Le mot de passe est annoncé « cleartext » par le centre de contrôle !

Et puis l’agent… qui envoit au C2C quelques informations d’usages…

Je ne sais pas quoi dire, sauf, que ce n’était pas très brillant de payer presque 500€ annuel pour un outil aussi … pourri !

L’agent commence par initialiser une connexion TCP/IP « inversée » avec le centre de contrôle.

Une parenthèse, sur le nom des binaires, choisie par le developpeur :

  • Le centre de contrôle a comme nom « client.exe »,
  • L’agent a pour nom « serveur.exe ».

Ici, la notion de client et serveur est un peu particulière :

  • Le client est en réalité le centre de contrôle (ce qui sous-entend qu’il joue un rôle de serveur),
  • Le serveur est en réalité l’agent du RAT, généralement chargé de se connecter à un ou plusieurs centres de contrôles, et d’attendre des instructions (ce qui sous-entend qu’il joue un rôle de client).

Donc, si on se place côté réseau, le port en écoute est sur le centre de contrôle.

Mais alors pourquoi ?

Peut-être que … tout simplement, il fut une époque ou les ordinateurs disposaient pour la plupart d’une adresse IP publique. Ainsi le « serveur » s’installait sur l’hôte ciblé, et, l’attaquant utilisait un « client » pour se connecter à distance.

Aujourd’hui, les firewall et le NAT ne permettent plus ce type de connection. C’est alors l’hôte, contenant la charge utile (l’agent), qui initialise la connexion avec son centre de contrôle.

En réalisant que le protocole de communication est aussi sécurisé que le stockage de la configuration, je décide dans un premier temps de coder un outils qui serait capable d’émuler une communication avec le centre de contrôle.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import socket

def create_socket(hostname, port) :
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.settimeout(2)
  try :
    s.connect((hostname, port))
  except(socket.error), message :
    print(message)
    s.close()
    return(0)
  return(s)

def recv_socket(socket) :
  data_stream = ""
  try :
    data_stream = socket.recv(4096)
  except(Exception), message :
    if(message == "timed out") : 
      sleep(1)
  finally :
    if(len(data_stream) != 0) :
      return(data_stream)
    else :
    return("")

def format_str(str) :
  s = ""
  i = 0
  for i in range(0, len(str)) :
    s = s + str[i]
    if(i < (len(str) - 1)) :
    s = s + chr(int('0x00', 16))
  return(s)
  
def unformat_str(str) :
  s = ""
  i = 0
  for i in range(0, len(str) - 1) :
    if not (i % 2) :
    s = s + str[i]
  return(s)
  
def bozok_client_register(socket, hostname, username, server_id, password) :
  from binascii import unhexlify
  
  client_fake_str = format_str(hostname + "|" + username + "|" + server_id + "|FRA|3|1.5.1|0|2|" + password + "|1|Program Manager|0|1|1023|592|Intel(R) Core(TM) i5-5200U CPU @ 2.20GHz|2699")
  try :
    socket.send(unhexlify("1401000000") + client_fake_str + unhexlify("0000"))
  except(socket.error), message :
    print(message)

def main() :
  from binascii import hexlify
  from time import sleep
  
  c2c_hostname = "192.168.XXX.XXX"
  c2c_port     = 1515
  
  # Initialisation d'une connexion vers le centre de controle.
  socket       = create_socket(c2c_hostname, c2c_port)
  if(socket == 0) : exit()
  print(" [*] Connected to %s:%d" % (c2c_hostname, c2c_port))
  
  # Le centre de controle envoi son mot de passe (en clair).
  data_stream = recv_socket(socket)
  if(hexlify(data_stream[:5]).upper() == "0E00000000") :
    password = unformat_str(data_stream[5:])
  else :
    exit(1)

  # 
  bozok_client_register(socket, "SBOX-XXXXXXXXXX", "Administrator", "PIRATES.RE", password)
  print(" [*] Registering to c2c completed")

  while(True) :	
    data_stream = ""
    command_id  = ""
  
  # 
    data_stream = recv_socket(socket)
    if(len(data_stream) == 6) :
      command_id = hexlify(data_stream).upper()
    elif(len(data_stream) > 6) :
      command_id = hexlify(data_stream[5:]).upper()
    else :
      sleep(1)
  
    if(len(command_id) != 0) :
      if(command_id == "020000006200") :     # Stop server
        print("[C2C] request to stop the server.")
        socket.close()
        exit(0)
      else :
        print("[C2C] Command not implemented : %s" % (command_id))

  socket.close()

if(__name__ == "__main__") :
  main()

Dans un second temps, je fais une copie de mon script et je l’ai modifié légèrement pour faire du « fuzzing ». Mais je ne me suis pas trop attardé sur le sujet étant donné que je n’ai pas regardé le centre de contrôle. Et aussi … que ce projet est mort.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import socket

def create_socket(hostname, port) :
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.settimeout(2)
  try :
    s.connect((hostname, port))
  except(socket.error), message :
    print(message)
    s.close()
    return(0)
  return(s)

def recv_socket(socket) :
  data_stream = ""
  try :
    data_stream = socket.recv(4096)
  except(Exception), message :
    if(message == "timed out") : 
      sleep(1)
  finally :
    if(len(data_stream) != 0) :
      return(data_stream)
    else :
    return("")

def format_str(str) :
  s = ""
  i = 0
  for i in range(0, len(str)) :
    s = s + str[i]
    if(i < (len(str) - 1)) :
    s = s + chr(int('0x00', 16))
  return(s)
  
def unformat_str(str) :
  s = ""
  i = 0
  for i in range(0, len(str) - 1) :
    if not (i % 2) :
    s = s + str[i]
  return(s)
  
def bozok_client_register(socket, hostname, username, server_id, password, fuzz_var) :
  from binascii import unhexlify
  
  client_fake_str  = format_str(fuzz_var + "|" + username + "|" + server_id + "|FRA|3|1.5.1|0|2|" + password + "|1|Program Manager|0|1|1023|128|Intel(R) Core(TM) i5-5200U CPU @ 2.20GHz|2699")
  try :
    socket.send(unhexlify("1401000000") + client_fake_str + unhexlify("0000"))
  except(socket.error), message :
    print(message)

def fuzz_c2c(str_fuzz) :
  from binascii import hexlify
  from time import sleep
  
  c2c_hostname = "192.168.XXX.XXX"
  c2c_port     = 1515
  
  # Initialisation d'une connexion vers le centre de controle.
  socket       = create_socket(c2c_hostname, c2c_port)
  if(socket == 0) : exit()
  print(" [*] Connected to %s:%d" % (c2c_hostname, c2c_port))
  
  # Le centre de controle envoi son mot de passe (en clair).
  # data_stream = socket.recv(4096)
  data_stream = recv_socket(socket)
  if(hexlify(data_stream[:5]).upper() == "0E00000000") :
    password = unformat_str(data_stream[5:])
  else :
    exit(1)	

  # 
  bozok_client_register(socket, "SBOX-XXXXXXXXXX", "Administrator", "PIRATES.RE", password, str_fuzz)
  print(" [*] Registering to c2c completed")

  sleep(2)
  socket.close()

def main() :
  F = "A" * 1
  i = 0
  while(True) :
    i = i + 1
    F = F + 'A'
    fuzz_c2c(F)

    print("[*] Count: %s" % (i))

if(__name__ == "__main__") :
  main()

Touver un « buffer overflow » sans qu’une opération soit demandée par le « C2C » aurait été intéressant. Aussi, ce passage me permet d’avoir une idée un peu plus précise sur la longueur des données qui sont envoyées au centre de contrôle.

Alors, je reste concentré sur l’objectif de créer plusieurs instances sur le centre de contrôle (en modifiant légèrement le script de départ).

Et pour terminer le protocole de communication, à ce stade, le script est capable d’interpréter la commande « Stop Server » envoyée par le centre de contrôle et se stopper. Toutes les autres commandes sont ignorées, il est aussi possible de créer n instance(s) sur le centre de contrôle.

J’ai essayer de créer un maximum d’instances (5000) et puis le script m’a refusé un nouveau « thread » à 882 instances, le centre de contrôle reste stable (pas de crash).

 

Autres projets (même artiste)

J’ai fais quelques recherches sur le concepteur, le compte twitter @slayer_616 servait à communiquer sur ses différents projets. Dans l’ordre :

  • Schwarze Sonne
  • Umbra loader
  • Bozok

J’ai téléchargé une version de « Schwarze Sonne » et « Umbra loader » et j’ai accordé un peu d’attention à trois points :

  1. Le fonctionnement général des agents (avec IDA), voir si il y a une correspondance avec « Bozok »,
  2. Dans les ressources à la recherche d’une trace de configuration,
  3. Une observation du protocole de communication.

Vous l’aurez compris … c’est la même merde (mais en plus vieux).

Du coté du code des agents :

  • A l’interieur de « Schwarze Sonne » tout semble complètement différent, ce n’est apparement pas le même code.
  • Et … dans « Umbra Loader » on retrouve un code un peu similaire à « Bozok », du coup, je n’exclus pas une réutilisation de portions de codes. Et comme par hasard, je retrouve aussi des références à « Tonyukuk ».

A propos de la configuration :

  • La configuration de « Schwarze Sonne » est également servie « cleartext » dans les ressources du PE.

Quant à « Umbra loader » SURPRISE ! la configuration est « cryptée ». En même temps, je me dis que ce ne sera pas plus évolué qu’un simple XOR.

Avec IDA, j’ai regardé le code en partant de la fonction principale. Quand je suis arrivé à la création du « mutex » je me suis dit que j’étais allé un peu trop loin. Du coup, je suis allé voir la fonction placée juste avant.

Cette fonction semble jouer un rôle dans le chargement de la configuration, je regarde dans celle-ci un « call » au hasard et … Un XOR.

Je modifie le script précédent (pour la lecture de la configuration de « Bozok ») et j’adapte un XOR « 0x0D » pour le décryptage de la configuration de « Umbra loader ».

Notez : La clé XOR est « codée en dur » dans l’agent. Elle ne change donc pas à chaque génération.

D’autre part « 0x00 ^ 0x0D = 0x0D », on retrouve ainsi la clé de cryptage un peu partout dans la ressources.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def read_pe_rsrc(file_in, rsrc_name) :
  from pefile import PE
  
  try :
    pe   = PE(file_in)
  except Exception, error :
    print("warning: pe_fail (with exception from pefile module) on file: %s" % (file_in))
    return(None, "(Exception):, %s" % (str(error)))
  
  offset = 0x0
  size   = 0x0
  for rsrc in pe.DIRECTORY_ENTRY_RESOURCE.entries :
    for entry in rsrc.directory.entries :
      if(entry.name is not None) :
        if(entry.name.__str__() == rsrc_name) :
          offset = entry.directory.entries[0].data.struct.OffsetToData
          size   = entry.directory.entries[0].data.struct.Size

  return((pe.get_memory_mapped_image()[offset : offset + size]), None)

def main() :
  import sys
  from argparse import ArgumentParser
  from binascii import hexlify

  parser = ArgumentParser(prog=sys.argv[0])
  parser.add_argument('-f', '--filename', type=unicode, help='Specify target filename.')
  parser.add_argument('-r', '--rsrcname', type=str, help='specify resource name.')
  args   = parser.parse_args()
  cfg    = read_pe_rsrc(args.filename, args.rsrcname)[0]

  plain  = ""
  for c in cfg :
    plain += chr(ord(c) ^ 0x0d)

  print("config: %s" % (plain))

if(__name__ == '__main__') :
  main()

Ci-dessous, une représentation d’une partie de la configuration « cryptée ».

Et pour ce qui est du protocole de communication, je n’ai pas pris le temps de regarder « Umbra loader » mais juste jeter un oeil sur « Schwarze Sonne ».

Je n’ai pas compris à quoi sert le mot de passe, il n’est pas possible de le configurer sur le C2C. Par contre, il est facile de deviner à quoi il ne sert pas. 😛

Le script ci-dessous est une version modifiée de celui que j’ai codé pour l’émulation d’un hôte avec « Bozok », adapté pour « Schwarze Sonne ».

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import socket

def create_socket(hostname, port) :
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.settimeout(2)
  try :
    s.connect((hostname, port))
  except(socket.error), message :
    print(message)
    s.close()
    return(0)
  return(s)

def recv_socket(socket) :
  data_stream = ""
  try :
    data_stream = socket.recv(4096)
  except(Exception), message :
    if(message == "timed out") : 
      sleep(1)
  finally :
    if(len(data_stream) != 0) :
      return(data_stream)
    else :
    return("")

def ss_client_register(socket, hostname, username, server_id) :
  from binascii import unhexlify

  client_fake_str = server_id + "|" + username + "@" + hostname + "|Windows XP|0|2.0 Beta 1|Program Manager|FRA|"
  
  try :
    socket.send(client_fake_str)
  except(socket.error), message :
    print(message)

def main() :
  from binascii import unhexlify, hexlify
  from time import sleep
  
  c2c_hostname = "192.168.XXX.XXX"
  c2c_port     = 1515
  
  # Initialisation d'une connexion vers le centre de controle.
  socket       = create_socket(c2c_hostname, c2c_port)
  if(socket == 0) : exit()
  print(" [*] Connected to %s:%d" % (c2c_hostname, c2c_port))
  
  # L'agent se signial a son centre de controle.
  try :
    socket.send(unhexlify("015200000001"))
  except(socket.error), message :
    print(message)
    exit(-1)
  sleep(1)

  ss_client_register(socket, "SBOX-XXXXXXXXXX", "Administrator", "PIRATES.RE")
  print(" [*] Registering to c2c completed")

  while(True) :	
    data_stream = ""
    command_id  = ""
    
    data_stream = recv_socket(socket)
    if(len(data_stream) == 6) :
      command_id = hexlify(data_stream).upper()
    elif(len(data_stream) > 6) :
      command_id = hexlify(data_stream[5:]).upper()
    else :
      sleep(1)
  
    if(len(command_id) != 0) :
      if(command_id == "010000000003") :     # Stop server
        print("[C2C] request to stop the server.")
        socket.close()
        exit(0)
      else :
        print("[C2C] Command not implemented : %s" % (command_id))

  socket.close()

if(__name__ == "__main__") :
  main()

 

Conclusions

Le RE (Reverese Engineering) est une pratique intéressante lorsqu’il s’agit de comprendre comment une technologie fonctionne. Ceci s’applique bien sûr aux logiciels.

Dans l’étude de « Bozok-RAT », enfin, plus précisément son « agent », on peut se rendre compte que rien n’est mis en oeuvre pour ralentir le « Reverse Engineering ».

  • Pas d’obfuscation de code,
  • Pas de techniques « Anti-RE, Anti-Debug, … »,

Egalement, la sécurité n’a pas été intégrée au produit.

  • La configuration de l’agent est accessible « cleartext » dans les ressources du PE.
  • Le C2C envoit son mot de passe à n’importe qui voulant initialiser une connextion.
  • Les échanges entre l’agent et le C2C ne sont pas chiffrés.

Ces trois outils (Schwarze Sonne, Umbra loader et Bozok) sont de très bons cas d’études pour apprendre le RE. Le coté plus « concret », « réel » fait un peu sortir de l’univers des CTF (Capture The Flag).

A savoir tout de même, très généralement, les « agents » sont « packer » avant d’être déployés. Ce qui permet de cacher le binaire exécuté aux anti-virus (d’une certaine façon).

Je pense que le sujet des « packers » sera abordé dans un prochain article 🙂

Je crois désormais que j’ai passé beaucoup trop de temps à étudier ceci alors, je ferme ce dossier.

J’èspère que cet article vous aura intéressé.

Ce contenu a été publié dans Reverse Engineering. Vous pouvez le mettre en favoris avec ce permalien.