├── .gitignore ├── Controller ├── Controller.py └── __init__.py ├── Core ├── CheckRealLogin.py ├── CreateWolfScan.py ├── Login.py ├── Search.py └── __init__.py ├── Image ├── screen-shot1.png ├── screen-shot2.png ├── screen-shot3.png ├── screen-shot4.png └── screen-shot5.png ├── README.md ├── Script ├── Welcome.py └── __init__.py └── main.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | Output/ 7 | 8 | config.conf 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | wheels/ 26 | share/python-wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .nox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | *.py,cover 53 | .hypothesis/ 54 | .pytest_cache/ 55 | cover/ 56 | 57 | # Translations 58 | *.mo 59 | *.pot 60 | 61 | # Django stuff: 62 | *.log 63 | local_settings.py 64 | db.sqlite3 65 | db.sqlite3-journal 66 | 67 | # Flask stuff: 68 | instance/ 69 | .webassets-cache 70 | 71 | # Scrapy stuff: 72 | .scrapy 73 | 74 | # Sphinx documentation 75 | docs/_build/ 76 | 77 | # PyBuilder 78 | .pybuilder/ 79 | target/ 80 | 81 | # Jupyter Notebook 82 | .ipynb_checkpoints 83 | 84 | # IPython 85 | profile_default/ 86 | ipython_config.py 87 | 88 | # pyenv 89 | # For a library or package, you might want to ignore these files since the code is 90 | # intended to run in multiple environments; otherwise, check them in: 91 | # .python-version 92 | 93 | # pipenv 94 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 95 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 96 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 97 | # install all needed dependencies. 98 | #Pipfile.lock 99 | 100 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 101 | __pypackages__/ 102 | 103 | # Celery stuff 104 | celerybeat-schedule 105 | celerybeat.pid 106 | 107 | # SageMath parsed files 108 | *.sage.py 109 | 110 | # Environments 111 | .env 112 | .venv 113 | env/ 114 | venv/ 115 | ENV/ 116 | env.bak/ 117 | venv.bak/ 118 | 119 | # Spyder project settings 120 | .spyderproject 121 | .spyproject 122 | 123 | # Rope project settings 124 | .ropeproject 125 | 126 | # mkdocs documentation 127 | /site 128 | 129 | # mypy 130 | .mypy_cache/ 131 | .dmypy.json 132 | dmypy.json 133 | 134 | # Pyre type checker 135 | .pyre/ 136 | 137 | # pytype static type analyzer 138 | .pytype/ 139 | 140 | # Cython debug symbols 141 | cython_debug/ 142 | # vscode 143 | .idea 144 | .vscode 145 | 146 | *.DS_Store -------------------------------------------------------------------------------- /Controller/Controller.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from Core.Login import Login 4 | from Core.Search import Search 5 | from Core.CheckRealLogin import Check 6 | from Core.CreateWolfScan import WolfScan 7 | 8 | class WgpIG(object): 9 | def __init__(self): 10 | self.login = Login() 11 | self.search = Search() 12 | self.check = Check() 13 | self.wolfscan = WolfScan() 14 | 15 | def _login(self, username): 16 | self.login.verify(username) 17 | 18 | def _search(self, type, pagenum, query, keyword, export): 19 | search = self.search 20 | if type != '' and query != '': 21 | search.requests_search_api(type, pagenum, query, export) 22 | if keyword != '': 23 | search.requests_kownledge_search_api(keyword) 24 | 25 | def _createwolfscan(self, url): 26 | wolfscan = self.wolfscan 27 | if url != None or url != '': 28 | wolfscan.requests_create_wolfscan_api(url) 29 | 30 | def Start(self, username, url, pagenum, type, query, keyword, export): 31 | if not os.path.exists('Output/'): 32 | os.mkdir('Output/') 33 | if not self.check.run(): 34 | self._login(username) 35 | self._search(type=type, query=query,pagenum=pagenum, keyword='', export=export) 36 | if keyword != '': 37 | self._search(type='', query='', pagenum=pagenum, keyword=keyword, export=export) 38 | if url != None and url != '': 39 | self._createwolfscan(url) 40 | 41 | 42 | -------------------------------------------------------------------------------- /Controller/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgpsec/Perception/a7d3bc76bf5615a0191c45016eef09985a6d8cc6/Controller/__init__.py -------------------------------------------------------------------------------- /Core/CheckRealLogin.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import configparser 3 | import os 4 | 5 | 6 | class Check(object): 7 | def __init__(self): 8 | self.requests_api = 'https://plat.wgpsec.org/api/v1/ws/search' 9 | self.config_file = 'config.conf' 10 | self.data = { 11 | "pageNo": 1, 12 | "pageSize": 100, 13 | "query": "city=武汉", 14 | "type": "web" 15 | } 16 | 17 | def get_user_token(self): 18 | user_token = '' 19 | config = configparser.ConfigParser() 20 | if os.path.exists(self.config_file): 21 | config.read(self.config_file) 22 | try: 23 | user_token = config['token']['token'] 24 | except: 25 | return 26 | return user_token 27 | 28 | def run(self): 29 | user_token = self.get_user_token() 30 | if user_token == None: 31 | return False 32 | else: 33 | headers = { 34 | "authorization": user_token, 35 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0" 36 | } 37 | res = requests.post(self.requests_api, json=self.data, headers=headers).json() 38 | if res['code'] == 4018: 39 | return False 40 | else: 41 | print('\033[33m[WARN]\033[0m 您已登陆,无须继续登陆') 42 | return True 43 | 44 | -------------------------------------------------------------------------------- /Core/CreateWolfScan.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import configparser 4 | import requests 5 | 6 | 7 | class WolfScan(object): 8 | def __init__(self): 9 | self.get_user_info_api = "https://plat.wgpsec.org/api/user/getUserInfo" 10 | self.create_wolfscan_api = "https://plat.wgpsec.org/api/wscan/saveUserWsJob" 11 | self.query_productlist_api = "https://plat.wgpsec.org/api/shop/queryProductList" 12 | self.take_order_api = "https://plat.wgpsec.org/api/shop/takeOrder" 13 | self.order_pay_api = "https://plat.wgpsec.org/api/shop/orderPay" 14 | self.config_file = 'config.conf' 15 | 16 | def get_user_token(self): 17 | user_token = '' 18 | config = configparser.ConfigParser() 19 | if os.path.exists(self.config_file): 20 | config.read(self.config_file) 21 | try: 22 | user_token = config['token']['token'] 23 | except: 24 | sys.exit(0) 25 | return user_token 26 | 27 | def requests_get_user_info_api(self): 28 | headers = { 29 | "authorization": self.get_user_token() 30 | } 31 | get_user_info_res = requests.get(url=self.get_user_info_api, headers=headers).json() 32 | # print(get_user_info_res) 33 | if get_user_info_res['code'] == 2000: 34 | print('\033[34m[INFO]\033[0m 您的狼币数量为: ' + str(get_user_info_res['data']['wolfCoin'])) 35 | return get_user_info_res['data']['wolfCoin'] 36 | elif get_user_info_res['code'] == 4018: 37 | print('\033[33m[WARN]\033[0m ' + get_user_info_res['msg']) 38 | else: 39 | print('\033[31m[ERRO]\033[0m') 40 | 41 | def requests_create_wolfscan_api(self, detected_url): 42 | if self.requests_get_user_info_api() == 0.0: 43 | print('\033[34m[INFO]\033[0m 您的狼币已经使用完了哦,请投稿高质量文章获取哦!') 44 | sys.exit(0) 45 | headers = { 46 | "authorization": self.get_user_token() 47 | } 48 | data = { 49 | "domain": detected_url, 50 | "area": "cn", 51 | "domainOption": "0" 52 | } 53 | create_wolfscan_api_res = requests.post(url=self.create_wolfscan_api, headers=headers, json=data).json() 54 | # print(create_wolfscan_api_res) # debug 55 | if create_wolfscan_api_res['code'] == 2000: 56 | print('\033[32m[SUCC] 任务添加完成!\033[0m') 57 | elif create_wolfscan_api_res['code'] == 4018: 58 | print('\033[33m[WARN]\033[0m 登陆过期,请重新登陆') 59 | sys.exit(0) 60 | elif create_wolfscan_api_res['code'] == 5001: 61 | if create_wolfscan_api_res['msg'] == '无法添加已经存在的任务!': 62 | print('\033[33m[WARN]\033[0m ' + create_wolfscan_api_res['msg']) 63 | print('\033[34m[INFO]\033[0m 感谢您的使用!') 64 | sys.exit(0) 65 | print('\033[33m[WARN]\033[0m ' + create_wolfscan_api_res['msg']) 66 | YorNPurchase = str(input('\033[34m[INFO]\033[0m 是否需要激活或购买次数? [\033[32mY\033[0m/\033[31mN\033[0m] ')) 67 | if YorNPurchase == 'Y' or YorNPurchase == 'y': 68 | self.purchase_scans() 69 | else: 70 | print('\033[34m[INFO]\033[0m 感谢您的使用!') 71 | sys.exit(0) 72 | 73 | def purchase_scans(self): 74 | headers = { 75 | "authorization": self.get_user_token() 76 | } 77 | take_order_data = { 78 | "num":"1", 79 | "orderRemark": "", 80 | "productId": "wPlatP-wolfscan" 81 | } 82 | take_order_res = requests.post(url=self.take_order_api, headers=headers, json=take_order_data).json() 83 | if take_order_res['code'] == 4018: 84 | print('\033[33m[WARN]\033[0m ' + take_order_res['msg']) 85 | sys.exit(0) 86 | elif take_order_res['code'] == 5001: 87 | print('\033[33m[WARN]\033[0m ' + take_order_res['msg']) 88 | sys.exit(0) 89 | order_pay_data = { 90 | "orderId": take_order_res['data']['orderId'] 91 | } 92 | order_pay_res = requests.post(url=self.order_pay_api, headers=headers, json=order_pay_data).json() 93 | # print(order_pay_res) 94 | if order_pay_res['code'] == 2000: 95 | print('\033[032m[SUCC]\033[0m wolfscan扫描器服务购买成功!') 96 | query_productlist_data = { 97 | "pageNo": "1", 98 | "pageSize": "12", 99 | "product": { 100 | } 101 | } 102 | query_productlist_res = requests.post(url=self.query_productlist_api, 103 | headers=headers, 104 | json=query_productlist_data).json() 105 | if query_productlist_res['code'] == 4018: 106 | print('\033[33m[WARN]\033[0m ' + query_productlist_res['msg']) 107 | sys.exit(0) 108 | for data in query_productlist_res['data']['productVoList']: 109 | if data['productId'] == 'wPlatP-wolfscan': 110 | print('\033[34m[INFO]\033[0m wolfscan扫描器服务库存还有: ' + str(data['productSize'])) # wolfscan扫描服务的库存数量 111 | 112 | -------------------------------------------------------------------------------- /Core/Login.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import random 3 | import sys 4 | import configparser 5 | import getpass 6 | import re 7 | from .CheckRealLogin import Check 8 | from getpass import getpass 9 | 10 | 11 | class Login(object): 12 | def __init__(self): 13 | self.login_api = "https://plat.wgpsec.org/api/user/passwordLogin" 14 | self.config_file = 'config.conf' 15 | 16 | def verify(self, username): 17 | if not Check().run(): # 登陆就为True 18 | if username == None: 19 | print('\033[33m[WARN]\033[0m 请使用-l参数进行登陆!') 20 | sys.exit(0) 21 | 22 | 23 | login_api = self.login_api 24 | config = configparser.ConfigParser() 25 | requests_type = 0 26 | # username = str(input('\033[34m[INFO]\033[0m 请输入您的账号: ')) 27 | # print(username) 28 | if re.match(r'^[0-9a-zA-Z_]{0,19}@[0-9a-zA-Z]{1,13}\.[com,cn,net]{1,3}$', username): 29 | requests_type = 1 30 | else: 31 | pass 32 | password = getpass('\033[34m[INFO]\033[0m 请输入账号密码(Tips:不可见): ') 33 | if password == '': 34 | print('\033[33m[WARN]\033[0m 密码不能为空!') 35 | sys.exit(0) 36 | login_data = { 37 | "userName": username, 38 | "userPassword": password, 39 | "captcha": random.randint(0, 65535), 40 | "type": requests_type 41 | } 42 | login_api_res = requests.post(login_api, json=login_data).json() 43 | login_res_code = int(login_api_res['code']) # 返回状态码 44 | if login_res_code == 5001: 45 | print('\033[31m[ERRO]\033[0m 密码或用户名错误,请重新登录!') 46 | sys.exit(0) 47 | login_token = login_api_res['data']['token'] 48 | if login_res_code == 2000: 49 | print('\033[032m[SUCC]\033[0m 登陆成功!') 50 | config['token'] = {'token': login_token} 51 | with open('config.conf', 'w') as config_file: 52 | config.write(config_file) 53 | 54 | -------------------------------------------------------------------------------- /Core/Search.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import os 3 | import configparser 4 | import sys 5 | import time 6 | 7 | import requests 8 | 9 | 10 | class Search(object): 11 | 12 | def __init__(self): 13 | self.search_api_url = 'https://plat.wgpsec.org/api/v1/ws/search' # 搜索模块api链接 14 | self.knowledge_api_url = 'https://plat.wgpsec.org/api/post/queryPlatPost' # 知识库api链接 15 | self.config_file = 'config.conf' 16 | 17 | def get_user_token(self): 18 | user_token = '' 19 | config = configparser.ConfigParser() 20 | if os.path.exists(self.config_file): 21 | config.read(self.config_file) 22 | try: 23 | user_token = config['token']['token'] 24 | except: 25 | sys.exit(0) 26 | return user_token 27 | 28 | def search_data(self, page_num, type, input_data): 29 | data = { 30 | "pageNo": page_num, 31 | "pageSize": 10, 32 | "query": input_data, 33 | "type": type 34 | } 35 | return data 36 | 37 | def requests_search_api(self, type, page_num, input_data, export_filename): 38 | search_api_url = self.search_api_url 39 | user_token = self.get_user_token() 40 | headers = { 41 | "authorization": user_token, 42 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0" 43 | } 44 | search_data = self.search_data(type=type, page_num=page_num, input_data=input_data) 45 | requests_res = requests.post(url=search_api_url, headers=headers, json=search_data).json() 46 | if requests_res['code'] == 4018: 47 | print("\033[31m[ERRO]\033[0m " + requests_res['msg']) 48 | sys.exit(0) 49 | if type == 'web': 50 | search_info = requests_res['data']['wsSubDomainInfoDtoList']['wsSubDomainInfoDtos'] 51 | if len(search_info) == 0: 52 | print('\033[33m[WARN]\033[0m 未查询到信息!') 53 | sys.exit(0) 54 | print('\033[32m[SUCC]\033[0m 查询成功') 55 | self.web_print_data(search_info, export_filename) 56 | else: 57 | search_info = requests_res['data']['wsPortInfoDtoList']['wsPortInfoDtos'] 58 | if len(search_info) == 0: 59 | print('\033[33m[WARN]\033[0m 未查询到信息!') 60 | sys.exit(0) 61 | print('\033[32m[SUCC]\033[0m 查询成功') 62 | 63 | self.host_print_data(search_info, export_filename) 64 | # print(search_info) 65 | 66 | def web_print_data(self, search_info, export_filename): 67 | for i in range(0, len(search_info)): 68 | if search_info[i]['subdomainTitle'] == None: 69 | search_info[i]['subdomainTitle'] = 'Unknow' 70 | if search_info[i]['subdomainBanner'] == None: 71 | search_info[i]['subdomainBanner'] = 'Unknow' 72 | print('\033[34m[INFO] \033[0m' + 73 | '\033[33mTitle:\033[0m[' + search_info[i]['subdomainTitle'] + ']', 74 | '\033[33mSubdomain:\033[0m[' + search_info[i]['subdomain'] + ']', 75 | '\033[33mIPADDR:\033[0m[' + search_info[i]['ipAdd'] + ']', 76 | '\033[33mWeb servers:\033[0m[' + search_info[i]['subdomainBanner'] + ']') 77 | if export_filename != '': 78 | print('\033[33m[INFO]\033[0m 查询结果保存至: %s' % ('./Output/' + export_filename)) 79 | with open('Output/%s' % export_filename, 'a', newline='') as csvfile: 80 | fieldnames = ['网站标题', '域名', 'IP地址', 'Web容器'] 81 | writer = csv.DictWriter(csvfile, fieldnames=fieldnames) 82 | writer.writeheader() 83 | for i in range(0, len(search_info)): 84 | if search_info[i]['subdomainTitle'] == None: 85 | search_info[i]['subdomainTitle'] = 'Unknow' 86 | if search_info[i]['subdomainBanner'] == None: 87 | search_info[i]['subdomainBanner'] = 'Unknow' 88 | result = { 89 | '网站标题': search_info[i]['subdomainTitle'], 90 | '域名': search_info[i]['subdomain'], 91 | 'IP地址': search_info[i]['ipAdd'], 92 | 'Web容器': search_info[i]['subdomainBanner'] 93 | } 94 | writer.writerow(result) 95 | csvfile.close() 96 | 97 | def host_print_data(self, search_info, export_filename): 98 | for i in range(0, len(search_info)): 99 | if search_info[i]['product'] == '': 100 | search_info[i]['product'] = 'Unknow' 101 | print('\033[34m[INFO] \033[0m' + 102 | '\033[33mSubdomain:\033[0m[' + search_info[i]['subdomain'] + ']', 103 | '\033[33mIPADDR:\033[0m[' + search_info[i]['ipAdd'] + ']', 104 | '\033[33mPort:\033[0m[' + str(search_info[i]['port']) + ']', # type: int 105 | '\033[33mService:\033[0m[' + search_info[i]['service'] + ']', 106 | '\033[33mProduct:\033[0m[' + search_info[i]['product'] + ']') 107 | if export_filename != '': 108 | print('\033[33m[INFO]\033[0m 查询结果保存至: %s' % ('./Output/' + export_filename)) 109 | with open('Output/%s' % export_filename, 'a', newline='') as csvfile: 110 | fieldnames = ['域名', 'IP地址', '端口', '服务', '产品'] 111 | writer = csv.DictWriter(csvfile, fieldnames=fieldnames) 112 | writer.writeheader() 113 | for i in range(0, len(search_info)): 114 | if search_info[i]['product'] == '': 115 | search_info[i]['product'] = 'Unknow' 116 | result = { 117 | '域名': search_info[i]['subdomain'], 118 | 'IP地址': search_info[i]['ipAdd'], 119 | '端口': search_info[i]['port'], 120 | '服务': str(search_info[i]['service']), 121 | '产品': search_info[i]['product'] 122 | } 123 | writer.writerow(result) 124 | csvfile.close() 125 | 126 | def kownledge_search(self, keyword): 127 | data = { 128 | "pageNo": 1, 129 | "pageSize": 12, 130 | "platPostDto": { 131 | "postTitle": keyword, 132 | "categoryId": "" 133 | } 134 | } 135 | return data 136 | 137 | def requests_kownledge_search_api(self, keyword): 138 | print('\033[34m[KEYW]\33[0m 关键字: %s' % keyword) 139 | knowledge_api_url = self.knowledge_api_url 140 | knowledge_data = self.kownledge_search(keyword) 141 | user_token = self.get_user_token() 142 | headers = { 143 | "authorization": user_token, 144 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0" 145 | } 146 | knowledge_api_res = requests.post(knowledge_api_url, headers=headers, json=knowledge_data) 147 | try: 148 | print('\033[32m[SUCC]\033[0m 查询成功') 149 | knowledge_api_res_json = knowledge_api_res.json() 150 | knowledge_info = knowledge_api_res_json['data']['platPostSVos'] 151 | for i in range(0, len(knowledge_info)): 152 | link = 'https://plat.wgpsec.org/knowledge/view/%s' % knowledge_info[i]['postId'] 153 | print('\033[34m[INFO]\033[0m ' + '\033[33mTitle:\033[0m[' + knowledge_info[i]['postTitle'] + ']', '\033[33mLink:\033[0m[' + link + ']') 154 | except: 155 | knowledge_api_res_json = knowledge_api_res.json() 156 | print('\033[31m[ERRO]\033[0m ' + knowledge_api_res_json['msg']) 157 | -------------------------------------------------------------------------------- /Core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgpsec/Perception/a7d3bc76bf5615a0191c45016eef09985a6d8cc6/Core/__init__.py -------------------------------------------------------------------------------- /Image/screen-shot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgpsec/Perception/a7d3bc76bf5615a0191c45016eef09985a6d8cc6/Image/screen-shot1.png -------------------------------------------------------------------------------- /Image/screen-shot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgpsec/Perception/a7d3bc76bf5615a0191c45016eef09985a6d8cc6/Image/screen-shot2.png -------------------------------------------------------------------------------- /Image/screen-shot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgpsec/Perception/a7d3bc76bf5615a0191c45016eef09985a6d8cc6/Image/screen-shot3.png -------------------------------------------------------------------------------- /Image/screen-shot4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgpsec/Perception/a7d3bc76bf5615a0191c45016eef09985a6d8cc6/Image/screen-shot4.png -------------------------------------------------------------------------------- /Image/screen-shot5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wgpsec/Perception/a7d3bc76bf5615a0191c45016eef09985a6d8cc6/Image/screen-shot5.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
4 |
5 |
6 |
7 |
8 |
9 |