Beispiel #1
0
/* Waits for authentication and association responses from the target AP */
static int process_authenticate_associate_resp(int want_assoc)
{
	struct pcap_pkthdr header;
	unsigned char *packet;
	struct radio_tap_header *rt_header;
	struct dot11_frame_header *dot11_frame;
	struct authentication_management_frame *auth_frame;
	struct association_response_management_frame *assoc_frame;
	int ret_val = 0;

	start_timer();

	while(!get_out_of_time())
	{
		if((packet = next_packet(&header)) == NULL) break;

		if(header.len < MIN_AUTH_SIZE) continue;

		rt_header = (void*) radio_header(packet, header.len);
		size_t rt_header_len = end_le16toh(rt_header->len);
		dot11_frame = (void*)(packet + rt_header_len);

		if((memcmp(dot11_frame->addr3, get_bssid(), MAC_ADDR_LEN) != 0) ||
		   (memcmp(dot11_frame->addr1, get_mac(), MAC_ADDR_LEN) != 0))
			continue;

		int isMgmtFrame = (dot11_frame->fc & end_htole16(IEEE80211_FCTL_FTYPE)) == end_htole16(IEEE80211_FTYPE_MGMT);
		if(!isMgmtFrame) continue;

		void *ptr = (packet + sizeof(struct dot11_frame_header) + rt_header_len);
		auth_frame = ptr;
		assoc_frame = ptr;

		int isAuthResp = (dot11_frame->fc & end_htole16(IEEE80211_FCTL_STYPE)) == end_htole16(IEEE80211_STYPE_AUTH);
		int isAssocResp = (dot11_frame->fc & end_htole16(IEEE80211_FCTL_STYPE)) == end_htole16(IEEE80211_STYPE_ASSOC_RESP);

		if(!isAuthResp && !isAssocResp) continue;

		if(isAuthResp && want_assoc) continue;

		/* Did we get an authentication packet with a successful status? */
		if(isAuthResp && (auth_frame->status == end_htole16(AUTHENTICATION_SUCCESS))) {
			ret_val = AUTH_OK;
			break;
		}
		/* Did we get an association packet with a successful status? */
		else if(isAssocResp && (assoc_frame->status == end_htole16(ASSOCIATION_SUCCESS))) {
			ret_val = ASSOCIATE_OK;
			break;
		}
        }

        return ret_val;
}
Beispiel #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;
}