diff --git a/credentials/crd.py b/credentials/crd.py new file mode 100644 index 0000000..f9d8011 --- /dev/null +++ b/credentials/crd.py @@ -0,0 +1,1002 @@ +#!/usr/bin/python + +import sys +import os +import subprocess +import random +import time +import sqlite3 +import threading +import hashlib +import gzip +import json +import datetime +import re + +if sys.version_info[0] >= 3: + from socketserver import ThreadingTCPServer + from urllib.request import urlopen, URLError + from urllib.parse import urlparse, parse_qs + from http.client import HTTPConnection + from http.server import SimpleHTTPRequestHandler +else: + from SocketServer import ThreadingTCPServer + from urllib2 import urlopen, URLError + from urlparse import urlparse, parse_qs + from httplib import HTTPConnection + from SimpleHTTPServer import SimpleHTTPRequestHandler + + bytes = lambda a, b : a + +port = 1337 +url = None +cid = None +tls = threading.local() +nets = {} +cracker = None + +class ServerHandler(SimpleHTTPRequestHandler): + def do_GET(s): + result = s.do_req(s.path) + + if not result: + return + + s.send_response(200) + s.send_header("Content-type", "text/plain") + s.end_headers() + s.wfile.write(bytes(result, "UTF-8")) + + def do_POST(s): + if ("dict" in s.path): + s.do_upload_dict() + + if ("cap" in s.path): + s.do_upload_cap() + + s.send_response(200) + s.send_header("Content-type", "text/plain") + s.end_headers() + s.wfile.write(bytes("OK", "UTF-8")) + + def do_upload_dict(s): + con = get_con() + + f = "dcrack-dict" + c = f + ".gz" + o = open(c, "wb") + cl = int(s.headers['Content-Length']) + o.write(s.rfile.read(cl)) + o.close() + + decompress(f) + + sha1 = hashlib.sha1() + x = open(f, "rb") + sha1.update(x.read()) + x.close() + h = sha1.hexdigest() + + x = open(f, "rb") + for i, l in enumerate(x): + pass + + i = i + 1 + x.close() + + n = "%s-%s.txt" % (f, h) + os.rename(f, n) + os.rename(c, "%s.gz" % n) + + c = con.cursor() + c.execute("INSERT into dict values (?, ?, 0)", (h, i)) + con.commit() + + def do_upload_cap(s): + cl = int(s.headers['Content-Length']) + f = open("dcrack.cap.tmp.gz", "wb") + f.write(s.rfile.read(cl)) + f.close() + + decompress("dcrack.cap.tmp") + os.rename("dcrack.cap.tmp.gz", "dcrack.cap.gz") + os.rename("dcrack.cap.tmp", "dcrack.cap") + + def do_req(s, path): + con = get_con() + + c = con.cursor() + + c.execute("""DELETE from clients where + (strftime('%s', datetime()) - strftime('%s', last)) + > 300""") + + con.commit() + + if ("ping" in path): + return s.do_ping(path) + + if ("getwork" in path): + return s.do_getwork(path) + + if ("dict" in path and "status" in path): + return s.do_dict_status(path) + + if ("dict" in path and "set" in path): + return s.do_dict_set(path) + + if ("dict" in path): + return s.get_dict(path) + + if ("net" in path and "/crack" in path): + return s.do_crack(path) + + if ("net" in path and "result" in path): + return s.do_result(path) + + if ("cap" in path): + return s.get_cap(path) + + if ("status" in path): + return s.get_status() + + if ("remove" in path): + return s.remove(path) + + return "error" + + def remove(s, path): + con = get_con() + + p = path.split("/") + n = p[4].upper() + + c = con.cursor() + c.execute("DELETE from nets where bssid = ?", (n,)) + con.commit() + + c.execute("DELETE from work where net = ?", (n,)) + con.commit() + + return "OK" + + def get_status(s): + con = get_con() + + c = con.cursor() + c.execute("SELECT * from clients") + + clients = [] + + for r in c.fetchall(): + clients.append(r['speed']) + + nets = [] + + c.execute("SELECT * from dict where current = 1") + dic = c.fetchone() + + c.execute("SELECT * from nets") + + for r in c.fetchall(): + n = { "bssid" : r['bssid'] } + if r['pass']: + n["pass"] = r['pass'] + + if r['state'] != 2: + n["tot"] = dic["lines"] + + did = 0 + cur = con.cursor() + cur.execute("""SELECT * from work where net = ? + and dict = ? and state = 2""", + (n['bssid'], dic['id'])) + for row in cur.fetchall(): + did += row['end'] - row['start'] + + n["did"] = did + + nets.append(n) + + d = { "clients" : clients, "nets" : nets } + + return json.dumps(d) + + def do_result_pass(s, net, pw): + con = get_con() + + pf = "dcrack-pass.txt" + + f = open(pf, "w") + f.write(pw) + f.write("\n") + f.close() + + cmd = ["aircrack-ng", "-w", pf, "-b", net, "-q", "dcrack.cap"] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, \ + stdin=subprocess.PIPE) + + res = p.communicate()[0] + res = str(res) + + os.remove(pf) + + if not "KEY FOUND" in res: + return "error" + + s.net_done(net) + + c = con.cursor() + c.execute("UPDATE nets set pass = ? where bssid = ?", \ + (pw, net)) + + con.commit() + + return "OK" + + def net_done(s, net): + con = get_con() + + c = con.cursor() + c.execute("UPDATE nets set state = 2 where bssid = ?", + (net,)) + + c.execute("DELETE from work where net = ?", (net,)) + con.commit() + + def do_result(s, path): + con = get_con() + + p = path.split("/") + n = p[4].upper() + + x = urlparse(path) + qs = parse_qs(x.query) + + if "pass" in qs: + return s.do_result_pass(n, qs['pass'][0]) + + wl = qs['wl'][0] + + c = con.cursor() + c.execute("SELECT * from nets where bssid = ?", (n,)) + r = c.fetchone() + if r and r['state'] == 2: + return "Already done" + + c.execute("""UPDATE work set state = 2 where + net = ? and dict = ? and start = ? and end = ?""", + (n, wl, qs['start'][0], qs['end'][0])) + + con.commit() + + if c.rowcount == 0: + c.execute("""INSERT into work values + (NULL, ?, ?, ?, ?, datetime(), 2)""", + (n, wl, qs['start'][0], qs['end'][0])) + con.commit() + + # check status + c.execute("""SELECT * from work where net = ? and dict = ? + and state = 2 order by start""", (n, wl)) + + i = 0 + r = c.fetchall() + for row in r: + if i == row['start']: + i = row['end'] + else: + break + + c.execute("SELECT * from dict where id = ? and lines = ?", + (wl, i)) + + r = c.fetchone() + + if r: + s.net_done(n) + + return "OK" + + def get_cap(s, path): + return s.serve_file("dcrack.cap.gz") + + def get_dict(s, path): + p = path.split("/") + n = p[4] + + fn = "dcrack-dict-%s.txt.gz" % n + + return s.serve_file(fn) + + def serve_file(s, fn): + s.send_response(200) + s.send_header("Content-type", "application/x-gzip") + s.end_headers() + + # XXX openat + f = open(fn, "rb") + s.wfile.write(f.read()) + f.close() + + return None + + def do_crack(s, path): + con = get_con() + + p = path.split("/") + + n = p[4].upper() + + c = con.cursor() + c.execute("INSERT into nets values (?, NULL, 1)", (n,)) + con.commit() + + return "OK" + + def do_dict_set(s, path): + con = get_con() + + p = path.split("/") + + h = p[4] + + c = con.cursor() + c.execute("UPDATE dict set current = 0") + c.execute("UPDATE dict set current = 1 where id = ?", (h,)) + con.commit() + + return "OK" + + def do_ping(s, path): + con = get_con() + + p = path.split("/") + + cid = p[4] + + x = urlparse(path) + qs = parse_qs(x.query) + + speed = qs['speed'][0] + + c = con.cursor() + c.execute("SELECT * from clients where id = ?", (cid,)) + r = c.fetchall() + if (not r): + c.execute("INSERT into clients values (?, ?, datetime())", + (cid, int(speed))) + else: + c.execute("""UPDATE clients set speed = ?, + last = datetime() where id = ?""", + (int(speed), cid)) + + con.commit() + + return "60" + + def try_network(s, net, d): + con = get_con() + + c = con.cursor() + c.execute("""SELECT * from work where net = ? and dict = ? + order by start""", (net['bssid'], d['id'])) + + r = c.fetchall() + + s = 5000000 + i = 0 + found = False + + for row in r: + if found: + if i + s > row['start']: + s = row['start'] - i + break + + if (i >= row['start'] and i <= row['end']): + i = row['end'] + else: + found = True + + if i + s > d['lines']: + s = d['lines'] - i + + if s == 0: + return None + + c.execute("INSERT into work values (NULL, ?, ?, ?, ?, datetime(), 1)", + (net['bssid'], d['id'], i, i + s)) + + con.commit() + + crack = { "net" : net['bssid'], \ + "dict" : d['id'], \ + "start" : i, \ + "end" : i + s } + + j = json.dumps(crack) + + return j + + def do_getwork(s, path): + con = get_con() + + c = con.cursor() + + c.execute("""DELETE from work where + ((strftime('%s', datetime()) - strftime('%s', last)) + > 3600) and state = 1""") + + con.commit() + + c.execute("SELECT * from dict where current = 1") + d = c.fetchone() + + c.execute("SELECT * from nets where state = 1") + r = c.fetchall() + + for row in r: + res = s.try_network(row, d) + if res: + return res + + # try some old stuff + c.execute("""select * from work where state = 1 + order by last limit 1""") + + res = c.fetchone() + + if res: + c.execute("DELETE from work where id = ?", (res['id'],)) + for row in r: + res = s.try_network(row, d) + if res: + return res + + res = { "interval" : "60" } + + return json.dumps(res) + + def do_dict_status(s, path): + p = path.split("/") + + d = p[4] + + try: + f = open("dcrack-dict-%s.txt" % d) + f.close() + + return "OK" + except: + return "NO" + +def create_db(): + con = get_con() + + c = con.cursor() + c.execute("""create table clients (id varchar(255), + speed integer, last datetime)""") + + c.execute("""create table dict (id varchar(255), lines integer, + current boolean)""") + c.execute("""create table nets (bssid varchar(255), pass varchar(255), + state integer)""") + + c.execute("""create table work (id integer primary key, + net varchar(255), dict varchar(255), + start integer, end integer, last datetime, state integer)""") + +def connect_db(): + con = sqlite3.connect('dcrack.db') + con.row_factory = sqlite3.Row + + return con + +def get_con(): + global tls + + try: + return tls.con + except: + tls.con = connect_db() + return tls.con + +def init_db(): + con = get_con() + c = con.cursor() + + try: + c.execute("SELECT * from clients") + except: + create_db() + +def server(): + init_db() + + server_class = ThreadingTCPServer + httpd = server_class(('', port), ServerHandler) + + print("Starting server") + httpd.serve_forever() + +def usage(): + print("""dcrack v0.3 + + Usage: dcrack.py [MODE] + server Runs coordinator + client Runs cracker + cmd [CMD] Sends a command to server + + [CMD] can be: + dict + cap + crack + remove + status""") + exit(1) + +def get_speed(): + print("Getting speed") + p = subprocess.Popen(["aircrack-ng", "-S"], stdout=subprocess.PIPE) + speed = p.stdout.readline() + speed = speed.split() + speed = speed[len(speed) - 2] + return int(speed) + +def get_cid(): + return random.getrandbits(64) + +def do_ping(speed): + global url, cid + + u = url + "client/" + str(cid) + "/ping?speed=" + str(speed) + stuff = urlopen(u).read() + interval = int(stuff) + + return interval + +def pinger(speed): + while True: + interval = try_ping(speed) + time.sleep(interval) + +def try_ping(speed): + while True: + try: + return do_ping(speed) + except URLError: + print("Conn refused (pinger)") + time.sleep(60) + +def get_work(): + global url, cid, cracker + + u = url + "client/" + str(cid) + "/getwork" + stuff = urlopen(u).read() + stuff = stuff.decode("utf-8") + + crack = json.loads(stuff) + + if "interval" in crack: + print("Waiting") + return int(crack['interval']) + + wl = setup_dict(crack) + cap = get_cap(crack) + + print("Cracking") + + cmd = ["aircrack-ng", "-w", wl, "-b", crack['net'], "-q", cap] + + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, \ + stdin=subprocess.PIPE) + + cracker = p + + res = p.communicate()[0] + res = str(res) + + cracker = None + + if ("not in dictionary" in res): + print("No luck") + u = "%snet/%s/result?wl=%s&start=%d&end=%d&found=0" % \ + (url, crack['net'], crack['dict'], \ + crack['start'], crack['end']) + + stuff = urlopen(u).read() + elif "KEY FOUND" in res: + pw = re.sub("^.*\[ ", "", res) + + i = pw.rfind(" ]") + if i == -1: + raise BaseException("Can't parse output") + + pw = pw[:i] + + print("Key for %s is %s" % (crack['net'], pw)) + + u = "%snet/%s/result?pass=%s" % (url, crack['net'], pw) + stuff = urlopen(u).read() + + return 0 + +def decompress(fn): + f = gzip.open(fn + ".gz") + o = open(fn, "wb") + o.writelines(f) + o.close() + f.close() + +def setup_dict(crack): + global url + + d = crack['dict'] + + fn = "dcrack-client-dict-%s.txt" % d + + try: + f = open(fn) + f.close() + except: + print("Downloading dictionary %s" % d) + + u = "%sdict/%s" % (url, d) + stuff = urlopen(u) + + f = open(fn + ".gz", "wb") + f.write(stuff.read()) + f.close() + + print("Uncompressing dictionary") + decompress(fn) + + sha1 = hashlib.sha1() + f = open(fn, "rb") + sha1.update(f.read()) + f.close() + h = sha1.hexdigest() + + if h != d: + print("bad dictionary") + exit(1) + + s = "dcrack-client-dict-%s-%d:%d.txt" \ + % (d, crack['start'], crack['end']) + + try: + f = open(s) + f.close() + except: + print("Splitting dict %s" % s) + f = open(fn, "rb") + o = open(s, "wb") + + for i, l in enumerate(f): + if i >= crack['end']: + break + + if i >= crack['start']: + o.write(l) + + f.close() + o.close() + + return s + +def get_cap(crack): + global url, nets + + fn = "dcrack-client.cap" + + bssid = crack['net'].upper() + + if bssid in nets: + return fn + + try: + f = open(fn, "rb") + f.close() + check_cap(fn, bssid) + except: + pass + + if bssid in nets: + return fn + + print("Downloading cap") + u = "%scap/%s" % (url, bssid) + + stuff = urlopen(u) + + f = open(fn + ".gz", "wb") + f.write(stuff.read()) + f.close() + + print("Uncompressing cap") + decompress(fn) + + nets = {} + check_cap(fn, bssid) + + if bssid not in nets: + raise BaseException("Can't find net %s" % bssid) + + return fn + +def process_cap(fn): + global nets + + nets = {} + + print("Processing cap") + p = subprocess.Popen(["aircrack-ng", fn], stdout=subprocess.PIPE, \ + stdin=subprocess.PIPE) + found = False + while True: + line = p.stdout.readline() + + try: + line = line.decode("utf-8") + except: + line = str(line) + + if "1 handshake" in line: + found = True + parts = line.split() + b = parts[1].upper() +# print("BSSID [%s]" % b) + nets[b] = True + + if (found and line == "\n"): + break + + p.stdin.write(bytes("1\n", "utf-8")) + p.communicate() + +def check_cap(fn, bssid): + global nets + + cmd = ["aircrack-ng", "-b", bssid, fn] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) + + res = p.communicate()[0] + res = str(res) + + if "No matching network found" not in res: + nets[bssid] = True + +def worker(): + while True: + interval = get_work() + time.sleep(interval) + +def set_url(): + global url, port + + if len(sys.argv) < 3: + print("Provide server addr") + usage() + + host = sys.argv[2] + + if not ":" in host: + host = "%s:%d" % (host, port) + + url = "http://" + host + "/" + "dcrack/" + +def client(): + global cid, cracker, url + + set_url() + url += "worker/" + + speed = get_speed() + print("Speed", speed) + + cid = get_cid() + + print("CID", cid) + + try_ping(speed) + t = threading.Thread(target=pinger, args=(speed,)) + t.start() + + while True: + try: + do_client() + break + except URLError: + print("Conn refused") + time.sleep(60) + +def do_client(): + try: + worker() + except KeyboardInterrupt: + if cracker: + cracker.kill() + print("one more time...") + +def upload_file(url, f): + x = urlparse(url) + c = HTTPConnection(x.netloc) + + # XXX not quite HTTP form + + f = open(f, "rb") + c.request("POST", x.path, f) + res = c.getresponse() + stuff = res.read() + c.close() + f.close() + + return stuff + +def compress_file(f): + i = open(f, "rb") + o = gzip.open(f + ".gz", "wb") + o.writelines(i) + o.close() + i.close() + +def send_dict(): + global url + + if len(sys.argv) < 5: + print("Need dict") + usage() + + d = sys.argv[4] + + print("Calculating dictionary hash for %s" % d) + + sha1 = hashlib.sha1() + f = open(d, "rb") + sha1.update(f.read()) + f.close() + + h = sha1.hexdigest() + + print("Hash is %s" % h) + + u = url + "dict/" + h + "/status" + stuff = urlopen(u).read() + + if "NO" in str(stuff): + u = url + "dict/create" + print("Compressing dictionary") + compress_file(d) + print("Uploading dictionary") + upload_file(u, d + ".gz") + + print("Setting dictionary to %s" % d) + u = url + "dict/" + h + "/set" + stuff = urlopen(u).read() + +def send_cap(): + global url + + if len(sys.argv) < 5: + print("Need cap") + usage() + + cap = sys.argv[4] + + print("Cleaning cap %s" % cap) + subprocess.Popen(["wpaclean", cap + ".clean", cap], \ + stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0] + + print("Compressing cap") + compress_file(cap + ".clean") + + u = url + "cap/create" + upload_file(u, cap + ".clean.gz") + +def cmd_crack(): + net_cmd("crack") + +def net_cmd(op): + global url + + if len(sys.argv) < 5: + print("Need BSSID") + usage() + + bssid = sys.argv[4] + + print("%s %s" % (op, bssid)) + u = "%snet/%s/%s" % (url, bssid, op) + stuff = urlopen(u).read() + +def cmd_remove(): + net_cmd("remove") + +def cmd_status(): + u = "%sstatus" % url + stuff = urlopen(u).read() + + stuff = json.loads(stuff.decode("utf-8")) + +# print(stuff) +# print("=============") + + i = 0 + speed = 0 + for c in stuff['clients']: + i += 1 + speed += c + + print("Clients\t%d\nSpeed\t%d\n" % (i, speed)) + + need = 0 + + for n in stuff['nets']: + out = n['bssid'] + " " + + if "pass" in n: + out += n['pass'] + elif "did" in n: + did = int(float(n['did']) / float(n['tot']) * 100.0) + out += str(did) + "%" + need += n['tot'] - n['did'] + else: + out += "-" + + print(out) + + if need != 0: + print("\nKeys left %d" % need) + if speed != 0: + s = int(float(need) / float(speed)) + sec = datetime.timedelta(seconds=s) + d = datetime.datetime(1,1,1) + sec + print("ETA %dh %dm" % (d.hour, d.minute)) + +def do_cmd(): + global url + + set_url() + url += "cmd/" + + if len(sys.argv) < 4: + print("Need CMD") + usage() + + cmd = sys.argv[3] + + if "dict" in cmd: + send_dict() + elif "cap" in cmd: + send_cap() + elif "crack" in cmd: + cmd_crack() + elif "status" in cmd: + cmd_status() + elif "remove" in cmd: + cmd_remove() + else: + print("Unknown cmd %s" % cmd) + usage() + +def main(): + if len(sys.argv) < 2: + usage() + + cmd = sys.argv[1] + + if cmd == "server": + server() + elif cmd == "client": + client() + elif cmd == "cmd": + do_cmd() + else: + print("Unknown cmd", cmd) + usage() + + exit(0) + +if __name__ == "__main__": + main()