I’d like to thanks Defensive Lab Agency and especially Esther for her help in the work on this sample

A couple of weeks ago, a suspicious sample that was masquerading the chat application Wire was detected. To our surprise, the application was detected as a Finspy sample based on rules written in 2020 by Defensive Lab Agency and Amnesty.

It is interesting to note that it seems to be the first time to have a Finspy sample is targetting a popular application. Wire didn’t seem to comment on that issue after being contacted through Twitter.

Overview

Field Value
Size 40.68MB
MD5 e162504122c224d4609ade9efa9af82d
SHA-1 4718bcf28bfffac1922a5c9f25140165563d6164
SHA-256 ae05bbd31820c566543addbb0ddc7b19b05be3c098d0f7aa658ab83d6f6cd5c8
Package org.xmlpush.v3.StartVersion

Certificate:

Field Value
MD5 6c6dd54955725ae5414c20e0a67ef6e4
SHA1 341c22ce9ab4e1008d3d507e5e8b3451a4efc2be
SHA256 e14f254656ff869bb738aec58656042171c8625c9defbcc6eb4f24d41d4ec929
Issuer Common Name: Unknown, Organizational Unit: Unknown, Organization: Zeta, Locality: Unknown, State/Province: Unknown, Country: Unknown
Owner C=Unknown, ST=Unknown, L=Unknown, O=Zeta, OU=Unknown, CN=Unknown
Signature Algorithm SHA256withRSA
Subject Public Key Algorithm 2048-bit RSA key
Version 3
Not Before 2021-04-26T10:51:28+00:00
Not After 2048-09-10T10:51:28+00:00

What Wire version is affected?

The analysed sample mimics the version 3.65.979 (2021/03/01).

Timeline?

  • First upload on VT (2021-05-19 04:31:51 UTC) Link
  • First upload on Pithus (2021-04-27T17:20:58.926579) Analyse
  • Twitter

What is the configuration of this malware?

We detected the application using the Yara rules developped by Defensive Lab Agency for their work on the Finspy samples in 2020. We can safely assume that those samples embbed the same artifacts and the same type of behaviour.

We extracted the configuration with the tools provided by Defensive Lab Agency and Amnesty:

  • C2: 78.46.120[.]20:443 (Hetzner) VT
  • C2: qa-demo.wire[.]link (Gandi) VT. Registered on 2018-09-05, expires on 2021-09-05. The whois data seems different form the legit wire[.]com website.

Here is a list of all the Finspy network indicators. It was updated with the detection discussed in this article.

