Example #1
0
def report_download(uuid):
    if not session.__node__:
        return redirect(url_for("node"))

    pd = phishdetect.PhishDetect(host=session.__node__["host"],
                                 api_key=session.__node__["key"])
    results = pd.reports.details(uuid=uuid)
    if "error" in results:
        return render_template("error.html",
                               msg="Unable to fetch report details: {}".format(
                                   results["error"]))

    content = results["content"]
    if content.strip() == "":
        return render_template("error.html",
                               msg="The fetched message seems empty")

    mem = io.BytesIO()
    mem.write(content.encode("utf-8"))
    mem.seek(0)

    if results["type"] == "email":
        mimetype = "message/rfc822"
        filename = "{}.eml".format(results["uuid"])
    else:
        mimetype = "text/plain"
        filename = "{}.txt".format(results["uuid"])

    return send_file(mem,
                     mimetype=mimetype,
                     as_attachment=True,
                     attachment_filename=filename)
Example #2
0
def indicators():
    if not session.__node__:
        return redirect(url_for("node"))

    # Get the form to add indicators.
    if request.method == "GET":
        ioc = request.args.get("ioc", None)
        if ioc:
            ioc = extract_domain(ioc)

        return render_template("indicators.html",
                               indicators=ioc,
                               page="Indicators")
    # Process new indicators to be added.
    elif request.method == "POST":
        indicators_string = request.form.get("indicators", "")
        tags_string = request.form.get("tags", "")

        indicators_string = indicators_string.strip()
        tags_string = tags_string.strip()

        if indicators_string == "":
            return render_template(
                "indicators.html",
                page="Indicators",
                error="You didn't provide a valid list of indicators")

        if tags_string == "":
            tags = []
        else:
            tags = [t.lower().strip() for t in tags_string.split(",")]

        indicators = [i.lower().strip() for i in indicators_string.split()]

        try:
            pd = phishdetect.PhishDetect(host=session.__node__["host"],
                                         api_key=session.__node__["key"])

            results = pd.indicators.add(indicators, tags)
        except Exception as e:
            return render_template(
                "error.html",
                msg="The connection to the PhishDetect Node failed: {}".format(
                    e))

        if "error" in results:
            return render_template("indicators.html",
                                   page="Indicators",
                                   error=results["error"],
                                   tags=tags_string,
                                   indicators=indicators_string)

        msg = "Added {} new indicators successfully!".format(
            results["counter"])
        return render_template("success.html", msg=msg)
Example #3
0
def alerts():
    if not session.__node__:
        return redirect(url_for("node"))

    try:
        pd = phishdetect.PhishDetect(host=session.__node__["host"],
                                     api_key=session.__node__["key"])
        results = pd.alerts.fetch()
    except Exception as e:
        return render_template(
            "error.html",
            msg="The connection to the PhishDetect Node failed: {}".format(e),
            current_node=session.__node__)

    if results and "error" in results:
        return render_template("error.html",
                               msg="Unable to fetch alerts: {}".format(
                                   results["error"]),
                               current_node=session.__node__)

    archived = request.args.get("archived", None)

    archived_alerts = load_archived_alerts()
    final = []
    for result in results:
        patterns = [
            "%Y-%m-%dT%H:%M:%S.%f%z",
            "%Y-%m-%dT%H:%M:%S.%f%Z",
            "%Y-%m-%dT%H:%M:%S.%fZ",
        ]

        date = None
        for pattern in patterns:
            try:
                date = datetime.datetime.strptime(result["datetime"], pattern)
            except ValueError:
                continue
            else:
                break

        if date:
            result["datetime"] = date.strftime("%Y-%m-%d %H:%M:%S %Z")

        if archived:
            if result["uuid"] in archived_alerts:
                final.append(result)
        else:
            if result["uuid"] not in archived_alerts:
                final.append(result)

    return render_template("alerts.html",
                           page="Alerts",
                           alerts=final,
                           archived=archived,
                           current_node=session.__node__)
Example #4
0
def indicator(sha256):
    if not session.__node__:
        return redirect(url_for("node"))

    pd = phishdetect.PhishDetect(host=session.__node__["host"],
                                 api_key=session.__node__["key"])
    details = pd.indicators.details(sha256)
    return render_template("indicator.html",
                           node=session.__node__["host"],
                           page="Indicator Details",
                           details=details)
