AvosLocker Ransomware Linux Version Analysis

ELF Analysis

The analyzed sample was found on the public platform MalwareBazaar and its sha256sum is 10ab76cd6d6b50d26fde5fe54e8d80fceeb744de8dbafddff470939fac6a98c4. Based on the ELF header, it was compiled with GCC 4.4.7.

$ readelf -p .comment 10ab76cd6d6b50d26fde5fe54e8d80fceeb744de8dbafddff470939fac6a98c4.elf
String dump of section '.comment':
  [     0]  GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-23)

Obviously, the binary is stripped and does not contain any symbols:

$ nm 10ab76cd6d6b50d26fde5fe54e8d80fceeb744de8dbafddff470939fac6a98c4.elf
nm: 10ab76cd6d6b50d26fde5fe54e8d80fceeb744de8dbafddff470939fac6a98c4.elf: no symbols

The ELF header also contains the sections .ctors and .dtors. The .ctors section contains a list of functions ran before the main function to initialize dynamic non-local variables.

$ readelf -S ./10ab76cd6d6b50d26fde5fe54e8d80fceeb744de8dbafddff470939fac6a98c4.elf
Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000400200  00000200
       000000000000001c  0000000000000000   A       0     0     1
....
snip
....
  [19] .ctors            PROGBITS         0000000000757000  00157000
       00000000000000a0  0000000000000000  WA       0     0     8
  [20] .dtors            PROGBITS         00000000007570a0  001570a0
       0000000000000010  0000000000000000  WA       0     0     8

The last constructor function called initializes three strings, the ransom notes, the sample ID, and base64 strings:

ransom_notes

The decoded base64 strings are 88-byte long and at first sight I couldn’t figure out what it was.

$echo -en "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE9U+h7UA0Do9mVDFVJM9Gj5Qi/5zn2b/5dH9qFMApEmVngoc4zlLk49U1iWc2l+in2CtyQb+/s+JKvyPvack9gw==" | base64 -d | xxd
00000000: 3056 3010 0607 2a86 48ce 3d02 0106 052b  0V0...*.H.=....+
00000010: 8104 000a 0342 0004 f54f a1ed 4034 0e8f  .....B...O..@4..
00000020: 6654 3155 24cf 468f 9422 ff9c e7d9 bff9  fT1U$.F.."......
00000030: 747f 6a14 c029 1265 6782 8738 ce52 e4e3  t.j..).eg..8.R..
00000040: d535 8967 3697 e8a7 d82b 7241 bfbf b3e2  .5.g6....+rA....
00000050: 4abf 23ef 69c9 3d83                      J.#.i.=.

Then, by digging further in the binary, it appears to be an elliptic curve public key generated using the secp256k1 curve.

$echo -en "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE9U+h7UA0Do9mVDFVJM9Gj5Qi/5zn2b/5dH9qFMApEmVngoc4zlLk49U1iWc2l+in2CtyQb+/s+JKvyPvack9gw==" | base64 -d | openssl asn1parse -inform DER -dump
    0:d=0  hl=2 l=  86 cons: SEQUENCE
    2:d=1  hl=2 l=  16 cons: SEQUENCE
    4:d=2  hl=2 l=   7 prim: OBJECT            :id-ecPublicKey
   13:d=2  hl=2 l=   5 prim: OBJECT            :secp256k1
   20:d=1  hl=2 l=  66 prim: BIT STRING
      0000 - 00 04 f5 4f a1 ed 40 34-0e 8f 66 54 31 55 24 cf   ...O..@4..fT1U$.
      0010 - 46 8f 94 22 ff 9c e7 d9-bf f9 74 7f 6a 14 c0 29   F.."......t.j..)
      0020 - 12 65 67 82 87 38 ce 52-e4 e3 d5 35 89 67 36 97   .eg..8.R...5.g6.
      0030 - e8 a7 d8 2b 72 41 bf bf-b3 e2 4a bf 23 ef 69 c9   ...+rA....J.#.i.
      0040 - 3d 83                                             =.

Finally, three objects are initialized, two of them will hold a public and private key, and one is for the random generator. These objects come from the crypto++ library.

ctors_object_init

Main function

No technique has been set up to obfuscate and protect the ransomware. The ransomware is basic and accepts two parameters, the number of threads to be used and the directories to encrypt:

