Skip to content

Instantly share code, notes, and snippets.

@snovvcrash
Last active December 29, 2022 19:53
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save snovvcrash/4e76aaf2a8750922f546eed81aa51438 to your computer and use it in GitHub Desktop.
Save snovvcrash/4e76aaf2a8750922f546eed81aa51438 to your computer and use it in GitHub Desktop.
Send request to the MS Exchange Autodiscover service (MS-OXDSCLI protocol) and parse the response. Hunting for the OABUrl value. Credits to @ptswarm: https://swarm.ptsecurity.com/attacking-ms-exchange-web-interfaces/
#!/usr/bin/env python3
# Usage: python3 oaburl.py MEGACORP/j.doe:'Passw0rd!'@mx.example.com -e existent.email@example.com
from xml.dom import minidom
from argparse import ArgumentParser
from getpass import getpass
import requests
GN = '\033[0;32m' # GREEN NORMAL
GB = '\033[1;32m' # GREEN BOLD
NC = '\033[0m' # NO COLOR
headers = {
'User-Agent': 'Microsoft Office/16.0 (Windows NT 10.0; Microsoft Outlook 16.0.10730; Pro)',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3',
'Accept-Encoding': 'gzip, deflate',
'Content-Type': 'text/xml'
}
data = """<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
<Request>
<EMailAddress>%s</EMailAddress>
<AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
</Request>
</Autodiscover>"""
def init_args():
parser = ArgumentParser()
parser.add_argument('target', help='<<domain/>username[:password]@><targetName_or_address>')
parser.add_argument('-e', '--email', required=True, help='any valid email address within the domain')
return parser.parse_args()
def parse_target(target):
creds, hostname = target.rsplit('@', 1)
domain, userpass = creds.split('/', 1)
try:
username, password = userpass.split(':', 1)
except ValueError:
username = userpass
password = getpass()
return (domain.upper(), username, password, hostname)
def print_node_value(dom, nodename, color=GN):
print(f'{color}[+] {nodename}: {dom.getElementsByTagName(nodename)[0].childNodes[0].nodeValue}{NC}')
if __name__ == '__main__':
args = init_args()
domain, username, password, hostname = parse_target(args.target)
headers['Host'] = hostname
data = data % (args.email,)
session = requests.Session()
session.auth = (f'{domain}\\{username}', password)
resp = session.post(f'https://{hostname}/autodiscover/autodiscover.xml', headers=headers, data=data, verify=False)
print(f'[*] Authenticated users\'s SID (X-BackEndCookie): {resp.headers["Set-Cookie"].split("=")[1]}')
dom = minidom.parseString(resp.text)
dom.normalize()
print_node_value(dom, 'DisplayName')
#print_node_value(dom, 'LegacyDN')
print_node_value(dom, 'Server')
#print_node_value(dom, 'ServerDN')
print_node_value(dom, 'AD')
print_node_value(dom, 'OABUrl', color=GB)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment