示例#1
0
def main():
    #    logging.basicConfig(stream=sys.stderr, level=logging.INFO)

    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    stream = logging.StreamHandler(sys.stderr)
    stream.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(levelname)s: %(message)s')
    #    formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')
    stream.setFormatter(formatter)
    logger.addHandler(stream)

    parser = argparse.ArgumentParser(
        add_help=True,
        description=
        'Python based ingestor for BloodHound\nFor help or reporting issues, visit https://github.com/Fox-IT/BloodHound.py',
        formatter_class=argparse.RawDescriptionHelpFormatter)

    parser.add_argument(
        '-c',
        '--collectionmethod',
        action='store',
        default='Default',
        help=
        'Which information to collect. Supported: Group, LocalAdmin, Session, '
        'Trusts, Default (all previous), DCOnly (no computer connections), DCOM, RDP,'
        'PSRemote, LoggedOn, ObjectProps, ACL, All (all except LoggedOn). '
        'You can specify more than one by separating them with a comma. (default: Default)'
    )
    parser.add_argument(
        '-u',
        '--username',
        action='store',
        help=
        'Username. Format: username[@domain]; If the domain is unspecified, the current domain is used.'
    )
    parser.add_argument('-p', '--password', action='store', help='Password')
    parser.add_argument('-k',
                        '--kerberos',
                        action='store_true',
                        help='Use kerberos')
    parser.add_argument('--hashes', action='store', help='LM:NLTM hashes')
    parser.add_argument('-ns',
                        '--nameserver',
                        action='store',
                        help='Alternative name server to use for queries')
    parser.add_argument('--dns-tcp',
                        action='store_true',
                        help='Use TCP instead of UDP for DNS queries')
    parser.add_argument('--dns-timeout',
                        action='store',
                        type=int,
                        default=3,
                        help='DNS query timeout in seconds (default: 3)')
    parser.add_argument('-d',
                        '--domain',
                        action='store',
                        help='Domain to query.')
    parser.add_argument('-dc',
                        '--domain-controller',
                        metavar='HOST',
                        action='store',
                        help='Override which DC to query (hostname)')
    parser.add_argument('-gc',
                        '--global-catalog',
                        metavar='HOST',
                        action='store',
                        help='Override which GC to query (hostname)')
    parser.add_argument(
        '-w',
        '--workers',
        action='store',
        type=int,
        default=10,
        help='Number of workers for computer enumeration (default: 10)')
    parser.add_argument('-v',
                        action='store_true',
                        help='Enable verbose output')
    parser.add_argument(
        '--disable-pooling',
        action='store_true',
        help=
        'Don\'t use subprocesses for ACL parsing (only for debugging purposes)'
    )
    parser.add_argument(
        '--disable-autogc',
        action='store_true',
        help=
        'Don\'t automatically select a Global Catalog (use only if it gives errors)'
    )

    args = parser.parse_args()

    if args.v is True:
        logger.setLevel(logging.DEBUG)

    if args.kerberos is True:
        logging.debug('Authentication: kerberos')
        kerberize()
        auth = ADAuthentication()
    elif args.username is not None and args.password is not None:
        logging.debug('Authentication: username/password')
        auth = ADAuthentication(username=args.username,
                                password=args.password,
                                domain=args.domain)
    elif args.username is not None and args.password is None and args.hashes is None:
        args.password = getpass.getpass()
        auth = ADAuthentication(username=args.username,
                                password=args.password,
                                domain=args.domain)
    elif args.username is None and (args.password is not None
                                    or args.hashes is not None):
        logging.error(
            'Authentication: password or hashes provided without username')
        sys.exit(1)
    elif args.hashes is not None and args.username is not None:
        logging.debug('Authentication: NTLM hashes')
        lm, nt = args.hashes.split(":")
        auth = ADAuthentication(lm_hash=lm,
                                nt_hash=nt,
                                username=args.username,
                                domain=args.domain)
    else:
        parser.print_help()
        sys.exit(1)

    ad = AD(auth=auth,
            domain=args.domain,
            nameserver=args.nameserver,
            dns_tcp=args.dns_tcp,
            dns_timeout=args.dns_timeout)

    # Resolve collection methods
    collect = resolve_collection_methods(args.collectionmethod)
    if not collect:
        return
    logging.debug('Resolved collection methods: %s', ', '.join(list(collect)))

    logging.debug('Using DNS to retrieve domain information')
    ad.dns_resolve(kerberos=args.kerberos, domain=args.domain, options=args)

    # Override the detected DC / GC if specified
    if args.domain_controller:
        if re.match(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}',
                    args.domain_controller):
            logging.error('The specified domain controller %s looks like an IP address, but requires a hostname (FQDN).\n'\
                          'Use the -ns flag to specify a DNS server IP if the hostname does not resolve on your default nameserver.',
                          args.domain_controller)
            sys.exit(1)
        ad.override_dc(args.domain_controller)
    if args.global_catalog:
        if re.match(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}',
                    args.global_catalog):
            logging.error('The specified global catalog server %s looks like an IP address, but requires a hostname (FQDN).\n'\
                          'Use the -ns flag to specify a DNS server IP if the hostname does not resolve on your default nameserver.',
                          args.global_catalog)
            sys.exit(1)
        ad.override_gc(args.global_catalog)

    bloodhound = BloodHound(ad)
    bloodhound.connect()
    bloodhound.run(collect=collect,
                   num_workers=args.workers,
                   disable_pooling=args.disable_pooling)