program_helper

If one of the given paths contains the strings « esxi » or « vmfs », a global variable is set to true and the running VMs (virtual machines) are killed using the esxcli command line:

killing_ESXi

Finally, it will browse the given lists of directories recursively, load the attackers’ public key and build a list of files that the encryption thread routine will consume.

main_encryption_flow

Generating the list of files to encrypt

The function that builds the list of files to encrypt is simple. First, it calls « opendir » with the directory path name to encrypt, and then, using « readdir », it iterates through the files in the directory. If it is a regular file and the name is not « README_FOR_RESTORE » or it does not end with the « .avoslinux » or « .avos2 » extension, it is added to the global list. If the esxi global variable is set to true, only files that end with « .vmdk », « .vmem », « .vswp », « .vmsn » or « .log » are added to the list:

build_files_list_to_encrypt

Unlike most Windows pieces of ransomware, that only encrypt data files based on their extension name using a whitelist or a blacklist, this Linux variant may encrypt all the files, including system files.

Load the attackers’ public key

Because the ransomware uses the crypto++ library, we recognize the particular concept of filters and pipes used by the library in the reversed code. Similarly to Unix, Pipes allows data flows from a source to a sink and filters them to transform them. The original function that decodes and loads the base64 attackers’ public key would probably look like this:

AutoSeededRandomPool prng;
string encoded = "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE9U+h7UA0Do9mVDFVJM9Gj5Qi/5zn2b/5dH9qFMApEmVngoc4zlLk49U1iWc2l+in2CtyQb+/+JKvyPvack9gw==";
string decoded;

StringSource ss(encoded, true, new Base64Decoder( new StringSink(decoded)));

ECIES<ECP>::Encryptor e0;
e0.AccessPublicKey().Load(decoded);
e0.GetPublicKey().ThrowIfInvalid(prng, 3); // Validate the public key
load_attackers_public_elliptic_curvre_key

Encryption

To encrypt files on the disk, Avoslinux uses the Salsa20 stream ciphers using the 12-round variant. For each file to encrypt, it generates a 32-byte long Salsa key and an 8-byte long nonce.

gen_salsa_key_nonce

The generated key and nonce are passed to the function « ECIES_n_b64 » to be encrypted using the ECIES (Elliptic Curve Integrated Encryption Scheme) crypto scheme, and then base64-encoded.

ECIES_encrypt_key_and_nonce

The function would probably look like this:

string key_nonce;
StringSource ss1 (key_nonce, true, new PK_EncryptorFilter(prng, e0, new Base64Encoder( new StringSink(b64_ecies_key_nonce))));

The ECIES-encrypted output is bigger than the original: 125-byte long. Based on the crypto++ ECIES documentation, « The output of the encryption function is the tuple {K,C,T}, where K is the encrypted common secret, C is the ciphertext, and T is the authentication tag. »

The number of Salsa rounds is set:

set_salsa_rounds_and_key

The file is encrypted using the Salsa20/12 algorithm, and the key with the previously encrypted nonce (ECIES and base64) is appended to the end of the file.

salsa20/12 encrypting

Then, the file is renamed by appending the « .avoslinux » extension to the file.

File renamed

Finally, the Salsa key and the nonce are erased from the memory:

Salsa key and nonce zeroing

Conclusion

The Linux variant is very simple and has no special features like network encryption or any anti-reverse techniques to obfuscate codes. The encryption process is not common for a piece of ransomware and it is different from the Windows variant, which uses the RSA and AES combination. Another thing to note is that unlike most Windows pieces of ransomware, that only encrypt data files based on their extension name using a whitelist or a blacklist, this Linux variant may encrypt all the files, including system files.

IOCs

Sample hash

  • SHA256: 10ab76cd6d6b50d26fde5fe54e8d80fceeb744de8dbafddff470939fac6a98c4
  • SHA1: 9c8f5c136590a08a3103ba3e988073cfd5779519
  • MD5: f659d1d15d2e0f3bd87379f8e88c6b42

Elliptic curve public key

  • MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE9U+h7UA0Do9mVDFVJM9Gj5Qi/5zn2b/5dH9qFMApEmVngoc4zlLk49U1iWc2l+in2CtyQb+/s+JKvyPvack9gw==