A few years ago, I investigated NTLM and PHP and managed to write a simple PHP script that can retrieve the current windows username. However, it was only partly finished as it did not authenticate the user. Inspired by a recent comment, I’ve decided to revisit this problem and solve the authentication issue. For the better part of the afternoon, I wrestled with the NTLMv2 hash checking as detailed here.
It turns out that NT passwords are stored as a MD4 hash of the UTF16LE password string. So once we have this hash, we can begin verifying passwords. Obtaining this hash for a user is relatively easy with Samba, but seems to pose a challenge on Windows. In a later blog post I will detail how to integrate PHP authentication with Samba. For now, the code will assume you have already obtained a database of your users MD4 hashed passwords.
The crux of the NTLMv2 authentication involves using HMAC-MD5 on challenges and nonces using the MD4 hashed password as the key. The result is a 150 line source code that perform authentication on clients supporting NTLMv2. On the support NTLMv2, Internet Explorer supports it fine. Firefox on the other hand only has limited support for NTLMv2. In Firefox on Windows, if you have whitelisted your server with network.automatic-ntlm-auth.trusted-uris, Firefox will attempt to use Windows’ SSPI support (sys-ntlm) to perform single sign on. The SSPI module supports NTLMv2 fine. However, if you are using Firefox’s own cross platform NTLM module, you’re out of luck, it only supports the legacy NTLM and LM hashes. Perhaps it will support NTLMv2 in the future.
For Internet Explorer 8, intranet settings are now off by default, which means single sign on won’t automatically activate. To fix this, you should see a yellow bar prompting you whether to apply intranet settings.
The php ntlm authentication library is available here: ntlm.php.zip
To use it just put
include('ntlm.php');
function get_ntlm_user_hash($user) {
$userdb = array('loune'=>'test', 'you'=>'gg', 'a'=> 'a');
if (!isset($userdb[strtolower($user)]))
return false;
return mhash(MHASH_MD4, ntlm_utf8_to_utf16le($userdb[strtolower($user)]));
}
session_start();
$auth = ntlm_prompt("testwebsite", "testdomain", "mycomputer", "testdomain.local", "mycomputer.local", "get_ntlm_user_hash");
if ($auth['authenticated']) {
print "You are authenticated as $auth[username] from $auth[domain]/$auth[workstation]";
}
You need to provide your own implementation of the callback function get_ntlm_user_hash($user) which should return the MD4/Unicode hashed password of the requested $user. You can get that by doing mhash(MHASH_MD4, ntlm_utf8_to_utf16le("password")). You also need session_start() as the script needs to persist challenge information across http requests.
Next time, I will blog about the best way to integrate it with Samba on Linux.
Hi,
could you describe the parameters in the ntlm_prompt function?
What are “testwebsite”, “testdomain”, etc.?
Furthermore, what should put in the $userdb hash?
Last but not least, when do you plan to write your next article about how to integrate this script with Samba?
Many thanks.
Phillip
The first 5 arguments in ntlm_prompt, $targetname, $domain, $computer, $dnsdomain, $dnscomputer are just values which are injected in the NTLM messages sent to the browser. I think they are quite irrelevant in most cases as the browser seems to ignore them and pass on credentials regardless if they match the current domain. But just to be on the safe side, you should probably put your current windows domain as the values. If you’re not part of a windows domain, then just put any value for those.
The $userdb in the example is a hard coded associative array of username as the key, and the plain text password as the value. You should rewrite this as a SQL query to lookup the password in a database.
I’ll probably write up the samba integration post next week.
cheers
Hi Loune,
thanks for sharing this! I needed a few moments to realize the different response types which are possible. To force the NTLMv2 response I needed to set:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\LSA\LMCompatibilityLevel
to 3
Can you provide more information on what the arguements for ntlm_prompt need to be? I get the authentication window but it never works. I am sure it is because I am not sending the right arguements to the ntlm_prompt function.
Thanks
Steve, I doubt it is the arguments that are causing the issue as the the first few string arguments are pretty much ignored by the browser. The only important bit is the callback function that returns the password. The PHP script only implements NTLMv2 hash authentication so make sure you’re using that (Firefox only supports v1, unless it’s SSO which uses windows’ SSPI).
I have complete control over my environment so can make any changes required.
The long and short of it is that all i want to make is a page that says
“welcome $USER”
that displays the currently logged on windows user.
I have used all your code examples and none work as I would like.
what code would I need to merely display the name of the currently logged in user using Windows and IE or firefox?
I will be extremely grateful if you can tell me.
Thanks
Dean
I am using IIS but am more than happy to move to APACHE if that makes life easier.
@Dean – the guide was made for Apache. If you’re using IIS, it should be even easier. After enabling AD authentication for the website, you can just get the username in $_SERVER['AUTH_USER']
Thank you so much! i will give that a shot, if it works ill click some ads on the site
Dean
This works for me! It isn’t automated but because of your help I have managed to refine the work i was doing and hopefully i can automate it later!
Thanks so much.
Dean
Dean, can you share your code example please?
Also, I am trying to get this working with ISA server doing FBA and passing NTLM to the backend web server which is IIS. Any help appreciated