@@ -46,6 +46,10 @@ func main() {
46
46
inputname := flag .String ("input" , "" , "File to read usernames from, uses stdin if not supplied" )
47
47
outputname := flag .String ("output" , "" , "File to write detected usernames to, uses stdout if not supplied" )
48
48
49
+ // evasive maneuvers
50
+ throttle := flag .Int ("throttle" , 0 , "Only do a request every N ms, 0 to disable" )
51
+ maxrequests := flag .Int ("maxrequests" , 0 , "Disconnect and reconnect a connection after n requests, 0 to disable" )
52
+
49
53
maxservers := flag .Int ("maxservers" , 8 , "Maximum amount of servers to run in parallel" )
50
54
maxstrategy := flag .String ("maxstrategy" , "fastest" , "How to select servers if more are found than wanted (fastest, random)" )
51
55
parallel := flag .Int ("parallel" , 8 , "How many connections per server to run in parallel" )
@@ -242,68 +246,92 @@ func main() {
242
246
243
247
var jobs sync.WaitGroup
244
248
249
+ var throttleTimer * time.Ticker
250
+ if * throttle > 0 {
251
+ throttleTimer = time .NewTicker (time .Millisecond * time .Duration (* throttle ))
252
+ }
253
+
245
254
jobs .Add (* parallel * len (servers ))
246
255
for _ , server := range servers {
247
256
for i := 0 ; i < * parallel ; i ++ {
248
257
go func (server string ) {
249
- connectMutex .Lock ()
250
-
251
- if connectError != nil {
252
- connectMutex .Unlock ()
253
- jobs .Done ()
254
- return
255
- }
258
+ var requests int
259
+ reconnectLoop:
260
+ for {
261
+ connectMutex .Lock ()
262
+ if connectError != nil {
263
+ connectMutex .Unlock ()
264
+ jobs .Done ()
265
+ return
266
+ }
256
267
257
- var conn * ldap.Conn
258
- switch tlsmode {
259
- case NoTLS :
260
- conn , err = ldap .Dial ("tcp" , fmt .Sprintf ("%s:%d" , server , * port ))
261
- case StartTLS :
262
- conn , err = ldap .Dial ("tcp" , fmt .Sprintf ("%s:%d" , server , * port ))
263
- if err == nil {
264
- err = conn .StartTLS (& tls.Config {ServerName : server })
268
+ var conn * ldap.Conn
269
+ switch tlsmode {
270
+ case NoTLS :
271
+ conn , err = ldap .Dial ("tcp" , fmt .Sprintf ("%s:%d" , server , * port ))
272
+ case StartTLS :
273
+ conn , err = ldap .Dial ("tcp" , fmt .Sprintf ("%s:%d" , server , * port ))
274
+ if err == nil {
275
+ err = conn .StartTLS (& tls.Config {ServerName : server })
276
+ }
277
+ case TLS :
278
+ config := & tls.Config {
279
+ ServerName : server ,
280
+ InsecureSkipVerify : * ignoreCert ,
281
+ }
282
+ conn , err = ldap .DialTLS ("tcp" , fmt .Sprintf ("%s:%d" , server , * port ), config )
265
283
}
266
- case TLS :
267
- config := & tls.Config {
268
- ServerName : server ,
269
- InsecureSkipVerify : * ignoreCert ,
284
+
285
+ if err != nil {
286
+ log .Printf ("Problem connecting to LDAP %v server: %v" , server , err )
287
+ connectError = err
288
+ jobs .Done ()
289
+ connectMutex .Unlock ()
290
+ return
270
291
}
271
- conn , err = ldap .DialTLS ("tcp" , fmt .Sprintf ("%s:%d" , server , * port ), config )
272
- }
273
292
274
- if err != nil {
275
- log .Printf ("Problem connecting to LDAP %v server: %v" , server , err )
276
- connectError = err
277
- jobs .Done ()
278
293
connectMutex .Unlock ()
279
- return
280
- }
281
294
282
- connectMutex .Unlock ()
283
-
284
- for username := range inputqueue {
285
- request := ldap .NewSearchRequest (
286
- "" , // The base dn to search
287
- ldap .ScopeBaseObject , ldap .NeverDerefAliases , 0 , 0 , false ,
288
- fmt .Sprintf ("(&(NtVer=\x06 \x00 \x00 \x00 )(AAC=\x10 \x00 \x00 \x00 )(User=" + username + "))" ), // The filter to apply
289
- []string {"NetLogon" }, // A list attributes to retrieve
290
- nil ,
291
- )
292
- response , err := conn .Search (request )
293
- if err != nil {
294
- if v , ok := err .(* ldap.Error ); ok && v .ResultCode == 201 {
295
+ for username := range inputqueue {
296
+ // do throttling if needed
297
+ if throttleTimer != nil {
298
+ <- throttleTimer .C
299
+ }
300
+
301
+ request := ldap .NewSearchRequest (
302
+ "" , // The base dn to search
303
+ ldap .ScopeBaseObject , ldap .NeverDerefAliases , 0 , 0 , false ,
304
+ fmt .Sprintf ("(&(NtVer=\x06 \x00 \x00 \x00 )(AAC=\x10 \x00 \x00 \x00 )(User=" + username + "))" ), // The filter to apply
305
+ []string {"NetLogon" }, // A list attributes to retrieve
306
+ nil ,
307
+ )
308
+ response , err := conn .Search (request )
309
+ if err != nil {
310
+ if v , ok := err .(* ldap.Error ); ok && v .ResultCode == 201 {
311
+ continue
312
+ }
313
+ log .Printf ("failed to execute search request: %v" , err )
295
314
continue
296
315
}
297
- log .Printf ("failed to execute search request: %v" , err )
298
- continue
299
- }
300
316
301
- // Did we catch something?
302
- res := response .Entries [0 ].Attributes [0 ].ByteValues [0 ]
303
- if len (res ) > 2 && res [0 ] == 0x17 && res [1 ] == 00 {
304
- outputqueue <- username
317
+ // Did we catch something?
318
+ res := response .Entries [0 ].Attributes [0 ].ByteValues [0 ]
319
+ if len (res ) > 2 && res [0 ] == 0x17 && res [1 ] == 00 {
320
+ outputqueue <- username
321
+ }
322
+
323
+ // Should we start a new connection to avoid detection
324
+ requests ++
325
+ if * maxrequests != 0 && requests == * maxrequests {
326
+ requests = 0
327
+ conn .Close ()
328
+ continue reconnectLoop
329
+ }
305
330
}
331
+ // No more input in channel, bye bye from this worker
332
+ break
306
333
}
334
+
307
335
jobs .Done ()
308
336
}(server )
309
337
}
0 commit comments