Example #5
0
def indicators_disable():
    content = request.json
    iocs = content["iocs"]

    pd = phishdetect.PhishDetect(host=session.__node__["host"],
                                 api_key=session.__node__["key"])
    result = pd.indicators.disable(iocs)
    if "error" in result:
        return abort(Response(result["error"]))

    return ("", 200)
Example #6
0
def main():
    parser = argparse.ArgumentParser(description="Fetch events from the PhishDetect Node")
    parser.add_argument('--node', default=os.getenv('PDNODE', 'http://127.0.0.1:7856'), help="URL to the PhishDetect Node (default env PDNODE)")
    parser.add_argument('--key', default=os.getenv('PDKEY', None), help="The API key for your PhishDetect Node user (default env PDKEY)")
    parser.add_argument('--misp', default=os.getenv('MISPURL', None), help="URL to the MISP instance (default env MISPURL)")
    parser.add_argument('--token', default=os.getenv('MISPTOKEN', None), help="The MISP api token (default env MISPTOKEN)")
    args = parser.parse_args()

    if (not args.node or
        not args.key or
        not args.misp or
        not args.token):
        parser.print_help()
        sys.exit(-1)

    seen_reports = load_data(raw_path)
    pd = phishdetect.PhishDetect(host=args.node, api_key=args.key)

    limit = 100
    offset = 0

    delay = 0
    print("Syncing email reports from {} to {}".format(args.node, args.misp))
    while True:
        time.sleep(delay)
        delay = 60
        print("Fetching email reports from offset {}".format(offset))
        try:
            reports = pd.reports.fetch(limit=limit, offset=offset, report_type='email')
            if not reports:
                print("Response is empty (nothing to do)")
                continue
        except:
            print("ERROR: Unable to connect to PhishDetect")
            continue

        if 'error' in reports:
            print("ERROR: {}".format(reports['error']))
        else:
            for report in reports:
                offset = offset + 1
                if report['uuid'] not in seen_reports:
                    print("Got a new email report with ID {}".format(report['uuid']))

                    res = send_misp_event(args.token, args.misp, report['content'], report['user_contact'])

                    if res.status_code == 200:
                        seen_reports.append(report['uuid'])
                        with open(raw_path, 'a') as handle:
                            handle.write('{}\n'.format(report['uuid']))
                    else:
                        print(res)
Example #7
0
def indicators_disabled():
    if not session.__node__:
        return redirect(url_for("node"))

    pd = phishdetect.PhishDetect(host=session.__node__["host"],
                                 api_key=session.__node__["key"])

    iocs = pd.indicators.get_disabled()
    return render_template("indicators_list.html",
                           iocs=iocs,
                           status="disabled",
                           page="Disabled Indicators",
                           current_node=session.__node__)
Example #8
0
def users_deactivate():
    if not session.__node__:
        return redirect(url_for("node"))

    uuid = request.form.get("uuid", "")

    # First we get the pending users (before activating the current).
    pd = phishdetect.PhishDetect(host=session.__node__["host"],
                                 api_key=session.__node__["key"])
    results = pd.users.get_active()
    if "error" in results:
        return render_template("error.html",
                               msg="Unable to fetch pending users: {}".format(
                                   users["error"]),
                               current_node=session.__node__)

    # Then we activate the user.
    result = pd.users.deactivate(uuid)
    if "error" in result:
        return render_template("error.html",
                               msg="Unable to deactivate user: {}".format(
                                   result["error"]),
                               current_node=session.__node__)

    email = None
    for user in results:
        if uuid == user["uuid"]:
            email = user["email"]
            break

    if not email:
        return render_template("error.html",
                               msg="User not found",
                               current_node=session.__node__)

    message = "Your PhishDetect secret token has been deactivated!\n\
If you have any questions, please contact your PhishDetect Node administrator."

    try:
        send_email(email, "Your PhishDetect secret token has been deactivated",
                   message)
    except Exception as e:
        return render_template(
            "error.html",
            msg="Failed to send email to user: {}".format(e),
            current_node=session.__node__)

    return render_template("success.html",
                           msg="The user has been deactivated successfully",
                           current_node=session.__node__)
Example #9
0
def users_active():
    if not session.__node__:
        return redirect(url_for("node"))

    pd = phishdetect.PhishDetect(host=session.__node__["host"],
                                 api_key=session.__node__["key"])
    results = pd.users.get_active()
    if "error" in results:
        return render_template("error.html",
                               msg="Unable to fetch users: {}".format(
                                   results["error"]))

    return render_template("users_active.html",
                           node=session.__node__["host"],
                           page="Users",
                           users=results)
