Skip to content

Blood Money

September 8, 2015

This is my write-up for Amnpardaz (Iranian AV company, I’ve played with their products before) and ISC (Iranian Society of Cryptology) Ransomware’s data decryption challenge. I’m not lying, it was really easy comparing to CTFs that I’ve played (and failed 😉 ). It was three steps in total, you get a bunch of files for each step and you most decrypt them in order to get the next step email address.

Step One

We have a screenshot from the Ransomware’s window which says your files got encrypted with AES-256 blah blah blah, a solveme.gif which we most decrypt in order to get the next level email address, and a PCAP file which contains network traffic at infection time. Obviously we most get encryption key from the PCAP file.

I used forensicPCAP for examining the PCAP file. forensicPCAP is python script based on scapy for Network Forensics. The given PCAP has 12026 packets captured inside, I started by looking on HTTP traffic:

PCAP's web traffic

As I expected there were some many of it, so I decided to take a look at DNS traffics to see if there is any unusual DNS requests or any random looking domain (like what a domain generation algorithm may produce). My suspicion was right and there was a domain that looks randomly generated in DNS records list:

DGA domain

Next thing I do was checking the DNS packet to find the domain IP address:

###[ DNS ]###
           id        = 60305
           qr        = 1L
           opcode    = QUERY
           aa        = 1L
           tc        = 0L
           rd        = 1L
           ra        = 1L
           z         = 0L
           rcode     = ok
           qdcount   = 1
           ancount   = 1
           nscount   = 1
           arcount   = 1
           \qd        \
            |###[ DNS Question Record ]###
            |  qname     = ''
            |  qtype     = A
            |  qclass    = IN
           \an        \
            |###[ DNS Resource Record ]###
            |  rrname    = ''
            |  type      = A
            |  rclass    = IN
            |  ttl       = 86400
            |  rdlen     = 4
            |  rdata     = ''
           \ns        \
            |###[ DNS Resource Record ]###
            |  rrname    = ''
            |  type      = NS
            |  rclass    = IN
            |  ttl       = 86400
            |  rdlen     = 20
            |  rdata     = ''
           \ar        \
            |###[ DNS Resource Record ]###
            |  rrname    = ''
            |  type      = A
            |  rclass    = IN
            |  ttl       = 86400
            |  rdlen     = 4
            |  rdata     = ''

Then I checked the corresponding packets and found a GZIP encoded reply from the web server:

DGA domain's traffic

Decoding the data and gave me this:


Then I wrote a python script to decrypt the given GIF file, deleted two junk bytes from beginning of the file to got the next level e-mail address.

Next level mail address

Step Two

Incident report says encryption algorithm is AES and we have solveme-enc.jpg which again we most decrypt, a bunch of files from a compromised Drupal website that used by Ransomware as some sort of key generation source.

I started by looking at the CHANGELOG of the given Drupal, got the Drupal version, downloaded the original one and started diffing the files. The only noticeable changes were in

Drupal comparison

I seems to me like lousy key generation algorithm. The only problem here for getting the right key is time() function which used as a seed to PHP random number generator, So I needed the exact EPOCH time to get the same key as malware got in the infection process. For getting the right time, I checked the given 7zip file, and there I see the solveme-enc.jpg‘s last modification time.

JPEG's last modification time

Unfortunately it misses the seconds, so I wrote another simple python script to generate a PHP script with EPOCH times in range of 10:34 PM. Then I had a file like this which produced some keys after I ran it through:

mt_srand(1440957610);for ($i=0;$i<128/8;$i++) echo sprintf("%02x", mt_rand(0,255)); echo "</br>";
mt_srand(1440957611);for ($i=0;$i<128/8;$i++) echo sprintf("%02x", mt_rand(0,255)); echo "</br>";
mt_srand(1440957612);for ($i=0;$i<128/8;$i++) echo sprintf("%02x", mt_rand(0,255)); echo "</br>";
mt_srand(1440957613);for ($i=0;$i<128/8;$i++) echo sprintf("%02x", mt_rand(0,255)); echo "</br>";
mt_srand(1440957614);for ($i=0;$i<128/8;$i++) echo sprintf("%02x", mt_rand(0,255)); echo "</br>";
mt_srand(1440957615);for ($i=0;$i<128/8;$i++) echo sprintf("%02x", mt_rand(0,255)); echo "</br>";

