加密本地文件内容的勒索软件原理与解决
A new ransomware variant, named “Fsociety Locker” (“Fsociety ALpha 1.0”), showed up recently seeking a place in the threat marketplace. The authors of this malware must be “Mr. Robot” fans, as the name “Fsociety” refers to the fictional group of hackers in that show.
This new ransomware variant is one of the very few examples of Python-based ransomware in the wild. Python is typically considered to be a fast, easy language to code in, so this maybe the start of a new malware trend.
In this article we answer several questions that readers might ask about this ransomware:
- What files will it encrypt?
- How does it encrypt files (what algorithm does it use)?
- Is there a way to decrypt the files?
- What are the payment instructions like?
Fsociety has also implemented several new dangerous features in this release, most of which were not included in its earlier version. These include such things as infecting network drives, anti-VM techniques, and downloading and executing new payloads off of the internet - something which we provide more details about below.
We have also included the “decryptor” code in this blog, which can be used to recover any files encrypted by this ransomware sample.
What Files Does Fsociety Encrypt?
The first thing ransomware has to do is to sneak into your system and find files to encrypt. Fsociety does a broad search through volumes “C:\” to “Z:\”. As you can see below, Fsociety calls functions with names “walk__drive ()” to iterate through each drive in order to find files to encrypt.
Figure 1. List of functions to literate
The target drives illustrated in Figure 1 above are simply drives that have been assigned with local drive letters. However, Fsociety also has the dangerous potential to infect network drives too. The code that is responsible of doing so has already been implemented. However, in the sample we tested, it had not yet been triggered.
Figure 2. Searching for network drives
Figure 3 (below) is a detailed example of one of these drive-iterating functions (“walk_C_drive()”)since the only difference between them is the drive letter. This function uses the Python built-in module “os” to get the full path of non-directory files in the targeted drive, and appends them to a list. Note that the targeted files are filtered with certain extensions (“ext”), which means this ransomware only chooses certain types of files to encrypt.
Figure 3. Gets files from one drive
Any files with an extension listed below will be encrypted. As you can see, Fsociety targets a wide range of file extensions, including files already encrypted with other ransomware. Which means that even files such as “locky” will be reencrypted with Fsociety.
Figure 4. Supported Extensions
How Does Fsociety Encrypt Files?
After locating targeted files, Fsociety then encrypts them using an AES algorithm with a hard-coded key. The original files are over-written with encrypted bytes.
Figure 5. Encryption
After encryption, the file names are appended with ".fs0ciety".
Figure 6. Appends extension to encrypted file names
Is There a Way to Recover the Encrypted Files?
For the current version of Fsociety, the answer is YES. We already know that the algorithm is AES and that the key it uses is hard-coded. All we have to do is to find the hard-coded key and use an AES decryption method to decrypt the files using this key. For example, the key for the sample we analyzed is "123456789123456", which makes us think this might be a test version of Fsociety.
Even though this might ony be a test version, this sample can still encrypt your important files. To help to recover those files, we have created a decryption script for the sample and included the decryption code in the “Appendix” section of this blog.
“Invisible” Payment Instructions
Normally, ransomware will show victims payment instruction on how to purchase a “decryptor” to decrypt and recover thire encrypted files. Fsociety has a sub-function to compose such an instruction, and uses a browser to open it. However, this sub-function is not called in its main function in this version, so victims are not able to see the instructions. In addition, the instructions themselves seem to be unfinished.
Figure 7. Instructions
Unused Malicious Features
Besides infecting network share resources, there are some additional features which have written, but are not being used. For example, one feature of Fsociety allows it to download an executable file from a link and run it locally. The executable it downloads, for example, might be a tor client to help Fsociety hide its network traffic, such as its payment server.
Figure 8. Downloads executable and runs
Another feature is an anti-VM evasion technique. If the malware detects that it is running in a VM environment, it will exit immediately.
Figure 9. Anti-VM code
Conclusion
Currently, it appears that Fsociety is still under early development, but as we described, it already has many dangerous features implemented. It is entirely possible that in the near future this new ransomware variant will be launched into the wild just as dangerous as any other mature ransomware, but with the time required for upgrades and modifications significantly shortened due to the relatively easiness of coding in Python. Moreover, since it’s written in Python and compiled with PyInstaller, authors can easily change it to support other platforms, such as Linux and MacOS.
NOTE: Fortinet detects Fscociety as “W32/Malicious_Behavior.VEX”.
Sample Information
MD5: d8a84048067f2b73fc8bb994bc0abe71
SHA256: 6369badfb87908562025fe09278b5648f33d42a737c76bacaa80e48183643ac6
References
http://www.bleepingcomputer.com/news/security/new-fsociety-ransomware-pays-homage-to-mr-robot/
Appendix
Below is the decryptor code for this ransomware sample. You can decrypt files one by one or decrypt all the files in a folder at once.
Usage: Please note that the recovered files will contain same data padding at the end.
Note: This decryptor code is provided 'as-is', and cannot be assumed to work on future variants. See disclaimer, below.
Disclaimer: This code is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the authors be liable for any claim, damage,s or other liability, whether in an action of contract, tor,t or otherwise, arising from, out of or in connection with this code, or the use thereof.
#!/usr/bin/env python |
# -*- coding: utf-8 -*- |
""" |
Created by ART, Fortinet Inc. |
Sample MD5: d8a84048067f2b73fc8bb994bc0abe71 |
""" |
import os |
import sys |
import hashlib |
import cStringIO |
from Crypto import Random |
from Crypto.Cipher import AES |
SIGNATURE = 'Dt0x__' |
PASSWORD = '123456789123456' |
def derive_key_and_iv(password, salt, key_length, iv_length): |
d = s = '' |
while len(d) < key_length + iv_length: |
s = hashlib.md5(s + password + salt).digest() |
d += s |
return d[:key_length], d[key_length:key_length+iv_length] |
def isEncryptedFile(filename): |
global SIGNATURE |
data = open(filename, "rb").read(len(SIGNATURE)) |
if data==SIGNATURE: |
return True |
return False |
def decrypt(in_file, out_file, password, key_length=32): |
global SIGNATURE |
ok = True |
try: |
bs = AES.block_size |
sig_len = len(SIGNATURE) |
salt = in_file.read(bs)[sig_len:] |
key, iv = derive_key_and_iv(password, salt, key_length, bs) |
cipher = AES.new(key, AES.MODE_CBC, iv) |
finished = False |
while not finished: |
chunk = in_file.read(1024 * bs) |
if len(chunk) == 0 or len(chunk) % bs != 0: |
padding_length = bs - (len(chunk) % bs) |
chunk += padding_length * chr(padding_length) |
finished = True |
out_file.write(cipher.decrypt(chunk)) |
except: |
ok = False |
return ok |
def decryptFile(infile): |
global PASSWORD |
if isEncryptedFile(infile): |
print "[*] Found encrypted file: %s", infile |
outfile = infile + ".decrypted" |
if decrypt(open(infile, "rb"), open(outfile, "wb"), PASSWORD): |
print "[+] Decrypt successfully! Store to:", outfile |
else: |
print "[-] Decrypt failed!" |
def decryptFiles(target): |
if os.path.exists(target): |
if os.path.isdir(target): |
for root, dirs, names in os.walk(target): |
for name in names: |
filename = os.path.join(root, name) |
decryptFile(filename) |
else: |
decryptFile(target) |
def bar(): |
print """Fs0ciety Ransomware Decryption Tool. |
Written by ART, Fortinet Inc. |
""" |
def main(): |
bar() |
for target in sys.argv[1:]: |
decryptFiles(target) |
if __name__ == "__main__": |
main() |