NTLM Challenge Message Decoder
On premise Exchange, OWA, Skype, and AD FS servers leak information through NTLM challenge messages, including the NetBIOS and DNS domains, computer name, and server version. These services, if exposed to the internet, can aid red teams in information gathering for brute force/password spray attacks. This post will describe discovering these services and using the ntlm_challenger tool to pull relevant information.
The Tool
ntlm_challenger can be found at: https://github.com/nopfor/ntlm_challenger
Example
$ python3 ntlm_challenger.py 'https://autodiscover.hackin.club/autodiscover/autodiscover.xml'
Target (Domain): HACKIN
Version: Server 2012 / Windows 8 (build 9200)
TargetInfo:
MsvAvNbDomainName: HACKIN
MsvAvNbComputerName: EXCH01
MsvAvDnsDomainName: hackin.club
MsvAvDnsComputerName: EXCH01.hackin.club
MsvAvDnsTreeName: hackin.club
MsvAvTimestamp: Nov 3, 2019 01:07:16.573170
Negotiate Flags:
NTLMSSP_NEGOTIATE_UNICODE
NTLMSSP_REQUEST_TARGET
NTLMSSP_NEGOTIATE_ALWAYS_SIGN
NTLMSSP_TARGET_TYPE_DOMAIN
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
NTLMSSP_NEGOTIATE_TARGET_INFO
NTLMSSP_NEGOTIATE_VERSION
Affected Services
Exposed Autodiscover, ActiveSync, OWA, Skype, and AD FS services can leak information through the challenge message. These HTTP services may accept NTLM authentication, so it’s possible to pull information from the NTLM challenge response.
Discovering Hosts
These services are usually on predictable subdomains. Below are some commonly used subdomain names for targeting certain services.
Exchange servers commonly use the following subdomains:
autodiscover
mail
webmail
owa
TrustedSec released a blog post titled Attacking Self-Hosted Skype for Business/Microsoft Lync Installations (by @nyxgeek) which describes a number of subdomains exposed when running Skype for Business:
lyncdiscover
lyncdiscoverinternal
dialin
scheduler
meet
lync-fe
Douglas Bienstock and Austin Baker listed a few subdomains for AD FS endpoints in their “I am AD FS and so can you” talk at Troopers 19 [slides | presentation] (I’d also include federation):
adfs
sts
fs
Discovering Paths
@nyxgeek recently released an automated tool to brute force common NTLM-protected paths given a subdomain: https://github.com/nyxgeek/ntlmscan. The tool provides a solid list for discovery, but may create unwanted noise during an engagement.
It’s possible to send targeted requests if you can identify the service being hosted. I often find Exchange and OWA services listening externally. The TrustedSec blog lists common endpoints for Lync and Skype services. The following table was taken directly from Nate Power’s talk “Hacking Corporate Em@il Systems” [slides | presentation]. The IIS Paths columns lists endpoints used by Autodiscover, ActiveSync, and OWA services.
Service | Vulnerable Header | IIS Paths |
---|---|---|
Autodiscover | 401 Basic Auth | /Autodiscover , /Autodiscover/Autodiscover.xml |
ActiveSync | 401 Basic Auth | /Microsoft-Server-ActiveSync , /Microsoft-Server-ActiveSync/default.eas |
OWA | 302 Location , 401 Basic Auth | /ECP , /EWS , /EWS/Exchange.asmx , /Exchange , /OWA |
AD FS servers configured with Windows Integrated Authentication (WIA) will accept NTLM authentication at the following endpoint:
/adfs/ls/wia
NTLM Over HTTP Protocol
Brief Overview
The NTLM protocol is a three-way handshake used to authenticate a client to a server. In an Active Directory environment, this is commonly used by Windows machines when Kerberos is not an option (as is the case in external services or standalone systems). The steps taken during an authentication attempt are below:
- Client sends a NEGOTIATE_MESSAGE
- Server sends a CHALLENGE_MESSAGE containing a nonce to prevent replay attacks
- Client does some fancy crypto with the nonce and their password hash, then sends the AUTHENTICATE_MESSAGE
After this handshake, the server will verify that the fancy crypto was done with the client’s password hash and the client will be authenticated.
The Challenge Message
The challenge message sent by the server contains all of the information we’re interested in. Specifically, hostname, domain, and OS version information. The message can be requested pre-authentication.
We can coax the server into coughing up this message by sending a negotiate message, shown below:
1GET /autodiscover/autodiscover.xml HTTP/1.1
2Host: autodiscover.hackin.club
3Authorization: NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=
The server response will look similar to the example:
1HTTP/1.1 401 Unauthorized
2Server: Microsoft-IIS/8.0
3request-id: 5def1285-5b0e-ae5b-8a42-fa90218b0fb9
4Set-Cookie: ClientId=CEBKNAAONVXLCNBEQ; expires=Fri, 16-Oct-2020 01:13:09 GMT; path=/; HttpOnly
5WWW-Authenticate: NTLM TlRMTVNTUAACAAAADAAMADgAAAAFgokCiw/BR0FOzkIAAAAAAAAAAIwAjABEAAAABgLwIwAAAA9IAEEAQwBLAEkATgACAAwASABBAEMASwBJAE4AAQAMAEUAWABDAEgAMAAxAAQAFgBoAGEAYwBrAGkAbgAuAGMAbAB1AGIAAwAkAEUAWABDAEgAMAAxAC4AaABhAGMAawBpAG4ALgBjAGwAdQBiAAUAFgBoAGEAYwBrAGkAbgAuAGMAbAB1AGIABwAIADL+6wmIhNUBAAAAAA==
6WWW-Authenticate: Negotiate
7WWW-Authenticate: Basic realm="autodiscover.hackin.club"
8X-Powered-By: ASP.NET
9X-FEServer: EXCH01
10Date: Thu, 17 Oct 2019 01:13:09 GMT
11Content-Length: 0
The WWW-Authenticate
header will contain the base64-encoded challenge message. Decoding this, we see the following:
$ echo -n 'TlRMTVNTUAACAAAADAAMADgAAAAFgokCiw/BR0FOzkIAAAAAAAAAAIwAjABEAAAABgLwIwAAAA9IAEEAQwBLAEkATgACAAwASABBAEMASwBJAE4AAQAMAEUAWABDAEgAMAAxAAQAFgBoAGEAYwBrAGkAbgAuAGMAbAB1AGIAAwAkAEUAWABDAEgAMAAxAC4AaABhAGMAawBpAG4ALgBjAGwAdQBiAAUAFgBoAGEAYwBrAGkAbgAuAGMAbAB1AGIABwAIADL+6wmIhNUBAAAAAA==' | base64 -d | xxd
00000000: 4e54 4c4d 5353 5000 0200 0000 0c00 0c00 NTLMSSP.........
00000010: 3800 0000 0582 8902 8b0f c147 414e ce42 8..........GAN.B
00000020: 0000 0000 0000 0000 8c00 8c00 4400 0000 ............D...
00000030: 0602 f023 0000 000f 4800 4100 4300 4b00 ...#....H.A.C.K.
00000040: 4900 4e00 0200 0c00 4800 4100 4300 4b00 I.N.....H.A.C.K.
00000050: 4900 4e00 0100 0c00 4500 5800 4300 4800 I.N.....E.X.C.H.
00000060: 3000 3100 0400 1600 6800 6100 6300 6b00 0.1.....h.a.c.k.
00000070: 6900 6e00 2e00 6300 6c00 7500 6200 0300 i.n...c.l.u.b...
00000080: 2400 4500 5800 4300 4800 3000 3100 2e00 $.E.X.C.H.0.1...
00000090: 6800 6100 6300 6b00 6900 6e00 2e00 6300 h.a.c.k.i.n...c.
000000a0: 6c00 7500 6200 0500 1600 6800 6100 6300 l.u.b.....h.a.c.
000000b0: 6b00 6900 6e00 2e00 6300 6c00 7500 6200 k.i.n...c.l.u.b.
000000c0: 0700 0800 32fe eb09 8884 d501 0000 0000 ....2...........
Interpreting the message
Information in the above message can stick out without parsing (ex: hostname EXCH01 and domain hackin.club). The ntlm_challenger tool can decode the full domain, version, target, and flag information from this message without making a request. The following Python script will do just that:
1from ntlm_challenger import *
2
3challenge_message = base64.b64decode('TlRMTVNTUAACAAAADAAMADgAAAAFgokCiw/BR0FOzkIAAAAAAAAAAIwAjABEAAAABgLwIwAAAA9IAEEAQwBLAEkATgACAAwASABBAEMASwBJAE4AAQAMAEUAWABDAEgAMAAxAAQAFgBoAGEAYwBrAGkAbgAuAGMAbAB1AGIAAwAkAEUAWABDAEgAMAAxAC4AaABhAGMAawBpAG4ALgBjAGwAdQBiAAUAFgBoAGEAYwBrAGkAbgAuAGMAbAB1AGIABwAIADL+6wmIhNUBAAAAAA==')
4challenge = parse_challenge(challenge_message)
5print_challenge(challenge)
Target (Domain): HACKIN
Version: Server 2012 / Windows 8 (build 9200)
TargetInfo:
MsvAvNbDomainName: HACKIN
MsvAvNbComputerName: EXCH01
MsvAvDnsDomainName: hackin.club
MsvAvDnsComputerName: EXCH01.hackin.club
MsvAvDnsTreeName: hackin.club
MsvAvTimestamp: Oct 17, 2019 01:13:09.417733
Negotiate Flags:
NTLMSSP_NEGOTIATE_UNICODE
NTLMSSP_REQUEST_TARGET
NTLMSSP_NEGOTIATE_ALWAYS_SIGN
NTLMSSP_TARGET_TYPE_DOMAIN
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
NTLMSSP_NEGOTIATE_TARGET_INFO
NTLMSSP_NEGOTIATE_VERSION
For more information, the NT LAN Manager (NTLM) Authentication Protocol Specification lives at https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/b38c36ed-2804-4868-a9ff-8dd3182128e4.
Prior Art
NTLM Challenge Decoder Burp plugin: https://github.com/PortSwigger/ntlm-challenge-decoder
nmap’s http-ntlm-info script: https://nmap.org/nsedoc/scripts/http-ntlm-info.html