示例#2
0
def main():
    #    logging.basicConfig(stream=sys.stderr, level=logging.INFO)

    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    stream = logging.StreamHandler(sys.stderr)
    stream.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(levelname)s: %(message)s')
    #    formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')
    stream.setFormatter(formatter)
    logger.addHandler(stream)

    parser = argparse.ArgumentParser(
        add_help=True,
        description=
        'Python based ingestor for BloodHound\nFor help or reporting issues, visit https://github.com/Fox-IT/BloodHound.py',
        formatter_class=argparse.RawDescriptionHelpFormatter)

    parser.add_argument(
        '-c',
        '--collectionmethod',
        action='store',
        default='Default',
        help=
        'Which information to collect. Supported: Group, LocalAdmin, Session, '
        'Trusts, Default/All (all the previous). You can specify more than one by '
        'separating them with a comma. (default: Default)')
    parser.add_argument(
        '-u',
        '--username',
        action='store',
        help=
        'Username. Format: username[@domain]; If the domain is unspecified, the current domain is used.'
    )
    parser.add_argument('-p', '--password', action='store', help='Password')
    parser.add_argument('-k',
                        '--kerberos',
                        action='store_true',
                        help='Use kerberos')
    parser.add_argument('--hashes', action='store', help='LM:NLTM hashes')
    parser.add_argument('-ns',
                        '--nameserver',
                        action='store',
                        help='Alternative name server to use for queries')
    parser.add_argument('--dns-tcp',
                        action='store_true',
                        help='Use TCP instead of UDP for DNS queries')
    parser.add_argument('-d',
                        '--domain',
                        action='store',
                        help='Domain to query.')
    parser.add_argument('-dc',
                        '--domain-controller',
                        metavar='HOST',
                        action='store',
                        help='Override which DC to query')
    parser.add_argument('-gc',
                        '--global-catalog',
                        metavar='HOST',
                        action='store',
                        help='Override which GC to query')
    parser.add_argument(
        '-w',
        '--workers',
        action='store',
        type=int,
        default=10,
        help='Number of workers for computer enumeration (default: 10)')
    parser.add_argument('-v',
                        action='store_true',
                        help='Enable verbose output')

    args = parser.parse_args()

    if args.v is True:
        logger.setLevel(logging.DEBUG)

    if args.kerberos is True:
        logging.debug('Authentication: kerberos')
        kerberize()
        auth = ADAuthentication()
    elif args.username is not None and args.password is not None:
        logging.debug('Authentication: username/password')
        auth = ADAuthentication(username=args.username,
                                password=args.password,
                                domain=args.domain)
    elif args.username is not None and args.password is None and args.hashes is None:
        args.password = getpass.getpass()
        auth = ADAuthentication(username=args.username,
                                password=args.password,
                                domain=args.domain)
    elif args.username is None and (args.password is not None
                                    or args.hashes is not None):
        logging.error(
            'Authentication: password or hashes provided without username')
        sys.exit(1)
    elif args.hashes is not None and args.username is not None:
        logging.debug('Authentication: NTLM hashes')
        lm, nt = args.hashes.split(":")
        auth = ADAuthentication(lm_hash=lm,
                                nt_hash=nt,
                                username=args.username,
                                domain=args.domain)
    else:
        parser.print_help()
        sys.exit(1)

    ad = AD(auth=auth,
            domain=args.domain,
            nameserver=args.nameserver,
            dns_tcp=args.dns_tcp)

    # Resolve collection methods
    collect = resolve_collection_methods(args.collectionmethod)
    if not collect:
        return
    logging.debug('Resolved collection methods: %s', ', '.join(list(collect)))

    logging.debug('Using DNS to retrieve domain information')
    ad.dns_resolve(kerberos=args.kerberos, domain=args.domain)

    # Override the detected DC / GC if specified
    if args.domain_controller:
        ad.override_dc(args.domain_controller)
    if args.global_catalog:
        ad.override_gc(args.global_catalog)

    bloodhound = BloodHound(ad)
    bloodhound.connect()
    bloodhound.run(collect=collect, num_workers=args.workers)