Last active
November 18, 2021 13:48
-
-
Save itc-lab/030844f88869eb3fbd3712363e766035 to your computer and use it in GitHub Desktop.
ldap_search from AD(Active Directory)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Copyright (c) 2021 ITC Lab. | |
// Released under the MIT license | |
// https://opensource.org/licenses/mit-license.php | |
$adServer = "ldap://ad.contoso.com"; | |
$ldap = ldap_connect($adServer); | |
$username = "Administrator"; | |
$password = "password"; | |
$ldaprdn = 'ad' . "\\" . $username; | |
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3); | |
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0); | |
$bind = ldap_bind($ldap, $ldaprdn, $password); | |
if ($bind) { | |
$filter = "objectclass=*"; | |
$rt = ldap_search($ldap, "dc=ad,dc=contoso,dc=com", $filter); | |
$results = array(); | |
$entry_id = @ldap_first_entry($ldap, $rt); | |
while ($entry_id != false) { | |
$result = array(); | |
$vals = @ldap_get_attributes($ldap, $entry_id); | |
$attrnum = intval($vals["count"]); | |
for ($n = 0; $n < $attrnum; $n ++) { | |
$attr = $vals[$n]; | |
$key = strtolower($attr); | |
$num = intval($vals[$attr]["count"]); | |
if ($num != 0) { | |
$result[$key] = array(); | |
for ($no = 0; $no < $num; $no ++) { | |
$value = $vals[$attr][$no]; | |
$result[$key][$no] = $value; | |
} | |
if (isset($result[$key]) && count($result[$key]) == 1) { | |
$result[$key] = $result[$key][0]; | |
} | |
} | |
} | |
$result["0dn"] = @ldap_get_dn($ldap, $entry_id); | |
Bin2String($result); | |
$results[] = $result; | |
$entry_id = @ldap_next_entry($ldap, $entry_id); | |
} | |
@ldap_close($ldap); | |
foreach ($results as $result) { | |
ksort($result); | |
foreach ($result as $key => $value) { | |
$attr = strcmp($key, "0dn") !== 0 ? $key : "dn"; | |
if (is_array($value)) { | |
echo $attr.": ".implode("; ", $value).";\n"; | |
} else { | |
echo $attr.": ".$value.";\n"; | |
} | |
} | |
echo "\n"; | |
} | |
} else { | |
$msg = "Invalid bind dn / password"; | |
echo $msg; | |
} | |
function Bin2String(&$result) | |
{ | |
$conv_func_attrs["SIDtoString"] = array("objectsid"); | |
$conv_func_attrs["GUIDtoString"] = array("objectguid", "msdfsr-replicationgroupguid", "msdfsr-contentsetguid"); | |
$conv_func_attrs["bin2hex"] = array("auditingpolicy", "dsasignature", "dnsrecord", "ipsecdata", "samdomainupdates", "msds-generationid", "logonhours"); | |
$conv_func_attrs["userParameters"] = array("userparameters"); | |
foreach ($conv_func_attrs as $func => $attrs) { | |
foreach ($attrs as $attr) { | |
if (isset($result[$attr]) && !empty($result[$attr])) { | |
$result[$attr] = @$func($result[$attr]); | |
} | |
} | |
} | |
} | |
function SIDtoString($value) | |
{ | |
$sid = @unpack('C1rev/C1count/x2/N1id', $value); | |
$subAuthorities = []; | |
if (!isset($sid['id']) || !isset($sid['rev'])) { | |
throw new \UnexpectedValueException( | |
'The revision level or identifier authority was not found when decoding the SID.' | |
); | |
} | |
$revisionLevel = $sid['rev']; | |
$identifierAuthority = $sid['id']; | |
$subs = isset($sid['count']) ? $sid['count'] : 0; | |
for ($i = 0; $i < $subs; $i++) { | |
$subAuthorities[] = unpack('V1sub', hex2bin(substr(bin2hex($value), 16 + ($i * 8), 8)))['sub']; | |
} | |
return 'S-'.$revisionLevel.'-'.$identifierAuthority.implode( | |
preg_filter('/^/', '-', $subAuthorities) | |
); | |
} | |
function GUIDtoString($ADguid) | |
{ | |
$guidinhex = str_split(bin2hex($ADguid), 2); | |
$guid = ""; | |
$first = array_reverse(array_slice($guidinhex, 0, 4)); | |
foreach ($first as $value) { | |
$guid .= $value; | |
} | |
$guid .= "-"; | |
$second = array_reverse(array_slice($guidinhex, 4, 2, true), true); | |
foreach ($second as $value) { | |
$guid .= $value; | |
} | |
$guid .= "-"; | |
$third = array_reverse(array_slice($guidinhex, 6, 2, true), true); | |
foreach ($third as $value) { | |
$guid .= $value; | |
} | |
$guid .= "-"; | |
$fourth = array_slice($guidinhex, 8, 2, true); | |
foreach ($fourth as $value) { | |
$guid .= $value; | |
} | |
$guid .= "-"; | |
$last = array_slice($guidinhex, 10, 16, true); | |
foreach ($last as $value) { | |
$guid .= $value; | |
} | |
return $guid; | |
} | |
function userParameters($userParameters) | |
{ | |
// userParameters data structure described at: http://msdn.microsoft.com/en-us/library/ff635189.aspx | |
// TSProperty data structure described at: http://msdn.microsoft.com/en-us/library/ff635169.aspx | |
// Input: userParameters blob returned from ldap_search | |
// Output: associative array of user parameters | |
$parameters = array(); | |
$userParameters = bin2hex($userParameters); | |
$userParameters = substr($userParameters, 96); | |
$Signature = chr(hexdec(substr($userParameters, 0, 2))); | |
$userParameters = substr($userParameters, 2); | |
if ($Signature != 'P') { | |
return false; | |
} | |
$TSPropertyCount = hexdec(substr($userParameters, 0, 2)); | |
$userParameters = substr($userParameters, 2); | |
for ($i = 0; $i < $TSPropertyCount; $i++) { | |
$NameLength = hexdec(substr($userParameters, 0, 2)); | |
$userParameters = substr($userParameters, 2); | |
$ValueLength = hexdec(substr($userParameters, 0, 2)) * 3; | |
if ($ValueLength == 0xc2 * 3) { | |
$userParameters = substr($userParameters, 2); | |
$ValueLength = hexdec(substr($userParameters, 0, 2)) * 3; | |
} | |
$userParameters = substr($userParameters, 2); | |
$Type = substr($userParameters, 0, 2); | |
$userParameters = substr($userParameters, 2); | |
$PropName = substr($userParameters, 0, $NameLength); | |
$PropName = hex2str($PropName); | |
$userParameters = substr($userParameters, $NameLength); | |
$PropValue = substr($userParameters, 0, $ValueLength); | |
$userParameters = substr($userParameters, $ValueLength); | |
switch ($PropName) { | |
case 'CtxWFHomeDir': | |
case 'CtxWFHomeDirW': | |
case 'CtxWFHomeDirDrive': | |
case 'CtxInitialProgram': | |
case 'CtxInitialProgramW': | |
case 'CtxWFProfilePath': | |
case 'CtxWFProfilePathW': | |
case 'CtxWorkDirectory': | |
case 'CtxWorkDirectoryW': | |
case 'CtxCallbackNumber': | |
$parameters[$PropName] = decode_PropValue($PropValue, true); | |
break; | |
case 'CtxCfgFlags1': | |
$parameters[$PropName] = parse_CtxCfgFlags1(decode_PropValue($PropValue)); | |
break; | |
case 'CtxShadow': | |
$parameters[$PropName] = parse_CtxShadow(decode_PropValue($PropValue)); | |
break; | |
default: | |
$parameters[$PropName] = decode_PropValue($PropValue); | |
} | |
} | |
//return $parameters; | |
array_walk_recursive($parameters, 'remove_null_string'); | |
return json_encode($parameters, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); | |
} | |
function remove_null_string(&$item, $key) | |
{ | |
$item = str_replace("\0", "", $item); | |
} | |
function hex2str($hex) | |
{ | |
$str = ''; | |
for ($i = 0; $i < strlen($hex); $i += 2) { | |
$str .= chr(hexdec(substr($hex, $i, 2))); | |
} | |
return $str; | |
} | |
function decode_PropValue($hex, $ascii=false) | |
{ | |
// Encoding described at: http://daduke.org/linux/userparameters.html | |
// for each character you want to encode, do: | |
// - split the character's byte into nibbles xxxx and yyyy | |
// - have a look at xxxx. If it's <= 9, control x (XXXXXX) equals 001011, otherwise it's 011010 | |
// - have a look at yyyy. Here the bit patterns for control y (YYYYYY) are 001110 (yyyy <= 9), 011010 otherwise | |
// - if xxxx > 9: xxxx -= 9 | |
// - if yyyy > 9: yyyy -= 9 | |
// - take the prefix (1110), control y, yyyy, control x and xxxx and glue them all together to yield a 24 bit string | |
// - convert this bit stream to three bytes: 1110 YYYY YYyy yyXX XXXX xxxx | |
$decode_PropValue = ''; | |
$blobs = str_split($hex, 6); | |
foreach ($blobs as $blob) { | |
$bin = decbin(hexdec($blob)); | |
$control_y = substr($bin, 4, 6); | |
$nibble_y = substr($bin, 10, 4); | |
$control_x = substr($bin, 14, 6); | |
$nibble_x = substr($bin, 20, 4); | |
$byte = nibble_control($nibble_x, $control_x).nibble_control($nibble_y, $control_y); | |
if ($ascii) { | |
$decode_PropValue .= chr(bindec($byte)); | |
} else { | |
$decode_PropValue = str_pad(dechex(bindec($byte)), 2, '0', STR_PAD_LEFT).$decode_PropValue; | |
} | |
} | |
return $decode_PropValue; | |
} | |
function nibble_control($nibble, $control) | |
{ | |
if ($control == '011010') { | |
$dec = bindec($nibble); | |
$dec += 9; | |
return str_pad(decbin($dec), 4, '0', STR_PAD_LEFT); | |
} | |
return $nibble; | |
} | |
function parse_CtxCfgFlags1($CtxCfgFlags1) | |
{ | |
// Flag bit mask values from: http://msdn.microsoft.com/en-us/library/ff635169.aspx | |
$parse_CtxCfgFlags1 = array(); | |
$CtxCfgFlags1 = hexdec($CtxCfgFlags1); | |
$flags = array( | |
'F1MSK_INHERITINITIALPROGRAM' => 268435456, | |
'F1MSK_INHERITCALLBACK' => 134217728, | |
'F1MSK_INHERITCALLBACKNUMBER' => 67108864, | |
'F1MSK_INHERITSHADOW' => 33554432, | |
'F1MSK_INHERITMAXSESSIONTIME' => 16777216, | |
'F1MSK_INHERITMAXDISCONNECTIONTIME' => 8388608, | |
'F1MSK_INHERITMAXIDLETIME' => 4194304, | |
'F1MSK_INHERITAUTOCLIENT' => 2097152, | |
'F1MSK_INHERITSECURITY' => 1048576, | |
'F1MSK_PROMPTFORPASSWORD' => 524288, | |
'F1MSK_RESETBROKEN' => 262144, | |
'F1MSK_RECONNECTSAME' => 131072, | |
'F1MSK_LOGONDISABLED' => 65536, | |
'F1MSK_AUTOCLIENTDRIVES' => 32768, | |
'F1MSK_AUTOCLIENTLPTS' => 16384, | |
'F1MSK_FORCECLIENTLPTDEF' => 8192, | |
'F1MSK_DISABLEENCRYPTION' => 4096, | |
'F1MSK_HOMEDIRECTORYMAPROOT' => 2048, | |
'F1MSK_USEDEFAULTGINA' => 1024, | |
'F1MSK_DISABLECPM' => 512, | |
'F1MSK_DISABLECDM' => 256, | |
'F1MSK_DISABLECCM' => 128, | |
'F1MSK_DISABLELPT' => 64, | |
'F1MSK_DISABLECLIP' => 32, | |
'F1MSK_DISABLEEXE' => 16, | |
'F1MSK_WALLPAPERDISABLED' => 8, | |
'F1MSK_DISABLECAM' => 4 | |
); | |
foreach ($flags as $flag => $bit) { | |
if ($CtxCfgFlags1 & $bit) { | |
$parse_CtxCfgFlags1[] = $flag; | |
} | |
} | |
return($parse_CtxCfgFlags1); | |
} | |
function parse_CtxShadow($CtxShadow) | |
{ | |
// Flag values from: http://msdn.microsoft.com/en-us/library/ff635169.aspx | |
$CtxShadow = hexdec($CtxShadow); | |
$flags = array('Disable','EnableInputNotify','EnableInputNoNotify','EnableNoInputNotify','EnableNoInputNoNotify'); | |
if ($CtxShadow < 0 || $CtxShadow > 4) { | |
return false; | |
} | |
return $flags[$CtxShadow]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment