SMTP NTLM authentication
This commit is contained in:
parent
df19facecd
commit
88da1d54b6
2 changed files with 206 additions and 2 deletions
|
@ -14,7 +14,7 @@
|
||||||
*
|
*
|
||||||
* @package NOCC
|
* @package NOCC
|
||||||
* @license http://www.gnu.org/licenses/ GNU General Public License
|
* @license http://www.gnu.org/licenses/ GNU General Public License
|
||||||
* @version SVN: $Id: class_smtp.php 3093 2023-07-21 17:05:24Z oheil $
|
* @version SVN: $Id: class_smtp.php 3097 2023-09-05 10:44:26Z oheil $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once 'exception.php';
|
require_once 'exception.php';
|
||||||
|
@ -193,6 +193,39 @@ class smtp {
|
||||||
}
|
}
|
||||||
return (true);
|
return (true);
|
||||||
break;
|
break;
|
||||||
|
case 'NTLM':
|
||||||
|
fputs($smtp, "helo " . $_SERVER['SERVER_NAME'] . "\r\n");
|
||||||
|
$response="";
|
||||||
|
if( $this->check_response("STARTTLS HELO",$smtp,$response) ) {
|
||||||
|
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
|
||||||
|
}
|
||||||
|
fputs($smtp, "AUTH NTLM\r\n");
|
||||||
|
$response="";
|
||||||
|
if( $this->check_response("STARTTLS AUTH NTLM",$smtp,$response) ) {
|
||||||
|
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
|
||||||
|
}
|
||||||
|
|
||||||
|
$message=NTLM_type1message();
|
||||||
|
fputs($smtp, base64_encode($message)."\r\n");
|
||||||
|
$response="";
|
||||||
|
if( $this->check_response("NTLMSSP",$smtp,$response) ) {
|
||||||
|
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
|
||||||
|
}
|
||||||
|
$matches=array();
|
||||||
|
if( preg_match("/^NTLMSSP:334\s+(.*)\s+|$/",$response,$matches) ) {
|
||||||
|
$response=$matches[1];
|
||||||
|
}
|
||||||
|
$response=base64_decode($response);
|
||||||
|
|
||||||
|
$message=NTLM_type3message($response,"","",$user, $password);
|
||||||
|
fputs($smtp, base64_encode($message)."\r\n");
|
||||||
|
$response="";
|
||||||
|
if( $this->check_response("NTLMSSP",$smtp,$response) ) {
|
||||||
|
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
break;
|
||||||
case 'TLS':
|
case 'TLS':
|
||||||
fputs($smtp, "STARTTLS\r\n");
|
fputs($smtp, "STARTTLS\r\n");
|
||||||
$response="";
|
$response="";
|
||||||
|
|
|
@ -14,9 +14,180 @@
|
||||||
* @package NOCC
|
* @package NOCC
|
||||||
* @subpackage Utilities
|
* @subpackage Utilities
|
||||||
* @license http://www.gnu.org/licenses/ GNU General Public License
|
* @license http://www.gnu.org/licenses/ GNU General Public License
|
||||||
* @version SVN: $Id: crypt.php 3016 2022-08-25 11:00:42Z oheil $
|
* @version SVN: $Id: crypt.php 3097 2023-09-05 10:44:26Z oheil $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns NTLM Type 3 message
|
||||||
|
* @param string $type2message the Type 2 message from the server as a binary string
|
||||||
|
* @param string $realm the clients realm/domain (not empty)
|
||||||
|
* @param string $workstation the clients host name (not empty)
|
||||||
|
* @param string $user the SMTP user name
|
||||||
|
* @param string $password the users password
|
||||||
|
* @return string $message the binary string composed NTLM Type 3 message to send to the server
|
||||||
|
*/
|
||||||
|
function NTLM_type3message($type2message="", $realm="", $workstation="", $user="", $password="") {
|
||||||
|
// https://davenport.sourceforge.net/ntlm.html
|
||||||
|
if( strlen($realm)==0 ) {
|
||||||
|
$realm="unknown";
|
||||||
|
}
|
||||||
|
if( strlen($workstation)==0 ) {
|
||||||
|
$workstation="unknown";
|
||||||
|
}
|
||||||
|
if( strlen($type2message)==0 ) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
$tn_sbuffer=unpack("vlength/vsize/Voffset",substr($type2message,12,8));
|
||||||
|
$flags=substr($type2message,20,4);
|
||||||
|
|
||||||
|
$domain=$realm;
|
||||||
|
if( $flags && 0x0100 ) { // Flag Target Type Domain (0x00010000) in little endian: 0x00000100
|
||||||
|
$tn_data=substr($type2message,$tn_sbuffer['offset'],$tn_sbuffer['size']);
|
||||||
|
$domain=mb_convert_encoding($tn_data,"ASCII","UCS-2LE");
|
||||||
|
}
|
||||||
|
|
||||||
|
$challenge=substr($type2message,24,8);
|
||||||
|
|
||||||
|
$pw_uni=mb_convert_encoding($password,"UCS-2LE");
|
||||||
|
|
||||||
|
$message="";
|
||||||
|
|
||||||
|
if( extension_loaded("openssl") && function_exists("openssl_encrypt")
|
||||||
|
&& extension_loaded("hash") && function_exists("hash")
|
||||||
|
&& in_array("md4",hash_algos())
|
||||||
|
&& count( preg_grep("/^des-ecb$/i",openssl_get_cipher_methods(true)) ) > 0
|
||||||
|
) {
|
||||||
|
$md4=hash("md4", $pw_uni, false);
|
||||||
|
$md4=hex2bin($md4);
|
||||||
|
$pad=$md4.str_repeat(chr(0),21-strlen($md4));
|
||||||
|
|
||||||
|
$iv_size=openssl_cipher_iv_length("des-ecb");
|
||||||
|
$iv="";
|
||||||
|
for($i=0;$i<21;$i+=7) {
|
||||||
|
$packed="";
|
||||||
|
for($p=$i;$p<$i+7;$p++) {
|
||||||
|
$packed.=str_pad(decbin(ord(substr($pad,$p,1))),8,"0",STR_PAD_LEFT);
|
||||||
|
}
|
||||||
|
$key="";
|
||||||
|
for($p=0;$p<strlen($packed);$p+=7) {
|
||||||
|
$s=substr($packed,$p,7);
|
||||||
|
$b=$s.((substr_count($s,"1") % 2) ? "0" : "1");
|
||||||
|
$key.=chr(bindec($b));
|
||||||
|
}
|
||||||
|
$message.=openssl_encrypt($challenge,"des-ecb",$key,$options=OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING,$iv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( extension_loaded("mcrypt") && function_exists("mcrypt_encrypt")
|
||||||
|
&& extension_loaded("hash") && function_exists("hash")
|
||||||
|
&& in_array("md4",hash_algos())
|
||||||
|
) {
|
||||||
|
$md4=hash("md4", $pw_uni, false);
|
||||||
|
$md4=hex2bin($md4);
|
||||||
|
$pad=$md4.str_repeat(chr(0),21-strlen($md4));
|
||||||
|
|
||||||
|
$iv_size=mcrypt_get_iv_size(MCRYPT_DES,MCRYPT_MODE_ECB);
|
||||||
|
$iv=mcrypt_create_iv($iv_size,MCRYPT_RAND);
|
||||||
|
for($i=0;$i<21;$i+=7) {
|
||||||
|
$packed="";
|
||||||
|
for($p=$i;$p<$i+7;$p++) {
|
||||||
|
$packed.=str_pad(decbin(ord(substr($pad,$p,1))),8,"0",STR_PAD_LEFT);
|
||||||
|
}
|
||||||
|
$key="";
|
||||||
|
for($p=0;$p<strlen($packed);$p+=7) {
|
||||||
|
$s=substr($packed,$p,7);
|
||||||
|
$b=$s.((substr_count($s,"1") % 2) ? "0" : "1");
|
||||||
|
$key.=chr(bindec($b));
|
||||||
|
}
|
||||||
|
$message.=mcrypt_encrypt(MCRYPT_DES,$key,$challenge,MCRYPT_MODE_ECB,$iv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
$r_unicode=mb_convert_encoding($domain,"UCS-2LE");
|
||||||
|
$r_length=strlen($r_unicode);
|
||||||
|
$r_offset=64;
|
||||||
|
$u_unicode=mb_convert_encoding($user,"UCS-2LE");
|
||||||
|
$u_length=strlen($u_unicode);
|
||||||
|
$u_offset=$r_offset+$r_length;
|
||||||
|
$ws_unicode=mb_convert_encoding($workstation,"UCS-2LE");
|
||||||
|
$ws_length=strlen($ws_unicode);
|
||||||
|
$ws_offset=$u_offset+$u_length;
|
||||||
|
$lm=mb_convert_encoding("","UCS-2LE");
|
||||||
|
$lm_length=strlen($lm);
|
||||||
|
$lm_offset=$ws_offset+$ws_length;
|
||||||
|
$ntlm=$message;
|
||||||
|
$ntlm_length=strlen($ntlm);
|
||||||
|
$ntlm_offset=$lm_offset+$lm_length;
|
||||||
|
$session="";
|
||||||
|
$session_length=strlen($session);
|
||||||
|
$session_offset=$ntlm_offset+$ntlm_length;
|
||||||
|
|
||||||
|
$message="NTLMSSP\0".
|
||||||
|
"\x03\x00\x00\x00".
|
||||||
|
pack("v",$lm_length).
|
||||||
|
pack("v",$lm_length).
|
||||||
|
pack("V",$lm_offset).
|
||||||
|
pack("v",$ntlm_length).
|
||||||
|
pack("v",$ntlm_length).
|
||||||
|
pack("V",$ntlm_offset).
|
||||||
|
pack("v",$r_length).
|
||||||
|
pack("v",$r_length).
|
||||||
|
pack("V",$r_offset).
|
||||||
|
pack("v",$u_length).
|
||||||
|
pack("v",$u_length).
|
||||||
|
pack("V",$u_offset).
|
||||||
|
pack("v",$ws_length).
|
||||||
|
pack("v",$ws_length).
|
||||||
|
pack("V",$ws_offset).
|
||||||
|
pack("v",$session_length).
|
||||||
|
pack("v",$session_length).
|
||||||
|
pack("V",$session_offset).
|
||||||
|
"\x01\x02\x00\x00".
|
||||||
|
$r_unicode.
|
||||||
|
$u_unicode.
|
||||||
|
$ws_unicode.
|
||||||
|
$lm.
|
||||||
|
$ntlm;
|
||||||
|
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns NTLM Type 1 message
|
||||||
|
* @param string $realm the clients realm/domain (not empty)
|
||||||
|
* @param string $workstation the clients host name (not empty)
|
||||||
|
* @return string $message the binary string composed NTLM Type 1 message to send to the server
|
||||||
|
*/
|
||||||
|
function NTLM_type1message($realm="", $workstation="") {
|
||||||
|
// https://davenport.sourceforge.net/ntlm.html
|
||||||
|
if( strlen($realm)==0 ) {
|
||||||
|
$realm="unknown";
|
||||||
|
}
|
||||||
|
if( strlen($workstation)==0 ) {
|
||||||
|
$workstation="unknown";
|
||||||
|
}
|
||||||
|
$r_length=strlen($realm);
|
||||||
|
$ws_length=strlen($workstation);
|
||||||
|
$ws_offset=32;
|
||||||
|
$r_offset=$ws_offset+$ws_length;
|
||||||
|
$message="NTLMSSP\0".
|
||||||
|
"\x01\x00\x00\x00".
|
||||||
|
"\x07\x32\x00\x00".
|
||||||
|
pack("v",$r_length).
|
||||||
|
pack("v",$r_length).
|
||||||
|
pack("V",$r_offset).
|
||||||
|
pack("v",$ws_length).
|
||||||
|
pack("v",$ws_length).
|
||||||
|
pack("V",$ws_offset).
|
||||||
|
$workstation.
|
||||||
|
$realm;
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
|
||||||
function encrXOR($string, $key) {
|
function encrXOR($string, $key) {
|
||||||
for ($i=0; $i<strlen($string); $i++) {
|
for ($i=0; $i<strlen($string); $i++) {
|
||||||
for ($j=0; $j<strlen($key); $j++) {
|
for ($j=0; $j<strlen($key); $j++) {
|
||||||
|
|
Loading…
Reference in a new issue