SMTP NTLM authentication

This commit is contained in:
oheil 2023-09-05 12:44:50 +02:00
parent df19facecd
commit 88da1d54b6
2 changed files with 206 additions and 2 deletions

View file

@ -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="";

View file

@ -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++) {