nuclei/pkg/js/libs/ldap/utils.go
Tarun Koyalwar 6cbd73f780
feat: improve ldap output with custom type: (#5387)
* feat: improve ldap output with custom type:

* js bindings update

* lint fix
2024-07-15 18:42:22 +05:30

261 lines
8.6 KiB
Go

package ldap
import (
"fmt"
"strconv"
"strings"
"time"
"github.com/go-ldap/ldap/v3"
)
type (
// SearchResult contains search result of any / all ldap search request
// @example
// ```javascript
// const ldap = require('nuclei/ldap');
// const client = new ldap.Client('ldap://ldap.example.com', 'acme.com');
// const results = client.Search('(objectClass=*)', 'cn', 'mail');
// ```
SearchResult struct {
// Referrals contains list of referrals
Referrals []string `json:"referrals"`
// Controls contains list of controls
Controls []string `json:"controls"`
// Entries contains list of entries
Entries []LdapEntry `json:"entries"`
}
// LdapEntry represents a single LDAP entry
LdapEntry struct {
// DN contains distinguished name
DN string `json:"dn"`
// Attributes contains list of attributes
Attributes LdapAttributes `json:"attributes"`
}
// LdapAttributes represents all LDAP attributes of a particular
// ldap entry
LdapAttributes struct {
// CurrentTime contains current time
CurrentTime []string `json:"currentTime,omitempty"`
// SubschemaSubentry contains subschema subentry
SubschemaSubentry []string `json:"subschemaSubentry,omitempty"`
// DsServiceName contains ds service name
DsServiceName []string `json:"dsServiceName,omitempty"`
// NamingContexts contains naming contexts
NamingContexts []string `json:"namingContexts,omitempty"`
// DefaultNamingContext contains default naming context
DefaultNamingContext []string `json:"defaultNamingContext,omitempty"`
// SchemaNamingContext contains schema naming context
SchemaNamingContext []string `json:"schemaNamingContext,omitempty"`
// ConfigurationNamingContext contains configuration naming context
ConfigurationNamingContext []string `json:"configurationNamingContext,omitempty"`
// RootDomainNamingContext contains root domain naming context
RootDomainNamingContext []string `json:"rootDomainNamingContext,omitempty"`
// SupportedLDAPVersion contains supported LDAP version
SupportedLDAPVersion []string `json:"supportedLDAPVersion,omitempty"`
// HighestCommittedUSN contains highest committed USN
HighestCommittedUSN []string `json:"highestCommittedUSN,omitempty"`
// SupportedSASLMechanisms contains supported SASL mechanisms
SupportedSASLMechanisms []string `json:"supportedSASLMechanisms,omitempty"`
// DnsHostName contains DNS host name
DnsHostName []string `json:"dnsHostName,omitempty"`
// LdapServiceName contains LDAP service name
LdapServiceName []string `json:"ldapServiceName,omitempty"`
// ServerName contains server name
ServerName []string `json:"serverName,omitempty"`
// IsSynchronized contains is synchronized
IsSynchronized []string `json:"isSynchronized,omitempty"`
// IsGlobalCatalogReady contains is global catalog ready
IsGlobalCatalogReady []string `json:"isGlobalCatalogReady,omitempty"`
// DomainFunctionality contains domain functionality
DomainFunctionality []string `json:"domainFunctionality,omitempty"`
// ForestFunctionality contains forest functionality
ForestFunctionality []string `json:"forestFunctionality,omitempty"`
// DomainControllerFunctionality contains domain controller functionality
DomainControllerFunctionality []string `json:"domainControllerFunctionality,omitempty"`
// DistinguishedName contains the distinguished name
DistinguishedName []string `json:"distinguishedName,omitempty"`
// SAMAccountName contains the SAM account name
SAMAccountName []string `json:"sAMAccountName,omitempty"`
// PWDLastSet contains the password last set time
PWDLastSet []string `json:"pwdLastSet,omitempty"`
// LastLogon contains the last logon time
LastLogon []string `json:"lastLogon,omitempty"`
// MemberOf contains the groups the entry is a member of
MemberOf []string `json:"memberOf,omitempty"`
// ServicePrincipalName contains the service principal names
ServicePrincipalName []string `json:"servicePrincipalName,omitempty"`
// Extra contains other extra fields which might be present
Extra map[string]any `json:"extra,omitempty"`
}
)
// getSearchResult converts a ldap.SearchResult to a SearchResult
func getSearchResult(sr *ldap.SearchResult) *SearchResult {
t := &SearchResult{
Referrals: []string{},
Controls: []string{},
Entries: []LdapEntry{},
}
// add referrals
t.Referrals = append(t.Referrals, sr.Referrals...)
// add controls
for _, ctrl := range sr.Controls {
t.Controls = append(t.Controls, ctrl.String())
}
// add entries
for _, entry := range sr.Entries {
t.Entries = append(t.Entries, parseLdapEntry(entry))
}
return t
}
func parseLdapEntry(entry *ldap.Entry) LdapEntry {
e := LdapEntry{
DN: entry.DN,
}
attrs := LdapAttributes{
Extra: make(map[string]any),
}
for _, attr := range entry.Attributes {
switch attr.Name {
case "currentTime":
attrs.CurrentTime = decodeTimestamps(attr.Values)
case "subschemaSubentry":
attrs.SubschemaSubentry = attr.Values
case "dsServiceName":
attrs.DsServiceName = attr.Values
case "namingContexts":
attrs.NamingContexts = attr.Values
case "defaultNamingContext":
attrs.DefaultNamingContext = attr.Values
case "schemaNamingContext":
attrs.SchemaNamingContext = attr.Values
case "configurationNamingContext":
attrs.ConfigurationNamingContext = attr.Values
case "rootDomainNamingContext":
attrs.RootDomainNamingContext = attr.Values
case "supportedLDAPVersion":
attrs.SupportedLDAPVersion = attr.Values
case "highestCommittedUSN":
attrs.HighestCommittedUSN = attr.Values
case "supportedSASLMechanisms":
attrs.SupportedSASLMechanisms = attr.Values
case "dnsHostName":
attrs.DnsHostName = attr.Values
case "ldapServiceName":
attrs.LdapServiceName = attr.Values
case "serverName":
attrs.ServerName = attr.Values
case "isSynchronized":
attrs.IsSynchronized = attr.Values
case "isGlobalCatalogReady":
attrs.IsGlobalCatalogReady = attr.Values
case "domainFunctionality":
attrs.DomainFunctionality = attr.Values
case "forestFunctionality":
attrs.ForestFunctionality = attr.Values
case "domainControllerFunctionality":
attrs.DomainControllerFunctionality = attr.Values
case "distinguishedName":
attrs.DistinguishedName = attr.Values
case "sAMAccountName":
attrs.SAMAccountName = attr.Values
case "pwdLastSet":
attrs.PWDLastSet = decodeTimestamps(attr.Values)
case "lastLogon":
attrs.LastLogon = decodeTimestamps(attr.Values)
case "memberOf":
attrs.MemberOf = attr.Values
case "servicePrincipalName":
attrs.ServicePrincipalName = attr.Values
default:
attrs.Extra[attr.Name] = attr.Values
}
}
e.Attributes = attrs
return e
}
// decodeTimestamps decodes multiple timestamps
func decodeTimestamps(timestamps []string) []string {
res := []string{}
for _, timestamp := range timestamps {
res = append(res, DecodeADTimestamp(timestamp))
}
return res
}
// DecodeSID decodes a SID string
// @example
// ```javascript
// const ldap = require('nuclei/ldap');
// const sid = ldap.DecodeSID('S-1-5-21-3623811015-3361044348-30300820-1013');
// log(sid);
// ```
func DecodeSID(s string) string {
b := []byte(s)
revisionLvl := int(b[0])
subAuthorityCount := int(b[1]) & 0xFF
var authority int
for i := 2; i <= 7; i++ {
authority = authority | int(b[i])<<(8*(5-(i-2)))
}
var size = 4
var offset = 8
var subAuthorities []int
for i := 0; i < subAuthorityCount; i++ {
var subAuthority int
for k := 0; k < size; k++ {
subAuthority = subAuthority | (int(b[offset+k])&0xFF)<<(8*k)
}
subAuthorities = append(subAuthorities, subAuthority)
offset += size
}
var builder strings.Builder
builder.WriteString("S-")
builder.WriteString(fmt.Sprintf("%d-", revisionLvl))
builder.WriteString(fmt.Sprintf("%d", authority))
for _, v := range subAuthorities {
builder.WriteString(fmt.Sprintf("-%d", v))
}
return builder.String()
}
// DecodeADTimestamp decodes an Active Directory timestamp
// @example
// ```javascript
// const ldap = require('nuclei/ldap');
// const timestamp = ldap.DecodeADTimestamp('132036744000000000');
// log(timestamp);
// ```
func DecodeADTimestamp(timestamp string) string {
adtime, _ := strconv.ParseInt(timestamp, 10, 64)
if (adtime == 9223372036854775807) || (adtime == 0) {
return "Not Set"
}
unixtime_int64 := adtime/(10*1000*1000) - 11644473600
unixtime := time.Unix(unixtime_int64, 0)
return unixtime.Format("2006-01-02 3:4:5 pm")
}
// DecodeZuluTimestamp decodes a Zulu timestamp
// @example
// ```javascript
// const ldap = require('nuclei/ldap');
// const timestamp = ldap.DecodeZuluTimestamp('2021-08-25T10:00:00Z');
// log(timestamp);
// ```
func DecodeZuluTimestamp(timestamp string) string {
zulu, err := time.Parse(time.RFC3339, timestamp)
if err != nil {
return ""
}
return zulu.Format("2006-01-02 3:4:5 pm")
}