diff --git a/Analyzer/analyzer.py b/Analyzer/analyzer.py index 7ea12da..1e68d4e 100644 --- a/Analyzer/analyzer.py +++ b/Analyzer/analyzer.py @@ -386,6 +386,10 @@ def preprocess(self, user_classes, user_functions, declared_interfaces, f.write(b'?>') self.target_file_list = self.s_analyzer.parse_file(EVAL_FILE) + # If PHP returns an empty array, Python treats it as a list. + if isinstance(user_classes, list): + user_classes = {} + target_class, target_function = \ self.d_analyzer.update_info(user_classes, user_functions, @@ -1153,6 +1157,11 @@ def write_code(item_name, item_info, cls=True, write=True): class_list = [] declared_flag = False + + # If PHP returns an empty array, Python treats it as a list. + if isinstance(user_classes, list): + user_classes = {} + for class_name, class_info in user_classes.items(): if not re.match(EXCLUDED_CLASSES_REGEX, class_name) and \ class_info['FILE_NAME'].startswith(self.target): diff --git a/Analyzer/dynamic.py b/Analyzer/dynamic.py index 4a3cdf2..b287287 100644 --- a/Analyzer/dynamic.py +++ b/Analyzer/dynamic.py @@ -124,6 +124,10 @@ def update_info(self, user_classes, user_functions, declared_classes, new_func_info['FILE_NAME'] = func_file target_function[func_name] = new_func_info + # If PHP returns an empty array, Python treats it as a list. + if isinstance(user_classes, list): + user_classes = {} + for class_name, class_info in user_classes.items(): if not re.match(EXCLUDED_CLASSES_REGEX, class_name): file_name = class_info['FILE_NAME'] diff --git a/Utils/HookFiles/HookHead.php b/Utils/HookFiles/HookHead.php index 651f076..0a7c58c 100644 --- a/Utils/HookFiles/HookHead.php +++ b/Utils/HookFiles/HookHead.php @@ -151,11 +151,13 @@ function get_class_props_r353t($clsname) { return $class_props; } -function get_user_classes_r353t() { +function get_user_classes_r353t($trigger_func, $func_argv) { $user_classes = Array(); - $declared_list = array_merge(get_declared_classes(), - get_declared_interfaces()); - $declared_list = array_merge($declared_list, get_declared_traits()); + $declared_list = array_merge(get_declared_classes(), get_declared_interfaces()); + $declared_list = filter_allowed_classes( + array_merge($declared_list, get_declared_traits()), + $trigger_func, + $func_argv); foreach ($declared_list as $clsname) { $cls = new ReflectionClass($clsname); $cls_org = $cls; @@ -251,9 +253,9 @@ function isPharDetected_r353t($case, $validator_md5) { return False; } -function get_declared_classes_r353t() { +function get_declared_classes_r353t($trigger_func, $func_argv) { $declared_classes = array(); - foreach (get_declared_classes() as $clsname) { + foreach (filter_allowed_classes(get_declared_classes(), $trigger_func, $func_argv) as $clsname) { $cls = new \ReflectionClass($clsname); $clsname = str_replace("\0", "", $clsname); $clsname = str_replace("/", "_", $clsname); @@ -286,6 +288,25 @@ function get_declared_traits_r353t() { return $traits; } +function filter_allowed_classes($array, $trigger_func, $func_argv) { + $return_array = $array; + if ($trigger_func == "unserialize" && count($func_argv) > 1) { + if (array_key_exists("allowed_classes", $func_argv[1])) { + if (gettype($func_argv[1]["allowed_classes"]) == "boolean") { + if ($func_argv[1]["allowed_classes"] == false) { + $return_array = Array(); + } else if ($func_argv[1]["allowed_classes"] == true) { + $return_array = $array; + } + } else if (gettype($func_argv[1]["allowed_classes"]) == "array") { + $allowed_classes = $func_argv[1]["allowed_classes"]; + $return_array = array_intersect($array, $allowed_classes); + } + } + } + return $return_array; +} + function saveDatas_r353t($argv_list, $trigger_func, $func_argv, $inject_idxs) { global $argv_list_r353t; $inject_points = explode(",", $inject_idxs); @@ -324,6 +345,21 @@ function saveDatas_r353t($argv_list, $trigger_func, $func_argv, $inject_idxs) { $class_list = Array(); $pid_list = Array(); + if ($trigger_func == "unserialize" && count($func_argv) > 1) { + if (array_key_exists("allowed_classes", $func_argv[1])) { + if (gettype($func_argv[1]["allowed_classes"]) == "boolean") { + if ($func_argv[1]["allowed_classes"] == false) { + $class_name_list = Array(); + } else if ($func_argv[1]["allowed_classes"] == true) { + $class_name_list = $class_name_list; + } + } else if (gettype($func_argv[1]["allowed_classes"]) == "array") { + $allowed_classes = $func_argv[1]["allowed_classes"]; + $class_name_list = array_intersect($class_name_list, $allowed_classes); + } + } + } + foreach($class_name_list as $cls_name) { $pid = pcntl_fork(); // error_log("Fork: $cls_name\n"); @@ -396,10 +432,10 @@ class_exists($cls_name); $argv_list_r353t['TRIGGER_FUNC'] = $trigger_func; $argv_list_r353t['FUNC_ARGV'] = $func_argv; - $argv_list_r353t['CLASSES'] = get_declared_classes_r353t(); + $argv_list_r353t['CLASSES'] = get_declared_classes_r353t($trigger_func, $func_argv); $argv_list_r353t['INTERFACES'] = get_declared_interfaces_r353t(); $argv_list_r353t['TRAITS'] = get_declared_traits_r353t(); - $argv_list_r353t['USER_CLASSES'] = get_user_classes_r353t(); + $argv_list_r353t['USER_CLASSES'] = get_user_classes_r353t($trigger_func, $func_argv); $argv_list_r353t['INCLUDED_FILES'] = get_included_files(); $copied_globals = new ArrayObject($GLOBALS); $argv_list_r353t['GLOBALS'] = $copied_globals->getArrayCopy();