Skip to content

Commit

Permalink
添加新功能:支持以当前用户token登录
Browse files Browse the repository at this point in the history
  • Loading branch information
2867a0 committed Aug 7, 2023
1 parent 17d1971 commit dac8a91
Show file tree
Hide file tree
Showing 8 changed files with 280 additions and 3 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ golang 实现的 Ldap 小工具
**功能类**
- [x] SSL连接
- [x] 导出查询结果
- [ ] (调研)以当前用户Token查询
- [x] (调研)以当前用户Token查询
- [x] 支持hash登陆

**搜索模块类**
Expand Down
2 changes: 2 additions & 0 deletions cli/cli.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build !windows

package cli

import (
Expand Down
68 changes: 68 additions & 0 deletions cli/cli_win.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//go:build windows

package cli

import (
"github.com/spf13/cobra"
"goLdapTools/cli/global"
"goLdapTools/cli/modify"
"goLdapTools/cli/search"
"goLdapTools/conn"
"goLdapTools/log"
"os"
)

func init() {
//global argument
rootCmd.PersistentFlags().StringP(global.DomainNameStr, "d", "", "domain name (example: test.lab)")
rootCmd.PersistentFlags().StringP(global.UserStr, "u", "", "username")
rootCmd.PersistentFlags().StringP(global.PassStr, "p", "", "password")
rootCmd.PersistentFlags().StringP(global.HashStr, "", "", "hash")
rootCmd.PersistentFlags().StringP(global.GssApiStr, "t", "", "login with current user token(example: --gssapi dc.test.lab)")
rootCmd.PersistentFlags().StringP(global.BaseDnStr, "b", "", "Specify DN (ou=xx,dc=xx,dc=xx)")
rootCmd.PersistentFlags().BoolP(global.SslStr, "s", false, "Use ssl to connect to ldap. default false")
rootCmd.PersistentFlags().StringP(global.ExportStr, "o", "", "save result to file.")

//search mode
rootCmd.AddCommand(search.SearchCmd)

//modify mode
rootCmd.AddCommand(modify.AddCmd)
}

var rootCmd = &cobra.Command{
Use: "goLdapTool",
Short: "golang ldap tool",
Long: `An Ldap operation tool written in golang,
with functions including searching and modifying Ldap entry attributes`,

Run: func(cmd *cobra.Command, args []string) {
config, err := global.ParseGlobalCommand(cmd)
if err != nil {
log.PrintErrorf("Parse global command error: %s", err.Error())
os.Exit(1)
}

log.PrintDebugf("Connect config:\n"+
" server: %s\n"+
" username: %s\n"+
" password: %s\n"+
" dn: %s", config.DomainName, config.UserName, config.Password, config.BaseDN)

// 不使用搜索模块,仅登陆
ldapConnector, err := conn.LdapConnect(config)
if err != nil {
log.PrintErrorf("error: %s", err.Error())
os.Exit(1)
}

log.PrintSuccessf("Connect %s successes", ldapConnector.Config.DomainName)
},
}

func Execute() {
if err := rootCmd.Execute(); err != nil {
log.PrintError(err)
os.Exit(1)
}
}
2 changes: 2 additions & 0 deletions cli/global/globals.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build !windows

package global

import (
Expand Down
108 changes: 108 additions & 0 deletions cli/global/globals_win.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
//go:build windows

package global

import (
"errors"
"fmt"
"github.com/spf13/cobra"
"goLdapTools/log"
"strings"
)

const (
DomainNameStr = "domain-name"
UserStr = "username"
PassStr = "password"
HashStr = "hash"
GssApiStr = "gssapi"
BaseDnStr = "base-dn"
SslStr = "ssl"
ExportStr = "output"
)

type GlobalCommand struct {
DomainName string
UserName string
Password string
PassHash string
GssApiLogin string
BaseDN string
SSLConn bool
Export string
}

func ParseGlobalCommand(cmd *cobra.Command) (config *GlobalCommand, err error) {
domainName, err := cmd.Flags().GetString(DomainNameStr)
if err != nil {
log.PrintDebugf("Failed to parse --domainName-- flag %s", err)
return nil, err
}
if domainName == "" {
return nil, errors.New("domain name is not specified")
}

u, err := cmd.Flags().GetString(UserStr)
if err != nil {
log.PrintDebugf("Failed to parse --username-- flag %s", err)
return nil, err
}

password, err := cmd.Flags().GetString(PassStr)
if err != nil {
log.PrintDebugf("Failed to parse --password-- flag %s", err)
return nil, err
}

passHash, err := cmd.Flags().GetString(HashStr)
if err != nil {
log.PrintDebugf("Failed to parse --hash-- flag %s", err)
return nil, err
}

gssapi, err := cmd.Flags().GetString(GssApiStr)
if err != nil {
log.PrintDebugf("Failed to parse --gssapi-- flag %s", err)
return nil, err
}

domainNameArr := strings.Split(domainName, ".")
baseDN, err := cmd.Flags().GetString(BaseDnStr)
if err != nil {
log.PrintDebugf("Failed to parse --base dn-- flag %s", err)
return nil, err
}
if baseDN == "" {
baseDN = fmt.Sprintf("dc=%s", strings.Join(domainNameArr, ",dc="))
}

ssl, err := cmd.Flags().GetBool(SslStr)
if err != nil {
log.PrintErrorf("Failed to parse --ssl-- flag %s", err)
return nil, err
}

export, err := cmd.Flags().GetString(ExportStr)
if err != nil {
log.PrintErrorf("Failed to parse --export-- flag %s", err)
return nil, err
}

log.SaveResultStr = export

var userName = u
if !strings.Contains(u, "@") && !strings.Contains(u, "\\") {
userName = fmt.Sprintf("%s@%s", u, domainName)
}

return &GlobalCommand{
DomainName: domainName,
UserName: userName,
Password: password,
PassHash: passHash,
GssApiLogin: gssapi,
BaseDN: baseDN,
SSLConn: ssl,
Export: export,
}, nil
}
2 changes: 2 additions & 0 deletions conn/conn.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build !windows

package conn

import (
Expand Down
94 changes: 94 additions & 0 deletions conn/conn_win.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//go:build windows

package conn

import (
"crypto/tls"
"fmt"
"github.com/go-ldap/ldap/v3"
"github.com/go-ldap/ldap/v3/gssapi"
"goLdapTools/cli/global"
"goLdapTools/log"
"strings"
)

type Connector struct {
Conn *ldap.Conn
Config *global.GlobalCommand
}

func LdapConnect(globalCommand *global.GlobalCommand) (*Connector, error) {
var conn *ldap.Conn
var sspiConn *gssapi.SSPIClient
var err error

if globalCommand.GssApiLogin != "" {
sspiConn, err = gssapi.NewSSPIClient()
if err != nil {
return nil, err
}
}

//非加密连接
if !globalCommand.SSLConn {
log.PrintInfof("Trying to connecting server Ldap://%s:389", globalCommand.DomainName)
conn, err = ldap.Dial("tcp", fmt.Sprintf("%s:389", globalCommand.DomainName))
if err != nil {
return nil, err
}
} else {
// SSL连接
log.PrintInfof("Trying to connecting server Ldaps://%s:636", globalCommand.DomainName)
conn, err = ldap.DialTLS("tcp", fmt.Sprintf("%s:636", globalCommand.DomainName),
&tls.Config{InsecureSkipVerify: true})
if err != nil {
return nil, err
}
}

if globalCommand.PassHash == "" && globalCommand.Password != "" {
log.PrintInfof("Trying to binding server with password")
log.PrintInfof("Domain Name: %s", globalCommand.DomainName)
log.PrintInfof("username: %s", globalCommand.UserName)
log.PrintInfof("password: %s", globalCommand.Password)

err = conn.Bind(globalCommand.UserName, globalCommand.Password)
if err != nil {
return nil, err
}
} else if globalCommand.UserName != "" && globalCommand.GssApiLogin == "" {
req := &ldap.NTLMBindRequest{
Domain: globalCommand.DomainName,
Username: strings.Split(globalCommand.UserName, "@")[0],
Hash: globalCommand.PassHash,
AllowEmptyPassword: true,
Controls: nil,
}

log.PrintInfof("Trying to binding server with hash")
log.PrintInfof("username: %s", strings.Split(globalCommand.UserName, "@")[0])
log.PrintInfof("pass-hash: %s", globalCommand.PassHash)

_, err = conn.NTLMChallengeBind(req)
if err != nil {
return nil, err
}
} else {
log.PrintInfo("Trying to binging server with current token")

err = conn.GSSAPIBind(sspiConn, fmt.Sprintf("ldap/%s", globalCommand.GssApiLogin), "")
if err != nil {
return nil, err
}
}

log.PrintSuccess("Binding success")

return &Connector{Conn: conn, Config: globalCommand}, nil
}

func (conn *Connector) DoModify(dn string, control []ldap.Control, attrType string, attrVals []string) error {
modifyReq := ldap.NewModifyRequest(dn, control)
modifyReq.Replace(attrType, attrVals)
return conn.Conn.Modify(modifyReq)
}
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ module goLdapTools
go 1.20

require (
github.com/go-asn1-ber/asn1-ber v1.5.4
github.com/go-ldap/ldap/v3 v3.4.5
github.com/gookit/color v1.5.3
github.com/gookit/slog v0.5.2
github.com/spf13/cobra v1.7.0
golang.org/x/text v0.10.0
)

require (
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 // indirect
github.com/gookit/goutil v0.6.10 // indirect
github.com/gookit/gsr v0.0.8 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
Expand All @@ -21,5 +23,4 @@ require (
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.9.0 // indirect
golang.org/x/text v0.10.0 // indirect
)

0 comments on commit dac8a91

Please sign in to comment.