1#!/usr/bin/python 2 3import sys 4import os 5import subprocess 6import random 7import time 8import sqlite3 9import threading 10import hashlib 11import gzip 12import json 13import datetime 14import re 15import socket 16import tempfile 17import errno 18 19if sys.version_info[0] >= 3: 20 from socketserver import ThreadingTCPServer 21 from urllib.request import urlopen, URLError 22 from urllib.parse import urlparse, parse_qs 23 from http.client import HTTPConnection 24 from http.server import SimpleHTTPRequestHandler 25else: 26 from SocketServer import ThreadingTCPServer 27 from urllib2 import urlopen, URLError 28 from urlparse import urlparse, parse_qs 29 from httplib import HTTPConnection 30 from SimpleHTTPServer import SimpleHTTPRequestHandler 31 32 bytes = lambda a, b : a 33 34port = 1337 35url = None 36cid = None 37tls = threading.local() 38nets = {} 39cracker = None 40 41class ServerHandler(SimpleHTTPRequestHandler): 42 def do_GET(s): 43 result = s.do_req(s.path) 44 45 if not result: 46 return 47 48 s.send_response(200) 49 s.send_header("Content-type", "text/plain") 50 s.end_headers() 51 s.wfile.write(bytes(result, "UTF-8")) 52 53 def do_POST(s): 54 if ("dict" in s.path): 55 s.do_upload_dict() 56 57 if ("cap" in s.path): 58 s.do_upload_cap() 59 60 s.send_response(200) 61 s.send_header("Content-type", "text/plain") 62 s.end_headers() 63 s.wfile.write(bytes("OK", "UTF-8")) 64 65 def do_upload_dict(s): 66 con = get_con() 67 68 f = "dcrack-dict" 69 c = f + ".gz" 70 with open(c, "wb") as fid: 71 cl = int(s.headers['Content-Length']) 72 fid.write(s.rfile.read(cl)) 73 74 decompress(f) 75 76 h = get_sha1sum_string(f) 77 78 with open(f, "rb") as fid: 79 for i, l in enumerate(fid): pass 80 i += 1 81 82 n = "%s-%s.txt" % (f, h) 83 os.rename(f, n) 84 os.rename(c, "%s.gz" % n) 85 86 c = con.cursor() 87 c.execute("INSERT into dict values (?, ?, 0)", (h, i)) 88 con.commit() 89 90 def do_upload_cap(s): 91 cl = int(s.headers['Content-Length']) 92 tmp_cap = "/tmp/" + next(tempfile._get_candidate_names()) + ".cap" 93 with open(tmp_cap + ".gz", "wb") as fid: 94 fid.write(s.rfile.read(cl)) 95 96 decompress(tmp_cap) 97 98 # Check file is valid 99 output = subprocess.check_output(['wpaclean', tmp_cap + ".tmp", tmp_cap]) 100 try: 101 os.remove(tmp_cap + ".tmp") 102 except: 103 pass 104 105 output_split = output.splitlines() 106 if len(output_split) > 2: 107 # We got more than 2 lines, which means there is a network 108 # in there with a WPA/2 PSK handshake 109 os.rename(tmp_cap + ".gz", "dcrack.cap.gz") 110 os.rename(tmp_cap, "dcrack.cap") 111 else: 112 # If nothing in the file, just delete it 113 os.remove(tmp_cap) 114 os.remove(tmp_cap + ".gz") 115 116 def do_req(s, path): 117 con = get_con() 118 119 c = con.cursor() 120 121 c.execute("""DELETE from clients where 122 (strftime('%s', datetime()) - strftime('%s', last)) 123 > 300""") 124 125 con.commit() 126 127 if ("ping" in path): 128 return s.do_ping(path) 129 130 if ("getwork" in path): 131 return s.do_getwork(path) 132 133 if ("dict" in path and "status" in path): 134 return s.do_dict_status(path) 135 136 if ("dict" in path and "set" in path): 137 return s.do_dict_set(path) 138 139 if ("dict" in path): 140 return s.get_dict(path) 141 142 if ("net" in path and "/crack" in path): 143 return s.do_crack(path) 144 145 if ("net" in path and "result" in path): 146 return s.do_result(path) 147 148 if ("cap" in path): 149 return s.get_cap(path) 150 151 if ("status" in path): 152 return s.get_status() 153 154 if ("remove" in path): 155 return s.remove(path) 156 157 return "error" 158 159 def remove(s, path): 160 p = path.split("/") 161 n = p[4].upper() 162 not_found = 0 163 164 # Validate BSSID 165 if not is_bssid_value(n): 166 return "NO" 167 168 con = get_con() 169 170 # Delete from nets 171 c = con.cursor() 172 c.execute("SELECT * from nets where bssid = ?", (n,)) 173 r = c.fetchall() 174 if r: 175 con.commit() 176 not_found += 1 177 c = con.cursor() 178 c.execute("DELETE from nets where bssid = ?", (n,)) 179 con.commit() 180 181 # Delete from works 182 c = con.cursor() 183 c.execute("SELECT * from work where net = ?", (n,)) 184 r = c.fetchall() 185 if r: 186 con.commit() 187 not_found += 1 188 c = con.cursor() 189 c.execute("DELETE from work where net = ?", (n,)) 190 con.commit() 191 192 # If both failed, return NO. 193 if not_found == 2: 194 return "NO" 195 196 # Otherwise, return OK 197 return "OK" 198 199 def get_status(s): 200 con = get_con() 201 202 c = con.cursor() 203 c.execute("SELECT * from clients") 204 205 clients = [r['speed'] for r in c.fetchall()] 206 207 nets = [] 208 209 c.execute("SELECT * from dict where current = 1") 210 dic = c.fetchone() 211 212 c.execute("SELECT * from nets") 213 214 for r in c.fetchall(): 215 n = { "bssid" : r['bssid'] } 216 if r['pass']: 217 n["pass"] = r['pass'] 218 219 if r['state'] != 2: 220 n["tot"] = dic["lines"] 221 222 did = 0 223 cur = con.cursor() 224 cur.execute("""SELECT * from work where net = ? 225 and dict = ? and state = 2""", 226 (n['bssid'], dic['id'])) 227 for row in cur.fetchall(): 228 did += row['end'] - row['start'] 229 230 n["did"] = did 231 232 nets.append(n) 233 234 d = { "clients" : clients, "nets" : nets } 235 236 return json.dumps(d) 237 238 def do_result_pass(s, net, pw): 239 con = get_con() 240 241 pf = "dcrack-pass.txt" 242 243 with open(pf, "w") as fid: 244 fid.write(pw) 245 fid.write("\n") 246 247 cmd = ["aircrack-ng", "-w", pf, "-b", net, "-q", "dcrack.cap"] 248 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, \ 249 stdin=subprocess.PIPE) 250 251 res = p.communicate()[0] 252 res = str(res) 253 254 os.remove(pf) 255 256 if not "KEY FOUND" in res: 257 return "error" 258 259 s.net_done(net) 260 261 c = con.cursor() 262 c.execute("UPDATE nets set pass = ? where bssid = ?", \ 263 (pw, net)) 264 265 con.commit() 266 267 return "OK" 268 269 def net_done(s, net): 270 con = get_con() 271 272 c = con.cursor() 273 c.execute("UPDATE nets set state = 2 where bssid = ?", 274 (net,)) 275 276 c.execute("DELETE from work where net = ?", (net,)) 277 con.commit() 278 279 def do_result(s, path): 280 con = get_con() 281 282 p = path.split("/") 283 n = p[4].upper() 284 if not is_bssid_value(n): 285 return "NO" 286 287 x = urlparse(path) 288 qs = parse_qs(x.query) 289 290 # TODO: Verify client ID sending it 291 if "pass" in qs: 292 return s.do_result_pass(n, qs['pass'][0]) 293 294 wl = qs['wl'][0] 295 296 c = con.cursor() 297 c.execute("SELECT * from nets where bssid = ?", (n,)) 298 r = c.fetchone() 299 if r and r['state'] == 2: 300 return "Already done" 301 302 c.execute("""UPDATE work set state = 2 where 303 net = ? and dict = ? and start = ? and end = ?""", 304 (n, wl, qs['start'][0], qs['end'][0])) 305 306 con.commit() 307 308 if c.rowcount == 0: 309 c.execute("""INSERT into work values 310 (NULL, ?, ?, ?, ?, datetime(), 2)""", 311 (n, wl, qs['start'][0], qs['end'][0])) 312 con.commit() 313 314 # check status 315 c.execute("""SELECT * from work where net = ? and dict = ? 316 and state = 2 order by start""", (n, wl)) 317 318 i = 0 319 r = c.fetchall() 320 for row in r: 321 if i == row['start']: 322 i = row['end'] 323 else: 324 break 325 326 c.execute("SELECT * from dict where id = ? and lines = ?", 327 (wl, i)) 328 329 r = c.fetchone() 330 331 if r: 332 s.net_done(n) 333 334 return "OK" 335 336 def get_cap(s, path): 337 return s.serve_file("dcrack.cap.gz") 338 339 def get_dict(s, path): 340 p = path.split("/") 341 n = p[4] 342 343 fn = "dcrack-dict-%s.txt.gz" % n 344 345 return s.serve_file(fn) 346 347 def serve_file(s, fn): 348 s.send_response(200) 349 s.send_header("Content-type", "application/x-gzip") 350 s.end_headers() 351 352 # XXX openat 353 with open(fn, "rb") as fid: 354 s.wfile.write(fid.read()) 355 356 return None 357 358 def do_crack(s, path): 359 con = get_con() 360 361 p = path.split("/") 362 363 n = p[4].upper() 364 # Validate BSSID 365 if not is_bssid_value(n): 366 return "NO" 367 368 # Only add network if it isn't already in there 369 # Update it if it failed cracking only 370 c = con.cursor() 371 c.execute("SELECT * from nets where bssid = ?", (n,)) 372 r = c.fetchone() 373 if r == None: 374 # Not in there, add it 375 c.execute("INSERT into nets values (?, NULL, 1)", (n,)) 376 con.commit() 377 return "OK" 378 379 # Network already exists but has failed cracking 380 if r['state'] == 2 and r['pass'] == None: 381 c.execute("UPDATE nets SET state = 1 WHERE bssid = ?", (n,)) 382 con.commit() 383 return "OK" 384 385 # State == 1: Just added or being worked on 386 # State == 2 and Pass exists: Already successfully cracked 387 con.commit() 388 return "NO" 389 390 def do_dict_set(s, path): 391 con = get_con() 392 393 p = path.split("/") 394 395 h = p[4] 396 # Validate hash 397 if not is_sha1sum(h): 398 return "NO" 399 400 c = con.cursor() 401 c.execute("UPDATE dict set current = 0") 402 c.execute("UPDATE dict set current = 1 where id = ?", (h,)) 403 con.commit() 404 405 return "OK" 406 407 def do_ping(s, path): 408 con = get_con() 409 410 p = path.split("/") 411 412 cid = p[4] 413 414 x = urlparse(path) 415 qs = parse_qs(x.query) 416 417 speed = qs['speed'][0] 418 419 c = con.cursor() 420 c.execute("SELECT * from clients where id = ?", (cid,)) 421 r = c.fetchall() 422 if (not r): 423 c.execute("INSERT into clients values (?, ?, datetime())", 424 (cid, int(speed))) 425 else: 426 c.execute("""UPDATE clients set speed = ?, 427 last = datetime() where id = ?""", 428 (int(speed), cid)) 429 430 con.commit() 431 432 return "60" 433 434 def try_network(s, net, d): 435 con = get_con() 436 437 c = con.cursor() 438 c.execute("""SELECT * from work where net = ? and dict = ? 439 order by start""", (net['bssid'], d['id'])) 440 441 r = c.fetchall() 442 443 s = 5000000 444 i = 0 445 found = False 446 447 for row in r: 448 if found: 449 if i + s > row['start']: 450 s = row['start'] - i 451 break 452 453 if (row['start'] <= i <= row['end']): 454 i = row['end'] 455 else: 456 found = True 457 458 if i + s > d['lines']: 459 s = d['lines'] - i 460 461 if s == 0: 462 return None 463 464 c.execute("INSERT into work values (NULL, ?, ?, ?, ?, datetime(), 1)", 465 (net['bssid'], d['id'], i, i + s)) 466 467 con.commit() 468 469 crack = { "net" : net['bssid'], \ 470 "dict" : d['id'], \ 471 "start" : i, \ 472 "end" : i + s } 473 474 j = json.dumps(crack) 475 476 return j 477 478 def do_getwork(s, path): 479 con = get_con() 480 481 c = con.cursor() 482 483 c.execute("""DELETE from work where 484 ((strftime('%s', datetime()) - strftime('%s', last)) 485 > 3600) and state = 1""") 486 487 con.commit() 488 489 c.execute("SELECT * from dict where current = 1") 490 d = c.fetchone() 491 492 c.execute("SELECT * from nets where state = 1") 493 r = c.fetchall() 494 495 for row in r: 496 res = s.try_network(row, d) 497 if res: 498 return res 499 500 # try some old stuff 501 c.execute("""select * from work where state = 1 502 order by last limit 1""") 503 504 res = c.fetchone() 505 506 if res: 507 c.execute("DELETE from work where id = ?", (res['id'],)) 508 for row in r: 509 res = s.try_network(row, d) 510 if res: 511 return res 512 513 res = { "interval" : "60" } 514 515 return json.dumps(res) 516 517 def do_dict_status(s, path): 518 p = path.split("/") 519 520 d = p[4] 521 522 try: 523 with open("dcrack-dict-%s.txt" % d): pass 524 return "OK" 525 except: 526 return "NO" 527 528def create_db(): 529 con = get_con() 530 531 c = con.cursor() 532 c.execute("""create table clients (id varchar(255), 533 speed integer, last datetime)""") 534 535 c.execute("""create table dict (id varchar(255), lines integer, 536 current boolean)""") 537 c.execute("""create table nets (bssid varchar(255), pass varchar(255), 538 state integer)""") 539 540 c.execute("""create table work (id integer primary key, 541 net varchar(255), dict varchar(255), 542 start integer, end integer, last datetime, state integer)""") 543 544def connect_db(): 545 con = sqlite3.connect('dcrack.db') 546 con.row_factory = sqlite3.Row 547 548 return con 549 550def get_con(): 551 global tls 552 553 try: 554 return tls.con 555 except: 556 tls.con = connect_db() 557 return tls.con 558 559def init_db(): 560 con = get_con() 561 c = con.cursor() 562 563 try: 564 c.execute("SELECT * from clients") 565 except: 566 create_db() 567 568def server(): 569 init_db() 570 571 server_class = ThreadingTCPServer 572 try: 573 httpd = server_class(('', port), ServerHandler) 574 except socket.error as exc: 575 print("Failed listening on port %d" % port) 576 return 577 578 print("Starting server") 579 try: 580 httpd.serve_forever() 581 except KeyboardInterrupt: 582 print("Bye!") 583 httpd.server_close() 584 585def usage(): 586 print("""dcrack v0.3 587 588 Usage: dcrack.py [MODE] 589 server Runs coordinator 590 client <server addr> Runs cracker 591 cmd <server addr> [CMD] Sends a command to server 592 593 [CMD] can be: 594 dict <file> 595 cap <file> 596 crack <bssid> 597 remove <bssid> 598 status""") 599 exit(1) 600 601def get_speed(): 602 print("Getting speed") 603 p = subprocess.Popen(["aircrack-ng", "-S"], stdout=subprocess.PIPE) 604 speed = p.stdout.readline() 605 speed = speed.split() 606 speed = speed[len(speed) - 2] 607 return int(speed) 608 609def get_cid(): 610 return random.getrandbits(64) 611 612def do_ping(speed): 613 global url, cid 614 615 u = url + "client/" + str(cid) + "/ping?speed=" + str(speed) 616 stuff = urlopen(u).read() 617 interval = int(stuff) 618 619 return interval 620 621def pinger(speed): 622 while True: 623 interval = try_ping(speed) 624 time.sleep(interval) 625 626def try_ping(speed): 627 while True: 628 try: 629 return do_ping(speed) 630 except URLError: 631 print("Conn refused (pinger)") 632 time.sleep(60) 633 634def get_work(): 635 global url, cid, cracker 636 637 u = url + "client/" + str(cid) + "/getwork" 638 stuff = urlopen(u).read() 639 stuff = stuff.decode("utf-8") 640 641 crack = json.loads(stuff) 642 643 if "interval" in crack: 644 # Validate value 645 try: 646 interval = int(crack['interval']) 647 if (interval < 0): 648 raise ValueError('Interval must be above or equal to 0') 649 except: 650 # In case of failure, default to 60 sec 651 interval = 60 652 print("Waiting %d sec" % interval) 653 return interval 654 655 wl = setup_dict(crack) 656 cap = get_cap(crack) 657 658 # If there's anything wrong with it, skip cracking 659 if wl == None or cap == None: 660 return 661 662 print("Cracking") 663 664 cmd = ["aircrack-ng", "-w", wl, "-b", crack['net'], "-q", cap] 665 666 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, \ 667 stdin=subprocess.PIPE) 668 669 cracker = p 670 671 res = p.communicate()[0] 672 res = str(res) 673 674 cracker = None 675 676 if ("not in dictionary" in res): 677 print("No luck") 678 u = "%snet/%s/result?wl=%s&start=%d&end=%d&found=0" % \ 679 (url, crack['net'], crack['dict'], \ 680 crack['start'], crack['end']) 681 682 stuff = urlopen(u).read() 683 elif "KEY FOUND" in res: 684 pw = re.sub("^.*\[ ", "", res) 685 686 i = pw.rfind(" ]") 687 if i == -1: 688 raise BaseException("Can't parse output") 689 690 pw = pw[:i] 691 692 print("Key for %s is %s" % (crack['net'], pw)) 693 694 u = "%snet/%s/result?pass=%s" % (url, crack['net'], pw) 695 stuff = urlopen(u).read() 696 697 return 0 698 699def decompress(fn): 700 with gzip.open(fn + ".gz") as fid1: 701 with open(fn, "wb") as fid2: 702 fid2.writelines(fid1) 703 704def setup_dict(crack): 705 global url 706 707 d = crack['dict'] 708 if not re.compile("^[a-f0-9]{5,40}").match(d): 709 print("Invalid dictionary: %s" % d) 710 return None 711 712 #if not re.match("^[0-9]+$", d['start']) or not re.match("^[0-9]+$", d['end']): 713 if crack['start'] < 0 or crack['end'] < 0: 714 print("Wordlist: Invalid start or end line positions") 715 return None 716 if crack['end'] <= crack['start']: 717 print("Wordlist: End line position must be greater than start position") 718 return None 719 720 fn = "dcrack-client-dict-%s.txt" % d 721 722 try: 723 with open(fn): pass 724 except: 725 print("Downloading dictionary %s" % d) 726 727 u = "%sdict/%s" % (url, d) 728 stuff = urlopen(u) 729 730 with open(fn + ".gz", "wb") as fid: 731 fid.write(stuff.read()) 732 733 print("Uncompressing dictionary") 734 decompress(fn) 735 736 h = get_sha1sum_string(fn) 737 738 if h != d: 739 print("Bad dictionary, SHA1 don't match") 740 return None 741 742 # Split wordlist 743 s = "dcrack-client-dict-%s-%d:%d.txt" \ 744 % (d, crack['start'], crack['end']) 745 746 try: 747 with open(s): pass 748 except: 749 print("Splitting dict %s" % s) 750 with open(fn, "rb") as fid1: 751 with open(s, "wb") as fid2: 752 for i, l in enumerate(fid1): 753 if i >= crack['end']: 754 break 755 if i >= crack['start']: 756 fid2.write(l) 757 758 # Verify wordlist isn't empty 759 try: 760 if os.stat(s).st_size == 0: 761 print("Empty dictionary file!") 762 return None 763 except: 764 print("Dictionary does not exists!") 765 return None; 766 767 return s 768 769def get_cap(crack): 770 global url, nets 771 772 fn = "dcrack-client.cap" 773 774 bssid = crack['net'].upper() 775 776 if bssid in nets: 777 return fn 778 779 try: 780 with open(fn, "rb"): pass 781 check_cap(fn, bssid) 782 except: 783 pass 784 785 if bssid in nets: 786 return fn 787 788 print("Downloading cap") 789 u = "%scap/%s" % (url, bssid) 790 791 stuff = urlopen(u) 792 793 with open(fn + ".gz", "wb") as fid: 794 fid.write(stuff.read()) 795 796 print("Uncompressing cap") 797 decompress(fn) 798 799 nets = {} 800 check_cap(fn, bssid) 801 802 if bssid not in nets: 803 printf("Can't find net %s" % bssid) 804 return None 805 806 return fn 807 808def process_cap(fn): 809 global nets 810 811 nets = {} 812 813 print("Processing cap") 814 p = subprocess.Popen(["aircrack-ng", fn], stdout=subprocess.PIPE, \ 815 stdin=subprocess.PIPE) 816 found = False 817 while True: 818 line = p.stdout.readline() 819 820 try: 821 line = line.decode("utf-8") 822 except: 823 line = str(line) 824 825 if "1 handshake" in line: 826 found = True 827 parts = line.split() 828 b = parts[1].upper() 829# print("BSSID [%s]" % b) 830 nets[b] = True 831 832 if (found and line == "\n"): 833 break 834 835 p.stdin.write(bytes("1\n", "utf-8")) 836 p.communicate() 837 838def check_cap(fn, bssid): 839 global nets 840 841 cmd = ["aircrack-ng", "-b", bssid, fn] 842 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) 843 844 res = p.communicate()[0] 845 res = str(res) 846 847 if "No matching network found" not in res: 848 nets[bssid] = True 849 850def worker(): 851 while True: 852 interval = get_work() 853 time.sleep(interval) 854 855def set_url(): 856 global url, port 857 858 if len(sys.argv) < 3: 859 print("Provide server addr") 860 usage() 861 862 host = sys.argv[2] 863 864 if not ":" in host: 865 host = "%s:%d" % (host, port) 866 867 url = "http://" + host + "/" + "dcrack/" 868 869def client(): 870 global cid, cracker, url 871 872 set_url() 873 url += "worker/" 874 875 speed = get_speed() 876 print("Speed", speed) 877 878 cid = get_cid() 879 880 print("CID", cid) 881 882 try_ping(speed) 883 t = threading.Thread(target=pinger, args=(speed,)) 884 t.daemon = True 885 t.start() 886 887 while True: 888 try: 889 do_client() 890 break 891 except URLError: 892 print("Conn refused") 893 time.sleep(60) 894 895def do_client(): 896 try: 897 worker() 898 except KeyboardInterrupt: 899 if cracker: 900 cracker.kill() 901 902def upload_file(url, f): 903 x = urlparse(url) 904 c = HTTPConnection(x.netloc) 905 906 # XXX not quite HTTP form 907 908 with open(f, "rb") as fid: 909 c.request("POST", x.path, fid) 910 res = c.getresponse() 911 stuff = res.read() 912 c.close() 913 914 return stuff 915 916def compress_file(f): 917 with open(f, "rb") as fid1: 918 with gzip.open(f + ".gz", "wb") as fid2: 919 fid2.writelines(fid1) 920 921def send_dict(): 922 global url 923 924 if len(sys.argv) < 5: 925 print("Need dict") 926 usage() 927 928 d = sys.argv[4] 929 930 # Check if file exists 931 try: 932 if os.stat(d).st_size == 0: 933 print("Empty dictionary file!") 934 return 935 except: 936 print("Dictionary does not exists!") 937 return; 938 939 print("Cleaning up dictionary") 940 new_dict = "/tmp/" + next(tempfile._get_candidate_names()) + ".txt" 941 with open(new_dict, 'w') as fout: 942 with open(d) as fid: 943 for line in fid: 944 cleaned_line = line.rstrip("\n") 945 if len(cleaned_line) >= 8 and len(cleaned_line) <= 63: 946 fout.write(cleaned_line + "\n") 947 948 if os.stat(new_dict).st_size == 0: 949 os.remove(new_dict) 950 print("No valid passphrase in dictionary") 951 return 952 953 print("Calculating dictionary hash for cleaned up %s" % d) 954 h = get_sha1sum_string(new_dict) 955 956 print("Hash is %s" % h) 957 958 u = url + "dict/" + h + "/status" 959 stuff = urlopen(u).read() 960 961 if "NO" in str(stuff): 962 u = url + "dict/create" 963 print("Compressing dictionary") 964 compress_file(new_dict) 965 os.remove(new_dict) 966 print("Uploading dictionary") 967 upload_file(u, new_dict + ".gz") 968 os.remove(new_dict + ".gz") 969 970 print("Setting dictionary to %s" % d) 971 u = url + "dict/" + h + "/set" 972 stuff = urlopen(u).read() 973 974def send_cap(): 975 global url 976 977 if len(sys.argv) < 5: 978 print("Need cap") 979 usage() 980 981 cap = sys.argv[4] 982 983 # Check if file exists 984 try: 985 if os.stat(cap).st_size <= 24: 986 # It may exists but contain no packets. 987 print("Empty capture file!") 988 return 989 except: 990 print("Capture file does not exists!") 991 return; 992 993 print("Cleaning cap %s" % cap) 994 clean_cap = "/tmp/" + next(tempfile._get_candidate_names()) + ".cap" 995 subprocess.Popen(["wpaclean", clean_cap, cap], \ 996 stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0] 997 998 # Check cleaned file size (24 bytes -> 0 packets in file) 999 if os.stat(clean_cap).st_size <= 24: 1000 print("Empty cleaned PCAP file, something's wrong with the original PCAP!") 1001 return 1002 1003 print("Compressing cap") 1004 compress_file(clean_cap) 1005 os.remove(clean_cap) 1006 1007 u = url + "cap/create" 1008 ret = upload_file(u, clean_cap + ".gz") 1009 if ret == "OK": 1010 print("Upload successful") 1011 elif ret == "NO": 1012 print("Failed uploading wordlist") 1013 else: 1014 print("Unknown return value from server: %s" % (ret,)) 1015 1016 # Delete temporary file 1017 os.remove(clean_cap + ".gz") 1018 1019def cmd_crack(): 1020 ret = net_cmd("crack") 1021 if ret == "OK": 1022 print("Cracking job successfully added") 1023 elif ret == "NO": 1024 print("Failed adding cracking job!") 1025 else: 1026 print("Unknown return value from server: %s" % (ret,)) 1027 1028def net_cmd(op): 1029 global url 1030 1031 if len(sys.argv) < 5: 1032 print("Need BSSID") 1033 usage() 1034 1035 bssid = sys.argv[4] 1036 1037 print("%s %s" % (op, bssid)) 1038 u = "%snet/%s/%s" % (url, bssid, op) 1039 return urlopen(u).read() 1040 1041def cmd_remove(): 1042 net_cmd("remove") 1043 1044def cmd_status(): 1045 u = "%sstatus" % url 1046 stuff = urlopen(u).read() 1047 1048 stuff = json.loads(stuff.decode("utf-8")) 1049 1050 speed = 0 1051 idx = 0 1052 for idx, c in enumerate(stuff['clients'], start=1): 1053 speed += c 1054 1055 print("Clients\t%d\nSpeed\t%d\n" % (idx, speed)) 1056 1057 need = 0 1058 1059 for n in stuff['nets']: 1060 out = n['bssid'] + " " 1061 1062 if "pass" in n: 1063 out += n['pass'] 1064 elif "did" in n: 1065 did = int(float(n['did']) / float(n['tot']) * 100.0) 1066 out += str(did) + "%" 1067 need += n['tot'] - n['did'] 1068 else: 1069 out += "-" 1070 1071 print(out) 1072 1073 if need != 0: 1074 print("\nKeys left %d" % need) 1075 if speed != 0: 1076 s = int(float(need) / float(speed)) 1077 sec = datetime.timedelta(seconds=s) 1078 d = datetime.datetime(1,1,1) + sec 1079 print("ETA %dh %dm" % (d.hour, d.minute)) 1080 1081def do_cmd(): 1082 global url 1083 1084 set_url() 1085 url += "cmd/" 1086 1087 if len(sys.argv) < 4: 1088 print("Need CMD") 1089 usage() 1090 1091 cmd = sys.argv[3] 1092 1093 if "dict" in cmd: 1094 send_dict() 1095 elif "cap" in cmd: 1096 send_cap() 1097 elif "crack" in cmd: 1098 cmd_crack() 1099 elif "status" in cmd: 1100 cmd_status() 1101 elif "remove" in cmd: 1102 cmd_remove() 1103 else: 1104 print("Unknown cmd %s" % cmd) 1105 usage() 1106 1107def get_sha1sum_string(f): 1108 sha1 = hashlib.sha1() 1109 with open(f, "rb") as fid: 1110 sha1.update(fid.read()) 1111 return sha1.hexdigest() 1112 1113def is_sha1sum(h): 1114 if re.match("[0-9a-fA-F]{40}", h): 1115 return True 1116 return False 1117 1118def is_bssid_value(b): 1119 if re.match("([A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}", b): 1120 return True 1121 return False 1122 1123def main(): 1124 if len(sys.argv) < 2: 1125 usage() 1126 1127 cmd = sys.argv[1] 1128 1129 if cmd == "server": 1130 server() 1131 elif cmd == "client": 1132 try: 1133 client() 1134 except KeyboardInterrupt: 1135 pass 1136 elif cmd == "cmd": 1137 try: 1138 do_cmd() 1139 except URLError as ue: 1140 if "Connection refused" in ue.reason: 1141 print("Connection to %s refused" % (sys.argv[2],)) 1142 else: 1143 print(ue.reason) 1144 except socket.error as se: 1145 if se.errno == errno.ECONNREFUSED: 1146 print("Connection refused") 1147 else: 1148 print(se) 1149 else: 1150 print("Unknown cmd", cmd) 1151 usage() 1152 1153 exit(0) 1154 1155if __name__ == "__main__": 1156 main() 1157