def login(email, password): """ 登陆到ZoomEye :param email: 账户email :param password: 账户password :return: None """ data = {'username': email, 'password': password} # dumps 将 python 对象转换成 json 字符串 data_encoded = json.dumps(data) try: # print('---------------------') r = requests.post(url='https://api.zoomeye.org/user/login', data=data_encoded) # loads() 将 json 字符串转换成 python 对象 # print('---------------------') r_decoded = json.loads(r.text) # print('---------------------') info('username : {}\tpasswd : {}'.format(email, password)) # 获取到账户的access_token global access_token access_token = r_decoded['access_token'] write_conf(path.config, 'zoomeye', 'access_token', access_token) # 写入access_token print('#######################################') except Exception: error( 'username or password is wrong, please check config file or input') pass
def set_cmd_opts(args): """ Set data using commandline args 解析命令行参数设置到cmd_opts中 :return: None """ # 先检查命令行参数一下是否正确设置 check_args(args) # --update 检查系统更新 if args.Update: update() # --list 列出所有的可用脚本信息 if args.list_scripts: show_scripts() # --threads 设置线程数 if args.threads: threads = args.threads set_threads(threads) # --script 加载脚本 if args.script_name: script_name = args.script_name # 检查是否存在该脚本 check_script_existence(script_name) # 设置攻击脚本 cmd_opts.script = script_name else: cmd_opts.script = '' set_targets(args) # --target 设置攻击目标 # --limit 设置从api接口获取的数量, 默认限额20 if args.limit: cmd_opts.limit = args.limit else: cmd_opts.limit = 20 # --offset 设置偏移量,从相应的api接口查询起始页,默认从第一页开始page=0 if args.offset: cmd_opts.offset = args.offset else: cmd_opts.offset = 0 # --query 设置查询语句,query='weblogic country:cn' if args.query: cmd_opts.query = args.query info('query : {}'.format(cmd_opts.query)) # 查找脚本,模糊查找,列出名字相似或相同的脚本,以便选择 if args.search_script: script_name = args.search_script search_script(script_name)
def fofa_api(): # TODO 付费获取结果的功能实现 """ Get query result from Fofa :param query: query string :param limit: query amount :param offset: start page :return: query result """ global email, key # load query, limit, offset from cmd_opts query = cmd_opts.query limit = cmd_opts.limit offset = cmd_opts.offset # 从配置文件中读取email和key try: email = read_conf(path.config, 'fofa', 'email') key = read_conf(path.config, 'fofa', 'key') print('{} - {}'.format(email, key)) if check(email, key): pass else: raise # will go to except block # 读取手工输入的email和key except: warning('Automatic authorization failed.') email = input("Fofa Email: ").strip() key = input("Fofa Key: ").strip() if not check(email, key): error( 'Fofa API authorization failed, Please re-run it and enter a valid key.' ) exit() query = base64.b64encode(query) request = "https://fofa.so/api/v1/search/all?email={0}&key={1}&qbase64={2}".format( email, key, query) global result try: response = requests.get(request, timeout=3) resp = response.readlines()[0] resp = json.loads(resp) if resp["error"] is None: for item in resp.get('results'): result.append(item[0]) if resp.get('size') >= 100: info("{0} items found! just 100 returned....".format( resp.get('size'))) except: sys.exit() finally: return result
def print_args(args): """ 输出参数信息,检测参数是否出现问题 :return: None """ print('---args for : {}'.format(args)) for k, v in args.items(): info('{} : {}'.format(k, v)) time.sleep(0.05) print('\r\n\r\n')
def init_shodan(): """ Init Shodan, read config file to fetch API_KEY 从配置文件中获取API_KEY :return: None """ global API_KEY, api API_KEY = read_conf(path.config, 'shodan', 'api_key') if API_KEY: info(API_KEY) else: API_KEY = input('please input API_KEY') api = shodan.Shodan(API_KEY) # init
def update(): """ Update this program 更新脚本: 直接使用git pull origin master :return: None """ info('update program \r\n...') try: # 使用git 命令更新脚本 os.system('git pull origin master') info('succeed ... ') except: error('something wrong with "git pull origin master", please try to re-download this repo for update') exit()
def init_zoomeye(): """ 初始化zoomeye, 读取配置文件 :return: None """ global access_token, email, password email = read_conf(path.config, 'zoomeye', 'email') password = read_conf(path.config, 'zoomeye', 'password') access_token = read_conf(path.config, 'zoomeye', 'access_token') # 输出读取的配置文件信息 info('zoomeye infomation \nemail : {} \npassword : {}\naccess_token : {}\n' ''.format(email, password, access_token)) pass
def getIp(query, page): """ Fect data from Shodan api :param query: query string :param page: page number :return: None """ info('page : {}'.format(page)) try: results = api.search(query, page=page) for result in results['matches']: ip_port = '{}:{}'.format(result['ip_str'], result['port']) iplist.append(ip_port) except: pass pass
def init_censys(): """ Init censys, read UID and SECRET from config file :return: """ global UID, SECRET # email = read_conf(path.config, 'zoomeye', 'email') UID = read_conf(path.config, 'censys', 'UID') SECRET = read_conf(path.config, 'censys', 'SECRET') if UID and SECRET: info('UID : {} SECRET:{}'.format(UID, SECRET)) else: warning( 'please refer to this url : {} and fill in UID and SECRET'.format( 'https://www.censys.io/account/api'))
def start(): """ start to exploit :return: None """ # 输出参数, 检查下是否有问题 # print_args(cmd_opts) # print_args(scripts) # 完成engined的一些初始化工作 initialize() info('concurrent threads : {}'.format(statistic.thread_num)) run() pass
def apiTest(query, offset, pages): """ Fetch data : 获取数据 :param query: 查询语句 :param offset: 起始页 :param pages: 页数 :return: None """ global access_token headers = { 'Authorization': 'JWT ' + access_token, } flag = True # 用来标记是否输出资源信息 for i in range(pages): page = offset + i try: url = 'https://api.zoomeye.org/host/search?query=' + query + '&page=' + str( page) r = requests.get(url=url, headers=headers) r_decoded = json.loads(r.text) # 输出一次查询的结果总数 if flag: info('Total result : {}'.format(r_decoded['total'])) flag = False info('url : {}'.format(url)) # 解析出ip:port 添加到结果列表 for x in r_decoded['matches']: ip_port = '{}:{}'.format(x['ip'], x['portinfo']['port']) print(ip_port) # result.append(ip_port) result.add(ip_port) except Exception as e: # 如果发生异常,其它先不用管,把获取的数据返回 return result if str(e.message) == 'matches': warning('account was break, excceeding the max limitations') else: warning(str(e.message))
def get_resource_info(): """ 获取跟ZoomEye资源相关信息: 用户类型和用户所剩的查询额度 :return: None """ global access_token headers = { 'Authorization': 'JWT ' + access_token, } try: url = 'https://api.zoomeye.org/resources-info' r = requests.get(url=url, headers=headers) info('url : {}'.format(url)) r_decoded = json.loads(r.text) info('plan : {} | resources available : {}'.format( r_decoded['plan'], r_decoded['resources']['search'])) except Exception as e: error(str(e.message)) pass
def run(): """ 开始扫描任务, 漏洞利用 :return: None """ # 线程数量 threads_num = cmd_opts.threads # 线程list,放在一个list方便管理 thread_list = [] # 加载攻击模块,放在外面作为参数传递给线程,这样在线程里就不用每次都去加载了,提高批量检测时的效率,因为是同一个payload module = load_module(cmd_opts.script) # 输出模块信息 info('using : {}'.format(module)) # 存放存在漏洞的主机 statistic.succeed = set() print('\n---------- Exploiting ----------\n') # 创建线程 for i in range(threads_num): t = threading.Thread(target=scan, args=(module, ), name=str(i)) thread_list.append(t) # 启动线程 for t in thread_list: t.setDaemon(True) t.start() # 等待线程终止 for t in thread_list: t.join() print('\n--- The following are vulnerable ---\n') for line in statistic.succeed: print(line) # 将结果写入文件 save_result()
def zoomeye_api(): """ Use ZoomEye to fetch data and return back 调用ZoomEye接口,获取数据并返回 :return: """ # print('fetch result from zoomeye') # 从配置文件中获取zoomeye账户信息:登陆需要使用的邮箱和密码 init_zoomeye() global email, password, access_token # 如果配置文件中有 if not access_token: # 如果配置文件中,存在email和password字段,则使用该字段登陆zoomeye, 获取access_token if email and password: login(email, password) else: email = input('please input email : ') password = input('please input password : '******'==>access_token : {}'.format(access_token)) # 查看资源信息 get_resource_info() # 设置查询参数: 查询语句,起始页和页数 query = cmd_opts.query offset = cmd_opts.offset # 设置更为合理的查询页数,其实无所谓啦 pages = int(cmd_opts.limit / 20) if pages * 20 != cmd_opts.limit: pages += 1 # 获取数据 apiTest(query, offset, pages) # 返回 return result
def getIp(query, page): """ Fetch ip:port by given query and page :param query: query string :param page: page number :return: None """ info('page : {}'.format(page)) data = {"query": query, "page": page, "fields": ["ip", "protocols"]} try: res = requests.post(API_URL + "/search/ipv4", data=json.dumps(data), auth=(UID, SECRET)) except: pass try: results = res.json() except: pass if res.status_code != 200: print("error occurred: %s" % results["error"]) sys.exit(1) # print(json.dumps(results)) tmp = [] # actually, censys is not very accurate, because we can not get a specific port when we search # eg: "weblogic", censys will give serveral ports that is open on this machine # so, we have to add it all for result in results["results"]: for i in result["protocols"]: tmp.append(result["ip"] + ':' + i) # remove http/https from the end for line in tmp: ip_port = line[:line.find('/')] iplist.append(ip_port) print(ip_port) pass
def check(): """ Check Authorization :param email: email address :param key: api key :return: login succeed or not | that is True or False """ global email, key if email and key: auth_url = "https://fofa.so/api/v1/info/my?email={0}&key={1}".format( email, key) info(auth_url) try: response = requests.get(auth_url, timeout=3) if response.status_code == 200: return True else: warning(response.text) return False except: return False return False
def set_targets(args): """ Set remote target 设置目标 :param args: 目标target, 来自命令行参数 :return: None """ # 目标队列 statistic.queue = queue.Queue() # 单个url if args.target_url: cmd_opts.target_mode = 'SINGLE' cmd_opts.target = args.target_url info('target : {}'.format(cmd_opts.target)) statistic.queue.put(cmd_opts.target) # 从文件中读取 elif args.target_file: cmd_opts.target_mode = 'FILE' cmd_opts.target = read_file(args.target_file) for line in cmd_opts.target: print(line) statistic.queue.put(line) # 从ZoomEye 获取 elif args.ZoomEye: cmd_opts.target_mode = 'ZoomEye' info('fetch targets using ZoomEye Api') # statistic.queue.put(zoomeye-api) # 从ZoomEye获取的ip:port列表,保存一份到文件中,以备日后之用 result = zoomeye_api() save_ip_port(result) info('There are {} hosts to test!'.format(len(result))) # 将ip:port放入到待检测的队列中 for line in result: statistic.queue.put(line) # 从Shodan 获取 elif args.Shodan: cmd_opts.target_mode = 'Shodan' info('fetch targets using Shodan Api') # statistic.queue.put(shodan-api) result = shodan_api() info('There are {} hosts to test!'.format(len(result))) for line in result: statistic.queue.put(line) statistic.queue.put('127.0.0.1') # shodan未经测试,要钱啊,故添加一个临时的127.0.0.1 # 从Censys获取 elif args.Censys: cmd_opts.target_mode = 'censys' info('fetch targets using Censys Api') # statistic.queue.put(censys-api) result = censys_api() info('{} to test!'.format(len(result))) for line in result: statistic.queue.put(line) statistic.queue.put('127.0.0.1') # censys 讲道理,获取的结果不准确 elif args.Fofa: cmd_opts.target_mode = 'fofa' info('fetch targets using Fofa Api') # statistic.queue.put(fofa-api) result = fofa_api() info('{} to test!'.format(len(result))) for line in result: statistic.queue.put(line) statistic.queue.put('127.0.0.1') # censys 讲道理,获取的结果不准确, else: cmd_opts.target_mode = '' cmd_opts.target = '' pass pass