@@ -204,6 +204,229 @@ func TestMongoDBBrute(t *testing.T) {
204204 t .Logf ("mongodb brute: user=%s pass=%s" , result .Username , result .Password )
205205}
206206
207+ // ── Memcached ──────────────────────────────────────────────────
208+
209+ func TestMemcachedUnauthorized (t * testing.T ) {
210+ session := testSession ()
211+ info := hostInfo (testHost , 11211 )
212+ plugin := services .NewMemcachedPlugin ()
213+
214+ ctx , cancel := context .WithTimeout (context .Background (), 15 * time .Second )
215+ defer cancel ()
216+
217+ result := plugin .Scan (ctx , info , session )
218+ if result == nil {
219+ t .Fatal ("result is nil" )
220+ }
221+ if ! result .Success {
222+ t .Fatalf ("expected memcached to succeed, got error: %v" , result .Error )
223+ }
224+ t .Logf ("memcached: type=%s banner=%s" , result .Type , result .Banner )
225+ }
226+
227+ // ── Elasticsearch ──────────────────────────────────────────────
228+
229+ func TestElasticsearchUnauthorized (t * testing.T ) {
230+ session := testSession ()
231+ info := hostInfo (testHost , 19200 )
232+ plugin := services .NewElasticsearchPlugin ()
233+
234+ ctx , cancel := context .WithTimeout (context .Background (), 15 * time .Second )
235+ defer cancel ()
236+
237+ result := plugin .Scan (ctx , info , session )
238+ if result == nil {
239+ t .Fatal ("result is nil" )
240+ }
241+ if ! result .Success {
242+ t .Fatalf ("expected elasticsearch to succeed, got error: %v" , result .Error )
243+ }
244+ t .Logf ("elasticsearch: type=%s vulinfo=%s" , result .Type , result .VulInfo )
245+ }
246+
247+ // ── MSSQL ──────────────────────────────────────────────────────
248+
249+ func TestMSSQLBrute (t * testing.T ) {
250+ session := testSession ()
251+ session .Config .Credentials .UserPassPairs = []config.CredentialPair {
252+ {Username : "sa" , Password : "wrong" },
253+ {Username : "sa" , Password : "MssqlTest123!" },
254+ }
255+ info := hostInfo (testHost , 11433 )
256+ plugin := services .NewMSSQLPlugin ()
257+
258+ ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
259+ defer cancel ()
260+
261+ result := plugin .Scan (ctx , info , session )
262+ if result == nil {
263+ t .Fatal ("result is nil" )
264+ }
265+ if ! result .Success {
266+ t .Fatalf ("expected mssql brute to succeed, got error: %v" , result .Error )
267+ }
268+ t .Logf ("mssql brute: user=%s pass=%s" , result .Username , result .Password )
269+ }
270+
271+ // ── RabbitMQ ───────────────────────────────────────────────────
272+
273+ func TestRabbitMQBrute (t * testing.T ) {
274+ session := testSession ()
275+ session .Config .Credentials .UserPassPairs = []config.CredentialPair {
276+ {Username : "admin" , Password : "wrong" },
277+ {Username : "admin" , Password : "rabbit123" },
278+ }
279+ info := hostInfo (testHost , 15672 )
280+ plugin := services .NewRabbitMQPlugin ()
281+
282+ ctx , cancel := context .WithTimeout (context .Background (), 15 * time .Second )
283+ defer cancel ()
284+
285+ result := plugin .Scan (ctx , info , session )
286+ if result == nil {
287+ t .Fatal ("result is nil" )
288+ }
289+ if ! result .Success {
290+ t .Fatalf ("expected rabbitmq brute to succeed, got error: %v" , result .Error )
291+ }
292+ t .Logf ("rabbitmq brute: user=%s pass=%s" , result .Username , result .Password )
293+ }
294+
295+ // ── MQTT ───────────────────────────────────────────────────────
296+
297+ func TestMQTTServiceDetect (t * testing.T ) {
298+ session := testSession ()
299+ info := hostInfo (testHost , 11883 )
300+ plugin := services .NewMQTTPlugin ()
301+
302+ ctx , cancel := context .WithTimeout (context .Background (), 15 * time .Second )
303+ defer cancel ()
304+
305+ result := plugin .Scan (ctx , info , session )
306+ if result == nil {
307+ t .Fatal ("result is nil" )
308+ }
309+ if ! result .Success {
310+ t .Fatalf ("expected mqtt service detect to succeed, got error: %v" , result .Error )
311+ }
312+ t .Logf ("mqtt: service=%s banner=%s" , result .Service , result .Banner )
313+ }
314+
315+ // ── SMB ────────────────────────────────────────────────────────
316+
317+ func TestSMBBrute (t * testing.T ) {
318+ t .Skip ("SMB requires port 445 which is reserved on WSL2" )
319+ }
320+
321+ // ── LDAP ───────────────────────────────────────────────────────
322+
323+ func TestLDAPBrute (t * testing.T ) {
324+ session := testSession ()
325+ session .Config .Credentials .UserPassPairs = []config.CredentialPair {
326+ {Username : "cn=admin,dc=test,dc=local" , Password : "wrong" },
327+ {Username : "cn=admin,dc=test,dc=local" , Password : "ldap123" },
328+ }
329+ info := hostInfo (testHost , 10389 )
330+ plugin := services .NewLDAPPlugin ()
331+
332+ ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
333+ defer cancel ()
334+
335+ result := plugin .Scan (ctx , info , session )
336+ if result == nil {
337+ t .Fatal ("result is nil" )
338+ }
339+ if ! result .Success {
340+ t .Fatalf ("expected ldap brute to succeed, got error: %v" , result .Error )
341+ }
342+ t .Logf ("ldap brute: user=%s pass=%s" , result .Username , result .Password )
343+ }
344+
345+ // ── Cassandra ──────────────────────────────────────────────────
346+
347+ func TestCassandraServiceDetect (t * testing.T ) {
348+ session := testSession ()
349+ session .Config .DisableBrute = true
350+ info := hostInfo (testHost , 19042 )
351+ plugin := services .NewCassandraPlugin ()
352+
353+ ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
354+ defer cancel ()
355+
356+ result := plugin .Scan (ctx , info , session )
357+ if result == nil {
358+ t .Fatal ("result is nil" )
359+ }
360+ if ! result .Success {
361+ t .Fatalf ("expected cassandra service detect to succeed, got error: %v" , result .Error )
362+ }
363+ t .Logf ("cassandra: type=%s banner=%s" , result .Type , result .Banner )
364+ }
365+
366+ // ── Neo4j ──────────────────────────────────────────────────────
367+
368+ func TestNeo4jBrute (t * testing.T ) {
369+ session := testSession ()
370+ session .Config .Credentials .UserPassPairs = []config.CredentialPair {
371+ {Username : "neo4j" , Password : "wrong" },
372+ {Username : "neo4j" , Password : "neo4jtest123" },
373+ }
374+ info := hostInfo (testHost , 17687 )
375+ plugin := services .NewNeo4jPlugin ()
376+
377+ ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
378+ defer cancel ()
379+
380+ result := plugin .Scan (ctx , info , session )
381+ if result == nil {
382+ t .Fatal ("result is nil" )
383+ }
384+ if ! result .Success {
385+ t .Fatalf ("expected neo4j brute to succeed, got error: %v" , result .Error )
386+ }
387+ t .Logf ("neo4j brute: user=%s pass=%s" , result .Username , result .Password )
388+ }
389+
390+ // ── Kafka ──────────────────────────────────────────────────────
391+
392+ func TestKafkaNoAuth (t * testing.T ) {
393+ session := testSession ()
394+ info := hostInfo (testHost , 19092 )
395+ plugin := services .NewKafkaPlugin ()
396+
397+ ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
398+ defer cancel ()
399+
400+ result := plugin .Scan (ctx , info , session )
401+ if result == nil {
402+ t .Fatal ("result is nil" )
403+ }
404+ if ! result .Success {
405+ t .Fatalf ("expected kafka to succeed, got error: %v" , result .Error )
406+ }
407+ t .Logf ("kafka: type=%s banner=%s" , result .Type , result .Banner )
408+ }
409+
410+ // ── SMTP ───────────────────────────────────────────────────────
411+
412+ func TestSMTPServiceDetect (t * testing.T ) {
413+ session := testSession ()
414+ info := hostInfo (testHost , 11025 )
415+ plugin := services .NewSMTPPlugin ()
416+
417+ ctx , cancel := context .WithTimeout (context .Background (), 15 * time .Second )
418+ defer cancel ()
419+
420+ result := plugin .Scan (ctx , info , session )
421+ if result == nil {
422+ t .Fatal ("result is nil" )
423+ }
424+ if ! result .Success {
425+ t .Fatalf ("expected smtp to succeed, got error: %v" , result .Error )
426+ }
427+ t .Logf ("smtp: type=%s banner=%s" , result .Type , result .Banner )
428+ }
429+
207430// ── 连接失败场景 ──────────────────────────────────────────────
208431
209432func TestRedisConnectionRefused (t * testing.T ) {
0 commit comments