WannaCry Ransomware Encryption and Decryption

UPDATE 1: there is a very comprehensive Wiki about this ransomware: https://en.wikipedia.org/wiki/WannaCry_cyber_attack. Keep on reading if you want to see some code.

UPDATE 2: patch your machines!!! This is coming directly from the dude who stopped WannaCry 1.0:


OK, back to the blog:

If you are one of the unfortunate 75,000 people who saw this pop-up in the past 72 hours:


Then I have some bad news and some good news for you. Let's start with the bad news: first, your files are gone. Well, technically they are not gone, they've just been encrypted in your machine. Good luck trying to decrypt them. So yes, they are gone my friend. Sorry.

But hey, if you managed to pay the 300 bucks, I do have some good news for you: you've just made a couple of guys somewhere (likely in Siberia or Finland) very, very happy!!! Isn't that a good feeling, to make people happy?! Good for you!!!

Jokes aside, the WannaCry ransomware (whose more information you can find here with this awesome video by Barnacules Nerdgasm: https://www.bing.com/videos/search?q=wannacry+barnacules+video&view=detail&mid=7124293C429EC9D7F45F7124293C429EC9D7F45F&FORM=VIRE) is shaking the internet down to its knees these days. It exploits some vulnerabilities in older versions of Windows, and propagates by itself (it is a worm, rather than a virus). Once it is in the computer, it encrypts everything you've got, asks for 300 bucks in bitcoin (not traceable) in exchange of a private key that you can use to decrypt the shit it did to you, but it never sends that private key back to you (and never will).

The worm has apparently halted after a dude cleverly created a web site which is used by the worm code to halt its execution - check out the amazing technical details here: http://blog.talosintelligence.com/2017/05/wannacry.html?m=1. However, a new version is spreading again without that halting condition, which is VERY scary - take a look at this: http://thehackernews.com/2017/05/wannacry-ransomware-cyber-attack.html).

75,000 people have been infected. Assuming a 10% desperation rate in which people just go ahead and pay the ransom (for nothing) in hopes to get the private key from the criminals, calculate the profit of the teenagers (girls or boys) who created this worm is straightforward:

Users: 75,000 * 10% = 7,500
Revenue: 7,500 * $300 = $2,250,000
Taxes: $2,250,000 * 0% = $0
Expenses: 30 days of pizza @ ~$30/pizza = ~$1,000
Profit = $2,250,000 - $1000 - $0 = $2,249,000

Not bad for a month of work!!!

Let's jump into coding: I want to focus on the encryption and decryption part of the code that WannaCry is probably using to encrypt the files. We'll show it in C#. .Net comes with a Cryptography library which you can use to:
 - Get the public key
 - Get the private key
 - Encrypt and decrypt any data

It uses RSA behind the scenes (for more information about the RSA check out this Numberphyle video from one of its creators: https://www.youtube.com/watch?v=YQw124CtvO0). In the code below we'll take as input any file and read it in bytes. Then we generate two keys, one public (used for encryption) and another one is private (used for decryption). The private one is the holy grail here: only the authors of the code know it. If you are curious to know what a private key looks like, it looks like this:

<?xml version="1.0" encoding="utf-16"?>
<RSAParameters xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Exponent>AQAB</Exponent>
  <Modulus>tihAcDR6TxbWbyMwP1C7G6NDuHWBFBbUjP9kUVWL+2mQ4XE4iH0Y5/HjorBWnLb125fJKXs9eYVe94PmF9qeYG1zPJuoA+0+HtBnPIoBeKF82+GCCwaGF+fISQAMw3AwTAN4EPM27nPGkjJioAFur/DtEzqkc3HufqxeQceEuH8jXS/lLuVJZFfhKGxy3FygzqkAZdD85KCV8zRPiyzbjQrgHeTdqxvps7aBDl3wqR5TYNjt3g58s7WYrZXTkt+PbyB8IQn69wqqcmkKA4y1m9YtRfDBN2MR2mSjd7lPovPepXMwW8FC3+/0YoaQ6sKCwB/i6tLuCzflNkjmDLkHnQ==</Modulus>
  <P>yZW76S0Tmo+TRRIqDm+OoaOgcbnyk1EfEY3o2G0biUoMzdNu0vNfaeonK9N0MtbtKn/R5fNC7fs8BVq82FdI8woNQKHqcvZ3OcNAUfSfd3xb/52cm6D7GFt2aeVUl6OomZaKrMyBm9m+5tL5ak5YYHNzqvkYuZIwIYz6gDgcwlM=</P>
  <Q>51P+aIfLoojAdObHNYckTQs99CPS7x4QouSpEq/+hct4Ecm7p3a35IO4fXA2IIjJnW/5jJTMujI2Cb5RtN4RUKgdVw5QA+dNNjOlfqORlkx+aMeMU5bwcOQSUHVRwdYJWI/lKtdPcavnU5beBwdInvDssfOHzH1i3C0aHOjAsE8=</Q>
  <DP>pfW7Pa5ZvF7FzRC2RSo80ACJP/fpqLUZkfc2IrA5Al9PiUivrcal3+nhk+hDevONT/bplJogmRLEiFf6r1W0/jphTLvA7CLTZ1/DHXX6r4FXsGtPGqV+87+hDm+6pBkd3kydIMRBVFEBJMG+i3Gyur1yFel8HJMpQwXw2gzYSHc=</DP>
  <DQ>EoNxX/JGRNrG9FQn60vGhvf4XFqlngd881xzf5BgQVr4YAwSHaPtsbctA7UAT/hCknwMr8iU3e34zyzRIzWGkzrxJi96DeXsEwNtIkZ691ll4ILf4yy4T4ChSpkpEudLVjAl+hjDPeixGcqAOHXHxRipCNDhtGbwi4h8h4XFLhc=</DQ>
  <InverseQ>CT9/FmtjsAnGMKuXU7l4HyDCTItCuBOzsuYWYhcv6auBBOXG974OrkSgVoACQP2C8eFVt/g1g8KMk1I0OA1v48mqT6m7tCyxi3lY2BRp/cGqK3gMeFiUh48Fw0GcuVNYzhQp16+gbj8xyzQAigFoLg4/W9w2+75bjIpXgymc6Q4=</InverseQ>
  <D>p63V43PrQvKa4iNaPm5qTr6zkBFaiMubTU+rYNOG0CAVJfG7QKknTBv2l8QLdqdVGpdWrcCsjjifeukH3d14/PrDoX8H4tV44ZSl86x2Pj0pWp7zvoJ63XaXf9tz5FRZoR9wXuoEHuykVd/bub6XzY3SLmlFCKBQEntJKPQo0EtqF66b2y/GEhOgnqyeNvtG5Mz0A1fNml4WtvrFyC212jCYNeddhnRfGqLycb11hCS0z5TBfB/gMtfoxbjgpSYW2hLf/piH2Vw0aY4aRSFSE31/dgt629eFAEh/Bix2PPRaZ3EFMg0Ej+BeOPW79OOsr8BV7/Emlxbtn//hQHwZYQ==</D>
</RSAParameters>

It contains a bunch of stuff needed by the RSA algorithm. The bigger the keys, the harder it is to break the code using brute-force techniques - that's why the WannaCry developers opted for keys with 2,048 bits in length, which are considered state-of-the-art in terms of cryptography strength. We're also using 2,048 bits below. Once we have both keys we then encrypt the content using the public key, save it off to a random file, and then decrypt the cypher back with the private key, saving it off to yet another file, which should be similar to the original one if the code works fine.

I start with one file, importantStuff.csv:


When I run the code against importantStuff.csv, the output is this:


If you open the cypher file, it won't make any sense, but the plain file is exactly the same as the original one. The code below only works for files with small content (the code to encrypt large data is a little more sophisticated and can be found here: http://www.technical-recipes.com/2013/using-rsa-to-encrypt-large-data-files-in-c/).

Code is below, but before I wrap up I'd like to say few more things:
a) What these guys have done is illegal, criminal, unethical, and many-many-many people now are suffering because of these thieves. I hope they are caught and go to jail for a long time.
b) Please upgrade your machines to the latest operating systems, and keep them up-to-date.
c) Back up your data. Sooner or later your computer will die. Back up the data before it is too late.
d) Computer professionals should definitely understand what's going on here in order to learn and avoid mistakes in the future which can lead to more and more of these incidents.

