Skip to content

Commit 113014e

Browse files
authored
Merge pull request #527 from kimocoder/eviltwin-fixes
Fix Evil Twin attack: make it actually work, and harden the portal
2 parents a0f0690 + 779b911 commit 113014e

14 files changed

Lines changed: 490 additions & 86 deletions

tests/test_adaptive_deauth_integration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def test_adaptive_deauth_initialized(self, mock_config):
3030
"""Test that adaptive deauth manager is initialized on attack creation."""
3131
# Set up Configuration mock with all required attributes
3232
mock_config.interface = 'wlan0'
33-
mock_config.evil_twin_deauth_interval = 5.0
33+
mock_config.eviltwin_deauth_interval = 5.0
3434
mock_config.wpa_attack_timeout = 60
3535

3636
from wifite.attack.eviltwin import EvilTwin

tests/test_eviltwin_e2e.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@
2828
# Set required Configuration attributes before importing other modules
2929
Configuration.wpa_attack_timeout = 600
3030
Configuration.interface = 'wlan0'
31-
Configuration.evil_twin_timeout = 0
32-
Configuration.evil_twin_portal_template = 'generic'
33-
Configuration.evil_twin_deauth_interval = 5
31+
Configuration.eviltwin_timeout = 0
32+
Configuration.eviltwin_template = 'generic'
33+
Configuration.eviltwin_deauth_interval = 5
3434

3535
from wifite.attack.eviltwin import EvilTwin, AttackState
3636
from wifite.model.target import Target
@@ -47,7 +47,7 @@ class TestRealRouterScenarios(unittest.TestCase):
4747
def setUp(self):
4848
"""Set up test fixtures."""
4949
Configuration.interface = 'wlan0'
50-
Configuration.evil_twin_timeout = 0
50+
Configuration.eviltwin_timeout = 0
5151

5252
def test_wpa2_personal_router_scenario(self):
5353
"""Test scenario: WPA2-Personal router with standard settings."""
@@ -593,7 +593,7 @@ def setUp(self):
593593
self.mock_target.wps = False
594594

595595
Configuration.interface = 'wlan0'
596-
Configuration.evil_twin_timeout = 0
596+
Configuration.eviltwin_timeout = 0
597597

598598
@patch('wifite.attack.eviltwin.Color')
599599
@patch('wifite.attack.eviltwin.input')

tests/test_eviltwin_unit.py

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,17 @@ def test_hostapd_initialization(self):
3535
self.assertEqual(hostapd.password, 'testpassword')
3636
self.assertFalse(hostapd.running)
3737

38-
def test_hostapd_default_password(self):
39-
"""Test hostapd uses default password when none provided."""
38+
def test_hostapd_open_network_when_no_password(self):
39+
"""With no password, the AP must be OPEN (captive portal requirement)."""
4040
hostapd = Hostapd('wlan0', 'TestNetwork', 6)
41-
42-
self.assertEqual(hostapd.password, 'temporarypassword123')
41+
42+
# No passphrase is stored, and the generated config must not enable WPA2
43+
# (otherwise clients couldn't associate to reach the portal).
44+
self.assertIsNone(hostapd.password)
45+
config = hostapd.generate_config()
46+
self.assertNotIn('wpa=2', config)
47+
self.assertNotIn('wpa_passphrase', config)
48+
self.assertIn('auth_algs=1', config)
4349

4450
def test_hostapd_config_generation(self):
4551
"""Test hostapd configuration file generation."""
@@ -66,8 +72,29 @@ def test_hostapd_config_special_characters(self):
6672
"""Test hostapd handles special characters in SSID."""
6773
hostapd = Hostapd('wlan0', 'Test Network 2.4GHz', 6, 'pass123')
6874
config = hostapd.generate_config()
69-
75+
7076
self.assertIn('ssid=Test Network 2.4GHz', config)
77+
78+
def test_hostapd_ssid_newline_injection_neutralized(self):
79+
"""A newline in the SSID must not inject hostapd directives."""
80+
# Malicious SSID attempting to append a directive on a new config line.
81+
malicious = 'Evil\nmacaddr_acl=1\nctrl_interface=/tmp/x'
82+
hostapd = Hostapd('wlan0', malicious, 6, 'pass123')
83+
config = hostapd.generate_config()
84+
85+
# The injected directives must NOT appear as standalone config lines.
86+
lines = config.split('\n')
87+
self.assertNotIn('ctrl_interface=/tmp/x', lines)
88+
# The SSID line must be hex-encoded (ssid2=) rather than a raw ssid=.
89+
self.assertTrue(any(line.startswith('ssid2=') for line in lines))
90+
self.assertFalse(any(line.startswith('ssid=Evil') for line in lines))
91+
92+
def test_hostapd_ssid_non_ascii_hex_encoded(self):
93+
"""Non-ASCII SSIDs are emitted as ssid2=<hex> (hostapd-safe)."""
94+
hostapd = Hostapd('wlan0', 'Café📶', 6, 'pass123')
95+
config = hostapd.generate_config()
96+
lines = config.split('\n')
97+
self.assertTrue(any(line.startswith('ssid2=') for line in lines))
7198

7299
def test_hostapd_config_file_creation(self):
73100
"""Test hostapd creates configuration file."""

wifite/args.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,13 @@ def _add_eviltwin_args(self, group):
531531
type=int,
532532
help=self._verbose('Seconds between deauth bursts (default: {G}5{W})'))
533533

534+
group.add_argument('--eviltwin-timeout',
535+
action='store',
536+
dest='eviltwin_timeout',
537+
metavar='[seconds]',
538+
type=int,
539+
help=self._verbose('Give up after N seconds (default: {G}0{W} = run until success/interrupt)'))
540+
534541
group.add_argument('--eviltwin-template',
535542
action='store',
536543
dest='eviltwin_template',

0 commit comments

Comments
 (0)