Again with help of another python script, I was able to decrypt the given file with each key until I found one of them actually got decrypts as valid JPEG file. Diffing it with the original famous picture, revealed the next level email.

Next level email address

Update :

@pwnslinger pointed out that no brute-force is needed, exact seed is filetime(solveme-enc.jpg) .

Step Three

Yes, here is the fun part 😉 We are given a PE and a Result.txt file, we most decrypt the Result.txt.

The given PE was packed with a custom packer, I used the old fashion PUSHAD/POPAD and hardware break points to get to the OEP and then dumped the unpacked version.

Packed binary

OpenSSL debug string and asserts helped me a bit to understand the program flow, it started by generating a 2048 RSA key and used the this freshly generated key to encrypt the result.txt content :

.rsrc:00401AF0                 push    ebp
.rsrc:00401AF1                 mov     ebp, esp
.rsrc:00401AF3                 sub     esp, 144h
.rsrc:00401AF9                 push    0
.rsrc:00401AFB                 push    0
.rsrc:00401AFD                 push    10001h
.rsrc:00401B02                 push    800h
.rsrc:00401B07                 call    RSA_generate_key
.rsrc:00402851                 lea     eax, [ebp+var_38]
.rsrc:00402854                 push    eax             ; output_buffer
.rsrc:00402855                 mov     ecx, [ebp+var_4]
.rsrc:00402858                 push    ecx             ; data size
.rsrc:00402859                 mov     edx, [ebp+var_154]
.rsrc:0040285F                 push    edx             ; rsa key
.rsrc:00402860                 mov     eax, [ebp+var_170]
.rsrc:00402866                 push    eax             ; data
.rsrc:00402867                 call    sub_401F80

Then it encodes the newly generated RSA private key using base64 encoding (function renamed manually after identification):

.rsrc:00402945                 mov     eax, [ebp+var_164]
.rsrc:0040294B                 push    eax
.rsrc:0040294C                 mov     ecx, [ebp+var_18]
.rsrc:0040294F                 push    ecx
.rsrc:00402950                 mov     edx, ds:dword_49DAD4
.rsrc:00402956                 add     edx, ds:dword_49DAD8
.rsrc:0040295C                 push    edx
.rsrc:0040295D                 mov     eax, [ebp+var_30]
.rsrc:00402960                 push    eax
.rsrc:00402961                 call    base64encode
.rsrc:00402966                 add     esp, 10h
.rsrc:00402969                 mov     [ebp+var_10], eax

After that It decodes the word “challenge” (Xor’ed with some 1 byte key) and passes it to the this function:

RC4 init phase

Loop counter (256) and memory writes look suspiciously like a RC4 key initiation phase. Using some trial and error I found that my suspicion was right and it is actually RC4 key initiation. Obviously the next function most be RC4 encryption function, so I renamed it to rc4_enc (after looking at it and making sure its actually RC4 encryption). In next step, program encrypts the base64 encoded RSA private key with the RC4 encryption algorithm:

.rsrc:004029B8                 lea     ecx, [ebp+var_148]
.rsrc:004029BE                 push    ecx             ; key
.rsrc:004029BF                 mov     edx, [ebp+var_164]
.rsrc:004029C5                 sub     edx, 1
.rsrc:004029C8                 push    edx             ; priv key base64 size
.rsrc:004029C9                 mov     eax, [ebp+var_18]
.rsrc:004029CC                 push    eax             ; base 64 priv key
.rsrc:004029CD                 call    rc4_enc
.rsrc:004029D2                 add     esp, 0Ch
.rsrc:004029D5                 jmp     loc_402B3B

After that, encrypted key is passed to another function which Rijndael_Te1 string immediately reveals its AES encryption:

.rsrc:0040500A                 mov     eax, ds:Rijndael_Te2[eax*4]
.rsrc:00405011                 mov     ebx, esi
.rsrc:00405013                 shr     ebx, 10h
.rsrc:00405016                 and     ebx, 0FFh
.rsrc:0040501C                 xor     eax, ds:Rijndael_Te1[ebx*4]
.rsrc:00405023                 mov     ebx, edx
.rsrc:00405025                 shr     ebx, 18h
.rsrc:00405028                 xor     eax, ds:Rijndael_Te0[ebx*4]
.rsrc:0040502F                 mov     ebx, edi
.rsrc:00405031                 and     ebx, 0FFh
.rsrc:00405037                 xor     eax, ds:Rijndael_Te3[ebx*4]
.rsrc:0040503E                 mov     ebx, ebp
.rsrc:00405040                 xor     eax, [ecx+10h]

Encryption key for AES phase is constant hex value “726A5C7C475670706F6862567E465E5C”. last encryption phase takes place right before writing the result into the disk, at first glance I thought I might be a variant of some simple encryption algorithms like TEA but I was totally wrong, It was way simpler than TEA 🙂 after a while and being unable to determine the encryption algorithm, I decided to reverse engineer it (it is really small 😉 ). Here is the whole code:

.rsrc:00402440 unknown_enc     proc near               ; CODE XREF: sub_402500+892p
.rsrc:00402440 var_4C          = byte ptr -4Ch
.rsrc:00402440 out_buff        = dword ptr -1Ch
.rsrc:00402440 var_18          = dword ptr -18h
.rsrc:00402440 out_buff_ret    = dword ptr -14h
.rsrc:00402440 var_10          = word ptr -10h
.rsrc:00402440 var_C           = dword ptr -0Ch
.rsrc:00402440 internal_size   = dword ptr -8
.rsrc:00402440 var_4           = dword ptr -4
.rsrc:00402440 inbuff          = dword ptr  8
.rsrc:00402440 size            = dword ptr  0Ch
.rsrc:00402440                 push    ebp
.rsrc:00402441                 mov     ebp, esp
.rsrc:00402443                 sub     esp, 1Ch
.rsrc:00402446                 push    ebx
.rsrc:00402447                 push    esi
.rsrc:00402448                 push    edi
.rsrc:00402449                 mov     eax, [ebp+size]
.rsrc:0040244C                 sub     eax, 1
.rsrc:0040244F                 mov     [ebp+var_4], eax
.rsrc:00402452                 mov     cx, word ptr [ebp+var_4]
.rsrc:00402456                 mov     [ebp+var_10], cx
.rsrc:0040245A                 mov     edx, [ebp+size]
.rsrc:0040245D                 add     edx, 1
.rsrc:00402460                 mov     [ebp+internal_size], edx
.rsrc:00402463                 mov     eax, [ebp+size]
.rsrc:00402466                 push    eax
.rsrc:00402467                 call    unknown_libname_5 ; Microsoft VisualC 2-10/net runtime
.rsrc:0040246C                 add     esp, 4
.rsrc:0040246F                 mov     [ebp+out_buff], eax
.rsrc:00402472                 mov     ecx, [ebp+out_buff]
.rsrc:00402475                 mov     [ebp+out_buff_ret], ecx
.rsrc:00402478                 pusha
.rsrc:00402479                 mov     esi, [ebp+inbuff]
.rsrc:0040247C                 mov     edi, [ebp+out_buff_ret]
.rsrc:0040247F                 add     edi, [ebp+var_4]
.rsrc:00402482                 inc     edi
.rsrc:00402483                 mov     bx, [ebp+var_10]
.rsrc:00402487                 mov     ebp, [ebp+internal_size]
.rsrc:0040248A loc_40248A:                             ; CODE XREF: unknown_enc+A3j
.rsrc:0040248A                 mov     dx, bx          ; size - 1
.rsrc:0040248D                 and     dx, 3
.rsrc:00402491                 mov     ax, 1C7h
.rsrc:00402495                 push    eax
.rsrc:00402496                 sahf
.rsrc:00402497                 jmp     short loc_4024BA ; al = inbuff[i]
.rsrc:00402499 ; ---------------------------------------------------------------------------
.rsrc:00402499 loc_402499:                             ; CODE XREF: unknown_enc+85j
.rsrc:00402499                 mov     [ebp+var_C], 0
.rsrc:004024A0                 mov     edx, [ebp+var_C]
.rsrc:004024A3                 add     edx, 0Ah
.rsrc:004024A6                 mov     [ebp+var_C], edx
.rsrc:004024A9                 mov     [ebp+var_18], 0Fh
.rsrc:004024B0                 mov     eax, [ebp+var_C]
.rsrc:004024B3                 imul    eax, [ebp+var_18]
.rsrc:004024B7                 mov     [ebp+var_C], eax
.rsrc:004024BA loc_4024BA:                             ; CODE XREF: unknown_enc+57j
.rsrc:004024BA                 lodsb                   ; al = inbuff[i]
.rsrc:004024BB                 pushf
.rsrc:004024BC                 db      36h
.rsrc:004024BC                 xor     al, [esp+50h+var_4C] ; 0xc7
.rsrc:004024C1                 xchg    dl, cl          ; 60
.rsrc:004024C3                 jmp     short loc_4024C7
.rsrc:004024C5 ; ---------------------------------------------------------------------------
.rsrc:004024C5                 jmp     short loc_402499
.rsrc:004024C7 ; ---------------------------------------------------------------------------
.rsrc:004024C7 loc_4024C7:                             ; CODE XREF: unknown_enc+83j
.rsrc:004024C7                 rol     ah, cl
.rsrc:004024C9                 popf
.rsrc:004024CA                 adc     al, ah          ; 1, 1, 2
.rsrc:004024CC                 xchg    dl, cl
.rsrc:004024CE                 xor     edx, edx
.rsrc:004024D0                 and     eax, 0FFh
.rsrc:004024D5                 add     bx, ax          ; resutl + size
.rsrc:004024D8                 stosb
.rsrc:004024D9                 mov     cx, dx
.rsrc:004024DC                 pop     eax
.rsrc:004024DD                 jecxz   short loc_4024E7
.rsrc:004024DF                 sub     edi, 2
.rsrc:004024E2                 dec     ebp
.rsrc:004024E3                 jnz     short loc_40248A ; size - 1
.rsrc:004024E5                 jmp     short loc_4024E9
.rsrc:004024E7 ; ---------------------------------------------------------------------------
.rsrc:004024E7 loc_4024E7:                             ; CODE XREF: unknown_enc+9Dj
.rsrc:004024E7                 xor     eax, eax
.rsrc:004024E9 loc_4024E9:                             ; CODE XREF: unknown_enc+A5j
.rsrc:004024E9                 popa
.rsrc:004024EA                 mov     eax, [ebp+out_buff_ret]
.rsrc:004024ED                 pop     edi
.rsrc:004024EE                 pop     esi
.rsrc:004024EF                 pop     ebx
.rsrc:004024F0                 mov     esp, ebp
.rsrc:004024F2                 pop     ebp
.rsrc:004024F3                 retn
.rsrc:004024F3 unknown_enc     endp