TLV value TLV Name Associated Value
16651088 TlvTypeRequestID 0
16668512 TlvTypeMobileTargetUID 00 00 00 00 00 00 00 00
16651584 TlvTypeVersion 0
16668784 TlvTypeMobileTargetID 600
8675648 TlvTypeMobileTargetHeartbeatInterval 300
8689712 Unknown 00
8676496 TlvTypeMobileTargetPositioning 82 87 86 81 83
8678192 Unknown 01
8678448 Unknown 01
8402800 TlvTypeConfigTargetProxy 78.46.120[.]20
8403008 TlvTypeConfigTargetPort 443
8676208 TlvTypeConfigSMSPhoneNumber +780702441553
8676976 TlvTypeMobileTrojanID 600
8676672 TlvTypeMobileTrojanUID 8819601
16654656 TlvTypeUserID 1000
8392000 TlvTypeTrojanMaxInfections 5
8677440 TlvTypeConfigMobileAutoRemovalDateTime 0
8403776 TlvTypeConfigAutoRemovalIfNoProxy 168
8675472 TlvTypeMobileTargetHeartbeatEvents - SIM changed: True
- Cell location changed: False
- Network changed: True
- Call: False
- Wifi connected: True
- Data link available: True
- Network activated: False
- Data available: True
8675984 TlvTypeMobileTargetHeartbeatRestrictions d0 00
8677296 TlvTypeMobileTargetLocationChangedRange 00
8681872 TlvTypeInstalledModules - Spy calls: False
- Intercept calls: False
- SMS: True
- Address book: True
- Logging: False
- Location: True
- Call log: True
- Calendar: True
- Spy chats: True
4535440 TlvTypeMobileTrackingConfigRaw 56 00 00 00 a0 33 45 00 0c 00 00 00 40 41 45 00 e8 03 00 00 0c 00 00 00 40 40 45 00 2c 01 00 00 0c 00 00 00 40 44 45 00 e8 03 00 00 0c 00 00 00 40 43 45 00 2c 01 00 00 09 00 00 00 30 42 45 00 00 09 00 00 00 30 52 45 00 00 0c 00 00 00 90 64 84 00 85 00 00 00
5521552 Unknown 5c 00 00 00 a0 40 54 00 0c 00 00 00 40 44 fe 00 50 00 00 00 09 00 00 00 30 43 fe 00 01 0c 00 00 00 40 46 fe 00 28 00 00 00 0c 00 00 00 40 45 fe 00 05 00 00 00 09 00 00 00 30 97 fe 00 00 09 00 00 00 30 98 fe 00 01 0c 00 00 00 50 99 fe 00 02 00 00 00 09 00 00 00 30 02 54 00 01
5456016 Unknown 5f 00 00 00 a0 41 53 00 0c 00 00 00 40 44 fe 00 50 00 00 00 09 00 00 00 30 43 fe 00 01 0c 00 00 00 40 46 fe 00 28 00 00 00 0c 00 00 00 40 45 fe 00 05 00 00 00 09 00 00 00 30 97 fe 00 00 09 00 00 00 30 98 fe 00 01 0c 00 00 00 50 99 fe 00 02 00 00 00 0c 00 00 00 40 3f fe 00 00 00 00 00
5570960 Unknown 14 00 00 00 a0 02 55 00 0c 00 00 00 40 42 fe 00<br>11 2b 00 00
5644432 Unknown 3b 00 00 00 a0 21 56 00 09 00 00 00 30 23 56 00 01 09 00 00 00 30 25 56 00 01 09 00 00 00 30 24 56 00 01 0c 00 00 00 40 22 56 00 00 00 00 ff 0c 00 00 00 40 26 56 00 1e 00 00 ff
16647056 TlvTypeEncryption 43 58 50 5d 4f 59 06 43 53 5f 35 4a 52 30 0e 5b 2d 5e 27 4b 40 0f 36

String obfuscation (TippyPad)

In the same fashion as the sample previously analysed by Defensive Lab Agency, strings are obfuscated with the same pattern.

  • String o1IoIlolii0lOio1Il1001(int i) returns the obfuscated string as bytes at the given index.
  • lloilioi1oi01I0I0liO(byte[] bArr, byte[] bArr2) decodes an obfuscated string
 private static byte[] lloilioi1oi01I0I0liO(byte[] bArr, byte[] bArr2) {
        byte[] bArr3 = new byte[bArr2.length];
        for (int i = 0; i < bArr2.length; i++) {
            bArr3[i] = (byte) (bArr2[i] ^ bArr[i % bArr.length]);
        }
        return bArr3;
    }

    private static String o1IoIlolii0lOio1Il1001(int i) {
        byte[] bArr = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102};
        byte[] bArr2 = {102, 101, 100, 99, 98, 97, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48};
        ArrayList arrayList = new ArrayList();
        arrayList.add(new byte[]{81, 95, 86, 65, 91, 92, 82, 104, 81, 93});
        arrayList.add(new byte[]{39, 32, 55});
        arrayList.add(new byte[]{113, 116, 97});
        return new String(lloilioi1oi01I0I0liO(i % 2 == 0 ? bArr : bArr2, (byte[]) arrayList.get(i)));
    }
}

The two pads are the same as the previous sample which was detected as TippyPad:

  • 0123456789abcdef
  • fedcba9876543210

Local socket address generation (TippyTime)

