Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,34 @@
1. download the script in HOME directory `wget https://raw.githubusercontent.com/Hax4us/Metasploit_termux/master/metasploit.sh`
2. run `chmod +x metasploit.sh && ./metasploit.sh`


### Escáner de redes Wi-Fi
El script `wifi_scanner.py` permite listar redes Wi-Fi cercanas y ver la potencia de señal de cada una.

**Uso básico**
```bash
python wifi_scanner.py # usa la interfaz wlan0 por defecto
```

**Opciones útiles**
- `-i/--interface`: seleccionar la interfaz inalámbrica (ej. `wlan1`).
- `--raw`: mostrar también la salida cruda del comando utilizado.
- `--iwlist`: forzar el uso de `iwlist` incluso si `termux-wifi-scaninfo` está disponible.

### Uso en Termux
1. Instala los binarios de la API: `pkg install termux-api`.
2. Otorga permiso de ubicación a Termux desde Android para que pueda leer escaneos Wi‑Fi.
3. Ejecuta el escáner normalmente:
```bash
python wifi_scanner.py
```
El script usará `termux-wifi-scaninfo` automáticamente (no requiere root).

### Uso en otras distribuciones de Linux
1. Instala `wireless-tools` (u otro paquete que provea `iwlist`).
2. Ejecuta con la interfaz deseada:
```bash
sudo python wifi_scanner.py -i wlan0
```

> Necesitas tener instalado `termux-api` **o** `iwlist` y permisos para realizar escaneos inalámbricos.
224 changes: 224 additions & 0 deletions wifi_scanner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
#!/usr/bin/env python3
"""Simple Wi-Fi scanner for listing nearby networks and signal strength.

The script shells out to ``iwlist`` to perform a scan and then parses the
results into a compact table. It is intended for quick use on Termux or other
Linux environments where ``iwlist`` is available.
"""

from __future__ import annotations

import argparse
import json
import re
import shutil
import subprocess
from dataclasses import dataclass
from typing import Iterable, List, Optional


@dataclass
class WiFiNetwork:
"""Represents a discovered Wi-Fi network."""

bssid: str
essid: str
frequency: Optional[str]
channel: Optional[int]
signal_dbm: Optional[int]
encryption: Optional[str]


CELL_PATTERN = re.compile(r"^\s*Cell \d+ - Address: (?P<bssid>[0-9A-F:]{17})", re.IGNORECASE)
FREQUENCY_PATTERN = re.compile(r"Frequency:(?P<freq>[0-9.]+) GHz")
CHANNEL_PATTERN = re.compile(r"Channel:(?P<channel>\d+)")
SIGNAL_PATTERN = re.compile(r"Signal level=-(?P<level>\d+) dBm")
ESSID_PATTERN = re.compile(r"ESSID:\"(?P<essid>.*)\"")
ENCRYPTION_PATTERN = re.compile(r"Encryption key:(?P<state>on|off)", re.IGNORECASE)


def parse_scan_output(raw_output: str) -> List[WiFiNetwork]:
"""Parse iwlist scanning output into a list of WiFiNetwork entries."""

networks: List[WiFiNetwork] = []
current: dict[str, Optional[str | int]] = {}

for line in raw_output.splitlines():
cell_match = CELL_PATTERN.match(line)
if cell_match:
if current:
networks.append(_build_network(current))
current = {"bssid": cell_match.group("bssid")}
continue

if not current:
continue

if (essid_match := ESSID_PATTERN.search(line)):
current["essid"] = essid_match.group("essid")
continue

if (freq_match := FREQUENCY_PATTERN.search(line)):
current["frequency"] = f"{freq_match.group('freq')} GHz"
continue

if (channel_match := CHANNEL_PATTERN.search(line)):
current["channel"] = int(channel_match.group("channel"))
continue

if (signal_match := SIGNAL_PATTERN.search(line)):
current["signal_dbm"] = -int(signal_match.group("level"))
continue

if (encryption_match := ENCRYPTION_PATTERN.search(line)):
current["encryption"] = "WPA/WEP" if encryption_match.group("state").lower() == "on" else "Open"
continue

if current:
networks.append(_build_network(current))

return networks


def _build_network(fields: dict[str, Optional[str | int]]) -> WiFiNetwork:
return WiFiNetwork(
bssid=str(fields.get("bssid", "Unknown")),
essid=str(fields.get("essid", "<hidden>")),
frequency=fields.get("frequency"),
channel=fields.get("channel") if isinstance(fields.get("channel"), int) else None,
signal_dbm=fields.get("signal_dbm") if isinstance(fields.get("signal_dbm"), int) else None,
encryption=fields.get("encryption"),
)


