Skip to content
This repository was archived by the owner on Sep 16, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@ Based on work from Scott Sutherland (@\_nullbind), Antti Rantasaari, Eric Gruber

## Install

Use the executables in the releases section. If you want to build it yourself, make sure that your go environment is setup according to the <a href="https://golang.org/doc/code.html">Go setup doc</a>. The goddi package also uses the below package.
`go install github.com/swarley7/goddi`

go get gopkg.in/ldap.v2
Or,

```
git clone https://github.com/swarley7/goddi.git
cd goddi
go install
```

### Windows

Expand Down
28 changes: 15 additions & 13 deletions ddi/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,19 @@ import (

// LdapInfo contains connection info
type LdapInfo struct {
LdapServer string
LdapIP string
LdapPort uint16
LdapTLSPort uint16
User string
Usergpp string
Pass string
Domain string
Conn *ldap.Conn
Unsafe bool
StartTLS bool
LdapServer string
LdapIP string
LdapPort uint16
LdapTLSPort uint16
User string
Usergpp string
Pass string
Domain string
Conn *ldap.Conn
Unsafe bool
StartTLS bool
ForceInsecureTLS bool
MntPoint string
}

func dial(li *LdapInfo) {
Expand All @@ -48,7 +50,7 @@ func dial(li *LdapInfo) {

fmt.Printf("[i] PLAINTEXT LDAP connection to '%s' (%s) successful...\n[i] Upgrade to StartTLS connection...\n", li.LdapServer, li.LdapIP)

err = conn.StartTLS(&tls.Config{ServerName: li.LdapServer})
err = conn.StartTLS(&tls.Config{ServerName: li.LdapServer, InsecureSkipVerify: li.ForceInsecureTLS})
if err != nil {
log.Fatal(err)
}
Expand All @@ -58,7 +60,7 @@ func dial(li *LdapInfo) {
} else {

fmt.Printf("[i] Begin LDAP TLS connection to '%s' (%s)...\n", li.LdapServer, li.LdapIP)
config := &tls.Config{ServerName: li.LdapServer}
config := &tls.Config{ServerName: li.LdapServer, InsecureSkipVerify: li.ForceInsecureTLS}
conn, err := ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", li.LdapServer, li.LdapTLSPort), config)
if err != nil {
log.Fatal(err)
Expand Down
7 changes: 3 additions & 4 deletions ddi/gpp_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
// GetGPP grabs all GPP passwords
// Reference: Scott Sutherland (@_nullbind), Chris Campbell (@obscuresec)
// https://github.com/PowerShellMafia/PowerSploit/blob/master/Exfiltration/Get-GPPPassword.ps1
func GetGPP(conn *ldap.Conn, baseDN string, dc string, user string, pass string) {
func GetGPP(conn *ldap.Conn, baseDN string, dc string, user string, pass string, mntpoint string) {

fmt.Printf("[i] GPP enumeration starting. This can take a bit...\n")

Expand Down Expand Up @@ -43,7 +43,6 @@ func GetGPP(conn *ldap.Conn, baseDN string, dc string, user string, pass string)

csv := [][]string{}
csv = append(csv, attributes)
mntpoint := "/mnt/goddi/"

existMount(mntpoint)
checkMount(mntpoint)
Expand Down Expand Up @@ -101,15 +100,15 @@ func existMount(mntpoint string) {
// if /mnt/goddi does not exist, mkdir the directory
if _, err := os.Stat(mntpoint); os.IsNotExist(err) {
os.Mkdir(mntpoint, os.ModePerm)
fmt.Println("[i] /mnt/goddi mount point created...\n")
fmt.Printf("[i] %s mount point created...\n", mntpoint)
}
}

// Check if mount point is mounted
func checkMount(mntpoint string) {

if len(getSubDirs(mntpoint)) != 0 {
fmt.Printf("[i] /mnt/goddi mounted, unmounting now...\n")
fmt.Printf("[i] %s mounted, unmounting now...\n", mntpoint)
_, err := removeUnix(mntpoint)
if err != nil {
log.Fatal(err)
Expand Down
3 changes: 2 additions & 1 deletion ddi/gpp_win.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package goddi
Expand All @@ -14,7 +15,7 @@ import (
// GetGPP grabs all GPP passwords
// Reference: Scott Sutherland (@_nullbind), Chris Campbell (@obscuresec)
// https://github.com/PowerShellMafia/PowerSploit/blob/master/Exfiltration/Get-GPPPassword.ps1
func GetGPP(conn *ldap.Conn, domain string, dc string, user string, pass string) {
func GetGPP(conn *ldap.Conn, domain string, dc string, user string, pass string, _ string) { //Mountpoint not needed here cos windows, lol

fmt.Printf("[i] GPP enumeration starting. This can take a bit...\n")

Expand Down
7 changes: 7 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module github.com/swarley7/goddi

go 1.18

require gopkg.in/ldap.v2 v2.5.1

require gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/ldap.v2 v2.5.1 h1:wiu0okdNfjlBzg6UWvd1Hn8Y+Ux17/u/4nlk4CQr6tU=
gopkg.in/ldap.v2 v2.5.1/go.mod h1:oI0cpe/D7HRtBQl8aTg+ZmzFUAvu4lsv3eLXMLGFxWk=
Binary file added goddi
Binary file not shown.
84 changes: 60 additions & 24 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,44 +14,80 @@ import (
"flag"
"fmt"
"log"
"os"
"strings"
"time"

"github.com/NetSPI/goddi/ddi"
goddi "github.com/swarley7/goddi/ddi"
)

func main() {
ldapServer := flag.String("dc", "", "Hostname of DC to connect to. ex. -dc=\"dc.test.local\"")
ldapIP := flag.String("dc-ip", "", "Optional: IP address of DC to connect to (useful if proxying without DNS magic)")
domain := flag.String("domain", "", "Domain, ex. -domain=\"test.local\"")
user := flag.String("username", "", "Username to connect with, ex. -username=\"testuser@example.org\"")
pass := flag.String("password", "", "Password to connect with, ex. -password=\"testpass!\"")
startTLS := flag.Bool("startTLS", false, "Use StartTLS on 389. Default is TLS on 636")
unsafe := flag.Bool("unsafe", false, "Use for testing with plaintext connection")
forceInsecureTLS := flag.Bool("insecure", false, "Ignore TLS errors (e.g., self-signed certificates)")
mntpoint := flag.String("mountpoint", "", "Mount point to use for gpp_password")
basednArg := flag.String("basedn", "", "Base DN to use. If set, this overrides the domain-based calculation.")

ldapServer := flag.String("dc", "", "DC to connect to, use IP or full hostname ex. -dc=\"dc.test.local\"")
domain := flag.String("domain", "", "domain ex. -domain=\"test.local\"")
user := flag.String("username", "", "username to connect with ex. -username=\"testuser\"")
pass := flag.String("password", "", "password to connect with ex. -password=\"testpass!\"")
startTLS := flag.Bool("startTLS", false, "Use for StartTLS on 389. Default is TLS on 636")
unsafe := flag.Bool("unsafe", false, "Use for testing and plaintext connection")
flag.Parse()

if len(*ldapServer) == 0 || len(*domain) == 0 || len(*user) == 0 || len(*pass) == 0 {

dir, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
if *mntpoint == "" {
*mntpoint = dir + "/goddi_mount"
}
if !strings.HasSuffix(*mntpoint, "/") {
*mntpoint = *mntpoint + "/"
}

if (len(*ldapServer) == 0 && len(*ldapIP) == 0) || len(*domain) == 0 || len(*user) == 0 || len(*pass) == 0 {
flag.PrintDefaults()
log.Fatal("[ERROR] Provide username, password, DC, and domain!\n")
}
if *ldapIP == "" {
*ldapServer, *ldapIP = goddi.ValidateIPHostname(*ldapServer, *domain)
} else {
ldapServer = ldapIP
}

var ldapIP string
*ldapServer, ldapIP = goddi.ValidateIPHostname(*ldapServer, *domain)
// If -basedn is set, we will use that. Otherwise, we require domain and derive baseDN.
var baseDN string
if *basednArg != "" {
baseDN = *basednArg
} else {
if len(*domain) == 0 {
flag.PrintDefaults()
log.Fatal("[ERROR] Provide either a valid domain (-domain) or a custom baseDN (-basedn)!\n")
}
baseDN = "dc=" + strings.Replace(*domain, ".", ",dc=", -1)
}

baseDN := "dc=" + strings.Replace(*domain, ".", ",dc=", -1)
username := *user + "@" + *domain
username := *user

li := &goddi.LdapInfo{
LdapServer: *ldapServer,
LdapIP: ldapIP,
LdapPort: uint16(389),
LdapTLSPort: uint16(636),
User: username,
Usergpp: *user,
Pass: *pass,
Domain: *domain,
Unsafe: *unsafe,
StartTLS: *startTLS}
LdapServer: *ldapServer,
LdapIP: *ldapIP,
LdapPort: uint16(389),
LdapTLSPort: uint16(636),
User: username,
Usergpp: *user,
Pass: *pass,
Domain: *domain,
Unsafe: *unsafe,
StartTLS: *startTLS,
ForceInsecureTLS: *forceInsecureTLS,
MntPoint: *mntpoint,
}
//fmt.Printf("[i] basedn: %s\n", baseDN)
//fmt.Printf("[i] user: %s\n", username)


goddi.Connect(li)
defer li.Conn.Close()
Expand All @@ -78,9 +114,9 @@ func main() {
goddi.GetFSMORoles(li.Conn, baseDN)
goddi.GetSPNs(li.Conn, baseDN)
goddi.GetLAPS(li.Conn, baseDN)
goddi.GetGPP(li.Conn, li.Domain, li.LdapServer, li.Usergpp, li.Pass)
goddi.GetGPP(li.Conn, li.Domain, li.LdapServer, li.Usergpp, li.Pass, li.MntPoint)
stop := time.Since(start)

cwd := goddi.GetCWD()
fmt.Printf("[i] CSVs written to 'csv' directory in %s\n[i] Execution took %s...\n[i] Exiting...\n", cwd, stop)
}
}