diff --git a/LdapUsrEnum-linux-386 b/LdapUsrEnum-linux-386 index f6b49f1..fedbd46 100755 --- a/LdapUsrEnum-linux-386 +++ b/LdapUsrEnum-linux-386 Binary files differ diff --git a/LdapUsrEnum-linux-386 b/LdapUsrEnum-linux-386 index f6b49f1..fedbd46 100755 --- a/LdapUsrEnum-linux-386 +++ b/LdapUsrEnum-linux-386 Binary files differ diff --git a/LdapUsrEnum-linux-amd64 b/LdapUsrEnum-linux-amd64 index f6b49f1..fedbd46 100755 --- a/LdapUsrEnum-linux-amd64 +++ b/LdapUsrEnum-linux-amd64 Binary files differ diff --git a/LdapUsrEnum-linux-386 b/LdapUsrEnum-linux-386 index f6b49f1..fedbd46 100755 --- a/LdapUsrEnum-linux-386 +++ b/LdapUsrEnum-linux-386 Binary files differ diff --git a/LdapUsrEnum-linux-amd64 b/LdapUsrEnum-linux-amd64 index f6b49f1..fedbd46 100755 --- a/LdapUsrEnum-linux-amd64 +++ b/LdapUsrEnum-linux-amd64 Binary files differ diff --git a/LdapUsrEnum-windows-386.exe b/LdapUsrEnum-windows-386.exe index d16567c..36639a7 100755 --- a/LdapUsrEnum-windows-386.exe +++ b/LdapUsrEnum-windows-386.exe Binary files differ diff --git a/LdapUsrEnum-linux-386 b/LdapUsrEnum-linux-386 index f6b49f1..fedbd46 100755 --- a/LdapUsrEnum-linux-386 +++ b/LdapUsrEnum-linux-386 Binary files differ diff --git a/LdapUsrEnum-linux-amd64 b/LdapUsrEnum-linux-amd64 index f6b49f1..fedbd46 100755 --- a/LdapUsrEnum-linux-amd64 +++ b/LdapUsrEnum-linux-amd64 Binary files differ diff --git a/LdapUsrEnum-windows-386.exe b/LdapUsrEnum-windows-386.exe index d16567c..36639a7 100755 --- a/LdapUsrEnum-windows-386.exe +++ b/LdapUsrEnum-windows-386.exe Binary files differ diff --git a/LdapUsrEnum-windows-amd64.exe b/LdapUsrEnum-windows-amd64.exe index d16567c..36639a7 100755 --- a/LdapUsrEnum-windows-amd64.exe +++ b/LdapUsrEnum-windows-amd64.exe Binary files differ diff --git a/LdapUsrEnum-linux-386 b/LdapUsrEnum-linux-386 index f6b49f1..fedbd46 100755 --- a/LdapUsrEnum-linux-386 +++ b/LdapUsrEnum-linux-386 Binary files differ diff --git a/LdapUsrEnum-linux-amd64 b/LdapUsrEnum-linux-amd64 index f6b49f1..fedbd46 100755 --- a/LdapUsrEnum-linux-amd64 +++ b/LdapUsrEnum-linux-amd64 Binary files differ diff --git a/LdapUsrEnum-windows-386.exe b/LdapUsrEnum-windows-386.exe index d16567c..36639a7 100755 --- a/LdapUsrEnum-windows-386.exe +++ b/LdapUsrEnum-windows-386.exe Binary files differ diff --git a/LdapUsrEnum-windows-amd64.exe b/LdapUsrEnum-windows-amd64.exe index d16567c..36639a7 100755 --- a/LdapUsrEnum-windows-amd64.exe +++ b/LdapUsrEnum-windows-amd64.exe Binary files differ diff --git a/LdapUsrEnum.go b/LdapUsrEnum.go index c9f3982..5618c91 100755 --- a/LdapUsrEnum.go +++ b/LdapUsrEnum.go @@ -87,14 +87,23 @@ // SEARCH FOR USERNAME'S "sAMAccountName" (basic test) // Filters must start and finish with ()! - fmt.Print("[+] query to get account username... ") + fmt.Print("[+] query shortname to get account username... ") + DCQueryName := baseDN var mainUser string = "" filter := fmt.Sprintf("(CN=%s)", ldap.EscapeFilter(*username)) - searchReq := ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName","distinguishedName", "primaryGroupID"}, []ldap.Control{}) + searchReq := ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName","distinguishedName", "primaryGroupID"}, []ldap.Control{}) result, err := l.Search(searchReq) if err != nil { - fmt.Println("[-] failed to query LDAP: %w", err) - os.Exit(1) + fmt.Print("[+] query full domain to get account username... ") + DCQueryName = *domain + + filter = fmt.Sprintf("(CN=%s)", ldap.EscapeFilter(*username)) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName","distinguishedName", "primaryGroupID"}, []ldap.Control{}) + result, err = l.Search(searchReq) + if err != nil { + fmt.Println("[-] failed to query LDAP: %w", err) + os.Exit(1) + } } if len(result.Entries) == 0{ fmt.Println("[-] user can't query LDAP") @@ -105,11 +114,12 @@ } fmt.Println( mainUser ) //result.PrettyPrint(2) + //os.Exit(1) // SEARCH FOR ALL UERNAME'S fmt.Print("[+] ALL usernames... ") filter = fmt.Sprintf("(&(objectCategory=person)(objectClass=user)(SamAccountName=*))") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName", "whenCreated", "whenChanged", "lastLogon",}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName", "whenCreated", "whenChanged", "lastLogon","description"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -122,18 +132,20 @@ var foundUCreated []string var foundUChanged []string var foundULogon []string + var foundUDesc []string for _, entry := range result.Entries { //fmt.Printf("%s: %v\n", entry.GetAttributeValues("memberOf"), entry.GetAttributeValue("sAMAccountName")) foundUsers = append(foundUsers, entry.GetAttributeValue("sAMAccountName") ) foundUCreated = append(foundUCreated, entry.GetAttributeValue("whenCreated") ) foundUChanged = append(foundUChanged, entry.GetAttributeValue("whenChanged") ) foundULogon = append(foundULogon, entry.GetAttributeValue("lastLogon") ) + foundUDesc = append(foundUDesc, entry.GetAttributeValue("description") ) } // SEARCH FOR ALL LOCKED OUT ACCOUNTS fmt.Print("[+] locked accounts... ") filter = fmt.Sprintf("(&(sAMAccountType=805306368)(lockoutTime>=1))") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -153,7 +165,7 @@ // SEARCH FOR ALL DISABLED ACCOUNTS fmt.Print("[+] disabled accounts... ") filter = fmt.Sprintf("(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=2))") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -172,7 +184,7 @@ // SEARCH FOR ALL PASSWORD NEVER EXPIRE fmt.Print("[+] non-expire passwords... ") filter = fmt.Sprintf("(&(samAccountType=805306368)(|(UserAccountControl:1.2.840.113556.1.4.803:=65536)(msDS-UserDontExpirePassword=TRUE)))") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -194,7 +206,7 @@ fmt.Print("[+] groups... ") filter = fmt.Sprintf("(&(objectCategory=group)(objectClass=group))") //filter = fmt.Sprintf("(&(CN=\"Administrator\"))") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"objectCategory", "sAMAccountName", "distinguishedName"}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"objectCategory", "sAMAccountName", "distinguishedName"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -209,7 +221,7 @@ // Search for all users of that group filter = fmt.Sprintf("(&(objectCategory=person)(objectClass=user)(SamAccountName=*)(memberOf:1.2.840.113556.1.4.1941:=%v))", strings.Trim(entry.GetAttributeValue("distinguishedName"), "\t \n" )) - searchReq2 := ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) + searchReq2 := ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) result2, err := l.Search(searchReq2) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -225,7 +237,7 @@ // All users of Default Group (RID 513) filter = fmt.Sprintf("(&(objectCategory=person)(objectClass=user)(primaryGroupID=513))") - searchReq2 := ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) + searchReq2 := ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) result2, err := l.Search(searchReq2) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -269,7 +281,7 @@ // SEARCH FOR PASSWORD POLICY fmt.Println("[+] password policy ") filter = fmt.Sprintf("(objectClass=domainDNS)") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"minPwdLength","minPwdAge","maxPwdAge","pwdHistoryLength","lockoutThreshold","lockoutDuration","lockOutObservationWindow"}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"minPwdLength","minPwdAge","maxPwdAge","pwdHistoryLength","lockoutThreshold","lockoutDuration","lockOutObservationWindow"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -311,6 +323,10 @@ }else{ fmt.Println(" Never Logged In") } + lasDesc := foundUDesc[i] + if lasDesc != "" { + fmt.Printf(" (Desc: %v)\n", lasDesc ) + } } fmt.Println("--- to try (ALL) ---") toTry := "" diff --git a/LdapUsrEnum-linux-386 b/LdapUsrEnum-linux-386 index f6b49f1..fedbd46 100755 --- a/LdapUsrEnum-linux-386 +++ b/LdapUsrEnum-linux-386 Binary files differ diff --git a/LdapUsrEnum-linux-amd64 b/LdapUsrEnum-linux-amd64 index f6b49f1..fedbd46 100755 --- a/LdapUsrEnum-linux-amd64 +++ b/LdapUsrEnum-linux-amd64 Binary files differ diff --git a/LdapUsrEnum-windows-386.exe b/LdapUsrEnum-windows-386.exe index d16567c..36639a7 100755 --- a/LdapUsrEnum-windows-386.exe +++ b/LdapUsrEnum-windows-386.exe Binary files differ diff --git a/LdapUsrEnum-windows-amd64.exe b/LdapUsrEnum-windows-amd64.exe index d16567c..36639a7 100755 --- a/LdapUsrEnum-windows-amd64.exe +++ b/LdapUsrEnum-windows-amd64.exe Binary files differ diff --git a/LdapUsrEnum.go b/LdapUsrEnum.go index c9f3982..5618c91 100755 --- a/LdapUsrEnum.go +++ b/LdapUsrEnum.go @@ -87,14 +87,23 @@ // SEARCH FOR USERNAME'S "sAMAccountName" (basic test) // Filters must start and finish with ()! - fmt.Print("[+] query to get account username... ") + fmt.Print("[+] query shortname to get account username... ") + DCQueryName := baseDN var mainUser string = "" filter := fmt.Sprintf("(CN=%s)", ldap.EscapeFilter(*username)) - searchReq := ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName","distinguishedName", "primaryGroupID"}, []ldap.Control{}) + searchReq := ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName","distinguishedName", "primaryGroupID"}, []ldap.Control{}) result, err := l.Search(searchReq) if err != nil { - fmt.Println("[-] failed to query LDAP: %w", err) - os.Exit(1) + fmt.Print("[+] query full domain to get account username... ") + DCQueryName = *domain + + filter = fmt.Sprintf("(CN=%s)", ldap.EscapeFilter(*username)) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName","distinguishedName", "primaryGroupID"}, []ldap.Control{}) + result, err = l.Search(searchReq) + if err != nil { + fmt.Println("[-] failed to query LDAP: %w", err) + os.Exit(1) + } } if len(result.Entries) == 0{ fmt.Println("[-] user can't query LDAP") @@ -105,11 +114,12 @@ } fmt.Println( mainUser ) //result.PrettyPrint(2) + //os.Exit(1) // SEARCH FOR ALL UERNAME'S fmt.Print("[+] ALL usernames... ") filter = fmt.Sprintf("(&(objectCategory=person)(objectClass=user)(SamAccountName=*))") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName", "whenCreated", "whenChanged", "lastLogon",}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName", "whenCreated", "whenChanged", "lastLogon","description"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -122,18 +132,20 @@ var foundUCreated []string var foundUChanged []string var foundULogon []string + var foundUDesc []string for _, entry := range result.Entries { //fmt.Printf("%s: %v\n", entry.GetAttributeValues("memberOf"), entry.GetAttributeValue("sAMAccountName")) foundUsers = append(foundUsers, entry.GetAttributeValue("sAMAccountName") ) foundUCreated = append(foundUCreated, entry.GetAttributeValue("whenCreated") ) foundUChanged = append(foundUChanged, entry.GetAttributeValue("whenChanged") ) foundULogon = append(foundULogon, entry.GetAttributeValue("lastLogon") ) + foundUDesc = append(foundUDesc, entry.GetAttributeValue("description") ) } // SEARCH FOR ALL LOCKED OUT ACCOUNTS fmt.Print("[+] locked accounts... ") filter = fmt.Sprintf("(&(sAMAccountType=805306368)(lockoutTime>=1))") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -153,7 +165,7 @@ // SEARCH FOR ALL DISABLED ACCOUNTS fmt.Print("[+] disabled accounts... ") filter = fmt.Sprintf("(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=2))") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -172,7 +184,7 @@ // SEARCH FOR ALL PASSWORD NEVER EXPIRE fmt.Print("[+] non-expire passwords... ") filter = fmt.Sprintf("(&(samAccountType=805306368)(|(UserAccountControl:1.2.840.113556.1.4.803:=65536)(msDS-UserDontExpirePassword=TRUE)))") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -194,7 +206,7 @@ fmt.Print("[+] groups... ") filter = fmt.Sprintf("(&(objectCategory=group)(objectClass=group))") //filter = fmt.Sprintf("(&(CN=\"Administrator\"))") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"objectCategory", "sAMAccountName", "distinguishedName"}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"objectCategory", "sAMAccountName", "distinguishedName"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -209,7 +221,7 @@ // Search for all users of that group filter = fmt.Sprintf("(&(objectCategory=person)(objectClass=user)(SamAccountName=*)(memberOf:1.2.840.113556.1.4.1941:=%v))", strings.Trim(entry.GetAttributeValue("distinguishedName"), "\t \n" )) - searchReq2 := ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) + searchReq2 := ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) result2, err := l.Search(searchReq2) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -225,7 +237,7 @@ // All users of Default Group (RID 513) filter = fmt.Sprintf("(&(objectCategory=person)(objectClass=user)(primaryGroupID=513))") - searchReq2 := ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) + searchReq2 := ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) result2, err := l.Search(searchReq2) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -269,7 +281,7 @@ // SEARCH FOR PASSWORD POLICY fmt.Println("[+] password policy ") filter = fmt.Sprintf("(objectClass=domainDNS)") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"minPwdLength","minPwdAge","maxPwdAge","pwdHistoryLength","lockoutThreshold","lockoutDuration","lockOutObservationWindow"}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"minPwdLength","minPwdAge","maxPwdAge","pwdHistoryLength","lockoutThreshold","lockoutDuration","lockOutObservationWindow"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -311,6 +323,10 @@ }else{ fmt.Println(" Never Logged In") } + lasDesc := foundUDesc[i] + if lasDesc != "" { + fmt.Printf(" (Desc: %v)\n", lasDesc ) + } } fmt.Println("--- to try (ALL) ---") toTry := "" diff --git a/README.md b/README.md index 14bef30..3a686f3 100644 --- a/README.md +++ b/README.md @@ -7,4 +7,57 @@ comma seperated list of all users except one used to scan with at end, or list of all users in groups that user used is not a member of.. for easy pasting into brute-force tools. -![LdapUsrEnum Screenshot](https://rossmarks.uk/git/0xRoM/LdapUsrEnum/raw/master/LdapUsrEnum_Screenshot.png) \ No newline at end of file +``` +╰» ./LdapUsrEnum-linux-amd64 -d 192.168.69.13 -w -redacted- -u Reno -p -redacted- +[i] DC/AD: 192.168.69.13 +[i] domain: -redacted- +[!] trying plaintext auth +[+] using: CN=Reno,DC=-redacted-,DC=-redacted- +[!] trying to connect with supplied password +[+] query shortname to get account username... Reno +[+] ALL usernames... 10 +[+] locked accounts... 0 +[+] disabled accounts... 3 +[+] non-expire passwords... 9 +[+] groups... 51 +[+] Matching users to groups.. this could take a while! +[+] password policy +--- pwd pol --- +minPwdLength: 7 +minPwdAge: -864000000000 +maxPwdAge: 42 +pwdHistoryLength: 24 +lockoutThreshold: 0 +lockoutDuration: 30 +lockOutObservationWindow: 30 +--- results --- +Administrator PassNevExp + 2022-02-21 09:52:35 (0 day(s) 00:22:24) + (Desc: Built-in account for administering the computer/domain) +Guest Disabled PassNevExp + Never Logged In + (Desc: Built-in account for guest access to the computer/domain) +krbtgt Disabled + Never Logged In + (Desc: Key Distribution Center Service Account) +Reno PassNevExp + 2022-02-17 09:05:41 (4 day(s) 01:09:18) +T.Holt Disabled PassNevExp + Never Logged In +pfSense PassNevExp + 2021-08-17 12:00:17 (188 day(s) 23:14:42) +r.marks PassNevExp + 2022-02-21 05:23:05 (0 day(s) 04:51:54) +Rude PassNevExp + 2021-08-17 15:35:04 (188 day(s) 19:39:55) +Cissnei PassNevExp + 2021-08-17 15:56:36 (188 day(s) 19:18:23) + (Desc: -redacted-) +Elena PassNevExp + 2021-08-17 15:56:36 (188 day(s) 19:18:23) +--- to try (ALL) --- +Administrator, pfSense, r.marks, Rude, Cissnei, Elena +--- to try (Diff Group) --- +Administrator, pfSense, r.marks + +``` \ No newline at end of file diff --git a/LdapUsrEnum-linux-386 b/LdapUsrEnum-linux-386 index f6b49f1..fedbd46 100755 --- a/LdapUsrEnum-linux-386 +++ b/LdapUsrEnum-linux-386 Binary files differ diff --git a/LdapUsrEnum-linux-amd64 b/LdapUsrEnum-linux-amd64 index f6b49f1..fedbd46 100755 --- a/LdapUsrEnum-linux-amd64 +++ b/LdapUsrEnum-linux-amd64 Binary files differ diff --git a/LdapUsrEnum-windows-386.exe b/LdapUsrEnum-windows-386.exe index d16567c..36639a7 100755 --- a/LdapUsrEnum-windows-386.exe +++ b/LdapUsrEnum-windows-386.exe Binary files differ diff --git a/LdapUsrEnum-windows-amd64.exe b/LdapUsrEnum-windows-amd64.exe index d16567c..36639a7 100755 --- a/LdapUsrEnum-windows-amd64.exe +++ b/LdapUsrEnum-windows-amd64.exe Binary files differ diff --git a/LdapUsrEnum.go b/LdapUsrEnum.go index c9f3982..5618c91 100755 --- a/LdapUsrEnum.go +++ b/LdapUsrEnum.go @@ -87,14 +87,23 @@ // SEARCH FOR USERNAME'S "sAMAccountName" (basic test) // Filters must start and finish with ()! - fmt.Print("[+] query to get account username... ") + fmt.Print("[+] query shortname to get account username... ") + DCQueryName := baseDN var mainUser string = "" filter := fmt.Sprintf("(CN=%s)", ldap.EscapeFilter(*username)) - searchReq := ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName","distinguishedName", "primaryGroupID"}, []ldap.Control{}) + searchReq := ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName","distinguishedName", "primaryGroupID"}, []ldap.Control{}) result, err := l.Search(searchReq) if err != nil { - fmt.Println("[-] failed to query LDAP: %w", err) - os.Exit(1) + fmt.Print("[+] query full domain to get account username... ") + DCQueryName = *domain + + filter = fmt.Sprintf("(CN=%s)", ldap.EscapeFilter(*username)) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName","distinguishedName", "primaryGroupID"}, []ldap.Control{}) + result, err = l.Search(searchReq) + if err != nil { + fmt.Println("[-] failed to query LDAP: %w", err) + os.Exit(1) + } } if len(result.Entries) == 0{ fmt.Println("[-] user can't query LDAP") @@ -105,11 +114,12 @@ } fmt.Println( mainUser ) //result.PrettyPrint(2) + //os.Exit(1) // SEARCH FOR ALL UERNAME'S fmt.Print("[+] ALL usernames... ") filter = fmt.Sprintf("(&(objectCategory=person)(objectClass=user)(SamAccountName=*))") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName", "whenCreated", "whenChanged", "lastLogon",}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName", "whenCreated", "whenChanged", "lastLogon","description"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -122,18 +132,20 @@ var foundUCreated []string var foundUChanged []string var foundULogon []string + var foundUDesc []string for _, entry := range result.Entries { //fmt.Printf("%s: %v\n", entry.GetAttributeValues("memberOf"), entry.GetAttributeValue("sAMAccountName")) foundUsers = append(foundUsers, entry.GetAttributeValue("sAMAccountName") ) foundUCreated = append(foundUCreated, entry.GetAttributeValue("whenCreated") ) foundUChanged = append(foundUChanged, entry.GetAttributeValue("whenChanged") ) foundULogon = append(foundULogon, entry.GetAttributeValue("lastLogon") ) + foundUDesc = append(foundUDesc, entry.GetAttributeValue("description") ) } // SEARCH FOR ALL LOCKED OUT ACCOUNTS fmt.Print("[+] locked accounts... ") filter = fmt.Sprintf("(&(sAMAccountType=805306368)(lockoutTime>=1))") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -153,7 +165,7 @@ // SEARCH FOR ALL DISABLED ACCOUNTS fmt.Print("[+] disabled accounts... ") filter = fmt.Sprintf("(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=2))") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -172,7 +184,7 @@ // SEARCH FOR ALL PASSWORD NEVER EXPIRE fmt.Print("[+] non-expire passwords... ") filter = fmt.Sprintf("(&(samAccountType=805306368)(|(UserAccountControl:1.2.840.113556.1.4.803:=65536)(msDS-UserDontExpirePassword=TRUE)))") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -194,7 +206,7 @@ fmt.Print("[+] groups... ") filter = fmt.Sprintf("(&(objectCategory=group)(objectClass=group))") //filter = fmt.Sprintf("(&(CN=\"Administrator\"))") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"objectCategory", "sAMAccountName", "distinguishedName"}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"objectCategory", "sAMAccountName", "distinguishedName"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -209,7 +221,7 @@ // Search for all users of that group filter = fmt.Sprintf("(&(objectCategory=person)(objectClass=user)(SamAccountName=*)(memberOf:1.2.840.113556.1.4.1941:=%v))", strings.Trim(entry.GetAttributeValue("distinguishedName"), "\t \n" )) - searchReq2 := ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) + searchReq2 := ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) result2, err := l.Search(searchReq2) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -225,7 +237,7 @@ // All users of Default Group (RID 513) filter = fmt.Sprintf("(&(objectCategory=person)(objectClass=user)(primaryGroupID=513))") - searchReq2 := ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) + searchReq2 := ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"sAMAccountName"}, []ldap.Control{}) result2, err := l.Search(searchReq2) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -269,7 +281,7 @@ // SEARCH FOR PASSWORD POLICY fmt.Println("[+] password policy ") filter = fmt.Sprintf("(objectClass=domainDNS)") - searchReq = ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"minPwdLength","minPwdAge","maxPwdAge","pwdHistoryLength","lockoutThreshold","lockoutDuration","lockOutObservationWindow"}, []ldap.Control{}) + searchReq = ldap.NewSearchRequest(DCQueryName, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"minPwdLength","minPwdAge","maxPwdAge","pwdHistoryLength","lockoutThreshold","lockoutDuration","lockOutObservationWindow"}, []ldap.Control{}) result, err = l.Search(searchReq) if err != nil { fmt.Println("[-] failed to query LDAP: %w", err) @@ -311,6 +323,10 @@ }else{ fmt.Println(" Never Logged In") } + lasDesc := foundUDesc[i] + if lasDesc != "" { + fmt.Printf(" (Desc: %v)\n", lasDesc ) + } } fmt.Println("--- to try (ALL) ---") toTry := "" diff --git a/README.md b/README.md index 14bef30..3a686f3 100644 --- a/README.md +++ b/README.md @@ -7,4 +7,57 @@ comma seperated list of all users except one used to scan with at end, or list of all users in groups that user used is not a member of.. for easy pasting into brute-force tools. -![LdapUsrEnum Screenshot](https://rossmarks.uk/git/0xRoM/LdapUsrEnum/raw/master/LdapUsrEnum_Screenshot.png) \ No newline at end of file +``` +╰» ./LdapUsrEnum-linux-amd64 -d 192.168.69.13 -w -redacted- -u Reno -p -redacted- +[i] DC/AD: 192.168.69.13 +[i] domain: -redacted- +[!] trying plaintext auth +[+] using: CN=Reno,DC=-redacted-,DC=-redacted- +[!] trying to connect with supplied password +[+] query shortname to get account username... Reno +[+] ALL usernames... 10 +[+] locked accounts... 0 +[+] disabled accounts... 3 +[+] non-expire passwords... 9 +[+] groups... 51 +[+] Matching users to groups.. this could take a while! +[+] password policy +--- pwd pol --- +minPwdLength: 7 +minPwdAge: -864000000000 +maxPwdAge: 42 +pwdHistoryLength: 24 +lockoutThreshold: 0 +lockoutDuration: 30 +lockOutObservationWindow: 30 +--- results --- +Administrator PassNevExp + 2022-02-21 09:52:35 (0 day(s) 00:22:24) + (Desc: Built-in account for administering the computer/domain) +Guest Disabled PassNevExp + Never Logged In + (Desc: Built-in account for guest access to the computer/domain) +krbtgt Disabled + Never Logged In + (Desc: Key Distribution Center Service Account) +Reno PassNevExp + 2022-02-17 09:05:41 (4 day(s) 01:09:18) +T.Holt Disabled PassNevExp + Never Logged In +pfSense PassNevExp + 2021-08-17 12:00:17 (188 day(s) 23:14:42) +r.marks PassNevExp + 2022-02-21 05:23:05 (0 day(s) 04:51:54) +Rude PassNevExp + 2021-08-17 15:35:04 (188 day(s) 19:39:55) +Cissnei PassNevExp + 2021-08-17 15:56:36 (188 day(s) 19:18:23) + (Desc: -redacted-) +Elena PassNevExp + 2021-08-17 15:56:36 (188 day(s) 19:18:23) +--- to try (ALL) --- +Administrator, pfSense, r.marks, Rude, Cissnei, Elena +--- to try (Diff Group) --- +Administrator, pfSense, r.marks + +``` \ No newline at end of file diff --git a/go.mod b/go.mod old mode 100755 new mode 100644 index 3f09e41..a2696da --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ require ( github.com/akamensky/argparse v1.3.1 - github.com/go-ldap/ldap/v3 v3.3.0 // indirect + github.com/go-ldap/ldap/v3 v3.3.0 gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect gopkg.in/ldap.v2 v2.5.1 // indirect )