Example #10
0
def report(uuid):
    if not session.__node__:
        return redirect(url_for("node"))

    pd = phishdetect.PhishDetect(host=session.__node__["host"],
                                 api_key=session.__node__["key"])
    results = pd.reports.details(uuid=uuid)
    if "error" in results:
        return render_template("error.html",
                               msg="Unable to fetch report details: {}".format(
                                   results["error"]))

    return render_template("report.html",
                           node=session.__node__["host"],
                           page="Report",
                           message=results)
Example #11
0
def indicators_add_confirm():
    # Process new indicators to be added.
    enabled = bool(request.form.get("enabled", False))
    indicators_string = request.form.get("indicators", "")
    tags_string = request.form.get("tags", "")

    indicators_string = indicators_string.strip()
    tags_string = tags_string.strip()

    if indicators_string == "":
        return render_template(
            "indicators_add.html",
            page="Add Indicators",
            error="You didn't provide a valid list of indicators",
            current_node=session.__node__)

    if tags_string == "":
        tags = []
    else:
        tags = [t.lower().strip() for t in tags_string.split(",")]

    indicators = [i.lower().strip() for i in indicators_string.split()]

    try:
        pd = phishdetect.PhishDetect(host=session.__node__["host"],
                                     api_key=session.__node__["key"])

        results = pd.indicators.add(indicators=indicators,
                                    tags=tags,
                                    enabled=enabled)
    except Exception as e:
        return render_template(
            "error.html",
            msg="The connection to the PhishDetect Node failed: {}".format(e),
            current_node=session.__node__)

    if "error" in results:
        return render_template("indicators_add.html",
                               page="Indicators",
                               error=results["error"],
                               tags=tags_string,
                               indicators=indicators_string,
                               current_node=session.__node__)

    msg = "Added {} new indicators successfully!".format(results["counter"])
    return render_template("success.html", msg=msg)
Example #12
0
def reports():
    if not session.__node__:
        return redirect(url_for("node"))

    pd = phishdetect.PhishDetect(host=session.__node__["host"],
                                 api_key=session.__node__["key"])
    results = pd.reports.fetch()

    if "error" in results:
        return render_template("error.html",
                               msg="Unable to fetch reports: {}".format(
                                   results["error"]),
                               current_node=session.__node__)

    return render_template("reports.html",
                           page="Reports",
                           reports=results,
                           current_node=session.__node__)
Example #13
0
def indicators_view(sha256):
    if not session.__node__:
        return redirect(url_for("node"))

    pd = phishdetect.PhishDetect(host=session.__node__["host"],
                                 api_key=session.__node__["key"])
    results = pd.indicators.details(sha256)

    if "error" in results:
        return render_template(
            "error.html",
            msg="Unable to fetch indicator details: {}".format(
                results["error"]),
            current_node=session.__node__)

    return render_template("indicators_view.html",
                           page="Indicator Details",
                           ioc=results,
                           current_node=session.__node__)
Example #14
0
def users_activate(api_key):
    if not session.__node__:
        return redirect(url_for("node"))

    # First we get the pending users (before activating the current).
    pd = phishdetect.PhishDetect(host=session.__node__["host"],
                                 api_key=session.__node__["key"])
    results = pd.users.get_pending()
    if "error" in results:
        return render_template("error.html",
                               msg="Unable to fetch pending users: {}".format(
                                   users["error"]))

    # Then we activate the user.
    result = pd.users.activate(api_key)
    if "error" in result:
        return render_template("error.html",
                               msg="Unable to activate user: {}".format(
                                   result["error"]))

    email = None
    for user in results:
        if api_key == user["key"]:
            email = user["email"]
            break

    if not email:
        return render_template("error.html", msg="User not found")

    message = "Your PhishDetect secret token has been activated!"

    try:
        send_email(email, "Your PhishDetect secret token has been activated",
                   message)
    except Exception as e:
        return render_template(
            "error.html", msg="Failed to send email to user: {}".format(e))

    return render_template("success.html",
                           msg="The user has been activated successfully")
Example #15
0
def main():
    parser = argparse.ArgumentParser(
        description="Send indicators to the PhishDetect Node")
    parser.add_argument("--node",
                        default="http://127.0.0.1:7856",
                        help="URL to the PhishDetect Node")
    parser.add_argument("--key",
                        required=True,
                        help="The API key for your PhishDetect Node user")
    parser.add_argument("--type",
                        required=True,
                        help="The type of indicator (\"domain\" or \"email\")")
    parser.add_argument(
        "--tags", help="Comma separated list of tags to to mark the indicator")
    parser.add_argument("--single",
                        metavar="IOC",
                        help="Send this single indicator to PhishDetect Node")
    parser.add_argument(
        "--file",
        metavar="FILE",
        help="Send all indicators contained in this file to PhishDetect Node")
    args = parser.parse_args()

    if (not args.single and not args.file) or (args.single and args.file):
        parser.print_help()
        print("\nERROR: You need to specify either --single or --file")
        sys.exit(-1)

    indicators = []
    if args.file:
        if not os.path.exists(args.file):
            print("ERROR: The file you specified at path {} does not exist.".
                  format(args.file))
            sys.exit(-1)

        with open(args.file, "r") as handle:
            for line in handle:
                line = line.strip()
                if line == "":
                    continue

                if line not in indicators:
                    print("Adding indicator: {}".format(line))
                    indicators.append(line)
    elif args.single:
        ioc = args.single.strip()
        if ioc not in indicators:
            print("Adding indicator: {}".format(ioc))
            indicators.append(ioc)

    if len(indicators) == 0:
        print("ERROR: Somehow there are no indicators to submit")
        sys.exit(-1)

    tags = []
    if args.tags:
        for tag in args.tags.split(","):
            tag = tag.strip()
            if tag == "":
                continue

            if tag not in tags:
                tags.append(tag)

    pd = phishdetect.PhishDetect(host=args.node, api_key=args.key)
    result = pd.indicators.add(indicators=indicators,
                               indicators_type=args.type,
                               tags=tags)

    print(result)
Example #16
0
def main():
    parser = argparse.ArgumentParser(
        description="Synchronize your PhishDetect Node with another")
    parser.add_argument(
        "--node",
        default=os.getenv("PDNODE", "http://127.0.0.1:7856"),
        help="URL to the target PhishDetect Node (default env PDNODE)")
    parser.add_argument(
        "--key",
        default=os.getenv("PDKEY", None),
        help="The API key for your PhishDetect Node user (default env PDKEY)")
    parser.add_argument(
        "--source-node",
        required=True,
        help="URL to the PhishDetect Node you want to fetch indicators from")
    parser.add_argument(
        "--source-key",
        default=os.getenv("PDSRCKEY", None),
        help="API key for the source PhishDetect Node, if needed")
    parser.add_argument(
        "--recent",
        action="store_true",
        help="Flag to fetch only indicators from last 24 hours")
    parser.add_argument("--enabled",
                        action="store_true",
                        default=False,
                        help="Flag to submit synced indicators as enabled")
    parser.add_argument("--tags", help="Comma-separated list of tags to add to the synced indicators. " \
                                       "If none is specified, one will be generated from the source node address")
    parser.add_argument(
        "--batch-size",
        type=int,
        default=500,
        help="Size of batches of indicators to add to target node")
    args = parser.parse_args()

    # We create a connection to the source PhishDetect Node.
    src_pd = phishdetect.PhishDetect(host=args.source_node,
                                     api_key=args.source_key)

    # We generate the list of tags to use.
    tags = generate_tags(args.tags, args.source_node)

    if args.recent:
        # Obtain only the most recent indicators.
        print("Fetching the list of recent indicators from source node...")
        src_iocs = src_pd.indicators.fetch_recent()
    else:
        # Obtain the list of all "active" indicators from the source node.
        # Should be all added in the last 6 months.
        print(
            "Fetching the full list of active indicators from the source node..."
        )
        src_iocs = src_pd.indicators.fetch()

    # We create a connection to the target PhishDetect Node.
    print("Fetching the current list of indicators from the target node...")
    dst_pd = phishdetect.PhishDetect(host=args.node, api_key=args.key)
    current_iocs = dst_pd.indicators.fetch()

    # We loop through the indicators fetched from the source node.
    for iocs_type, indicators in src_iocs.items():
        # We first we clean the list from the source node by comparing it to
        # the list we got from the target node.
        cleaned_list = []
        for ioc in indicators:
            if ioc not in current_iocs[iocs_type]:
                cleaned_list.append(ioc)

        if len(cleaned_list) == 0:
            print(f"No new indicators of type {iocs_type} to add. Skip.")
            continue

        print(f"From a list of {len(indicators)} of type {iocs_type} " \
              f"submitting a filtered list of {len(cleaned_list)}...")

        # Now we loop through the cleaned list of indicators.
        for i in range(0, len(cleaned_list), args.batch_size):
            batch = cleaned_list[i:i + args.batch_size]
            result = dst_pd.indicators.add(
                indicators=batch,
                tags=tags,
                indicators_type=iocs_type.rstrip("s"),
                enabled=args.enabled)
            if "error" in result:
                print(
                    f"ERROR: Failed to add indicators to target node: {result['error']}"
                )
            else:
                print(result["msg"])