The local socket address generation is similar to the previous samples:

    public static int m2108c(String str) {
        Ii0I011oo0iiOIlI00();
        byte[] bytes = str.getBytes();
        int length = bytes.length;
        int i = length / 4;
        int i2 = length ^ 0;
        int i3 = 0;
        while (i3 < i) {
            int i4 = i3 * 4;
            int i5 = (((bytes[i4 + 3] & 255) << 24) + (bytes[i4 + 0] & 255) + ((bytes[i4 + 1] & 255) << 8) + ((bytes[i4 + 2] & 255) << 16)) * 1540483477;
            i3++;
            i2 = ((i5 ^ (i5 >>> 24)) * 1540483477) ^ (i2 * 1540483477);
        }
        switch (length % 4) {
            case 3:
                i2 ^= (bytes[(length & -4) + 2] & 255) << 16;
            case 2:
                i2 ^= (bytes[(length & -4) + 1] & 255) << 8;
            case 1:
                i2 = (i2 ^ (bytes[length & -4] & 255)) * 1540483477;
                break;
        }
        int i6 = (i2 ^ (i2 >>> 13)) * 1540483477;
        return i6 ^ (i6 >>> 15);
    }

Suspicious ELFs found in the app

Most of our work was following the steps of Defensive Lab Agency and Amnesty. Further down in the analysis, there was some suspicious strings that looked like binary data. After contacting Defensive Lab Agency, they mentionned having found them as well.

There are a couple of java files that are larger than 2 megabytes:

-> find . -size +2M
./da2b11bb/b094ffd.java
./da2b11bb/afbffbc.java

With some Frida hooks, we managed to get the strings:

import frida

jscode = """
console.log("script loaded");
Java.perform(function () {
    const evilClass = Java.use("org.xmlpush.v3.da2b11bb.d552b92f");
    let stage1 = evilClass.o1IoIlolii0lOio1Il1001(1);

    let bytes = [];
    let stage2 = [];
    for (let i = 0; i < stage1.length; i++) {
        let code = stage1.charCodeAt(i);
        let stage2 = bytes.concat([code]);
    }

    // m2404c(byte[]) -> byte[]
    let stage3 = evilClass.c();
    console.log(stage3)

    let buffer = Java.array("byte", stage3);
    let result = "";
    for (let i = 0; i < buffer.length; ++i){
        result+= (String.fromCharCode(buffer[i]));
    }

    console.log(result);
    });
"""

if __name__ == '__main__':
    process = frida.get_device('emulator-5554').attach('com.wire')
    script = process.create_script(jscode)
    script.load()

And analysing the result:

-> % readelf -h res.bin [1]
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: ARM
Version: 0x1
Entry point address: 0x810
Start of program headers: 52 (bytes into file)
Start of section headers: 463781871 (bytes into file)
Flags: 0x2, GNU EABI, <unknown>
Size of this header: 1280 (bytes)
Size of program headers: 52 (bytes)
Number of program headers: 32
Size of section headers: 8 (bytes)
Number of section headers: 40
Section header string table index: 24
readelf: Error: The e_shentsize field in the ELF header is less than the size of an ELF section header
readelf: Warning: The e_phentsize field in the ELF header is larger than the size of an ELF program header
readelf: Error: the PHDR segment is not covered by a LOAD segment

ELF header manual inspection
e_ident: 7f45 4c46 0101 0100 0000 0000 0000 0000
e_type: 0300
e_machine: 2800
e_version: 0100 000
e_entry: 1008 0000 3400 0000
e_phoff: efbf a41b 0200 0000
e_shoff: 0005 3400 2000 0800
e_flags: 2800 1800
e_ehsize: 1700
e_phentsize: 0600
e_phnum: 0000
e_shentizie: 3400
e_shnum: 0000
e_shstrndx: 3400

Unfortunately, the binary has some sections corrupted and even if we managed to make it ignore some specific headers, the sections headers were so far, impossible for us to reverse.

Thoughts about this sample

This sample presents the same characteristics as the other samples: contact gathering, spying on phone calls and chats, getting data from other application as well. It is interesting to see Finspy putting its artifacts into another application. What is however more worrying is that fact that this was targetting a popular and well-known application.

It is unclear at this moment what and who this trojanised version of Wire was targetting and so far, no other samples alike have been identified.