44 if (!function_exists(
'mcrypt_module_open')) {
45 throw new LogicException(
'The mcrypt functions need to be enabled to use the NTLM authenticator.');
48 if (!function_exists(
'openssl_random_pseudo_bytes')) {
49 throw new LogicException(
'The OpenSSL extension must be enabled to use the NTLM authenticator.');
52 if (!function_exists(
'bcmul')) {
53 throw new LogicException(
'The BCMatch functions must be enabled to use the NTLM authenticator.');
62 $timestamp = func_num_args() > 3 ? func_get_arg(3) : $this->
getCorrectTimestamp(bcmul(microtime(
true),
'1000'));
63 $client = func_num_args() > 4 ? func_get_arg(4) : $this->
getRandomBytes(8);
76 protected function si2bin($si, $bits = 32)
79 if ($si >= -pow(2, $bits - 1) && ($si <= pow(2, $bits - 1))) {
82 $bin = base_convert($si, 10, 2);
84 $bin_length = strlen($bin);
85 if ($bin_length < $bits) {
86 $bin = str_repeat(
'0', $bits - $bin_length).$bin;
90 $si = -$si - pow(2, $bits);
91 $bin = base_convert($si, 10, 2);
92 $bin_length = strlen($bin);
93 if ($bin_length > $bits) {
94 $bin = str_repeat(
'1', $bits - $bin_length).$bin;
126 $length = floor(hexdec(substr($responseHex, 28, 4)) / 256) * 2;
127 $offset = floor(hexdec(substr($responseHex, 32, 4)) / 256) * 2;
128 $challenge = $this->
hex2bin(substr($responseHex, 48, 16));
129 $context = $this->
hex2bin(substr($responseHex, 64, 16));
130 $targetInfoH = $this->
hex2bin(substr($responseHex, 80, 16));
131 $targetName = $this->
hex2bin(substr($responseHex, $offset, $length));
132 $offset = floor(hexdec(substr($responseHex, 88, 4)) / 256) * 2;
133 $targetInfoBlock = substr($responseHex, $offset);
134 list($domainName, $serverName, $DNSDomainName, $DNSServerName, $terminatorByte) = $this->
readSubBlock($targetInfoBlock);
145 $this->
hex2bin($targetInfoBlock),
160 $block = substr($block, 0, -8);
162 $length = strlen($block);
165 while ($offset < $length) {
166 $blockLength = hexdec(substr(substr($block, $offset, 8), -4)) / 256;
168 $data[] = $this->
hex2bin(substr($block, $offset, $blockLength * 2));
169 $offset += $blockLength * 2;
172 if (count($data) == 3) {
208 $lmResponse = $this->
createLMv2Password($password, $username, $domain, $challenge, $client);
210 $ntlmResponse = $this->
createNTLMv2Hash($password, $username, $domain, $challenge, $blob, $timestamp, $client);
213 $message = $this->
createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse);
215 return $agent->
executeCommand(sprintf(
"%s\r\n", base64_encode($message)), array(235));
226 .$this->createByte(
'01')
227 .$this->createByte(
'0702');
241 protected function createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse)
255 .$this->createByte(
'03')
261 .$this->createByte(
'000000009a', 8)
262 .$this->createByte(
'01020000')
263 .$this->convertTo16bit($domain)
264 .$this->convertTo16bit($username)
265 .$this->convertTo16bit($workstation)
277 protected function createBlob($timestamp, $client, $targetInfo)
280 .$this->createByte(
'00')
283 .$this->createByte(
'00')
285 .$this->createByte(
'00');
299 if (strpos($name,
'\\') !==
false) {
300 return explode(
'\\', $name);
303 list($user, $domain) = explode(
'@', $name);
305 return array($domain, $user);
319 $password = $this->
createByte(strtoupper($password), 14,
false);
320 list($key1, $key2) = str_split($password, 7);
328 list($key1, $key2, $key3) = str_split($constantDecrypt, 7);
334 return $this->
desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3);
349 list($key1, $key2, $key3) = str_split($ntlmHash, 7);
355 return $this->
desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3);
370 $time = number_format($time, 0,
'.',
'');
371 $time = bcadd($time,
'11644473600000');
372 $time = bcmul($time, 10000);
374 $binary = $this->
si2bin($time, 64);
376 for ($i = 0; $i < 8; $i++) {
377 $timestamp .= chr(bindec(substr($binary, -(($i + 1) * 8), 8)));
398 if (strlen($password) <= 15) {
402 $lmPass = bin2hex($this->
md5Encrypt($ntml2Hash, $challenge.$client).$client);
423 protected function createNTLMv2Hash($password, $username, $domain, $challenge, $targetInfo, $timestamp, $client)
429 $blob = $this->
createBlob($timestamp, $client, $targetInfo);
431 $ntlmv2Response = $this->
md5Encrypt($ntml2Hash, $challenge.$blob);
433 return $ntlmv2Response.$blob;
438 $material = array(bin2hex($key[0]));
440 for ($i = 1; $i < $len; $i++) {
441 list($high, $low) = str_split(bin2hex($key[$i]));
442 $v = $this->
castToByte(ord($key[$i - 1]) << (7 + 1 - $i) | $this->
uRShift(hexdec(dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xf)), $i));
443 $material[] = str_pad(substr(dechex($v), -2), 2,
'0', STR_PAD_LEFT);
445 $material[] = str_pad(substr(dechex($this->
castToByte(ord($key[6]) << 1)), -2), 2,
'0');
448 foreach ($material as $k => $v) {
452 ^ $this->
uRShift($b, 1)) & 0x01) == 0;
454 list($high, $low) = str_split($v);
456 $material[$k] = dechex(hexdec($high) | 0x0).dechex(hexdec($low) | 0x1);
458 $material[$k] = dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xe);
462 return $this->
hex2bin(implode(
'', $material));
477 $length = strlen(bin2hex($value));
478 $length = $is16 ? $length / 2 : $length;
479 $length = $this->
createByte(str_pad(dechex($length), 2,
'0', STR_PAD_LEFT), 2);
481 return $length.$length.$this->createByte(dechex($offset), 4);
493 $length = floor(hexdec(substr($value, 0, 4)) / 256) * 2;
494 $offset = floor(hexdec(substr($value, 8, 4)) / 256) * 2;
496 return array($length, $offset);
508 return (($v + 128) % 256) - 128;
526 return ($a >> $b) & ~(1 << (8 * PHP_INT_SIZE - 1) >> ($b - 1));
538 protected function createByte($input, $bytes = 4, $isHex =
true)
541 $byte = $this->
hex2bin(str_pad($input, $bytes * 2,
'00'));
543 $byte = str_pad($input, $bytes,
"\x00");
558 $bytes = openssl_random_pseudo_bytes($length, $strong);
560 if (
false !== $bytes &&
true === $strong) {
564 throw new RuntimeException(
'OpenSSL did not produce a secure random number.');
578 $cipher = mcrypt_module_open(MCRYPT_DES,
'',
'ecb',
'');
579 mcrypt_generic_init($cipher, $key, mcrypt_create_iv(mcrypt_enc_get_iv_size($cipher), MCRYPT_DEV_RANDOM));
581 return mcrypt_generic($cipher, $value);
595 if (strlen($key) > $blocksize) {
596 $key = pack(
'H*', md5($key));
599 $key = str_pad($key, $blocksize,
"\0");
600 $ipadk = $key ^ str_repeat(
"\x36", $blocksize);
601 $opadk = $key ^ str_repeat(
"\x5c", $blocksize);
603 return pack(
'H*', md5($opadk.pack(
'H*', md5($ipadk.$msg))));
619 return function_exists(
'hash') ? $this->
hex2bin(hash(
'md4', $input)) : mhash(MHASH_MD4, $input);
631 return iconv(
'UTF-8',
'UTF-16LE', $input);
643 if (function_exists(
'hex2bin')) {
646 return pack(
'H*', $hex);
655 $message = bin2hex($message);
656 $messageId = substr($message, 16, 8);
657 echo substr($message, 0, 16).
" NTLMSSP Signature<br />\n";
658 echo $messageId.
" Type Indicator<br />\n";
660 if ($messageId ==
'02000000') {
664 'Target Information Security Buffer',
666 'NetBIOS Domain Name',
667 'NetBIOS Server Name',
671 'Target Information Terminator',
676 foreach ($map as $key => $value) {
677 echo bin2hex($data[$key]).
' - '.$data[$key].
' ||| '.$value.
"<br />\n";
679 }
elseif ($messageId ==
'03000000') {
681 $data[$i++] = substr($message, 24, 16);
684 $data[$i++] = substr($message, 40, 16);
687 $data[$i++] = substr($message, 56, 16);
690 $data[$i++] = substr($message, 72, 16);
693 $data[$i++] = substr($message, 88, 16);
696 $data[$i++] = substr($message, 104, 16);
697 $data[$i++] = substr($message, 120, 8);
698 $data[$i++] = substr($message, $targetOffset, $targetLength);
699 $data[$i++] = substr($message, $userOffset, $userLength);
700 $data[$i++] = substr($message, $workOffset, $workLength);
701 $data[$i++] = substr($message, $lmOffset, $lmLength);
702 $data[$i] = substr($message, $ntmlOffset, $ntmlLength);
705 'LM Response Security Buffer',
706 'NTLM Response Security Buffer',
707 'Target Name Security Buffer',
708 'User Name Security Buffer',
709 'Workstation Name Security Buffer',
710 'Session Key Security Buffer',
714 'Workstation Name Data',
716 'NTLM Response Data',
719 foreach ($map as $key => $value) {
720 echo $data[$key].
' - '.$this->
hex2bin($data[$key]).
' ||| '.$value.
"<br />\n";