Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 37 additions & 9 deletions FindUncommonShares.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,23 @@
]


def strip_cli_value(value):
"""Remove surrounding whitespace, including non-breaking spaces."""
return value.strip()


def parse_auth_identity(default_domain, username):
"""Return the authentication domain and bare username."""
if username is None or "\\" not in username:
return default_domain, username

auth_domain, auth_username = username.split("\\", 1)
if not auth_domain or not auth_username or "\\" in auth_username:
raise ValueError("--auth-user must use the format DOMAIN\\username")

return auth_domain, auth_username


class MicrosoftDNS(object):
"""
Class to interact with Microsoft DNS servers for resolving domain names to IP addresses.
Expand Down Expand Up @@ -170,7 +187,7 @@ def check_presence_of_wildcard_dns(self):
use_ldaps=self.use_ldaps
)

target_dn = "CN=MicrosoftDNS,DC=DomainDnsZones," + ldap_server.info.other["rootDomainNamingContext"][0]
target_dn = "CN=MicrosoftDNS,DC=DomainDnsZones," + ldap_server.info.other["defaultNamingContext"][0]

ldapresults = list(ldap_session.extend.standard.paged_search(target_dn, "(&(objectClass=dnsNode)(dc=\\2A))", attributes=["distinguishedName", "dNSTombstoned"]))

Expand Down Expand Up @@ -429,17 +446,17 @@ def parseArgs():
parser.add_argument("--debug", dest="debug", action="store_true", default=False, help="Debug mode. (default: False).")
parser.add_argument("-no-colors", dest="colors", action="store_false", default=True, help="Disables colored output mode.")
parser.add_argument("-t", "--threads", dest="threads", action="store", type=int, default=20, required=False, help="Number of threads (default: 20).")
parser.add_argument("-ns", "--nameserver", dest="nameserver", default=None, required=False, help="IP of the DNS server to use, instead of the --dc-ip.")
parser.add_argument("-ns", "--nameserver", dest="nameserver", default=None, type=strip_cli_value, required=False, help="IP of the DNS server to use, instead of the --dc-ip.")

group_targets_source = parser.add_argument_group("Targets")
group_targets_source.add_argument("-tf", "--targets-file", default=None, type=str, help="Path to file containing a line by line list of targets.")
group_targets_source.add_argument("-tt", "--target", default=[], type=str, action='append', help="Target IP, FQDN or CIDR.")
group_targets_source.add_argument("-tu", "--target-url", default=[], type=str, action='append', help="Target URL to the tomcat manager.")
group_targets_source.add_argument("-tU", "--targets-urls-file", default=None, type=str, help="Path to file containing a line by line list of target URLs.")
group_targets_source.add_argument("-tp", "--target-ports", default="80,443,8080,8081,8180,9080,9081,10080", type=str, help="Target ports to scan top search for Apache Tomcat servers.")
group_targets_source.add_argument("-ad", "--auth-domain", default="", type=str, help="Windows domain to authenticate to.")
group_targets_source.add_argument("-ai", "--auth-dc-ip", default=None, type=str, help="IP of the domain controller.")
group_targets_source.add_argument("-au", "--auth-user", default=None, type=str, help="Username of the domain account.")
group_targets_source.add_argument("-ad", "--auth-domain", default="", type=strip_cli_value, help="Target Windows domain. Also used for authentication unless --auth-user is DOMAIN\\user.")
group_targets_source.add_argument("-ai", "--auth-dc-ip", default=None, type=strip_cli_value, help="IP of the domain controller.")
group_targets_source.add_argument("-au", "--auth-user", default=None, type=strip_cli_value, help="Username of the domain account, optionally in DOMAIN\\user format.")
group_targets_source.add_argument("--ldaps", default=False, action="store_true", help="Use LDAPS (default: False)")
group_targets_source.add_argument("--no-ldap", default=False, action="store_true", help="Do not perform LDAP queries.")
group_targets_source.add_argument("--subnets", default=False, action="store_true", help="Get all subnets from the domain and use them as targets (default: False)")
Expand All @@ -452,7 +469,7 @@ def parseArgs():
cred.add_argument("-ah", "--auth-hashes", default=None, type=str, help="LM:NT hashes to pass the hash for this user.")
cred.add_argument("--aes-key", dest="auth_key", action="store", metavar="hex key", help="AES key to use for Kerberos Authentication (128 or 256 bits)")
secret.add_argument("-k", "--kerberos", dest="auth_use_kerberos", action="store_true", help="Use Kerberos authentication. Grabs credentials from .ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line")
secret.add_argument("--kdcHost", dest="auth_kdcHost", default=None, type=str, help="IP of the domain controller.")
secret.add_argument("--kdcHost", dest="auth_kdcHost", default=None, type=strip_cli_value, help="IP of the domain controller.")

# Shares
shares = parser.add_argument_group("Shares")
Expand All @@ -475,6 +492,12 @@ def parseArgs():

options = parser.parse_args()

options.target_domain = options.auth_domain
try:
options.auth_domain, options.auth_user = parse_auth_identity(options.auth_domain, options.auth_user)
except ValueError as e:
parser.error(str(e))

if options.auth_password is None and options.no_pass == False and options.auth_hashes is None:
print("[+] No password or hashes provided and --no-pass is '%s'" % options.no_pass)
from getpass import getpass
Expand Down Expand Up @@ -792,7 +815,7 @@ def load_targets(options):
if not options.no_ldap:
if options.auth_dc_ip is not None and options.auth_user is not None and (options.auth_password is not None or options.auth_hashes is not None) and options.target_ldap_query is None:
if options.debug:
print("[debug] Loading targets from computers in the domain '%s'" % options.auth_domain)
print("[debug] Loading targets from computers in the domain '%s'" % options.target_domain)
targets += get_computers_from_domain(
auth_domain=options.auth_domain,
auth_dc_ip=options.auth_dc_ip,
Expand Down Expand Up @@ -826,7 +849,7 @@ def load_targets(options):
if not options.no_ldap:
if options.subnets and options.auth_dc_ip is not None and options.auth_user is not None and (options.auth_password is not None or options.auth_hashes is not None):
if options.debug:
print("[debug] Loading targets from subnetworks of the domain '%s'" % options.auth_domain)
print("[debug] Loading targets from subnetworks of the domain '%s'" % options.target_domain)
targets += get_subnets(
auth_domain=options.auth_domain,
auth_dc_ip=options.auth_dc_ip,
Expand Down Expand Up @@ -931,7 +954,12 @@ def load_targets(options):
use_ldaps=options.ldaps,
verbose=options.verbose
)
mdns.check_presence_of_wildcard_dns()
try:
mdns.check_presence_of_wildcard_dns()
except Exception as e:
if options.debug:
traceback.print_exc()
print("[!] Wildcard DNS check failed: %s. Continuing." % e)

if not options.quiet:
print("[>] Parsing targets ...")
Expand Down
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@
```
./FindUncommonShares.py -au user -ap 'Podalirius123!' -ad DOMAIN --auth-dc-ip 192.168.1.71 --check-user-access
```

+ Enumerate DOMAIN_B with an account from a trusted DOMAIN_A:
```
./FindUncommonShares.py -au 'DOMAIN_A\user' -ap 'Podalirius123!' -ad DOMAIN_B --auth-dc-ip 192.168.1.71 --check-user-access
```

When `--auth-user` uses the `DOMAIN\user` format, that domain is used for LDAP and SMB authentication. `--auth-domain` remains the target domain. Quote the username so the shell preserves the backslash.

## Usage

Expand Down Expand Up @@ -79,11 +86,11 @@ Targets:
-tp TARGET_PORTS, --target-ports TARGET_PORTS
Target ports to scan top search for Apache Tomcat servers.
-ad AUTH_DOMAIN, --auth-domain AUTH_DOMAIN
Windows domain to authenticate to.
Target Windows domain. Also used for authentication unless --auth-user is DOMAIN\user.
-ai AUTH_DC_IP, --auth-dc-ip AUTH_DC_IP
IP of the domain controller.
-au AUTH_USER, --auth-user AUTH_USER
Username of the domain account.
Username of the domain account, optionally in DOMAIN\user format.
--ldaps Use LDAPS (default: False)
--no-ldap Do not perform LDAP queries.
--subnets Get all subnets from the domain and use them as targets (default: False)
Expand Down