Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/js/libs/ldap/utils.go
2070 views
1
package ldap
2
3
import (
4
"fmt"
5
"strconv"
6
"strings"
7
"time"
8
9
"github.com/go-ldap/ldap/v3"
10
)
11
12
type (
13
// SearchResult contains search result of any / all ldap search request
14
// @example
15
// ```javascript
16
// const ldap = require('nuclei/ldap');
17
// const client = new ldap.Client('ldap://ldap.example.com', 'acme.com');
18
// const results = client.Search('(objectClass=*)', 'cn', 'mail');
19
// ```
20
SearchResult struct {
21
// Referrals contains list of referrals
22
Referrals []string `json:"referrals"`
23
// Controls contains list of controls
24
Controls []string `json:"controls"`
25
// Entries contains list of entries
26
Entries []LdapEntry `json:"entries"`
27
}
28
29
// LdapEntry represents a single LDAP entry
30
LdapEntry struct {
31
// DN contains distinguished name
32
DN string `json:"dn"`
33
// Attributes contains list of attributes
34
Attributes LdapAttributes `json:"attributes"`
35
}
36
37
// LdapAttributes represents all LDAP attributes of a particular
38
// ldap entry
39
LdapAttributes struct {
40
// CurrentTime contains current time
41
CurrentTime []string `json:"currentTime,omitempty"`
42
// SubschemaSubentry contains subschema subentry
43
SubschemaSubentry []string `json:"subschemaSubentry,omitempty"`
44
// DsServiceName contains ds service name
45
DsServiceName []string `json:"dsServiceName,omitempty"`
46
// NamingContexts contains naming contexts
47
NamingContexts []string `json:"namingContexts,omitempty"`
48
// DefaultNamingContext contains default naming context
49
DefaultNamingContext []string `json:"defaultNamingContext,omitempty"`
50
// SchemaNamingContext contains schema naming context
51
SchemaNamingContext []string `json:"schemaNamingContext,omitempty"`
52
// ConfigurationNamingContext contains configuration naming context
53
ConfigurationNamingContext []string `json:"configurationNamingContext,omitempty"`
54
// RootDomainNamingContext contains root domain naming context
55
RootDomainNamingContext []string `json:"rootDomainNamingContext,omitempty"`
56
// SupportedLDAPVersion contains supported LDAP version
57
SupportedLDAPVersion []string `json:"supportedLDAPVersion,omitempty"`
58
// HighestCommittedUSN contains highest committed USN
59
HighestCommittedUSN []string `json:"highestCommittedUSN,omitempty"`
60
// SupportedSASLMechanisms contains supported SASL mechanisms
61
SupportedSASLMechanisms []string `json:"supportedSASLMechanisms,omitempty"`
62
// DnsHostName contains DNS host name
63
DnsHostName []string `json:"dnsHostName,omitempty"`
64
// LdapServiceName contains LDAP service name
65
LdapServiceName []string `json:"ldapServiceName,omitempty"`
66
// ServerName contains server name
67
ServerName []string `json:"serverName,omitempty"`
68
// IsSynchronized contains is synchronized
69
IsSynchronized []string `json:"isSynchronized,omitempty"`
70
// IsGlobalCatalogReady contains is global catalog ready
71
IsGlobalCatalogReady []string `json:"isGlobalCatalogReady,omitempty"`
72
// DomainFunctionality contains domain functionality
73
DomainFunctionality []string `json:"domainFunctionality,omitempty"`
74
// ForestFunctionality contains forest functionality
75
ForestFunctionality []string `json:"forestFunctionality,omitempty"`
76
// DomainControllerFunctionality contains domain controller functionality
77
DomainControllerFunctionality []string `json:"domainControllerFunctionality,omitempty"`
78
// DistinguishedName contains the distinguished name
79
DistinguishedName []string `json:"distinguishedName,omitempty"`
80
// SAMAccountName contains the SAM account name
81
SAMAccountName []string `json:"sAMAccountName,omitempty"`
82
// PWDLastSet contains the password last set time
83
PWDLastSet []string `json:"pwdLastSet,omitempty"`
84
// LastLogon contains the last logon time
85
LastLogon []string `json:"lastLogon,omitempty"`
86
// MemberOf contains the groups the entry is a member of
87
MemberOf []string `json:"memberOf,omitempty"`
88
// ServicePrincipalName contains the service principal names
89
ServicePrincipalName []string `json:"servicePrincipalName,omitempty"`
90
// Extra contains other extra fields which might be present
91
Extra map[string]any `json:"extra,omitempty"`
92
}
93
)
94
95
// getSearchResult converts a ldap.SearchResult to a SearchResult
96
func getSearchResult(sr *ldap.SearchResult) *SearchResult {
97
t := &SearchResult{
98
Referrals: []string{},
99
Controls: []string{},
100
Entries: []LdapEntry{},
101
}
102
// add referrals
103
t.Referrals = append(t.Referrals, sr.Referrals...)
104
// add controls
105
for _, ctrl := range sr.Controls {
106
t.Controls = append(t.Controls, ctrl.String())
107
}
108
// add entries
109
for _, entry := range sr.Entries {
110
t.Entries = append(t.Entries, parseLdapEntry(entry))
111
}
112
return t
113
}
114
115
func parseLdapEntry(entry *ldap.Entry) LdapEntry {
116
e := LdapEntry{
117
DN: entry.DN,
118
}
119
attrs := LdapAttributes{
120
Extra: make(map[string]any),
121
}
122
for _, attr := range entry.Attributes {
123
switch attr.Name {
124
case "currentTime":
125
attrs.CurrentTime = decodeTimestamps(attr.Values)
126
case "subschemaSubentry":
127
attrs.SubschemaSubentry = attr.Values
128
case "dsServiceName":
129
attrs.DsServiceName = attr.Values
130
case "namingContexts":
131
attrs.NamingContexts = attr.Values
132
case "defaultNamingContext":
133
attrs.DefaultNamingContext = attr.Values
134
case "schemaNamingContext":
135
attrs.SchemaNamingContext = attr.Values
136
case "configurationNamingContext":
137
attrs.ConfigurationNamingContext = attr.Values
138
case "rootDomainNamingContext":
139
attrs.RootDomainNamingContext = attr.Values
140
case "supportedLDAPVersion":
141
attrs.SupportedLDAPVersion = attr.Values
142
case "highestCommittedUSN":
143
attrs.HighestCommittedUSN = attr.Values
144
case "supportedSASLMechanisms":
145
attrs.SupportedSASLMechanisms = attr.Values
146
case "dnsHostName":
147
attrs.DnsHostName = attr.Values
148
case "ldapServiceName":
149
attrs.LdapServiceName = attr.Values
150
case "serverName":
151
attrs.ServerName = attr.Values
152
case "isSynchronized":
153
attrs.IsSynchronized = attr.Values
154
case "isGlobalCatalogReady":
155
attrs.IsGlobalCatalogReady = attr.Values
156
case "domainFunctionality":
157
attrs.DomainFunctionality = attr.Values
158
case "forestFunctionality":
159
attrs.ForestFunctionality = attr.Values
160
case "domainControllerFunctionality":
161
attrs.DomainControllerFunctionality = attr.Values
162
case "distinguishedName":
163
attrs.DistinguishedName = attr.Values
164
case "sAMAccountName":
165
attrs.SAMAccountName = attr.Values
166
case "pwdLastSet":
167
attrs.PWDLastSet = decodeTimestamps(attr.Values)
168
case "lastLogon":
169
attrs.LastLogon = decodeTimestamps(attr.Values)
170
case "memberOf":
171
attrs.MemberOf = attr.Values
172
case "servicePrincipalName":
173
attrs.ServicePrincipalName = attr.Values
174
default:
175
attrs.Extra[attr.Name] = attr.Values
176
}
177
}
178
e.Attributes = attrs
179
return e
180
}
181
182
// decodeTimestamps decodes multiple timestamps
183
func decodeTimestamps(timestamps []string) []string {
184
res := []string{}
185
for _, timestamp := range timestamps {
186
res = append(res, DecodeADTimestamp(timestamp))
187
}
188
return res
189
}
190
191
// DecodeSID decodes a SID string
192
// @example
193
// ```javascript
194
// const ldap = require('nuclei/ldap');
195
// const sid = ldap.DecodeSID('S-1-5-21-3623811015-3361044348-30300820-1013');
196
// log(sid);
197
// ```
198
func DecodeSID(s string) string {
199
b := []byte(s)
200
revisionLvl := int(b[0])
201
subAuthorityCount := int(b[1]) & 0xFF
202
203
var authority int
204
for i := 2; i <= 7; i++ {
205
authority = authority | int(b[i])<<(8*(5-(i-2)))
206
}
207
208
var size = 4
209
var offset = 8
210
var subAuthorities []int
211
for i := 0; i < subAuthorityCount; i++ {
212
var subAuthority int
213
for k := 0; k < size; k++ {
214
subAuthority = subAuthority | (int(b[offset+k])&0xFF)<<(8*k)
215
}
216
subAuthorities = append(subAuthorities, subAuthority)
217
offset += size
218
}
219
220
var builder strings.Builder
221
builder.WriteString("S-")
222
builder.WriteString(fmt.Sprintf("%d-", revisionLvl))
223
builder.WriteString(fmt.Sprintf("%d", authority))
224
for _, v := range subAuthorities {
225
builder.WriteString(fmt.Sprintf("-%d", v))
226
}
227
return builder.String()
228
}
229
230
// DecodeADTimestamp decodes an Active Directory timestamp
231
// @example
232
// ```javascript
233
// const ldap = require('nuclei/ldap');
234
// const timestamp = ldap.DecodeADTimestamp('132036744000000000');
235
// log(timestamp);
236
// ```
237
func DecodeADTimestamp(timestamp string) string {
238
adtime, _ := strconv.ParseInt(timestamp, 10, 64)
239
if (adtime == 9223372036854775807) || (adtime == 0) {
240
return "Not Set"
241
}
242
unixtime_int64 := adtime/(10*1000*1000) - 11644473600
243
unixtime := time.Unix(unixtime_int64, 0)
244
return unixtime.Format("2006-01-02 3:4:5 pm")
245
}
246
247
// DecodeZuluTimestamp decodes a Zulu timestamp
248
// @example
249
// ```javascript
250
// const ldap = require('nuclei/ldap');
251
// const timestamp = ldap.DecodeZuluTimestamp('2021-08-25T10:00:00Z');
252
// log(timestamp);
253
// ```
254
func DecodeZuluTimestamp(timestamp string) string {
255
zulu, err := time.Parse(time.RFC3339, timestamp)
256
if err != nil {
257
return ""
258
}
259
return zulu.Format("2006-01-02 3:4:5 pm")
260
}
261
262