Hope you enjoy - cheers, Marcelo.

using System;
using System.IO;
using System.Security.Cryptography;

namespace RsaCryptoExample
{
    static class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine("RSA.exe <file>");
                return;
            }

            string fileName = args[0];
            Random rd = new Random();

            RSAParameters privateKey = new RSAParameters();
            RSAParameters publickKey = new RSAParameters();
            GetKeys(out privateKey, out publickKey);

            PrintKey(privateKey, "PRIVATE");

            byte[] original = ReadContentToEncrypt(fileName);

            string cypherFileName = "cypher_" + rd.Next().ToString() + "_" + fileName;
            byte[] cypher = EncryptStuff(original, publickKey);
            WriteContent(cypherFileName, cypher);

            string plainFileName = "plain_" + rd.Next().ToString() + "_" + fileName;
            byte[] plain = DecryptStuff(cypher, privateKey);
            WriteContent(plainFileName, plain);
        }
        static byte[] ReadContentToEncrypt(string fileName)
        {
            FileInfo fi = new FileInfo(fileName);
            FileStream fs = fi.Open(FileMode.Open);
            int len = 0;
            while (fs.ReadByte() != -1) len++;

            fs.Close();
            fs = fi.Open(FileMode.Open);
            byte[] retVal = new byte[len];
            int index = 0;
            for (;;)
            {
                int c = fs.ReadByte();
                if (c != -1)
                {
                    retVal[index++] = (byte)c;
                }
                else
                {
                    break;
                }
            }

            return retVal;
        }

        static void PrintKey(RSAParameters key, string token)
        {
            string keyString;
            {
                var sw = new System.IO.StringWriter();
                var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
                xs.Serialize(sw, key);
                keyString = sw.ToString();
            }
            Console.WriteLine("There it is, the {0} key: {1}", token, keyString);
        }

        static void WriteContent(string fileName, byte[] stuff)
        {
            FileInfo fi = new FileInfo(fileName);
            FileStream fs = fi.Open(FileMode.Create);

            for (int i = 0; i < stuff.Length; i++)
                fs.WriteByte(stuff[i]);

            fs.Close();
        }

        static void GetKeys(out RSAParameters privateKey, out RSAParameters publicKey)
        {
            //Make it VERY safe, 2048 bits ftw
            var csp = new RSACryptoServiceProvider(2048);

            privateKey = csp.ExportParameters(true);
            publicKey = csp.ExportParameters(false);
        }

        static byte[] EncryptStuff(byte[] stuff, RSAParameters publicKey)
        {
            var csp = new RSACryptoServiceProvider();
            csp.ImportParameters(publicKey);
            var cypher = csp.Encrypt(stuff, false);

            return cypher;
        }

        static byte[] DecryptStuff(byte[] stuff, RSAParameters privateKey)
        {
            var csp = new RSACryptoServiceProvider();
            csp.ImportParameters(privateKey);
            var plain = csp.Decrypt(stuff, false);

            return plain;
        }
    }
}

Comments

Post a Comment

Popular posts from this blog

Changing the root of a binary tree

ProjectEuler Problem 719 (some hints, but no spoilers)

The Power Sum, a recursive problem by HackerRank