-
Notifications
You must be signed in to change notification settings - Fork 6
/
honeycred.go
157 lines (135 loc) · 4.1 KB
/
honeycred.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
Honeycred is used to stage credentials into a live running process to be used
as bait to detect credential abuse within Windows domains.
NOTE: Most applications that inject honey credentials terminate after making a
call to advapi32.CreateProcessWithLogonW. Unfortunately, after MS16-137, this
stopped being an option. This patch more aggressively cleans up credentials
from lsass.
To avoid credentials from being cleaned up, this application forks and runs
silently.
*/
package main
import (
"flag"
"strings"
"os"
"syscall"
"unsafe"
"runtime"
)
var (
advapi32 = syscall.NewLazyDLL("advapi32.dll")
procCreateProcessWithLogonW = advapi32.NewProc("CreateProcessWithLogonW")
)
const (
// Use only network credentials for login
LOGON_NETCREDENTIALS_ONLY uint32 = 0x00000002
// The new process does not inherit the error mode of the calling process.
// Instead, CreateProcessWithLogonW gives the new process the current
// default error mode.
CREATE_DEFAULT_ERROR_MODE uint32 = 0x04000000
// Flag parameter that indicates to use the value set in ShowWindow
STARTF_USESHOWWINDOW = 0x00000001
// Tell windows not to show the window
ShowWindow = 0
)
// CreateProcessWithLogonW is a wrapper around the matching advapi32.dll
// function. This allows the running process to launch a process as a
// different user. It can also be used to stage credentials.
func CreateProcessWithLogonW(
username *uint16,
domain *uint16,
password *uint16,
logonFlags uint32,
applicationName *uint16,
commandLine *uint16,
creationFlags uint32,
environment *uint16,
currentDirectory *uint16,
startupInfo *syscall.StartupInfo,
processInformation *syscall.ProcessInformation) error {
r1, _, e1 := procCreateProcessWithLogonW.Call(
uintptr(unsafe.Pointer(username)),
uintptr(unsafe.Pointer(domain)),
uintptr(unsafe.Pointer(password)),
uintptr(logonFlags),
uintptr(unsafe.Pointer(applicationName)),
uintptr(unsafe.Pointer(commandLine)),
uintptr(creationFlags),
uintptr(unsafe.Pointer(environment)), // env
uintptr(unsafe.Pointer(currentDirectory)),
uintptr(unsafe.Pointer(startupInfo)),
uintptr(unsafe.Pointer(processInformation)))
runtime.KeepAlive(username)
runtime.KeepAlive(domain)
runtime.KeepAlive(password)
runtime.KeepAlive(applicationName)
runtime.KeepAlive(commandLine)
runtime.KeepAlive(environment)
runtime.KeepAlive(currentDirectory)
runtime.KeepAlive(startupInfo)
runtime.KeepAlive(processInformation)
if int(r1) == 0 {
return os.NewSyscallError("CreateProcessWithLogonW", e1)
}
return nil
}
// ListToEnvironmentBlock converts a list of string pointers to a Windows
// environment block.
func ListToEnvironmentBlock(list *[]string) *uint16 {
if list == nil {
return nil
}
size := 1
for _, v := range *list {
size += len(syscall.StringToUTF16(v))
}
result := make([]uint16, size)
tail := 0
for _, v := range *list {
uline := syscall.StringToUTF16(v)
copy(result[tail:], uline)
tail += len(uline)
}
result[tail] = 0
return &result[0]
}
func main() {
user := flag.String("u", `contoso.com\svc_dlp`, "")
pw := flag.String("pw", `foobar9000`, "")
path := flag.String("path", `.\agent.exe`, "")
flag.Parse()
userSplit := strings.Split(*user, `\`)
var logonDomain string
if ( len(userSplit) > 1 ) {
logonDomain = userSplit[0]
} else {
logonDomain = ""
}
user = &userSplit[len(userSplit)-1]
username := syscall.StringToUTF16Ptr(*user)
domain := syscall.StringToUTF16Ptr(logonDomain)
password := syscall.StringToUTF16Ptr(*pw)
logonFlags := LOGON_NETCREDENTIALS_ONLY
applicationName := syscall.StringToUTF16Ptr(*path)
commandLine := syscall.StringToUTF16Ptr(``)
creationFlags := CREATE_DEFAULT_ERROR_MODE
environment := ListToEnvironmentBlock(nil)
currentDirectory := syscall.StringToUTF16Ptr(`c:\`)
startupInfo := &syscall.StartupInfo{}
startupInfo.ShowWindow = ShowWindow
startupInfo.Flags = startupInfo.Flags | STARTF_USESHOWWINDOW
processInfo := &syscall.ProcessInformation{}
_ = CreateProcessWithLogonW(
username,
domain,
password,
logonFlags,
applicationName,
commandLine,
creationFlags,
environment,
currentDirectory,
startupInfo,
processInfo)
}