├── .gitattributes ├── .gitignore ├── NsfocusTool.py ├── POST.py ├── RSAS.py ├── RSASConfig.ini ├── XLS.py └── baseConfig.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /NsfocusTool.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*-coding:UTF-8-*- 3 | from optparse import OptionParser 4 | from XLS import BalanceSheet 5 | from RSAS import RSAS 6 | from POST import POST 7 | from baseConfig import BASECONFIG 8 | 9 | 10 | def dealIPArray(ipList): 11 | realIPlist = [] 12 | for i in ipList: 13 | ipdict = { 14 | "ip_range": i.encode('utf-8'), 15 | "admin_id": "", 16 | "protocol": "", 17 | "port": "", 18 | "os": "", 19 | "user_name": "", 20 | "user_pwd": "", 21 | "ostpls": [], 22 | "apptpls": [], 23 | "dbtpls": [], 24 | "virttpls": [], 25 | "devtpls": [], 26 | "statustpls": "", 27 | "jhosts": [], 28 | "tpltype": "", 29 | "protect": "", 30 | "protect_level": "", 31 | "jump_ifuse": "", 32 | "host_ifsave": "", 33 | "oracle_ifuse": "", 34 | "ora_username": "", 35 | "ora_userpwd": "", 36 | "ora_port": "", 37 | "ora_usersid": "" 38 | } 39 | realIPlist.append(ipdict) 40 | return str(realIPlist) 41 | 42 | 43 | banner = """ 44 | mm m m"" mmmmmmm ""# 45 | #"m # mmm mm#mm mmm mmm m m mmm # mmm mmm # 46 | # #m # # " # #" "# #" " # # # " # #" "# #" "# # 47 | # # # \"""m # # # # # # \"""m # # # # # # 48 | # ## "mmm" # "#m#" "#mm" "mm"# "mmm" # "#m#" "#m#" "mm 49 | """ 50 | 51 | 52 | if __name__ == '__main__': 53 | print(banner) 54 | usage = "usage: %prog [options] arg" 55 | parser = OptionParser(usage=usage) 56 | parser.add_option("-f", "--file", dest="filename", 57 | help="The Excel Documention You Need To Process", metavar="FILE") 58 | (options, args) = parser.parse_args() 59 | if options.filename == None: 60 | raise SystemExit("[-] 使用方法: python NsfocusTool.py -f xls-Filename") 61 | xls = BalanceSheet('./{}'.format(options.filename)) 62 | mainConfig = BASECONFIG() 63 | RSAS_Obj = RSAS(USERNAME = mainConfig.getUSERNAME(), PASSWD = mainConfig.getPASSWD(), IP = mainConfig.getIP()) 64 | SYS_TIME = RSAS_Obj.getSysTimeAndDelyFiveMin() 65 | for i in range(1,xls.len()): 66 | ipName = xls.sheetName(i).encode('utf-8') 67 | ipList = '' 68 | for j in xls.IPTable(i): 69 | j = j + '\n' 70 | ipList += j.encode('utf-8') 71 | IPARRAY = dealIPArray(xls.IPTable(i)) 72 | POST_Obj = POST(CSRFTOKEN = RSAS_Obj.CSRFTOKEN, ipList= ipList, NAME= ipName,IPARRAY= IPARRAY, TIME = SYS_TIME,RSAS= RSAS_Obj) 73 | RSAS_Obj.RSASTask(POST_Obj.getPostData(), ipName) -------------------------------------------------------------------------------- /POST.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*-coding:UTF-8-*- 3 | import re 4 | import time 5 | from baseConfig import BASECONFIG 6 | 7 | 8 | class POST: 9 | def __init__(self, CSRFTOKEN, ipList, NAME, IPARRAY,TIME ,RSAS): 10 | self.CSRFTOKEN = CSRFTOKEN 11 | self.ipList = ipList 12 | self.NAME = NAME 13 | self.iparray = IPARRAY 14 | self.post_BASECONFFIG = BASECONFIG() 15 | self.TIME = TIME 16 | self.RSAS = RSAS 17 | self.DATA = { 18 | 'csrfmiddlewaretoken': self.CSRFTOKEN, 19 | 'vul_or_pwd':'vul', 20 | 'target':'ip', 21 | 'ipList': self.ipList, 22 | 'domainList':'', 23 | 'name':self.NAME, 24 | 'exec':'timing', 25 | 'exec_timing_date': self.TIME, 26 | 'exec_everyday_time':'00:00', 27 | 'exec_everyweek_day':'1', 28 | 'exec_everyweek_time':'00:00', 29 | 'exec_emonthdate_day':'1', 30 | 'exec_emonthdate_time':'00:00', 31 | 'exec_emonthweek_pre':'1', 32 | 'exec_emonthweek_day':'1', 33 | 'exec_emonthweek_time':'00:00', 34 | 'tpl':'0', 35 | 'login_ifuse':'yes', 36 | 'isguesspwd':'yes', 37 | 'exec_range':'', 38 | 'scan_pri':'2', 39 | 'taskdesc':'', 40 | 'report_type_html':'html', 41 | 'report_type_xls':'xls', 42 | 'report_content_sum':'sum', 43 | 'report_content_host':'host', 44 | 'report_tpl_sum':'1', 45 | 'report_tpl_host':'101', 46 | 'report_ifcreate':'yes', 47 | 'report_ifsent_type':'html', 48 | 'report_ifsent_email':'', 49 | 'port_strategy':'user', 50 | 'port_strategy_userports': self.post_BASECONFFIG.getPort(), 51 | 'port_speed':'3', 52 | 'port_tcp':'T', 53 | 'live':'on', 54 | 'live_icmp':'on', 55 | 'live_tcp':'on', 56 | 'live_tcp_ports':'21,22,23,25,80,443,445,139,3389,6000', 57 | 'scan_level':'3', 58 | 'timeout_plugins':'40', 59 | 'timeout_read':'5', 60 | 'alert_msg':'远程安全评估系统将对您的主机进行安全评估。', 61 | 'scan_oracle':'yes', 62 | 'encoding':'GBK', 63 | 'csrfmiddlewaretoken':self.CSRFTOKEN, 64 | 'pwd_smb':'yes', 65 | 'pwd_type_smb':'c', 66 | 'pwd_user_smb':'smb_user.default', 67 | 'pwd_pass_smb':'smb_pass.default', 68 | 'pwd_userpass_smb':'smb_userpass.default', 69 | 'pwd_rdp':'yes', 70 | 'pwd_type_rdp':'c', 71 | 'pwd_user_rdp':'tomcat_user.default', 72 | 'pwd_pass_rdp':'tomcat_pass.default', 73 | 'pwd_telnet':'yes', 74 | 'pwd_type_telnet':'s', 75 | 'pwd_userpass_telnet': self.RSAS.getWeakPassConfig(3), 76 | 'pwd_ftp':'yes', 77 | 'pwd_type_ftp':'s', 78 | 'pwd_userpass_ftp':self.RSAS.getWeakPassConfig(5), 79 | 'pwd_ssh':'yes', 80 | 'pwd_type_ssh':'s', 81 | 'pwd_userpass_ssh':self.RSAS.getWeakPassConfig(1), 82 | 'pwd_tomcat':'yes', 83 | 'pwd_type_tomcat':'c', 84 | 'pwd_user_tomcat':'tomcat_user.default', 85 | 'pwd_pass_tomcat':'tomcat_pass.default', 86 | 'pwd_mssql':'yes', 87 | 'pwd_type_mssql':'s', 88 | 'pwd_userpass_mssql':self.RSAS.getWeakPassConfig(6), 89 | 'pwd_mysql':'yes', 90 | 'pwd_type_mysql':'s', 91 | 'pwd_userpass_mysql':self.RSAS.getWeakPassConfig(2), 92 | 'pwd_oracle':'yes', 93 | 'pwd_type_oracle':'s', 94 | 'pwd_userpass_oracle':self.RSAS.getWeakPassConfig(4), 95 | 'pwd_sybase':'yes', 96 | 'pwd_type_sybase':'s', 97 | 'pwd_userpass_sybase':self.RSAS.getWeakPassConfig(7), 98 | 'pwd_db2':'yes', 99 | 'pwd_type_db2':'c', 100 | 'pwd_user_db2':'db2_user.default', 101 | 'pwd_pass_db2':'db2_pass.default', 102 | 'pwd_snmp':'yes', 103 | 'pwd_pass_snmp':'snmp_pass.default', 104 | 'pwd_timeout':'5', 105 | 'pwd_timeout_time':'120', 106 | 'pwd_interval':'0', 107 | 'pwd_num':'0', 108 | 'pwd_threadnum':'5', 109 | 'loginarray': self.iparray.replace('\'','"') 110 | } 111 | 112 | def getPostData(self): 113 | return self.DATA -------------------------------------------------------------------------------- /RSAS.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*-coding:UTF-8-*- 3 | import requests 4 | import re 5 | import datetime 6 | from baseConfig import BASECONFIG 7 | 8 | class RSAS: 9 | def __init__(self,USERNAME,PASSWD,IP): 10 | self.URL = "https://" + IP 11 | self.HOST = IP 12 | self.USERNAME = USERNAME 13 | self.PASSWD = PASSWD 14 | self.SESSION = '' 15 | self.CSRFTOKEN = '' 16 | self.RSAS_HEADER = self.login() 17 | self.RSASCONFIG = BASECONFIG() 18 | 19 | def getCSRFToken(self,HTML,n = 0): 20 | try: 21 | if n == 1: 22 | return re.findall(r"""name='csrfmiddlewaretoken' value="(.*?)">""",HTML)[0] 23 | if n == 0: 24 | return re.findall(r"""{'data':d_s,"(.*?)',"targets":targets}""",HTML)[0] 25 | if n == 3: 26 | return re.findall(r"""""",HTML)[0] 27 | except: 28 | raise SystemExit('[-] Get Token Fail, Exitting') 29 | 30 | def getCookie(self,HEADER,CSRF): 31 | setCookie = HEADER['set-cookie'] 32 | session = re.findall(r'sessionid=(.*?);',setCookie)[0] 33 | return 'csrftoken={}; sessionid={}'.format(CSRF,session) 34 | 35 | def getsession(self,cookie): 36 | return re.findall(r'=(.*?);',cookie)[0] 37 | 38 | def init_session(self): 39 | headers = { 40 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0', 41 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 42 | 'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 43 | 'Accept-Encoding':' gzip, deflate, br', 44 | 'DNT': '1', 45 | 'Connection': 'close', 46 | 'Upgrade-Insecure-Requests': '1' 47 | } 48 | res = requests.get(url = self.URL, verify = False, headers = headers, allow_redirects = False) 49 | return self.getsession(res.headers['set-cookie']) 50 | 51 | def second_session(self): 52 | Cookie = self.init_session() 53 | self.SESSION = Cookie 54 | headers = { 55 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0', 56 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 57 | 'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 58 | 'Accept-Encoding':' gzip, deflate, br', 59 | 'DNT': '1', 60 | 'Connection': 'close', 61 | 'Upgrade-Insecure-Requests': '1', 62 | 'Cookie': 'sessionid=' + Cookie 63 | } 64 | return headers 65 | 66 | def check_login(self,HEADER): 67 | if HEADER['location'] == self.URL + '/': 68 | print("[+] 登录成功....") 69 | 70 | def login(self): 71 | tmp_header = self.second_session() 72 | res = requests.get(url = self.URL + '/accounts/login/', verify = False, headers = tmp_header, allow_redirects = False) 73 | CSRFTOKEN = self.getCSRFToken(res.content,1) 74 | self.CSRFTOKEN = CSRFTOKEN 75 | data = { 76 | 'username' : self.USERNAME, 77 | 'password' : self.PASSWD, 78 | 'csrfmiddlewaretoken' : CSRFTOKEN 79 | } 80 | tmp_cookie = 'csrftoken='+ CSRFTOKEN + '; sessionid=' + self.SESSION 81 | headers={ 82 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0', 83 | 'Host': self.HOST, 84 | 'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 85 | 'Connection': 'close', 86 | 'Cookie': tmp_cookie, 87 | 'Referer': self.URL + '/accounts/login/', 88 | 'Upgrade-Insecure-Requests': '1', 89 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 90 | 'Content-Length': '87' 91 | } 92 | cookie_html = requests.post(url = self.URL + '/accounts/login_view/',data = data, verify = False, headers=headers,allow_redirects = False) 93 | self.check_login(cookie_html.headers) 94 | Cookie = self.getCookie(cookie_html.headers, CSRFTOKEN) 95 | headers = { 96 | 'Host': self.HOST, 97 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0', 98 | 'Accept': '*/*', 99 | 'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 100 | 'Content-Type': 'application/x-www-form-urlencoded', 101 | 'X-Requested-With': 'XMLHttpRequest', 102 | 'Referer': 'https://120.197.234.141/task/', 103 | 'Cookie': Cookie +'; left_menustatue_NSFOCUSRSAS=1|0|https://'+ self.HOST +'/task/', 104 | 'DNT': '1', 105 | 'Connection': 'close' 106 | } 107 | return headers 108 | 109 | def RSASTask(self,DATA,NAME): 110 | sub_res = requests.post(url=self.URL+'/task/vul/tasksubmit',data=DATA,headers=self.RSAS_HEADER, verify=False) 111 | if 'msg:suc' in sub_res.content: 112 | print("[+] 成功添加任务 {}".format(NAME)) 113 | else: 114 | print("[-] 添加任务失败 {}".format(NAME)) 115 | 116 | def getrealPass(self, Keyword, HTML): 117 | return re.findall("""""".format(Keyword),HTML) 118 | 119 | def getWeakPassConfig(self, n): 120 | URL = self.URL + '/task/vul/base/guess/{"pwd_smb":"yes","pwd_type_smb":"c","pwd_user_smb":"smb_user.default","pwd_pass_smb":"smb_pass.default","pwd_telnet":"yes","pwd_type_telnet":"c","pwd_user_telnet":"telnet_user.default","pwd_pass_telnet":"telnet_pass.default","pwd_ssh":"yes","pwd_type_ssh":"c","pwd_user_ssh":"ssh_user.default","pwd_pass_ssh":"ssh_pass.default","pwd_timeout":"5","pwd_timeout_time":"120","pwd_interval":"0","pwd_num":"0","pwd_threadnum":"5"}' 121 | WeakPassPage = requests.get(url = URL, verify = False, headers = self.RSAS_HEADER) 122 | passwd = self.RSASCONFIG.getWeakPasswdDict() 123 | try: 124 | realSSH = self.getrealPass(passwd.pop('SSH'),WeakPassPage.content)[0] 125 | realMySQL = self.getrealPass(passwd.pop('MySQL'),WeakPassPage.content)[0] 126 | realTelnet = self.getrealPass(passwd.pop('Telnet'),WeakPassPage.content)[0] 127 | realOracle= self.getrealPass(passwd.pop('Oracle'),WeakPassPage.content)[0] 128 | realFTP = self.getrealPass(passwd.pop('FTP'),WeakPassPage.content)[0] 129 | realMSSQL = self.getrealPass(passwd.pop('MSSQL'),WeakPassPage.content)[0] 130 | realSybase = self.getrealPass(passwd.pop('Sybase'),WeakPassPage.content)[0] 131 | if n == 1: 132 | return realSSH 133 | if n == 2: 134 | return realMySQL 135 | if n == 3: 136 | return realTelnet 137 | if n == 4: 138 | return realOracle 139 | if n == 5: 140 | return realFTP 141 | if n == 6: 142 | return realMSSQL 143 | if n == 7: 144 | return realSybase 145 | except: 146 | raise SystemExit("[-] 请检查配置文件中弱密码字典配置是否有误") 147 | 148 | def getSysTime(self,HTML): 149 | try: 150 | sysTime = re.findall(r'(.*?)',HTML)[0] 151 | print("[information] RSAS 系统时间: {} 所有任务延时5分钟开始".format(sysTime)) 152 | return sysTime 153 | except: 154 | raise SystemExit("[-] 获取绿盟扫描器系统时间失败,请检查用户名或密码,现在处于登录失败状态") 155 | 156 | def delayFiveMin(self,TIME): 157 | stime = datetime.datetime.strptime(TIME,"%H:%M %Y-%m-%d") 158 | delayTime = stime + datetime.timedelta(minutes=5) 159 | return delayTime.strftime('%Y-%m-%d %H:%M:%S') 160 | 161 | def getSysTimeAndDelyFiveMin(self): 162 | url = self.URL + '/' 163 | clock_page = requests.get(url=url, verify=False, headers=self.RSAS_HEADER) 164 | return self.delayFiveMin(self.getSysTime(clock_page.content)) 165 | -------------------------------------------------------------------------------- /RSASConfig.ini: -------------------------------------------------------------------------------- 1 | [RSAS] 2 | IP = x.x.x.x 3 | 4 | [LOGIN] 5 | Username = admin 6 | Passwd = passwd 7 | 8 | 9 | [WEAK-PASSWD-CONFIG] 10 | SSH = SSH 11 | Telnet = TELNET 12 | MySQL = MySQL 13 | Oracle = Oracle 14 | FTP = FTP 15 | Sybase = Sybase 16 | MSSQL = SQL Server 17 | 18 | [SCANNER-CONFIG] 19 | port = 1-65535 20 | -------------------------------------------------------------------------------- /XLS.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*-coding:UTF-8-*- 3 | try: 4 | import xlrd 5 | except: 6 | raise SystemExit('[Error] Please install "xlrd": e.g. pip install xlrd') 7 | import re 8 | 9 | class BalanceSheet: 10 | def __init__(self,PATH): 11 | self.PATH = PATH 12 | self.DATA = self.openXls(PATH) 13 | 14 | def IPTable(self,n): 15 | list_content = self.getAllValue(self.xlsSheet(self.DATA,n)) 16 | if list_content != 0: 17 | return self.cleanAndRmDup(list_content) 18 | 19 | def openXls(self,PATH): 20 | try: 21 | data = xlrd.open_workbook(self.PATH) 22 | except: 23 | raise SystemExit('[Error] 打开文件失败,请把Excel文件另存为Excel 97-2003 工作薄后重试!') 24 | return data 25 | 26 | def xlsSheet(self,data,num): 27 | return data.sheets()[num] 28 | 29 | def getNrows(self,sheet): 30 | return sheet.nrows 31 | 32 | def getNcols(self,sheet): 33 | return sheet.ncols 34 | 35 | def getValue(self,sheet,row,col): 36 | return sheet.cell(row,col).value 37 | 38 | def getAllValue(self,sheet): 39 | if self.getNcols(sheet) == 0 or self.getNrows(sheet) == 0: 40 | print '[-] Sheet为空......' 41 | return 0 42 | else: 43 | ValueList=[] 44 | for i in range(self.getNrows(sheet)): 45 | for j in range(self.getNcols(sheet)): 46 | ValueList.append(self.getValue(sheet,i,j)) 47 | return ValueList 48 | 49 | def cleanAndRmDup(self,list): 50 | cleanList=[] 51 | for i in list: 52 | if i != '' and isinstance(i,(str,unicode)): 53 | foundItem = re.findall(r'(\d+\.\d+\.\d+\.\d+/?\d*)',i)# 究竟'/'是不是表示一个网段 54 | if len(foundItem) > 0: 55 | cleanList.append(foundItem[0].strip()) 56 | return set(cleanList) 57 | 58 | def sheetName(self,n): 59 | return self.DATA.sheets()[n].name 60 | 61 | def len(self): 62 | return len(self.DATA.sheets()) 63 | -------------------------------------------------------------------------------- /baseConfig.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*-coding:UTF-8-*- 3 | import ConfigParser 4 | 5 | 6 | 7 | class BASECONFIG: 8 | def __init__(self): 9 | self.cfg = ConfigParser.ConfigParser() 10 | try: 11 | self.configFile = open('./RSASConfig.ini', 'r') 12 | except: 13 | raise SystemExit('[-] Open config-file Fail') 14 | self.cfg.readfp(self.configFile) 15 | 16 | def getUSERNAME(self): 17 | USERNAME = self.cfg.get('LOGIN','Username') 18 | return USERNAME 19 | def getPASSWD(self): 20 | PASSWD = self.cfg.get('LOGIN','Passwd') 21 | return PASSWD 22 | def getIP(self): 23 | IP = self.cfg.get('RSAS','IP') 24 | return IP 25 | def getWeakPasswdDict(self): 26 | SSH = self.cfg.get('WEAK-PASSWD-CONFIG', 'SSH') 27 | telnet = self.cfg.get('WEAK-PASSWD-CONFIG', 'Telnet') 28 | Oracle = self.cfg.get('WEAK-PASSWD-CONFIG', 'Oracle') 29 | FTP = self.cfg.get('WEAK-PASSWD-CONFIG', 'FTP') 30 | Sybase = self.cfg.get('WEAK-PASSWD-CONFIG', 'Sybase') 31 | MSSQL = self.cfg.get('WEAK-PASSWD-CONFIG','MSSQL') 32 | MySQL = self.cfg.get('WEAK-PASSWD-CONFIG','MySQL') 33 | WeakPass = { 34 | 'SSH' : SSH, 35 | 'Telnet' : telnet, 36 | 'Oracle' : Oracle, 37 | 'FTP' : FTP, 38 | 'Sybase' : Sybase, 39 | 'MSSQL' : MSSQL, 40 | 'MySQL' : MySQL 41 | } 42 | return WeakPass 43 | 44 | def getPort(self): 45 | port = self.cfg.get('SCANNER-CONFIG','port') 46 | return port 47 | --------------------------------------------------------------------------------