def parse_termux_output(raw_output: str) -> List[WiFiNetwork]:
"""Parse output from ``termux-wifi-scaninfo`` (JSON array of APs)."""

try:
access_points = json.loads(raw_output)
except json.JSONDecodeError:
return []

networks: List[WiFiNetwork] = []
for ap in access_points if isinstance(access_points, list) else []:
bssid = ap.get("bssid", "Unknown") if isinstance(ap, dict) else "Unknown"
essid = ap.get("ssid", "<hidden>") if isinstance(ap, dict) else "<hidden>"
frequency = ap.get("frequency") if isinstance(ap, dict) else None
signal_dbm = ap.get("level") if isinstance(ap, dict) else None
channel = _frequency_to_channel(frequency) if isinstance(frequency, (int, float)) else None

networks.append(
WiFiNetwork(
bssid=bssid,
essid=essid,
frequency=f"{frequency} MHz" if frequency else None,
channel=channel,
signal_dbm=signal_dbm if isinstance(signal_dbm, int) else None,
encryption=ap.get("capabilities") if isinstance(ap, dict) else None,
)
)

return networks


def _frequency_to_channel(frequency_mhz: float) -> Optional[int]:
"""Best-effort conversion from frequency (MHz) to Wi-Fi channel number."""

if frequency_mhz is None:
return None
if 2412 <= frequency_mhz <= 2472:
return int((frequency_mhz - 2407) / 5)
if frequency_mhz == 2484:
return 14
if 5170 <= frequency_mhz <= 5825:
return int((frequency_mhz - 5000) / 5)
return None


def scan(interface: str, prefer_iwlist: bool = False) -> tuple[List[WiFiNetwork], str]:
"""Run a scan and return parsed results and raw output.

On Termux, it prefers ``termux-wifi-scaninfo`` if available to avoid
requiring root. Pass ``prefer_iwlist=True`` to force iwlist usage.
"""

termux_cmd = shutil.which("termux-wifi-scaninfo")
if termux_cmd and not prefer_iwlist:
result = subprocess.run([termux_cmd], check=True, capture_output=True, text=True)
return parse_termux_output(result.stdout), result.stdout

iwlist_cmd = shutil.which("iwlist")
if iwlist_cmd:
result = subprocess.run(
[iwlist_cmd, interface, "scanning"], check=True, capture_output=True, text=True
)
return parse_scan_output(result.stdout), result.stdout

raise FileNotFoundError(
"No se encontró 'termux-wifi-scaninfo' ni 'iwlist'. Instala termux-api o wireless-tools."
)


def format_table(networks: Iterable[WiFiNetwork]) -> str:
"""Return a formatted table ready for printing."""

rows = [
(n.essid, n.bssid, n.signal_dbm or "-", n.channel or "-", n.frequency or "-", n.encryption or "-" )
for n in networks
]

headers = ("SSID", "BSSID", "Signal (dBm)", "Channel", "Frequency", "Encryption")
col_widths = [max(len(str(row[i])) for row in rows + [headers]) for i in range(len(headers))]

def fmt_row(row: Iterable[object]) -> str:
return " ".join(str(cell).ljust(col_widths[i]) for i, cell in enumerate(row))

lines = [fmt_row(headers), fmt_row(["-" * w for w in col_widths])]
lines.extend(fmt_row(row) for row in rows)
return "\n".join(lines)


def main() -> None:
parser = argparse.ArgumentParser(
description="Escanea redes Wi-Fi cercanas y muestra sus detalles básicos."
)
parser.add_argument(
"-i",
"--interface",
default="wlan0",
help="Interfaz inalámbrica a escanear (por defecto: wlan0)",
)
parser.add_argument(
"--raw",
action="store_true",
help="Mostrar salida cruda del comando de escaneo además de la tabla resumida.",
)
parser.add_argument(
"--iwlist",
action="store_true",
help="Forzar uso de iwlist incluso en Termux (requiere wireless-tools y permisos)",
)

args = parser.parse_args()

try:
networks, raw_output = scan(args.interface, prefer_iwlist=args.iwlist)
except FileNotFoundError as exc:
raise SystemExit(str(exc))
except subprocess.CalledProcessError as exc:
raise SystemExit(
f"Error al ejecutar el escaneo: {exc}. Asegúrate de tener permisos y que la interfaz existe."
)

if args.raw:
print(raw_output)

if not networks:
print("No se encontraron redes. Verifica la interfaz y repite el comando.")
return

print(format_table(networks))


if __name__ == "__main__":
main()