Skip to content

Commit 2fcae31

Browse files
committed
Fixes #7, Fixes #8: Added iteration over naming contexts + search_base option in powershell version
1 parent 5eba453 commit 2fcae31

File tree

2 files changed

+110
-41
lines changed

2 files changed

+110
-41
lines changed

powershell/psLDAPmonitor.ps1

+107-38
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
# File name : psLDAPmonitor.ps1
22
# Author : Podalirius (@podalirius_)
3-
# Date created : 17 Oct 2021
3+
# Date created : 3 Jan 2022
44

55
Param (
66
[parameter(Mandatory=$true)][string]$dcip = $null,
77
[parameter(Mandatory=$false)][string]$Username = $null,
88
[parameter(Mandatory=$false)][string]$Password = $null,
99
[parameter(Mandatory=$false)][string]$LogFile = $null,
1010
[parameter(Mandatory=$false)][int]$PageSize = 5000,
11+
[parameter(Mandatory=$false)][string]$SearchBase = $null,
1112
[parameter(Mandatory=$false)][int]$Delay = 1,
1213
[parameter(Mandatory=$false)][switch]$LDAPS,
1314
[parameter(Mandatory=$false)][switch]$Randomize,
@@ -17,7 +18,7 @@ Param (
1718

1819
If ($Help) {
1920
Write-Host "[+]======================================================"
20-
Write-Host "[+] Powershell LDAP live monitor v1.1 @podalirius_ "
21+
Write-Host "[+] Powershell LDAP live monitor v1.3 @podalirius_ "
2122
Write-Host "[+]======================================================"
2223
Write-Host ""
2324

@@ -29,6 +30,7 @@ If ($Help) {
2930
Write-Host " -Username : User to authenticate as."
3031
Write-Host " -Password : Password for authentication."
3132
Write-Host " -PageSize : Sets the LDAP page size to use in queries (default: 5000)."
33+
Write-Host " -SearchBase : Sets the LDAP search base."
3234
Write-Host " -LDAPS : Use LDAPS instead of LDAP."
3335
Write-Host " -LogFile : Log file to save output to."
3436
Write-Host " -Delay : Delay between two queries in seconds (default: 1)."
@@ -71,13 +73,96 @@ Function Write-Logger {
7173
}
7274
}
7375

76+
Function Init-LdapConnection {
77+
[CmdletBinding()]
78+
[OutputType([Nullable])]
79+
Param
80+
(
81+
[Parameter(Mandatory=$true)] $connectionString,
82+
[Parameter(Mandatory=$false)] $SearchBase,
83+
[Parameter(Mandatory=$false)] $Username,
84+
[Parameter(Mandatory=$false)] $Password,
85+
[Parameter(Mandatory=$false)] $PageSize
86+
)
87+
Begin
88+
{
89+
$ldapSearcher = New-Object System.DirectoryServices.DirectorySearcher
90+
if ($Username) {
91+
if ($SearchBase.Length -ne 0) {
92+
# Connect to Domain with credentials
93+
$ldapSearcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry(("{0}/{1}" -f $connectionString, $SearchBase), $Username, $Password)
94+
} else {
95+
# Connect to Domain with current session
96+
$ldapSearcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry("$connectionString", $Username, $Password)
97+
}
98+
} else {
99+
if ($SearchBase.Length -ne 0) {
100+
# Connect to Domain with credentials
101+
$ldapSearcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry(("{0}/{1}" -f $connectionString, $SearchBase))
102+
} else {
103+
# Connect to Domain with current session
104+
$ldapSearcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry("$connectionString")
105+
}
106+
}
107+
$ldapSearcher.SearchScope = "Subtree"
108+
if ($PageSize) {
109+
$ldapSearcher.PageSize = $PageSize
110+
} else {
111+
Write-Verbose ("Setting PageSize to $PageSize");
112+
$ldapSearcher.PageSize = 5000
113+
}
114+
return $ldapSearcher;
115+
}
116+
}
117+
118+
119+
Function Query-AllNamingContextsOrSearchBase {
120+
[CmdletBinding()]
121+
[OutputType([Nullable])]
122+
Param
123+
(
124+
[Parameter(Mandatory=$true)] $namingContexts,
125+
[Parameter(Mandatory=$true)] $connectionString,
126+
[Parameter(Mandatory=$false)] $SearchBase,
127+
[Parameter(Mandatory=$false)] $Username,
128+
[Parameter(Mandatory=$false)] $Password,
129+
[Parameter(Mandatory=$false)] $PageSize
130+
)
131+
Begin
132+
{
133+
if ($SearchBase.Length -ne 0) {
134+
Write-Verbose "Using SearchBase: $nc"
135+
$ldapSearcher = Init-LdapConnection -connectionString $connectionString -SearchBase $SearchBase -Username $Username -Password $Password -PageSize $PageSize
136+
$ldapSearcher.Filter = "(objectClass=*)"
137+
return $ldapSearcher.FindAll();
138+
} else {
139+
$results = [ordered]@{};
140+
foreach ($nc in $namingContexts) {
141+
Write-Verbose "Using namingContext as search base: $nc"
142+
$ldapSearcher = Init-LdapConnection -connectionString $connectionString -SearchBase $nc -Username $Username -Password $Password -PageSize $PageSize
143+
$ldapSearcher.Filter = "(objectClass=*)"
144+
145+
Foreach ($item in $ldapSearcher.FindAll()) {
146+
if (!($results.Keys -contains $item.Path)) {
147+
$results[$item.Path] = $item.Properties;
148+
} else {
149+
Write-Host "[debug] key already exists: $key (this shouldn't be possible)"
150+
}
151+
}
152+
}
153+
return $results;
154+
}
155+
}
156+
}
157+
158+
74159
Function ResultsDiff {
75160
[CmdletBinding()]
76161
[OutputType([Nullable])]
77162
Param
78163
(
79-
[Parameter(Mandatory=$true)] $Before,
80-
[Parameter(Mandatory=$true)] $After,
164+
[Parameter(Mandatory=$true)] $ResultsBefore,
165+
[Parameter(Mandatory=$true)] $ResultsAfter,
81166
[Parameter(Mandatory=$true)] $connectionString,
82167
[Parameter(Mandatory=$true)] $Logfile,
83168
[parameter(Mandatory=$false)][switch]$IgnoreUserLogons
@@ -90,23 +175,18 @@ Function ResultsDiff {
90175
}
91176

92177
$dateprompt = ("[{0}] " -f (Get-Date -Format "yyyy/MM/dd hh:mm:ss"));
93-
# Get Keys
94-
$dict_results_before = [ordered]@{};
95-
$dict_results_after = [ordered]@{};
96-
Foreach ($itemBefore in $Before) { $dict_results_before[$itemBefore.Path] = $itemBefore.Properties; }
97-
Foreach ($itemAfter in $After) { $dict_results_after[$itemAfter.Path] = $itemAfter.Properties; }
98178

99179
# Get created and deleted entries, and common_keys
100180
[System.Collections.ArrayList]$commonPaths = @();
101-
Foreach ($bpath in $dict_results_before.Keys) {
102-
if (!($dict_results_after.Keys -contains $bpath)) {
181+
Foreach ($bpath in $ResultsBefore.Keys) {
182+
if (!($ResultsAfter.Keys -contains $bpath)) {
103183
Write-Logger -Logfile $Logfile -Message ("{0}'{1}' was deleted." -f $dateprompt, $bpath.replace($connectionString+"/",""))
104184
} else {
105185
$commonPaths.Add($bpath) | Out-Null
106186
}
107187
}
108-
Foreach ($apath in $dict_results_after.Keys) {
109-
if (!($dict_results_before.Keys -contains $apath)) {
188+
Foreach ($apath in $ResultsAfter.Keys) {
189+
if (!($ResultsBefore.Keys -contains $apath)) {
110190
Write-Logger -Logfile $Logfile -Message ("{0}'{1}' was created." -f $dateprompt, $apath.replace($connectionString+"/",""))
111191
}
112192
}
@@ -120,14 +200,14 @@ Function ResultsDiff {
120200
$dict_direntry_before = [ordered]@{};
121201
$dict_direntry_after = [ordered]@{};
122202

123-
Foreach ($propkey in $dict_results_before[$path].Keys) {
203+
Foreach ($propkey in $ResultsBefore[$path].Keys) {
124204
if (!($ignored_keys -Contains $propkey.ToLower())) {
125-
$dict_direntry_before.Add($propkey, $dict_results_before[$path][$propkey][0]);
205+
$dict_direntry_before.Add($propkey, $ResultsBefore[$path][$propkey][0]);
126206
}
127207
};
128-
Foreach ($propkey in $dict_results_after[$path].Keys) {
208+
Foreach ($propkey in $ResultsAfter[$path].Keys) {
129209
if (!($ignored_keys -Contains $propkey.ToLower())) {
130-
$dict_direntry_after.Add($propkey, $dict_results_after[$path][$propkey][0]);
210+
$dict_direntry_after.Add($propkey, $ResultsAfter[$path][$propkey][0]);
131211
}
132212
};
133213

@@ -165,7 +245,7 @@ Function ResultsDiff {
165245
#===============================================================================
166246

167247
Write-Logger -Logfile $Logfile -Message "[+]======================================================"
168-
Write-Logger -Logfile $Logfile -Message "[+] Powershell LDAP live monitor v1.1 @podalirius_ "
248+
Write-Logger -Logfile $Logfile -Message "[+] Powershell LDAP live monitor v1.3 @podalirius_ "
169249
Write-Logger -Logfile $Logfile -Message "[+]======================================================"
170250
Write-Logger -Logfile $Logfile -Message ""
171251

@@ -176,43 +256,32 @@ If ($LDAPS) {
176256
} else {
177257
$connectionString = ($connectionString -f $dcip, "389");
178258
}
179-
Write-Verbose "$connectionString"
259+
Write-Verbose "Using connectionString: $connectionString"
180260

181261
# Connect to LDAP
182262
try {
183-
# Connect to Domain with credentials
184-
if ($Username) {
185-
$objDomain = New-Object System.DirectoryServices.DirectoryEntry("$connectionString", $Username, $Password)
186-
} else {
187-
$objDomain = New-Object System.DirectoryServices.DirectoryEntry("$connectionString")
188-
}
189-
$searcher = New-Object System.DirectoryServices.DirectorySearcher
190-
$searcher.SearchRoot = $objDomain
191-
if ($PageSize) {
192-
$searcher.PageSize = $PageSize
193-
} else {
194-
Write-Verbose ("Setting PageSize to $PageSize");
195-
$searcher.PageSize = 5000
196-
}
263+
$rootDSE = New-Object System.DirectoryServices.DirectoryEntry("{0}/RootDSE" -f $connectionString);
264+
$namingContexts = $rootDSE.Properties["namingContexts"];
197265

198266
Write-Verbose ("Authentication successful!");
199267

200268
# First query
201-
$searcher.Filter = "(objectClass=*)"
202-
$results_before = $searcher.FindAll();
269+
$results_before = Query-AllNamingContextsOrSearchBase -connectionString $connectionString -SearchBase $SearchBase -namingContexts $namingContexts -Username $Username -Password $Password -PageSize $PageSize
203270

204271
Write-Logger -Logfile $Logfile -Message "[>] Listening for LDAP changes ...";
205272
Write-Logger -Logfile $Logfile -Message "";
206273

207274
While ($true) {
208275
# Update query
209-
$results_after = $searcher.FindAll();
276+
$results_after = Query-AllNamingContextsOrSearchBase -connectionString $connectionString -SearchBase $SearchBase -namingContexts $namingContexts -Username $Username -Password $Password -PageSize $PageSize
277+
210278
# Diff
211279
if ($IgnoreUserLogons) {
212-
ResultsDiff -Before $results_before -After $results_after -connectionString $connectionString -Logfile $Logfile -IgnoreUserLogons
280+
ResultsDiff -ResultsBefore $results_before -ResultsAfter $results_after -connectionString $connectionString -Logfile $Logfile -IgnoreUserLogons
213281
} else {
214-
ResultsDiff -Before $results_before -After $results_after -connectionString $connectionString -Logfile $Logfile
282+
ResultsDiff -ResultsBefore $results_before -ResultsAfter $results_after -connectionString $connectionString -Logfile $Logfile
215283
}
284+
216285
$results_before = $results_after;
217286
if ($Randomize) {
218287
$DelayInSeconds = Get-Random -Minimum 1 -Maximum 5

python/pyLDAPmonitor.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -470,14 +470,14 @@ def query_all_naming_contexts(ldap_server, ldap_session, logger, page_size, sear
470470
naming_contexts = [search_base]
471471
else:
472472
naming_contexts = ldap_server.info.other["defaultNamingContext"]
473-
for nm in naming_contexts:
474-
lc = LDAPConsole(ldap_server, ldap_session, nm, logger=logger, page_size=page_size)
473+
for nc in naming_contexts:
474+
lc = LDAPConsole(ldap_server, ldap_session, nc, logger=logger, page_size=page_size)
475475
_r = lc.query("(objectClass=*)", attributes=['*'])
476476
for key in _r.keys():
477477
if key not in results:
478478
results[key] = _r[key]
479479
else:
480-
print('[debug] key already exists: %s' % key)
480+
print("[debug] key already exists: %s (this shouldn't be possible)" % key)
481481
return results
482482

483483

0 commit comments

Comments
 (0)