Crypto updates to crimeware toolkits
We’ve been tracking some of the recent updates to underground exploit kits such as Neutrino and Redkit. We noticed few interesting updates that we want to share:
- Target fingerprinting: In this the exploit works only in presence of certain ‘Referrer’ or only when it encounters a specially crafted request query;
- Data Encryption: Encrypting data between client and server sides of the kit;
- De-obfuscation routine: In this, the malicious executable gets de-obfuscated after it lands on the victim’s hard drive.
The latter feature is somewhat new in the cybercrime business involving exploit kits. It helps to evade NIPS solutions analyzing network traffic. In this article we dissect the encryption algorithm used in a PDF exploit we found in the wild.
Some kits were reported to use AES algorithm in Java exploits to decrypt the malware binary, but it seems like some of the x86 shellcode also got this ‘feature’ update. Obviously any typical shellcode is way to ‘small’ to have a built-in AES implementation (or any other semantically secure cipher) so malware authors need more light weight solution. The PDF exploit we found in the wild takes advantage of an old widely discussed CVE-2010-0188 (LibTIFF). Analysis of this vulnerability and its exploitation can be found here and here .
The de-obfuscated script depending on the version of Adobe Reader calls the corresponding payload:
The two shellcodes are almost identical except for the preamble. First the shellcode resolves the required APIs:
Then it generates a random name (using CPU counter) and downloads the encrypted executable to the user’s temporary folder. Then it calls the decryption function:
Finally it calls WinExec to run the downloaded file and then tries to register it as command component in the registry using Regsvr32.exe /s. This command takes a DLL path as an argument which means that the sequence of calls WinExec(“<binary>”), WinExec(“regsvr32 /s <binary>”) is used to launch for both executables and dynamic link libraries. This is another feature that was not used before in exploit kits.
The encryption algorithm is based on Linear Congruential Generator. Its formula is ax+c (mod m), where x is a seed, a and c are constants and m is the modulus. In this implementation values 0x343FD, 0x269EC3 and 32 were used respectively. The output of LCG is reduced to 31 byte (the sign bit is always 0).
It is some sort of a block cipher, which takes 1 byte at a time and encrypts/decrypts it. The 32 bit long key is stored as the first 4 bytes of the encrypted binary. First step of decryption is extracting these bytes and replacing them with 0x00905A4D (MZ header). Then it computes values x=key(mod 3) and y=key(mod 2). The decryption of one block looks like this:
The step keys k1 and k2 are derived from the key using LCG. For the i-th byte these values are calculated like this (i=[1, 2, …]):
- k1 =LCG(2i, key)(mod 0xF1)+0xF
- k2 = LCG(2i+1, key)(mod 6)+1
Permutation 1 cyclically shifts the input block by k2 bits to the right if y=0 and to the left otherwise. Permutation 2 XORs the input value with k1 if x=0, if x=1, then subtracts k1 from the input value, otherwise adds k1 to the input value. Here’s the python code for the file decryption and encryption:
import sys import struct def LCG(x): return ( ( (x*0x343FD)&0xFFFFFFFF )+0x269EC3)&0x7FFFFFFF def rol(a,b): return ((a<<b)|(a>>(8-b)))&0xFF def ror(a,b): return ((a>>b)|(a<<(8-b)))&0xFF def decrypt(key, data): a = key%3 b = key%2 data = list(data) data='\x4d' data='\x5A' data='\x90' data='\x00' for i in range(4, len(data)): key = LCG(key) k1 = (key%0xF1)+0xF key = LCG(key) k2 = (key%0x6)+1 byte = ord(data[i]) if b==0: byte = rol(byte, k2) else: byte = ror(byte, k2) if a==0: byte = (byte^k1) elif a==1: byte-=k1 else: byte+=k1 data[i]=chr(byte&0xFF) return ''.join(data) def encrypt(key, data): a = key%3 b = key%2 data = list(data) key = struct.pack('<I', key) data=keystr data=keystr data=keystr data=keystr for i in range(4, len(data)): key = LCG(key) k1 = (key%0xF1)+0xF key = LCG(key) k2 = (key%0x6)+1 byte = ord(data[i]) if a==0: byte = byte^k1 elif a==1: byte = byte+k1 else: byte = byte-k1 byte&=0xFF if b==0: byte = ror(byte, k2) else: byte = rol(byte, k2) data[i]=chr(byte) return ''.join(data) def main(): if len(sys.argv)!=4: print 'Usage %s <encrypt|decrypt>'%sys.argv sys.exit() fd = open(sys.argv) filecontents = fd.read() fd.close() key = int(sys.argv, 16) if sys.argv=='encrypt': data = encrypt(key, filecontents) elif sys.argv=='decrypt': data = decrypt(key, filecontents) else: print 'Unknown argument %s'%sys.argv sys.exit() sys.stdout.write(data) if __name__ == '__main__': main()
The encryption scheme is analogous; it requires us to apply permutations in reverse order. The cipher has all that it needs to effectively evade traffic analysis:
- it is small enough to implemented in the shellcode;
- it is good enough to skew structure and frequency distribution of the PE file.
Below are the character distributions of 4 Windows executables encrypted with randomly generated keys:
Although the distribution is a bit biased (red line on each plot shows how the perfectly random distribution would look like) it’s good enough to be confused by a network inspection device like NIDS with some other binary data (say, an archive, compressed image, etc).
This might indicate another step of evolution of the windows shellcode used in drive-by-download attacks like obfuscation and hash-based API resolving which was seen some years ago.
While loaders (executables bearing obfuscated payload) provide a certain level of stealthiness on the hard drive, the encryption scheme used in our example protects the file on its way from malicious server to the target system. It will be quite difficult to write a signature for such kind of file since it’s just a binary blob which could be anything. It clearly shows that crimeware business lives and evolves. It appears that instead of discovering new attack techniques for Windows 7+, Chrome, Adobe Reader X+ etc. malware authors try to take as much as possible from the older and more vulnerable systems by increasing the quality of malicious content delivery.
These developments call for the use of new endpoint based techniques for protection and analysis as network based inspection technologies are effectively blind to these new developments. As obfuscation techniques continue to evolve, the need for a robust analysis environment increases.