Example #17
0
def main():
    parser = argparse.ArgumentParser(description="Fetch alerts from the PhishDetect Node")
    parser.add_argument("--node", default=os.getenv("PDNODE", "http://127.0.0.1:7856"), help="URL to the PhishDetect Node (default env PDNODE)")
    parser.add_argument("--key", default=os.getenv("PDKEY", None), help="The API key for your PhishDetect Node user (default env PDKEY)")
    parser.add_argument("--token", default=os.getenv("POTOKEN", None), help="The Pushover token (default env POTOKEN)")
    parser.add_argument("--user", default=os.getenv("POUSER", None), help="The Pushover user (default env POUSER)")
    parser.add_argument("--delay", type=int, default=300, help="Define a delay in seconds between checks")
    args = parser.parse_args()

    if (not args.node or
        not args.key or
        not args.token or
        not args.user):
        parser.print_help()
        sys.exit(-1)

    seen_alerts = load_data(alerts_path)
    seen_reports = load_data(reports_path)
    seen_users = load_data(users_path)

    pd = phishdetect.PhishDetect(host=args.node, api_key=args.key)

    while True:
        print("Checking for new records to report...")

        try:
            alerts = pd.alerts.fetch()
            if not alerts:
                raise NothingToReport
        except NothingToReport:
            pass
        except Exception as e:
            traceback.print_stack()
        else:
            if "error" in alerts:
                print("ERROR: {}".format(alerts["error"]))
            else:
                for alert in alerts:
                    if alert["uuid"] not in seen_alerts:
                        print("Got a new alert with ID {}".format(alert["uuid"]))

                        msg = ""
                        user = alert["user_contact"].strip()
                        if user:
                            msg += "User \"{}\"".format(alert["user_contact"])
                        else:
                            msg += "Unknown user"

                        match = alert["match"].replace("http", "hxxp")
                        match = match.replace(".", "[.]")
                        match = match.replace("@", "[@]")

                        msg += " triggered a {} alert for {}".format(alert["type"], match)

                        send_notification(args.token, args.user, msg)

                        seen_alerts.append(alert["uuid"])
                        add_to_data(alerts_path, alert["uuid"])

        try:
            reports = pd.reports.fetch()
            if not reports:
                raise NothingToReport
        except NothingToReport:
            pass
        except Exception as e:
            traceback.print_stack()
        else:
            if "error" in reports:
                print("ERROR: {}".format(reports["error"]))
            else:
                for report in reports:
                    if report["uuid"] not in seen_reports:
                        print("Got a new report with ID {}".format(report["uuid"]))

                        msg = ""
                        user = report["user_contact"].strip()
                        if user:
                            msg += "User \"{}\"".format(report["user_contact"])
                        else:
                            msg += "Unknown user"

                        msg += " shared a report of type \"{}\" with UUID {}".format(report["type"], report["uuid"])

                        send_notification(args.token, args.user, msg)

                        seen_reports.append(report["uuid"])
                        add_to_data(reports_path, report["uuid"])

        try:
            users = pd.users.get_pending()
            if not users:
                raise NothingToReport
        except NothingToReport:
            pass
        except Exception as e:
            traceback.print_stack()
        else:
            if "error" in users:
                print("ERROR: {}".format(users["error"]))
            else:
                for user in users:
                    if user["key"] not in seen_users:
                        print("Got a new user request for {}".format(user["email"]))

                        msg = "Received a users request for \"{}\" with email {}".format(user["name"], user["email"])
                        send_notification(args.token, args.user, msg)

                        seen_users.append(user["key"])
                        add_to_data(users_path, user["key"])

        time.sleep(args.delay)