363 lines
11 KiB
Bash
Executable File
363 lines
11 KiB
Bash
Executable File
#!/bin/zsh
|
||
# Advanced Wi-Fi MAC spoofing script for macOS
|
||
# Automatically detects phone hotspot MAC or allows manual input
|
||
# Usage:
|
||
# spoof-wifi-mac.sh # auto-detect connected hotspot MAC
|
||
# spoof-wifi-mac.sh --phone-mac # detect phone MAC from hotspot
|
||
# spoof-wifi-mac.sh AA:BB:CC:DD:EE:FF # set specific MAC
|
||
# spoof-wifi-mac.sh --revert # restore original MAC
|
||
|
||
set -euo pipefail
|
||
|
||
# Get absolute path to script
|
||
if [ -n "${ZSH_VERSION:-}" ]; then
|
||
SCRIPT_PATH="${0:A}"
|
||
else
|
||
SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")"
|
||
fi
|
||
# Fallback if still empty
|
||
if [ -z "$SCRIPT_PATH" ] || [ ! -f "$SCRIPT_PATH" ]; then
|
||
SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")"
|
||
fi
|
||
|
||
STATE_FILE="/tmp/wifi_mac_spoof_state"
|
||
ORIGINAL_MAC_FILE="/tmp/wifi_mac_original"
|
||
|
||
# Colors for output
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
require_root() {
|
||
if [ "$EUID" -ne 0 ] && [ "$(id -u)" -ne 0 ]; then
|
||
echo -e "${YELLOW}Re-running with sudo...${NC}"
|
||
exec sudo -E "$0" "${@}"
|
||
fi
|
||
}
|
||
|
||
detect_wifi_if() {
|
||
local iface
|
||
iface=$(networksetup -listallhardwareports | awk '/Wi-Fi/{getline; print $2; exit}')
|
||
if [ -z "$iface" ]; then
|
||
echo -e "${RED}Error: Could not detect Wi-Fi interface${NC}"
|
||
exit 1
|
||
fi
|
||
echo "$iface"
|
||
}
|
||
|
||
get_current_mac() {
|
||
local iface="$1"
|
||
ifconfig "$iface" 2>/dev/null | awk '/ether/{print $2; exit}' || echo ""
|
||
}
|
||
|
||
get_connected_network() {
|
||
local iface="$1"
|
||
/System/Library/PrivateFrameworks/Apple80211.framework/Resources/airport -I 2>/dev/null | awk '/ SSID:/ {print substr($0, index($0,$2))}' || echo ""
|
||
}
|
||
|
||
get_connected_bssid() {
|
||
local iface="$1"
|
||
/System/Library/PrivateFrameworks/Apple80211.framework/Resources/airport -I 2>/dev/null | awk '/ BSSID:/ {print $2}' || echo ""
|
||
}
|
||
|
||
detect_phone_hotspot_mac() {
|
||
local iface="$1"
|
||
local bssid
|
||
|
||
echo -e "${BLUE}Detecting connected hotspot MAC...${NC}"
|
||
|
||
bssid=$(get_connected_bssid "$iface")
|
||
if [ -z "$bssid" ] || [ "$bssid" = "none" ]; then
|
||
echo -e "${YELLOW}Warning: Not connected to Wi-Fi or cannot detect BSSID${NC}"
|
||
return 1
|
||
fi
|
||
|
||
echo -e "${GREEN}Found hotspot BSSID: $bssid${NC}"
|
||
echo "$bssid"
|
||
return 0
|
||
}
|
||
|
||
validate_mac() {
|
||
local mac="$1"
|
||
if ! [[ "$mac" =~ ^([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}$ ]]; then
|
||
echo -e "${RED}Invalid MAC format: $mac (expected AA:BB:CC:DD:EE:FF)${NC}"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
power_wifi() {
|
||
local iface="$1"
|
||
local state="$2" # on|off
|
||
networksetup -setairportpower "$iface" "$state" 2>/dev/null || true
|
||
sleep 1
|
||
}
|
||
|
||
save_original_mac() {
|
||
local iface="$1"
|
||
local mac="$2"
|
||
|
||
if [ ! -f "$ORIGINAL_MAC_FILE" ]; then
|
||
echo "$iface|$mac" > "$ORIGINAL_MAC_FILE"
|
||
echo -e "${GREEN}Saved original MAC for permanent restore: $mac${NC}"
|
||
fi
|
||
}
|
||
|
||
check_sip_status() {
|
||
local sip_status
|
||
sip_status=$(csrutil status 2>/dev/null | grep -i "enabled" || echo "unknown")
|
||
if [[ "$sip_status" == *"enabled"* ]]; then
|
||
return 0 # SIP enabled
|
||
else
|
||
return 1 # SIP disabled or unknown
|
||
fi
|
||
}
|
||
|
||
set_mac() {
|
||
local iface="$1"
|
||
local mac="$2"
|
||
|
||
local current_mac
|
||
current_mac=$(get_current_mac "$iface")
|
||
|
||
if [ -z "$current_mac" ]; then
|
||
echo -e "${RED}Error: Cannot read current MAC address${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
echo -e "${BLUE}Current MAC: $current_mac${NC}"
|
||
echo -e "${BLUE}Target MAC: $mac${NC}"
|
||
|
||
if [ "$current_mac" = "$mac" ]; then
|
||
echo -e "${YELLOW}MAC already set to target value${NC}"
|
||
return 0
|
||
fi
|
||
|
||
# Check SIP status
|
||
if check_sip_status; then
|
||
echo -e "${YELLOW}⚠ System Integrity Protection (SIP) is enabled${NC}"
|
||
echo -e "${YELLOW}MAC spoofing may be blocked on Apple Silicon with SIP enabled${NC}"
|
||
fi
|
||
|
||
# Save original MAC if not saved
|
||
save_original_mac "$iface" "$current_mac"
|
||
|
||
# Save for revert
|
||
echo "$iface $current_mac" > "$STATE_FILE"
|
||
|
||
echo -e "${YELLOW}Turning Wi-Fi off...${NC}"
|
||
power_wifi "$iface" off
|
||
|
||
echo -e "${YELLOW}Setting MAC to $mac...${NC}"
|
||
|
||
# Try ifconfig method
|
||
local success=false
|
||
if ifconfig "$iface" ether "$mac" 2>/dev/null; then
|
||
success=true
|
||
fi
|
||
|
||
if [ "$success" = false ]; then
|
||
echo -e "${RED}✗ Error: Failed to set MAC address${NC}"
|
||
echo ""
|
||
echo -e "${BLUE}=== РЕШЕНИЕ ПРОБЛЕМЫ ===${NC}"
|
||
echo ""
|
||
|
||
if check_sip_status; then
|
||
echo -e "${YELLOW}На Apple Silicon (M1/M2/M3) с включенным SIP подмена MAC заблокирована${NC}"
|
||
echo ""
|
||
echo -e "${YELLOW}Варианты решения:${NC}"
|
||
echo "1. Отключить SIP (НЕ рекомендуется - снижает безопасность)"
|
||
echo " - Перезагрузите в Recovery Mode (Cmd+R)"
|
||
echo " - Утилиты → Терминал → csrutil disable"
|
||
echo " - Перезагрузите Mac"
|
||
echo ""
|
||
echo "2. Использовать альтернативные методы:"
|
||
echo " • VPN на телефоне (рекомендуется)"
|
||
echo " • USB Tethering вместо Wi-Fi hotspot"
|
||
echo " • Bluetooth Tethering"
|
||
echo ""
|
||
echo -e "${BLUE}Важно:${NC}"
|
||
echo "Оператор сотовой связи видит IMEI телефона, а не MAC MacBook."
|
||
echo "MAC клиента виден только на уровне локальной Wi-Fi сети."
|
||
echo "Подмена MAC не меняет идентификацию на уровне оператора."
|
||
else
|
||
echo -e "${YELLOW}Интерфейс может не поддерживать подмену MAC${NC}"
|
||
echo -e "${YELLOW}Или требуется дополнительная настройка${NC}"
|
||
fi
|
||
|
||
power_wifi "$iface" on
|
||
exit 1
|
||
fi
|
||
|
||
echo -e "${YELLOW}Turning Wi-Fi on...${NC}"
|
||
power_wifi "$iface" on
|
||
|
||
sleep 2
|
||
|
||
local new_mac
|
||
new_mac=$(get_current_mac "$iface")
|
||
|
||
if [ "$new_mac" = "$mac" ]; then
|
||
echo -e "${GREEN}✓ Success! MAC changed to: $new_mac${NC}"
|
||
else
|
||
echo -e "${RED}⚠ Warning: MAC may not have changed${NC}"
|
||
echo -e "${YELLOW}Current MAC: $new_mac${NC}"
|
||
echo -e "${YELLOW}Target MAC: $mac${NC}"
|
||
echo -e "${YELLOW}This may require disabling SIP or using a different method${NC}"
|
||
fi
|
||
}
|
||
|
||
revert_mac() {
|
||
local iface
|
||
local original_mac
|
||
|
||
if [ -f "$STATE_FILE" ]; then
|
||
read iface original_mac < "$STATE_FILE"
|
||
elif [ -f "$ORIGINAL_MAC_FILE" ]; then
|
||
local saved
|
||
saved=$(cat "$ORIGINAL_MAC_FILE")
|
||
iface=$(echo "$saved" | cut -d'|' -f1)
|
||
original_mac=$(echo "$saved" | cut -d'|' -f2)
|
||
else
|
||
echo -e "${RED}No saved MAC found. Cannot revert.${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
if [ -z "${iface:-}" ] || [ -z "${original_mac:-}" ]; then
|
||
echo -e "${RED}State file is corrupted. Delete $STATE_FILE and $ORIGINAL_MAC_FILE${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
echo -e "${BLUE}Restoring MAC for $iface to $original_mac...${NC}"
|
||
power_wifi "$iface" off
|
||
ifconfig "$iface" ether "$original_mac" 2>/dev/null || {
|
||
echo -e "${RED}Failed to restore MAC${NC}"
|
||
power_wifi "$iface" on
|
||
exit 1
|
||
}
|
||
power_wifi "$iface" on
|
||
sleep 2
|
||
|
||
rm -f "$STATE_FILE"
|
||
local current
|
||
current=$(get_current_mac "$iface")
|
||
echo -e "${GREEN}✓ Reverted. Current MAC: $current${NC}"
|
||
}
|
||
|
||
show_instructions() {
|
||
echo -e "${BLUE}=== ИНСТРУКЦИИ ПО ПОЛУЧЕНИЮ MAC ТЕЛЕФОНА ===${NC}"
|
||
echo ""
|
||
echo -e "${YELLOW}iPhone:${NC}"
|
||
echo "1. Настройки → Wi-Fi"
|
||
echo "2. Нажмите (i) рядом с сетью"
|
||
echo "3. Отключите 'Частный Wi-Fi адрес' (Private Wi-Fi Address)"
|
||
echo "4. MAC-адрес будет показан как 'Адрес Wi-Fi'"
|
||
echo ""
|
||
echo -e "${YELLOW}Android:${NC}"
|
||
echo "1. Настройки → О телефоне → Статус"
|
||
echo "2. Найдите 'MAC-адрес Wi-Fi'"
|
||
echo ""
|
||
echo -e "${YELLOW}Альтернативный способ (если подключены к hotspot):${NC}"
|
||
echo "Скрипт может автоматически определить MAC точки доступа"
|
||
echo "Используйте: $0 --phone-mac"
|
||
echo ""
|
||
}
|
||
|
||
main() {
|
||
# Check if we need root and restart with sudo if needed
|
||
# Skip check for help/instructions commands that don't need root
|
||
local arg="${1:-}"
|
||
local needs_root=false
|
||
|
||
if [ "$arg" != "--help" ] && [ "$arg" != "-h" ] && [ "$arg" != "--instructions" ]; then
|
||
needs_root=true
|
||
fi
|
||
|
||
if [ "$needs_root" = true ] && [ "$(id -u)" -ne 0 ]; then
|
||
echo -e "${YELLOW}Re-running with sudo...${NC}"
|
||
exec sudo -E "$SCRIPT_PATH" "${@}"
|
||
exit 0
|
||
fi
|
||
|
||
if [ "$arg" = "--help" ] || [ "$arg" = "-h" ]; then
|
||
echo "Usage: $0 [OPTIONS] [MAC_ADDRESS]"
|
||
echo ""
|
||
echo "Options:"
|
||
echo " --phone-mac Auto-detect phone hotspot MAC"
|
||
echo " --revert Restore original MAC"
|
||
echo " --instructions Show instructions for finding phone MAC"
|
||
echo " --help Show this help"
|
||
echo ""
|
||
echo "Examples:"
|
||
echo " $0 # Interactive mode"
|
||
echo " $0 --phone-mac # Auto-detect hotspot MAC"
|
||
echo " $0 AA:BB:CC:DD:EE:FF # Set specific MAC"
|
||
echo " $0 --revert # Restore original"
|
||
exit 0
|
||
fi
|
||
|
||
if [ "$arg" = "--instructions" ]; then
|
||
show_instructions
|
||
exit 0
|
||
fi
|
||
|
||
if [ "$arg" = "--revert" ]; then
|
||
revert_mac
|
||
exit 0
|
||
fi
|
||
|
||
local iface
|
||
iface=$(detect_wifi_if)
|
||
echo -e "${GREEN}Wi-Fi interface: $iface${NC}"
|
||
|
||
local target_mac=""
|
||
|
||
if [ "$arg" = "--phone-mac" ]; then
|
||
target_mac=$(detect_phone_hotspot_mac "$iface")
|
||
if [ -z "$target_mac" ]; then
|
||
echo -e "${RED}Could not detect phone hotspot MAC${NC}"
|
||
echo -e "${YELLOW}Make sure you're connected to phone hotspot and try manual input${NC}"
|
||
show_instructions
|
||
exit 1
|
||
fi
|
||
elif [ -n "$arg" ]; then
|
||
target_mac="$arg"
|
||
else
|
||
# Try auto-detect first
|
||
local detected
|
||
detected=$(detect_phone_hotspot_mac "$iface" 2>/dev/null || echo "")
|
||
|
||
if [ -n "$detected" ]; then
|
||
echo -e "${GREEN}Detected hotspot MAC: $detected${NC}"
|
||
read "confirm?Use this MAC? (y/n): "
|
||
if [[ "$confirm" =~ ^[Yy] ]]; then
|
||
target_mac="$detected"
|
||
else
|
||
read "target_mac?Enter phone Wi-Fi MAC (AA:BB:CC:DD:EE:FF): "
|
||
fi
|
||
else
|
||
show_instructions
|
||
read "target_mac?Enter phone Wi-Fi MAC (AA:BB:CC:DD:EE:FF): "
|
||
fi
|
||
fi
|
||
|
||
if [ -z "$target_mac" ]; then
|
||
echo -e "${RED}No MAC address provided${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
validate_mac "$target_mac"
|
||
|
||
set_mac "$iface" "$target_mac"
|
||
|
||
echo ""
|
||
echo -e "${BLUE}=== ВАЖНО ===${NC}"
|
||
echo -e "${YELLOW}• MAC сбросится после перезагрузки или переподключения Wi-Fi${NC}"
|
||
echo -e "${YELLOW}• Используйте '$0 --revert' для восстановления${NC}"
|
||
echo -e "${YELLOW}• Для постоянной подмены может потребоваться отключение SIP${NC}"
|
||
echo -e "${YELLOW}• Оператор видит трафик через точку доступа, MAC клиента виден только на уровне Wi-Fi${NC}"
|
||
}
|
||
|
||
main "$@"
|