-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 81f397f
Showing
13 changed files
with
2,313 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
|
||
package goddi | ||
|
||
import ( | ||
"crypto/tls" | ||
"fmt" | ||
"github.com/go-ldap/ldap/v3" | ||
"log" | ||
) | ||
|
||
// LdapInfo contains connection info | ||
type LdapInfo struct { | ||
LdapServer string | ||
LdapIP string | ||
LdapPort uint16 | ||
LdapTLSPort uint16 | ||
User string | ||
Usergpp string | ||
Hash string | ||
Pass string | ||
Domain string | ||
Conn *ldap.Conn | ||
Unsafe bool | ||
StartTLS bool | ||
} | ||
|
||
func dial(li *LdapInfo) { | ||
|
||
if li.Unsafe { | ||
|
||
fmt.Printf("[i] Try to connect '%s'\n", li.LdapServer) | ||
conn, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", li.LdapServer, li.LdapPort)) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
//fmt.Printf("[c] connected successfully!\n") | ||
li.Conn = conn | ||
|
||
} else if li.StartTLS { | ||
|
||
fmt.Printf("[c] Begin PLAINTEXT LDAP connection to '%s' (%s)...\n", li.LdapServer, li.LdapIP) | ||
conn, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", li.LdapServer, li.LdapPort)) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
fmt.Printf("[c] 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}) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
fmt.Printf("[c] Upgrade to StartTLS connection successful...\n") | ||
li.Conn = conn | ||
|
||
} else { | ||
|
||
fmt.Printf("[c] Begin LDAP TLS connection to '%s' (%s)...\n", li.LdapServer, li.LdapIP) | ||
config := &tls.Config{ServerName: li.LdapServer} | ||
conn, err := ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", li.LdapServer, li.LdapTLSPort), config) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
fmt.Printf("[c] LDAP TLS connection to '%s' (%s) successful...\n", li.LdapServer, li.LdapIP) | ||
li.Conn = conn | ||
} | ||
} | ||
|
||
// Connect authenticated bind to ldap connection | ||
func Connect(li *LdapInfo,ishash bool) { | ||
|
||
dial(li) | ||
if ishash { | ||
//err := li.Conn.Bind(li.User, li.Pass) | ||
fmt.Printf("[c] Auth Domain: "+li.Domain+"\n") | ||
fmt.Printf("[c] Auth user: "+li.User+"\n") | ||
fmt.Printf("[c] Auth hash: "+li.Hash+"\n") | ||
|
||
err := li.Conn.NTLMBindWithHash(li.Domain,li.User, li.Hash) | ||
//fmt.Printf(li.Domain+li.User+li.Ntlm+"\n") | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} else { | ||
fmt.Printf("[c] Auth Domain: "+li.Domain+"\n") | ||
fmt.Printf("[c] Auth user: "+li.User+"\n") | ||
fmt.Printf("[c] Auth Pass: "+li.Pass+"\n") | ||
err := li.Conn.Bind(li.User, li.Pass) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
fmt.Printf("[c] connected successfully,try to dump domain info\n") | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
// Helper functions | ||
|
||
package goddi | ||
|
||
import ( | ||
"crypto/aes" | ||
"crypto/cipher" | ||
"encoding/base64" | ||
"encoding/csv" | ||
"encoding/hex" | ||
"log" | ||
"math" | ||
"os" | ||
"path/filepath" | ||
"strconv" | ||
"strings" | ||
"time" | ||
) | ||
|
||
// WindowsEpochFiletime January 1, 1601 UTC (coordinate universal time) | ||
const WindowsEpochFiletime int64 = 116444736000000000 | ||
|
||
// Writing output to csv | ||
// Reference: https://golangcode.com/write-data-to-a-csv-file/ | ||
func writeCSV(filename string, data [][]string) { | ||
|
||
cwd := GetCWD() | ||
csvdir := cwd + "/csv/" | ||
if _, err := os.Stat(csvdir); os.IsNotExist(err) { | ||
os.Mkdir(csvdir, os.ModePerm) | ||
} | ||
|
||
file, err := os.Create(csvdir + filename + ".csv") | ||
|
||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
defer file.Close() | ||
|
||
writer := csv.NewWriter(file) | ||
defer writer.Flush() | ||
|
||
for _, value := range data { | ||
err := writer.Write(value) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
} | ||
|
||
// Get sub directories | ||
func getSubDirs(drive string) []string { | ||
|
||
file, err := os.Open(drive) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
defer file.Close() | ||
|
||
list, _ := file.Readdirnames(0) | ||
return list | ||
} | ||
|
||
// GetCWD returns executable's current directory | ||
func GetCWD() string { | ||
|
||
exe, err := os.Executable() | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
cwd := filepath.Dir(exe) | ||
return cwd | ||
} | ||
|
||
// Helper function to decrypt GPP cpassword | ||
// References: | ||
// https://github.com/leonteale/pentestpackage/blob/master/Gpprefdecrypt.py | ||
// https://github.com/PowerShellMafia/PowerSploit/blob/master/Exfiltration/Get-GPPPassword.ps1 | ||
func decrypt(cpassword string) string { | ||
|
||
// 32 byte AES key | ||
// http://msdn.microsoft.com/en-us/library/2c15cbf0-f086-4c74-8b70-1f2fa45dd4be%28v=PROT.13%29#endNote2 | ||
key := "4e9906e8fcb66cc9faf49310620ffee8f496e806cc057990209b09a433b66c1b" | ||
|
||
// hex decode the key | ||
decoded, _ := hex.DecodeString(key) | ||
block, err := aes.NewCipher(decoded) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
// add padding to base64 cpassword if necessary | ||
m := len(cpassword) % 4 | ||
if m != 0 { | ||
cpassword += strings.Repeat("=", 4-m) | ||
} | ||
|
||
// base64 decode cpassword | ||
decodedpassword, errs := base64.StdEncoding.DecodeString(cpassword) | ||
if errs != nil { | ||
log.Fatal(errs) | ||
} | ||
|
||
if len(decodedpassword) < aes.BlockSize { | ||
log.Fatal("Cpassword block size too short...\n") | ||
} | ||
|
||
var iv = []byte{00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00} | ||
|
||
if (len(decodedpassword) % aes.BlockSize) != 0 { | ||
log.Fatal("Blocksize must be multiple of decoded message length...\n") | ||
} | ||
|
||
cbc := cipher.NewCBCDecrypter(block, iv) | ||
cbc.CryptBlocks(decodedpassword, decodedpassword) | ||
|
||
// remove the padding at the end of password | ||
length := len(decodedpassword) | ||
unpadding := int(decodedpassword[length-1]) | ||
clear := decodedpassword[:(length - unpadding)] | ||
|
||
return string(clear) | ||
} | ||
|
||
// Converts ldap password age | ||
func convertPwdAge(pwdage string) string { | ||
|
||
f, _ := strconv.ParseFloat((strings.Replace(pwdage, "-", "", -1)), 64) | ||
age := ((f / (60 * 10000000)) / 60) / 24 | ||
flr := math.Floor(age) | ||
s := strconv.Itoa(int(flr)) | ||
|
||
return s | ||
} | ||
|
||
// Convers ldap lockout | ||
func convertLockout(lockout string) string { | ||
|
||
i, _ := strconv.Atoi(strings.Replace(lockout, "-", "", -1)) | ||
age := i / (60 * 10000000) | ||
s := strconv.Itoa(age) | ||
|
||
return s | ||
} | ||
|
||
func ConvertLDAPTime(t int) time.Time { | ||
LDAPtime := t | ||
winSecs := LDAPtime / 10000000 | ||
timeStamp := winSecs - 11644473600 | ||
return time.Unix(int64(timeStamp), 0) | ||
} | ||
|
||
func wordLE(arr []byte, index int) byte { | ||
//wordLE([4 0 1 0 5 240 0 0 178 3 0 0 0 0 2 88 0 0 0 0 241 73 56 0 192 168 200 207],2) | ||
find := int(arr[index+1])*256 + int(arr[index]) | ||
return byte(find) | ||
} | ||
|
||
func processDnsRecordAttribute(record []byte) []byte { | ||
//record=[4 0 1 0 5 240 0 0 178 3 0 0 0 0 2 88 0 0 0 0 241 73 56 0 192 168 200 207] | ||
var rdatatype = wordLE(record, 2) | ||
if rdatatype == 1 { | ||
a := []byte{record[24], record[25], record[26], record[27]} | ||
return a | ||
} | ||
return nil | ||
} | ||
|
||
// https://stackoverflow.com/questions/24836044/case-insensitive-string-search-in-golang | ||
func caseInsensitiveContains(s, substr string) bool { | ||
return strings.Contains(strings.ToUpper(s), strings.ToUpper(substr)) | ||
} | ||
|
||
// ValidateIPHostname parses and returns hostname and ip for dc | ||
/* | ||
func ValidateIPHostname(ldapServer string, domain string) (string, string) { | ||
var ldapIP string | ||
//ldapServer=192.168.129.10 | ||
//ParseIP=192.168.129.10 | ||
if net.ParseIP(ldapServer) != nil { | ||
ldapIP = ldapServer | ||
hostnames, err := net.LookupAddr(ldapServer) | ||
//LookupAddr查找dns解析记录 | ||
//hostnames=dc1.redteam.lab | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
for _, host := range hostnames { | ||
//host=dc1.redteam.lab | ||
//domain=redteam.lab | ||
if caseInsensitiveContains(host, domain) { | ||
ldapServer = strings.Trim(host, ".") | ||
//ldapServer=redteam.lab | ||
} | ||
} | ||
} else { | ||
//ldapServer=dc1.redteam.lab | ||
addr, err := net.LookupIP(ldapServer) | ||
//net.LookupIP寻找A记录 | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
ldapIP = addr[0].String() | ||
} | ||
return ldapServer, ldapIP | ||
} | ||
*/ |
Oops, something went wrong.