├── .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 |
--------------------------------------------------------------------------------