Esempio n. 1
0
    def _upload_report(self):
        try:
            self.cloud_api = CloudApi()
        except Exception as e:
            Logger().critical("CloudApi init failed!", exc_info=e)

        Logger().info("Init cloud_api success.")
        while True:
            time.sleep(10)
            try:
                self.cloud_api.upload_report()
            except Exception as e:
                Logger().warning("Upload report error.", exc_info=e)
Esempio n. 2
0
class Monitor(base.BaseModule):
    """
    用于监控运行状态、启停其他模块的模块
    """
    def __init__(self):
        """
        初始化
        """
        self.preprocessor_proc = None
        self.crash_module = None
        self.cloud_thread = None
        self.web_console_thread = None

    def _upload_report(self):
        try:
            self.cloud_api = CloudApi()
        except Exception as e:
            Logger().critical("CloudApi init failed!", exc_info=e)

        Logger().info("Init cloud_api success.")
        while True:
            time.sleep(10)
            try:
                self.cloud_api.upload_report()
            except Exception as e:
                Logger().warning("Upload report error.", exc_info=e)

    def _check_alive(self):
        """
        判断其他模块是否正常运行
        """
        ppid = os.getppid()
        if ppid <= 1:
            Logger().warning("Detect main process stopped, Monitor exit!")
            self.crash_module = "main"
            return False

        # http server存活检测
        # if not self.web_console_thread.isAlive():
        #     Logger().error("Detect monitor web console stopped, Monitor exit!")
        #     self.crash_module = "Monitor_web_console"
        #     return False

        if self.cloud_thread is not None and not self.cloud_thread.isAlive():
            Logger().error(
                "Detect monitor cloud thread stopped, Monitor exit!")
            self.crash_module = "cloud_thread"
            return False

        if self.transaction_thread is not None and not self.transaction_thread.isAlive(
        ):
            Logger().error(
                "Detect monitor cloud transaction thread stopped, Monitor exit!"
            )
            self.crash_module = "transaction_thread"
            return False

        if self.preprocessor_proc is None:
            pid = Communicator().get_value("pid", "Preprocessor")
            if pid != 0:
                try:
                    self.preprocessor_proc = psutil.Process(pid)
                except Exception:
                    Logger().error(
                        "Init Preprocessor proc fail, Monitor exit!")
                    self.crash_module = "preprocessor"
                    return False
            return True

        elif not self.preprocessor_proc.is_running():
            Logger().error("Detect preprocessor stopped, Monitor exit!")
            self.crash_module = "preprocessor"
            return False

        return True

    def _terminate_modules(self):
        """
        结束其他所有模块
        """
        all_procs = []
        scanner_num = Config().get_config("scanner.max_module_instance")

        for i in range(scanner_num):
            pid = Communicator().get_value("pid", "Scanner_" + str(i))
            if pid != 0:
                all_procs.append(pid)
        all_procs.append(Communicator().get_value("pid", "Preprocessor"))
        all_procs += Communicator().get_pre_http_pid()
        for pid in all_procs:
            if pid != 0:
                self._kill_proc_tree(pid)

        ppid = os.getppid()
        if ppid > 1:
            try:
                p = psutil.Process(ppid)
                p.kill()
            except Exception as e:
                Logger().error("Kill launcher failed", exc_info=e)

    def _kill_proc_tree(self, pid):
        """
        结束进程树, 递归结束目标和其子进程

        Parameters:
            pid - 进程pid
        """
        try:
            root_proc = psutil.Process(pid)
            procs = root_proc.children(recursive=True)
            procs.append(root_proc)
            for p in procs:
                p.send_signal(psutil.signal.SIGKILL)
        except Exception:
            pass

    def _get_self_ip(self):
        """
        获取本机ip
        """
        info = psutil.net_if_addrs()
        for name, value in info.items():
            for item in value:
                if (item[0] == 2 and item[1].find(".") > 0
                        and item[1] != '127.0.0.1' and item[2] is not None):
                    return item[1]
        return "127.0.0.1"

    def _clean_mei(self):
        """
        清理pyinstaller运行时的临时文件
        """
        if hasattr(sys, "_MEIPASS"):
            try:
                shutil.rmtree(sys._MEIPASS)
            except Exception as e:
                Logger().error("Clean pyinstaller temp path {} failed".format(
                    sys._MEIPASS),
                               exc_info=e)

    def run(self):
        """
        Monitor 主函数
        """

        # 多线程开始前初始化
        RuntimeInfo()

        if Config().get_config("cloud_api.enable"):
            self.cloud_thread = threading.Thread(target=self._upload_report,
                                                 name="upload_report_thread",
                                                 daemon=True)
            self.cloud_thread.start()

        # 初始化调度类
        scanner_schedulers = {}
        for module_name in RuntimeInfo().get_latest_info().keys():
            if module_name.startswith("Scanner"):
                scanner_schedulers[module_name] = ScannerScheduler(module_name)
        ScannerManager().init_manager(scanner_schedulers)

        # 启动后台http server
        # web_console = WebConsole()
        # self.web_console_thread = threading.Thread(
        #     target=web_console.run,
        #     name="web_console_thread",
        #     daemon=True
        # )
        # self.web_console_thread.start()

        # 向云控后台发送心跳,用于建立ws连接

        transaction = Transaction()
        self.transaction_thread = threading.Thread(target=transaction.run,
                                                   name="transaction_thread",
                                                   daemon=True)
        self.transaction_thread.start()

        time.sleep(1)
        if self._check_alive():
            print("[-] OpenRASP-IAST init success!")
            print("[-] Visit web console in cloud server: {}".format(
                Config().get_config("cloud_api.backend_url")))
            print(
                "[-] Before start scan task, set OpenRASP agent plugin algorithmConfig option 'fuzz_server' (edit iast.js or use cloud server web console)  with url: 'http://{}:{}{}'"
                .format(self._get_self_ip(),
                        Config().get_config("preprocessor.http_port"),
                        Config().get_config("preprocessor.api_path")))

            Logger().info("Monitor init success!")
        else:
            self._terminate_modules()
            sys.exit(1)

        while True:
            try:
                # 执行调度
                RuntimeInfo().refresh_info()
                for module_name in scanner_schedulers:
                    scanner_schedulers[module_name].do_schedule()
                time.sleep(Config().get_config("monitor.schedule_interval"))

                # 检测模块存活
                if not self._check_alive():
                    self._terminate_modules()
                    if self.crash_module == "main":
                        Logger().info("OpenRASP-IAST exit!")
                        print("[!] OpenRASP-IAST exit!")
                        self._clean_mei()
                        sys.exit(0)
                    else:
                        Logger().critical(
                            "Detect Module {} down, exit!".format(
                                self.crash_module))
                        self._clean_mei()
                        sys.exit(1)

            except Exception as e:
                Logger().critical("Monitor module crash with unknow error!",
                                  exc_info=e)
                self._terminate_modules()
                self._clean_mei()
                sys.exit(2)