Encryption mechanism is bit tricky (saving/restoring EFLAGS and using ADC while carry flag is always set on). After some messy prototypes, I wrote the following C code for the encryption pahse:

void EncryptBuffer(char* input, char* output, int size)
    int i = 0;
    char internal_size = size - 1;

        output[size] = (input[i] ^ 0xc7) + __rol(1, (internal_size &amp; 3)) + 1;
        internal_size += output[size];

    } while (size >= 0);

The hard part was writing the decryption phase of the algorithm, I had to produce the same state (internal_size value) for each iteration to get the right input. Again, after playing with it, I wrote the decryption algorithm as follows:

void DecryptBuffer(char* input, char* output, int size)
    int i = 0;
    char internal_size = size -1;

        output[i] = (input[size] - (__rol(1, (internal_size &amp; 3)) + 1)) ^ 0xc7;
        internal_size += input[size];

    } while (size >= 0);

Program uses this algorithm to encrypt 3 blocks of 50 bytes each at locations 0, 100 and 200 of the encrypted RSA key buffer (from the last AES step), then It wrote encrypted RSA key alongside the RSA encrypted file content in the result.txt . Getting the RAS key was just matter of doing the same encryption chain in backwards. By doing this, I got the following RSA private key from given result.txt :


Decrypting the file content  gave me final email address which was “”.

You can get files from my github account.


From → Reversing

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: