From e7d30b628354b4cd483563b8d93a4618162ea398 Mon Sep 17 00:00:00 2001 From: felix-20 Date: Tue, 30 May 2023 09:24:16 +0200 Subject: [PATCH 1/3] review php patterns --- .../10_return_by_reference.json | 4 +- .../1_instance_10_return_by_reference.bash | 57 +- .../1_instance_10_return_by_reference.json | 1 + .../1_instance_10_return_by_reference.php | 4 +- PHP/10_return_by_reference/README.md | 159 +- .../docs/description.md | 1 + .../11_foreach_with_reference.json | 6 +- .../1_instance_11_foreach_with_reference.bash | 34 +- .../1_instance_11_foreach_with_reference.json | 3 +- PHP/11_foreach_with_reference/README.md | 129 +- .../docs/description.md | 19 + PHP/12_make_ref/12_make_ref.json | 4 +- PHP/12_make_ref/12_make_ref.sc | 6 + .../1_instance_12_make_ref.bash | 38 +- .../1_instance_12_make_ref.json | 7 +- .../1_instance_12_make_ref.php | 6 +- .../1_instance_12_make_ref.sc | 2 +- .../2_instance_12_make_ref.bash | 20 + .../2_instance_12_make_ref.json | 13 +- .../2_instance_12_make_ref.php | 6 +- PHP/12_make_ref/README.md | 256 ++-- PHP/12_make_ref/docs/description.md | 1 + .../13_assign_static_prop_ref.json | 4 +- .../1_instance_13_assign_static_prop_ref.bash | 31 +- .../1_instance_13_assign_static_prop_ref.json | 3 +- .../1_instance_13_assign_static_prop_ref.php | 4 +- PHP/13_assign_static_prop_ref/README.md | 126 +- .../docs/description.md | 1 + .../14_object_assigned_by_reference.json | 4 +- ....sc => 14_object_assigned_by_reference.sc} | 0 ...tance_14_object_assigned_by_reference.bash | 38 +- ...tance_14_object_assigned_by_reference.json | 5 +- ...stance_14_object_assigned_by_reference.php | 4 +- ...tance_14_object_assigned_by_reference.bash | 20 + ...tance_14_object_assigned_by_reference.json | 13 +- ...stance_14_object_assigned_by_reference.php | 4 +- ...tance_14_object_assigned_by_reference.bash | 21 + ...tance_14_object_assigned_by_reference.json | 13 +- ...stance_14_object_assigned_by_reference.php | 4 +- PHP/14_object_assigned_by_reference/README.md | 334 +++- .../docs/description.md | 1 + .../docs/discovery_notes.md | 1 + .../15_nested_function.json | 6 +- PHP/15_nested_function/15_nested_function.sc | 6 + .../1_instance_15_nested_function.bash | 61 +- .../1_instance_15_nested_function.json | 11 +- .../1_instance_15_nested_function.php | 5 +- .../1_instance_15_nested_function.sc | 2 +- .../2_instance_15_nested_function.bash | 34 + .../2_instance_15_nested_function.json | 12 +- .../2_instance_15_nested_function.php | 9 +- PHP/15_nested_function/README.md | 288 +++- PHP/15_nested_function/docs/description.md | 1 + .../16_variadic_functions.json | 4 +- ..._functions.sc => 16_variadic_functions.sc} | 0 .../1_instance_16_variadic_functions.bash | 58 +- .../1_instance_16_variadic_functions.json | 11 +- .../1_instance_16_variadic_functions.php | 7 +- .../2_instance_16_variadic_functions.bash | 28 + .../2_instance_16_variadic_functions.json | 13 +- .../2_instance_16_variadic_functions.php | 3 +- .../3_instance_16_variadic_functions.bash | 37 + .../3_instance_16_variadic_functions.json | 13 +- .../3_instance_16_variadic_functions.php | 7 +- PHP/16_variadic_functions/README.md | 375 ++++- PHP/16_variadic_functions/docs/description.md | 1 + PHP/17_get_arguments/17_get_arguments.json | 4 +- ...7_get_arguments.sc => 17_get_arguments.sc} | 0 .../1_instance_17_get_arguments.bash | 58 +- .../1_instance_17_get_arguments.json | 5 +- .../1_instance_17_get_arguments.php | 6 +- .../2_instance_17_get_arguments.bash | 28 + .../2_instance_17_get_arguments.json | 7 +- PHP/17_get_arguments/README.md | 277 +++- PHP/17_get_arguments/docs/description.md | 30 + PHP/18_send_unpack/18_send_unpack.json | 4 +- ...ce_18_send_unpack.sc => 18_send_unpack.sc} | 0 .../1_instance_18_send_unpack.bash | 56 +- .../1_instance_18_send_unpack.json | 5 +- .../1_instance_18_send_unpack.php | 6 +- .../2_instance_18_send_unpack.bash | 31 + .../2_instance_18_send_unpack.json | 7 +- .../2_instance_18_send_unpack.php | 6 +- .../3_instance_18_send_unpack.bash | 26 + .../3_instance_18_send_unpack.json | 11 +- .../3_instance_18_send_unpack.php | 6 +- PHP/18_send_unpack/README.md | 359 ++++- PHP/18_send_unpack/docs/description.md | 1 + PHP/18_send_unpack/docs/discovery_notes.md | 1 + PHP/19_closures/19_closures.json | 4 +- ...instance_19_closures.sc => 19_closures.sc} | 0 .../1_instance_19_closures.bash | 26 + .../1_instance_19_closures.json | 15 +- .../1_instance_19_closures.php | 5 +- .../2_instance_19_closures.bash | 89 +- .../2_instance_19_closures.json | 11 +- .../2_instance_19_closures.php | 6 +- .../2_instance_19_closures.sc | 6 - PHP/19_closures/README.md | 352 +++-- PHP/19_closures/docs/description.md | 3 + PHP/19_closures/docs/remediation_notes.md | 1 + .../1_instance_1_static_variables.bash | 54 +- .../1_instance_1_static_variables.json | 3 +- .../1_instance_1_static_variables.php | 2 +- .../1_instance_1_static_variables.sc | 4 +- .../docs/discovery_notes.md | 3 + PHP/1_static_variables/README.md | 173 ++- .../1_instance_20_use_with_closures.bash | 56 +- .../1_instance_20_use_with_closures.json | 1 + .../1_instance_20_use_with_closures.php | 4 +- .../1_instance_20_use_with_closures.sc | 2 +- .../20_use_with_closures.json | 4 +- .../2_instance_20_use_with_closures.bash | 56 +- .../2_instance_20_use_with_closures.json | 1 + .../2_instance_20_use_with_closures.php | 4 +- .../2_instance_20_use_with_closures.sc | 2 +- PHP/20_use_with_closures/README.md | 300 ++-- PHP/20_use_with_closures/docs/description.md | 1 + .../1_instance_21_simple_object.bash | 72 +- .../1_instance_21_simple_object.json | 9 +- .../1_instance_21_simple_object.php | 14 +- PHP/21_simple_object/21_simple_object.json | 4 +- PHP/21_simple_object/README.md | 175 ++- PHP/21_simple_object/docs/description.md | 1 + .../1_instance_22_assign_object.bash | 42 +- .../1_instance_22_assign_object.json | 5 +- .../1_instance_22_assign_object.php | 6 +- .../1_instance_22_assign_object.sc | 2 +- PHP/22_assign_object/22_assign_object.json | 4 +- PHP/22_assign_object/README.md | 135 +- PHP/22_assign_object/docs/description.md | 1 + PHP/22_assign_object/docs/discovery_notes.md | 3 + .../1_instance_23_object_argument.bash | 66 +- .../1_instance_23_object_argument.json | 5 +- .../1_instance_23_object_argument.php | 4 +- .../23_object_argument.json | 4 +- PHP/23_object_argument/README.md | 159 +- PHP/23_object_argument/docs/description.md | 1 + .../1_instance_24_new_self.bash | 92 +- .../1_instance_24_new_self.json | 11 +- .../1_instance_24_new_self.php | 27 +- PHP/24_new_self/24_new_self.json | 4 +- PHP/24_new_self/README.md | 218 +-- PHP/24_new_self/docs/description.md | 1 + .../1_instance_25_clone.bash | 77 +- .../1_instance_25_clone.json | 9 +- .../1_instance_25_clone.php | 19 +- PHP/25_clone/25_clone.json | 4 +- PHP/25_clone/README.md | 136 ++ PHP/25_clone/docs/description.md | 1 + .../1_instance_26_late_static_binding.bash | 82 +- .../1_instance_26_late_static_binding.json | 7 +- .../1_instance_26_late_static_binding.php | 11 +- .../26_late_static_binding.json | 4 +- .../2_instance_26_late_static_binding.bash | 82 +- .../2_instance_26_late_static_binding.json | 7 +- .../2_instance_26_late_static_binding.php | 11 +- PHP/26_late_static_binding/README.md | 282 ++++ .../docs/description.md | 1 + .../1_instance_27_get_called_class.bash | 86 +- .../1_instance_27_get_called_class.json | 5 +- .../1_instance_27_get_called_class.php | 11 +- .../27_get_called_class.json | 2 +- PHP/27_get_called_class/README.md | 145 ++ PHP/27_get_called_class/docs/description.md | 1 + .../1_instance_28_static_methods.bash | 64 +- .../1_instance_28_static_methods.json | 9 +- .../1_instance_28_static_methods.php | 15 +- PHP/28_static_methods/28_static_methods.json | 4 +- PHP/28_static_methods/README.md | 127 ++ PHP/28_static_methods/docs/description.md | 1 + .../1_instance_29_static_properties.bash | 72 +- .../1_instance_29_static_properties.json | 9 +- .../1_instance_29_static_properties.php | 15 +- .../29_static_properties.json | 4 +- PHP/29_static_properties/README.md | 133 ++ PHP/29_static_properties/docs/description.md | 1 + .../1_instance_2_global_variables.bash | 50 +- .../1_instance_2_global_variables.json | 1 + PHP/2_global_variables/README.md | 144 +- .../1_instance_30_anonymous_classes.bash | 54 +- .../1_instance_30_anonymous_classes.json | 9 +- .../1_instance_30_anonymous_classes.php | 10 +- .../30_anonymous_classes.json | 4 +- PHP/30_anonymous_classes/README.md | 129 ++ PHP/30_anonymous_classes/docs/description.md | 1 + .../1_instance_31_static_method_variable.bash | 25 + .../1_instance_31_static_method_variable.json | 9 +- .../1_instance_31_static_method_variable.php | 14 +- .../31_static_method_variable.json | 2 +- PHP/31_static_method_variable/README.md | 115 ++ .../docs/description.md | 1 + .../1_instance_32_set_overloading.bash | 51 +- .../1_instance_32_set_overloading.json | 9 +- .../1_instance_32_set_overloading.php | 8 +- .../2_instance_32_set_overloading.bash | 27 + .../2_instance_32_set_overloading.json | 38 + .../2_instance_32_set_overloading.php | 12 + .../32_set_overloading.json | 7 +- ...t_overloading.sc => 32_set_overloading.sc} | 4 +- PHP/32_set_overloading/README.md | 237 +++ PHP/32_set_overloading/docs/description.md | 1 + .../docs/discovery_notes.md | 3 + .../1_instance_33_get_overloading.bash | 42 + .../1_instance_33_get_overloading.json | 5 +- .../1_instance_33_get_overloading.php | 16 +- .../1_instance_33_get_overloading.sc | 4 +- .../33_get_overloading.json | 2 +- PHP/33_get_overloading/README.md | 142 ++ PHP/33_get_overloading/docs/description.md | 1 + .../1_instance_34_isset_overloading.bash | 41 + .../1_instance_34_isset_overloading.json | 11 +- .../1_instance_34_isset_overloading.php | 18 +- .../1_instance_34_isset_overloading.sc | 7 - .../2_instance_34_isset_overloading.bash | 41 + .../2_instance_34_isset_overloading.json | 11 +- .../2_instance_34_isset_overloading.php | 18 +- .../2_instance_34_isset_overloading.sc | 7 - .../34_isset_overloading.json | 7 +- .../34_isset_overloading.sc | 8 + .../3_instance_34_isset_overloading.bash | 41 + .../3_instance_34_isset_overloading.json | 38 + .../3_instance_34_isset_overloading.php | 21 + .../4_instance_34_isset_overloading.bash | 30 + .../4_instance_34_isset_overloading.json | 38 + .../4_instance_34_isset_overloading.php | 17 + PHP/34_isset_overloading/README.md | 539 +++++++ PHP/34_isset_overloading/docs/description.md | 1 + .../docs/discovery_notes.md | 3 + .../1_instance_35_unset_overloading.bash | 39 + .../1_instance_35_unset_overloading.json | 11 +- .../1_instance_35_unset_overloading.php | 20 +- .../1_instance_35_unset_overloading.sc | 7 - .../2_instance_35_unset_overloading.bash | 39 + .../2_instance_35_unset_overloading.json | 38 + .../2_instance_35_unset_overloading.php | 18 + .../35_unset_overloading.json | 8 +- .../35_unset_overloading.sc | 7 + .../3_instance_35_unset_overloading.bash | 28 + .../3_instance_35_unset_overloading.json | 38 + .../3_instance_35_unset_overloading.php | 14 + PHP/35_unset_overloading/README.md | 386 +++++ PHP/35_unset_overloading/docs/description.md | 1 + .../docs/discovery_notes.md | 3 + .../1_instance_36_call_overloading.bash | 73 +- .../1_instance_36_call_overloading.json | 11 +- .../1_instance_36_call_overloading.php | 17 +- .../1_instance_36_call_overloading.sc | 5 +- .../36_call_overloading.json | 2 +- PHP/36_call_overloading/README.md | 134 ++ PHP/36_call_overloading/docs/description.md | 1 + .../1_instance_37_callstatic_overloading.bash | 71 +- .../1_instance_37_callstatic_overloading.json | 7 +- .../1_instance_37_callstatic_overloading.php | 14 +- .../1_instance_37_callstatic_overloading.sc | 4 +- .../37_callstatic_overloading.json | 2 +- PHP/37_callstatic_overloading/README.md | 133 ++ .../docs/description.md | 1 + .../1_instance_38_invoke.bash | 58 +- .../1_instance_38_invoke.json | 9 +- .../1_instance_38_invoke.php | 15 +- .../1_instance_38_invoke.sc | 4 +- PHP/38_invoke/38_invoke.json | 4 +- PHP/38_invoke/README.md | 121 ++ PHP/38_invoke/docs/description.md | 1 + .../1_instance_39_serialize_unserialize.bash | 90 +- .../1_instance_39_serialize_unserialize.json | 7 +- .../1_instance_39_serialize_unserialize.php | 25 +- .../39_serialize_unserialize.json | 4 +- PHP/39_serialize_unserialize/README.md | 146 ++ .../docs/description.md | 1 + .../1_instance_3_global_array.bash | 23 + .../1_instance_3_global_array.json | 9 +- .../1_instance_3_global_array.php | 3 +- .../1_instance_3_global_array.sc | 2 +- .../2_instance_3_global_array.bash | 13 + .../2_instance_3_global_array.json | 11 +- .../2_instance_3_global_array.php | 3 +- .../2_instance_3_global_array.sc | 2 +- PHP/3_global_array/3_global_array.json | 4 +- PHP/3_global_array/README.md | 241 ++- PHP/3_global_array/docs/description.md | 1 + .../1_instance_40_trait.bash | 54 +- .../1_instance_40_trait.json | 9 +- .../1_instance_40_trait.php | 12 +- PHP/40_trait/40_trait.json | 4 +- PHP/40_trait/README.md | 125 ++ PHP/40_trait/docs/description.md | 1 + .../1_instance_41_self_methods.bash | 73 +- .../1_instance_41_self_methods.json | 9 +- .../1_instance_41_self_methods.php | 17 +- .../_1_instance_41_self_methods.bash | 41 + PHP/41_self_methods/41_self_methods.json | 4 +- PHP/41_self_methods/README.md | 136 ++ PHP/41_self_methods/docs/description.md | 1 + .../1_instance_42_destructor.bash | 72 +- .../1_instance_42_destructor.json | 11 +- .../1_instance_42_destructor.php | 7 +- .../1_instance_42_destructor.sc | 4 +- PHP/42_destructor/42_destructor.json | 4 +- PHP/42_destructor/README.md | 133 ++ PHP/42_destructor/docs/description.md | 1 + .../1_instance_43_tostring_echo_object.bash | 73 +- .../1_instance_43_tostring_echo_object.json | 11 +- .../1_instance_43_tostring_echo_object.php | 11 +- .../1_instance_43_tostring_echo_object.sc | 4 +- .../43_tostring_echo_object.json | 4 +- PHP/43_tostring_echo_object/README.md | 149 ++ .../docs/description.md | 1 + .../1_instance_44_verify_return_type.bash | 101 +- .../1_instance_44_verify_return_type.json | 15 +- .../1_instance_44_verify_return_type.php | 18 +- .../1_instance_44_verify_return_type.sc | 5 +- .../2_instance_44_verify_return_type.bash | 104 +- .../2_instance_44_verify_return_type.json | 13 +- .../2_instance_44_verify_return_type.php | 20 +- .../2_instance_44_verify_return_type.sc | 2 +- .../44_verify_return_type.json | 4 +- .../44_verify_return_type.sc | 6 - PHP/44_verify_return_type/README.md | 328 ++++ PHP/44_verify_return_type/docs/description.md | 1 + .../1_instance_46_object_to_array.bash | 59 +- .../1_instance_46_object_to_array.json | 7 +- .../1_instance_46_object_to_array.php | 16 +- .../46_object_to_array.json | 6 +- PHP/46_object_to_array/README.md | 125 ++ PHP/46_object_to_array/docs/description.md | 1 + ...nstance_48_construct_with_inheritance.bash | 55 +- ...nstance_48_construct_with_inheritance.json | 7 +- ...instance_48_construct_with_inheritance.php | 17 +- ..._instance_48_construct_with_inheritance.py | 77 - ..._instance_48_construct_with_inheritance.sc | 7 +- .../48_construct_with_inheritance.json | 4 +- PHP/48_construct_with_inheritance/README.md | 121 ++ .../docs/description.md | 1 + .../1_instance_49_static_instance.bash | 77 +- .../1_instance_49_static_instance.json | 5 +- .../1_instance_49_static_instance.php | 16 +- .../1_instance_49_static_instance.sc | 13 +- .../49_static_instance.json | 4 +- PHP/49_static_instance/README.md | 141 ++ PHP/49_static_instance/docs/description.md | 1 + .../1_instance_4_conditional_assignment.bash | 40 +- .../1_instance_4_conditional_assignment.json | 5 +- .../4_conditional_assignment.json | 4 +- PHP/4_conditional_assignment/README.md | 146 +- .../docs/description.md | 1 + .../1_instance_50_throw_exception.bash | 93 +- .../1_instance_50_throw_exception.json | 5 +- .../1_instance_50_throw_exception.php | 4 +- .../50_throw_exception.json | 4 +- PHP/50_throw_exception/README.md | 142 ++ PHP/50_throw_exception/docs/description.md | 1 + .../1_instance_51_catch_exceptions.bash | 48 + .../1_instance_51_catch_exceptions.json | 9 +- .../1_instance_51_catch_exceptions.php | 17 + .../51_catch_exceptions.json | 4 +- PHP/51_catch_exceptions/README.md | 144 ++ PHP/51_catch_exceptions/docs/description.md | 1 + .../1_instance_52_try_catch_finally.bash | 96 +- .../1_instance_52_try_catch_finally.json | 9 +- .../1_instance_52_try_catch_finally.php | 8 +- .../1_instance_52_try_catch_finally.sc | 4 +- .../2_instance_52_try_catch_finally.bash | 101 +- .../2_instance_52_try_catch_finally.json | 9 +- .../2_instance_52_try_catch_finally.php | 8 +- .../52_try_catch_finally.json | 4 +- .../52_try_catch_finally.sc | 6 + PHP/52_try_catch_finally/README.md | 304 ++++ PHP/52_try_catch_finally/docs/description.md | 1 + .../1_instance_53_track_error.bash | 42 +- .../1_instance_53_track_error.json | 5 +- .../1_instance_53_track_error.php | 6 +- .../1_instance_53_track_error.sc | 4 +- PHP/53_track_error/53_track_error.json | 4 +- PHP/53_track_error/README.md | 106 ++ PHP/53_track_error/docs/description.md | 1 + .../1_instance_54_generators.bash | 77 +- .../1_instance_54_generators.json | 9 +- .../1_instance_54_generators.php | 5 +- .../1_instance_54_generators.sc | 4 +- PHP/54_generators/54_generators.json | 4 +- PHP/54_generators/README.md | 128 ++ PHP/54_generators/docs/description.md | 1 + .../1_instance_55_goto.bash | 37 +- .../1_instance_55_goto.json | 3 +- .../1_instance_55_goto/1_instance_55_goto.php | 6 +- PHP/55_goto/55_goto.json | 4 +- PHP/55_goto/README.md | 129 ++ PHP/55_goto/docs/description.md | 1 + .../1_instance_56_exit.bash | 20 +- .../1_instance_56_exit.json | 5 +- .../1_instance_56_exit/1_instance_56_exit.php | 5 +- .../1_instance_56_exit/1_instance_56_exit.sc | 4 +- PHP/56_exit/56_exit.json | 4 +- PHP/56_exit/README.md | 93 ++ PHP/56_exit/docs/description.md | 2 + .../1_instance_57_js_redirect.json | 17 +- .../1_instance_57_js_redirect.sc | 7 + .../1_instance_57_js_redirect_0.bash | 12 + .../1_instance_57_js_redirect_0.php | 4 + .../1_instance_57_js_redirect_1.bash | 17 + .../1_instance_57_js_redirect_1.php | 6 + PHP/57_js_redirect/57_js_redirect.json | 8 +- PHP/57_js_redirect/README.md | 114 ++ PHP/57_js_redirect/docs/description.md | 1 + .../1_instance_58_simple_array.bash | 35 +- .../1_instance_58_simple_array.json | 7 +- .../1_instance_58_simple_array.php | 5 +- .../2_instance_58_simple_array.bash | 35 +- .../2_instance_58_simple_array.json | 7 +- .../2_instance_58_simple_array.php | 5 +- PHP/58_simple_array/58_simple_array.json | 4 +- PHP/58_simple_array/58_simple_array.sc | 6 + PHP/58_simple_array/README.md | 202 +++ PHP/58_simple_array/docs/description.md | 1 + .../1_instance_59_foreach_with_array.bash | 63 +- .../1_instance_59_foreach_with_array.json | 5 +- .../1_instance_59_foreach_with_array.php | 6 +- .../1_instance_59_foreach_with_array.sc | 4 +- .../2_instance_59_foreach_with_array.bash | 57 +- .../2_instance_59_foreach_with_array.json | 5 +- .../2_instance_59_foreach_with_array.php | 6 +- .../2_instance_59_foreach_with_array.sc | 4 +- .../59_foreach_with_array.json | 6 +- PHP/59_foreach_with_array/README.md | 243 +++ PHP/59_foreach_with_array/docs/description.md | 1 + .../1_instance_5_combined_operator.bash | 24 +- .../1_instance_5_combined_operator.json | 10 +- .../1_instance_5_combined_operator.php | 4 +- .../2_instance_5_combined_operator.bash | 22 +- .../2_instance_5_combined_operator.json | 14 +- .../2_instance_5_combined_operator.php | 4 +- .../2_instance_5_combined_operator.sc | 2 +- .../3_instance_5_combined_operator.bash | 14 + .../3_instance_5_combined_operator.json | 14 +- .../3_instance_5_combined_operator.php | 6 +- .../3_instance_5_combined_operator.sc | 6 + .../5_combined_operator.json | 4 +- PHP/5_combined_operator/README.md | 319 +++- PHP/5_combined_operator/docs/description.md | 1 + .../docs/remediation_notes.md | 1 + .../1_instance_60_array_walk.bash | 29 + .../1_instance_60_array_walk.json | 11 +- .../1_instance_60_array_walk.php | 7 +- .../2_instance_60_array_walk.bash | 32 + .../2_instance_60_array_walk.json | 11 +- .../2_instance_60_array_walk.php | 7 +- PHP/60_array_walk/60_array_walk.json | 2 +- PHP/60_array_walk/60_array_walk.sc | 6 + PHP/60_array_walk/README.md | 258 ++++ PHP/60_array_walk/docs/description.md | 1 + .../1_instance_61_array_map.bash | 31 + .../1_instance_61_array_map.json | 7 +- .../1_instance_61_array_map.php | 4 +- .../2_instance_61_array_map.bash | 32 + .../2_instance_61_array_map.json | 11 +- .../2_instance_61_array_map.php | 9 +- PHP/61_array_map/61_array_map.json | 2 +- PHP/61_array_map/61_array_map.sc | 6 + PHP/61_array_map/README.md | 237 +++ PHP/61_array_map/docs/description.md | 1 + ...stance_62_parse_str_built_in_function.bash | 40 +- ...stance_62_parse_str_built_in_function.json | 5 +- ...nstance_62_parse_str_built_in_function.php | 4 +- ...instance_62_parse_str_built_in_function.sc | 4 +- .../62_parse_str_built_in_function.json | 6 +- PHP/62_parse_str_built_in_function/README.md | 106 ++ .../docs/description.md | 1 + ...3_substring_replace_built_in_function.bash | 50 +- ...3_substring_replace_built_in_function.json | 9 +- ...63_substring_replace_built_in_function.php | 9 +- ..._63_substring_replace_built_in_function.sc | 4 +- ...3_substring_replace_built_in_function.json | 6 +- .../README.md | 104 ++ .../docs/description.md | 1 + .../1_instance_64_preg_match.bash | 33 +- .../1_instance_64_preg_match.json | 9 +- .../1_instance_64_preg_match.php | 6 +- .../1_instance_64_preg_match.sc | 4 +- PHP/64_preg_match/64_preg_match.json | 4 +- PHP/64_preg_match/README.md | 101 ++ PHP/64_preg_match/docs/description.md | 1 + .../1_instance_65_system.bash | 26 +- .../1_instance_65_system.json | 5 +- .../1_instance_65_system.php | 4 +- .../1_instance_65_system.sc | 4 +- .../2_instance_65_system.bash | 26 +- .../2_instance_65_system.json | 5 +- .../2_instance_65_system.php | 4 +- .../2_instance_65_system.sc | 4 +- .../3_instance_65_system.bash | 24 +- .../3_instance_65_system.json | 5 +- .../3_instance_65_system.php | 4 +- .../3_instance_65_system.sc | 4 +- PHP/65_system/65_system.json | 4 +- PHP/65_system/README.md | 280 ++++ PHP/65_system/docs/description.md | 5 + .../1_instance_66_superglobals.bash | 18 +- .../1_instance_66_superglobals.json | 7 +- .../1_instance_66_superglobals.php | 3 +- .../2_instance_66_superglobals.json | 15 +- .../2_instance_66_superglobals_0.bash | 11 + .../2_instance_66_superglobals_0.php | 3 + .../2_instance_66_superglobals_1.bash | 16 + .../2_instance_66_superglobals_1.php | 6 + .../3_instance_66_superglobals.bash | 18 +- .../3_instance_66_superglobals.json | 7 +- .../3_instance_66_superglobals.php | 4 +- .../3_instance_66_superglobals.sc | 4 +- .../4_instance_66_superglobals.bash | 18 +- .../4_instance_66_superglobals.json | 7 +- .../4_instance_66_superglobals.php | 4 +- PHP/66_superglobals/66_superglobals.json | 4 +- PHP/66_superglobals/README.md | 361 +++++ PHP/66_superglobals/docs/description.md | 1 + .../1_instance_67_odbc.bash | 49 +- .../1_instance_67_odbc.json | 5 +- .../1_instance_67_odbc/1_instance_67_odbc.php | 7 +- PHP/67_odbc/67_odbc.json | 6 +- PHP/67_odbc/README.md | 109 ++ PHP/67_odbc/docs/description.md | 1 + .../1_instance_68_compact.bash | 19 + .../1_instance_68_compact.json | 5 +- .../1_instance_68_compact.php | 4 +- .../2_instance_68_compact.bash | 52 +- .../2_instance_68_compact.json | 5 +- .../2_instance_68_compact.php | 4 +- PHP/68_compact/68_compact.json | 2 +- PHP/68_compact/68_compact.sc | 6 + PHP/68_compact/README.md | 212 +++ PHP/68_compact/docs/description.md | 1 + .../1_instance_69_create_function.bash | 35 +- .../1_instance_69_create_function.json | 5 +- .../1_instance_69_create_function.php | 5 +- .../1_instance_69_create_function.sc | 4 +- .../69_create_function.json | 2 +- PHP/69_create_function/README.md | 102 ++ PHP/69_create_function/docs/description.md | 2 + .../1_instance_70_extract.bash | 37 +- .../1_instance_70_extract.json | 3 +- .../1_instance_70_extract.php | 8 +- .../1_instance_70_extract.sc | 4 +- PHP/70_extract/70_extract.json | 2 +- PHP/70_extract/README.md | 103 ++ PHP/70_extract/docs/description.md | 1 + .../1_instance_71_array_functions.bash | 44 +- .../1_instance_71_array_functions.json | 3 +- .../1_instance_71_array_functions.php | 13 +- .../2_instance_71_array_functions.bash | 38 +- .../2_instance_71_array_functions.json | 3 +- .../2_instance_71_array_functions.php | 5 +- .../71_array_functions.json | 2 +- PHP/71_array_functions/README.md | 208 +++ PHP/71_array_functions/docs/description.md | 1 + .../1_instance_72_procedural_queries.bash | 49 +- .../1_instance_72_procedural_queries.json | 5 +- .../1_instance_72_procedural_queries.php | 4 +- .../2_instance_72_procedural_queries.bash | 49 +- .../2_instance_72_procedural_queries.json | 5 +- .../2_instance_72_procedural_queries.php | 4 +- .../3_instance_72_procedural_queries.bash | 48 +- .../3_instance_72_procedural_queries.json | 5 +- .../3_instance_72_procedural_queries.php | 4 +- .../72_procedural_queries.json | 4 +- PHP/72_procedural_queries/README.md | 315 ++++ PHP/72_procedural_queries/docs/description.md | 1 + .../1_instance_73_wrong_sanitizer.bash | 36 +- .../1_instance_73_wrong_sanitizer.json | 5 +- .../1_instance_73_wrong_sanitizer.php | 4 +- .../2_instance_73_wrong_sanitizer.bash | 25 +- .../2_instance_73_wrong_sanitizer.json | 9 +- .../2_instance_73_wrong_sanitizer.php | 7 +- .../73_wrong_sanitizer.json | 4 +- PHP/73_wrong_sanitizer/README.md | 199 +++ PHP/73_wrong_sanitizer/docs/description.md | 1 + .../1_instance_74_dirname.bash | 18 + .../1_instance_74_dirname.json | 21 +- .../1_instance_74_dirname.php | 8 + .../1_instance_74_dirname.sc | 6 + .../_code/1_instance_74_dirname_0.bash | 21 + .../_code/1_instance_74_dirname_0.php | 7 + .../_includes/1_instance_74_dirname_1.bash | 9 + .../_includes/1_instance_74_dirname_1.php | 2 + PHP/74_dirname/74_dirname.json | 2 +- PHP/74_dirname/README.md | 115 ++ PHP/74_dirname/docs/description.md | 1 + .../1_instance_76_function_variable.bash | 22 +- .../1_instance_76_function_variable.json | 3 +- .../1_instance_76_function_variable.php | 3 +- .../2_instance_76_function_variable.bash | 6 +- .../2_instance_76_function_variable.json | 5 +- .../2_instance_76_function_variable.php | 2 +- .../76_function_variable.json | 4 +- .../76_function_variable.sc | 6 + PHP/76_function_variable/README.md | 220 +++ PHP/76_function_variable/docs/description.md | 1 + .../1_instance_77_object_callable.bash | 75 +- .../1_instance_77_object_callable.json | 7 +- .../1_instance_77_object_callable.php | 21 +- .../2_instance_77_object_callable.bash | 84 +- .../2_instance_77_object_callable.json | 7 +- .../2_instance_77_object_callable.php | 19 +- .../77_object_callable.json | 4 +- PHP/77_object_callable/77_object_callable.sc | 2 +- PHP/77_object_callable/README.md | 267 ++++ PHP/77_object_callable/docs/description.md | 1 + .../1_instance_78_autoloading_classes.bash | 75 +- .../1_instance_78_autoloading_classes.json | 11 +- .../1_instance_78_autoloading_classes.php | 7 +- .../1_instance_78_autoloading_classes.sc | 4 +- .../78_autoloading_classes.json | 4 +- PHP/78_autoloading_classes/README.md | 159 ++ .../docs/description.md | 18 + .../1_instance_79_dynamic_include.json | 13 +- .../1_instance_79_dynamic_include.sc | 4 +- .../1_instance_79_dynamic_include_0.bash | 12 + .../1_instance_79_dynamic_include_0.php | 4 + .../1_instance_79_dynamic_include_1.bash | 8 + .../1_instance_79_dynamic_include_1.php | 2 + .../2_instance_79_dynamic_include.json | 15 +- .../2_instance_79_dynamic_include.sc | 4 +- .../2_instance_79_dynamic_include_0.bash | 8 + .../2_instance_79_dynamic_include_0.php | 2 + .../2_instance_79_dynamic_include_1.bash | 18 + .../2_instance_79_dynamic_include_1.php | 9 + .../2_instance_79_dynamic_include_2.bash | 8 + .../2_instance_79_dynamic_include_2.php | 2 + .../3_instance_79_dynamic_include.json | 15 +- .../3_instance_79_dynamic_include.sc | 4 +- .../3_instance_79_dynamic_include_0.bash | 14 + .../3_instance_79_dynamic_include_0.php | 5 + .../3_instance_79_dynamic_include_1.bash | 8 + .../3_instance_79_dynamic_include_1.php | 2 + .../4_instance_79_dynamic_include.json | 15 +- .../4_instance_79_dynamic_include.sc | 4 +- .../4_instance_79_dynamic_include_0.bash | 8 + .../4_instance_79_dynamic_include_0.php | 2 + .../4_instance_79_dynamic_include_1.bash | 13 + .../4_instance_79_dynamic_include_1.php | 4 + .../5_instance_79_dynamic_include.json | 13 +- .../5_instance_79_dynamic_include.sc | 4 +- .../5_instance_79_dynamic_include_0.bash | 8 + .../5_instance_79_dynamic_include_0.php | 2 + .../5_instance_79_dynamic_include_1.bash | 11 + .../5_instance_79_dynamic_include_1.php | 3 + .../79_dynamic_include.json | 4 +- PHP/79_dynamic_include/README.md | 499 ++++++ PHP/79_dynamic_include/docs/description.md | 1 + ...stance_7_string_arithmetic_operations.bash | 20 + ...stance_7_string_arithmetic_operations.json | 3 +- ...nstance_7_string_arithmetic_operations.php | 8 +- ...stance_7_string_arithmetic_operations.bash | 20 + ...stance_7_string_arithmetic_operations.json | 3 +- ...nstance_7_string_arithmetic_operations.php | 8 +- ...stance_7_string_arithmetic_operations.bash | 20 + ...stance_7_string_arithmetic_operations.json | 3 +- ...nstance_7_string_arithmetic_operations.php | 8 +- ...stance_7_string_arithmetic_operations.bash | 12 + ...stance_7_string_arithmetic_operations.json | 3 +- ...nstance_7_string_arithmetic_operations.php | 6 +- ...stance_7_string_arithmetic_operations.bash | 12 + ...stance_7_string_arithmetic_operations.json | 3 +- ...nstance_7_string_arithmetic_operations.php | 6 +- ...stance_7_string_arithmetic_operations.bash | 12 + ...stance_7_string_arithmetic_operations.json | 3 +- ...nstance_7_string_arithmetic_operations.php | 6 +- ...stance_7_string_arithmetic_operations.bash | 12 + ...stance_7_string_arithmetic_operations.json | 3 +- ...nstance_7_string_arithmetic_operations.php | 6 +- ...stance_7_string_arithmetic_operations.bash | 15 + ...stance_7_string_arithmetic_operations.json | 3 +- ...nstance_7_string_arithmetic_operations.php | 6 +- ...stance_7_string_arithmetic_operations.bash | 15 + ...stance_7_string_arithmetic_operations.json | 3 +- ...nstance_7_string_arithmetic_operations.php | 8 +- ...instance_7_string_arithmetic_operations.sc | 2 +- ...stance_7_string_arithmetic_operations.bash | 15 + ...stance_7_string_arithmetic_operations.json | 3 +- ...nstance_7_string_arithmetic_operations.php | 8 +- ...instance_7_string_arithmetic_operations.sc | 2 +- .../7_string_arithmetic_operations.json | 4 +- ...stance_7_string_arithmetic_operations.bash | 15 + ...stance_7_string_arithmetic_operations.json | 3 +- ...nstance_7_string_arithmetic_operations.php | 8 +- ...stance_7_string_arithmetic_operations.bash | 20 + ...stance_7_string_arithmetic_operations.json | 3 +- ...nstance_7_string_arithmetic_operations.php | 8 +- PHP/7_string_arithmetic_operations/README.md | 1341 +++++++++++++---- .../docs/description.md | 1 + .../1_instance_80_callback_functions.bash | 25 +- .../1_instance_80_callback_functions.json | 5 +- .../1_instance_80_callback_functions.php | 5 +- .../1_instance_80_callback_functions.sc | 4 +- .../2_instance_80_callback_functions.bash | 43 +- .../2_instance_80_callback_functions.json | 3 +- .../2_instance_80_callback_functions.php | 6 +- .../3_instance_80_callback_functions.bash | 46 +- .../3_instance_80_callback_functions.json | 5 +- .../3_instance_80_callback_functions.php | 8 +- .../3_instance_80_callback_functions.sc | 4 +- .../4_instance_80_callback_functions.bash | 46 +- .../4_instance_80_callback_functions.json | 5 +- .../4_instance_80_callback_functions.php | 6 +- .../4_instance_80_callback_functions.sc | 4 +- .../5_instance_80_callback_functions.bash | 49 +- .../5_instance_80_callback_functions.json | 5 +- .../5_instance_80_callback_functions.php | 6 +- .../5_instance_80_callback_functions.sc | 4 +- .../80_callback_functions.json | 4 +- PHP/80_callback_functions/README.md | 653 ++++++++ PHP/80_callback_functions/docs/description.md | 14 + .../1_instance_81_new_from_variable.bash | 69 +- .../1_instance_81_new_from_variable.json | 7 +- .../1_instance_81_new_from_variable.php | 14 +- .../1_instance_81_new_from_variable.sc | 6 +- .../2_instance_81_new_from_variable.bash | 73 +- .../2_instance_81_new_from_variable.json | 7 +- .../2_instance_81_new_from_variable.php | 14 +- .../2_instance_81_new_from_variable.sc | 6 +- .../3_instance_81_new_from_variable.bash | 78 +- .../3_instance_81_new_from_variable.json | 7 +- .../3_instance_81_new_from_variable.php | 12 +- .../3_instance_81_new_from_variable.sc | 6 +- .../81_new_from_variable.json | 4 +- PHP/81_new_from_variable/README.md | 354 +++++ PHP/81_new_from_variable/docs/description.md | 1 + .../1_instance_82_methods_variable.bash | 55 +- .../1_instance_82_methods_variable.json | 7 +- .../1_instance_82_methods_variable.php | 12 +- .../1_instance_82_methods_variable.sc | 4 +- .../2_instance_82_methods_variable.bash | 59 +- .../2_instance_82_methods_variable.json | 7 +- .../2_instance_82_methods_variable.php | 14 +- .../2_instance_82_methods_variable.sc | 4 +- .../82_methods_variable.json | 4 +- PHP/82_methods_variable/README.md | 236 +++ PHP/82_methods_variable/docs/description.md | 1 + .../1_instance_84_variable_variables.bash | 25 +- .../1_instance_84_variable_variables.json | 7 +- .../1_instance_84_variable_variables.php | 7 +- .../1_instance_84_variable_variables.sc | 4 +- .../2_instance_84_variable_variables.bash | 29 +- .../2_instance_84_variable_variables.json | 3 +- .../2_instance_84_variable_variables.php | 6 +- .../2_instance_84_variable_variables.sc | 2 +- .../84_variable_variables.json | 4 +- PHP/84_variable_variables/README.md | 202 +++ PHP/84_variable_variables/docs/description.md | 14 + .../1_instance_85_test_pattern.bash | 11 + .../1_instance_85_test_pattern.json | 38 + .../1_instance_85_test_pattern.php | 8 + .../1_instance_85_test_pattern.sc | 7 + PHP/85_test_pattern/85_test_pattern.json | 13 + PHP/85_test_pattern/docs/description.md | 0 .../1_instance_8_simple_reference.bash | 29 +- .../1_instance_8_simple_reference.json | 3 +- .../1_instance_8_simple_reference.php | 2 +- .../8_simple_reference.json | 4 +- PHP/8_simple_reference/README.md | 122 +- PHP/8_simple_reference/docs/description.md | 1 + .../1_instance_9_reference_argument.bash | 48 +- .../1_instance_9_reference_argument.json | 5 +- .../1_instance_9_reference_argument.php | 4 +- .../9_reference_argument.json | 4 +- PHP/9_reference_argument/README.md | 157 +- PHP/9_reference_argument/docs/description.md | 1 + 767 files changed, 21360 insertions(+), 5727 deletions(-) create mode 100644 PHP/10_return_by_reference/docs/description.md create mode 100644 PHP/11_foreach_with_reference/docs/description.md create mode 100644 PHP/12_make_ref/12_make_ref.sc create mode 100644 PHP/12_make_ref/2_instance_12_make_ref/2_instance_12_make_ref.bash create mode 100644 PHP/12_make_ref/docs/description.md create mode 100644 PHP/13_assign_static_prop_ref/docs/description.md rename PHP/14_object_assigned_by_reference/{1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.sc => 14_object_assigned_by_reference.sc} (100%) create mode 100644 PHP/14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference.bash create mode 100644 PHP/14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference.bash create mode 100644 PHP/14_object_assigned_by_reference/docs/description.md create mode 100644 PHP/14_object_assigned_by_reference/docs/discovery_notes.md create mode 100644 PHP/15_nested_function/15_nested_function.sc create mode 100644 PHP/15_nested_function/2_instance_15_nested_function/2_instance_15_nested_function.bash create mode 100644 PHP/15_nested_function/docs/description.md rename PHP/16_variadic_functions/{1_instance_16_variadic_functions/1_instance_16_variadic_functions.sc => 16_variadic_functions.sc} (100%) create mode 100644 PHP/16_variadic_functions/2_instance_16_variadic_functions/2_instance_16_variadic_functions.bash create mode 100644 PHP/16_variadic_functions/3_instance_16_variadic_functions/3_instance_16_variadic_functions.bash create mode 100644 PHP/16_variadic_functions/docs/description.md rename PHP/17_get_arguments/{1_instance_17_get_arguments/1_instance_17_get_arguments.sc => 17_get_arguments.sc} (100%) create mode 100644 PHP/17_get_arguments/2_instance_17_get_arguments/2_instance_17_get_arguments.bash create mode 100644 PHP/17_get_arguments/docs/description.md rename PHP/18_send_unpack/{1_instance_18_send_unpack/1_instance_18_send_unpack.sc => 18_send_unpack.sc} (100%) create mode 100644 PHP/18_send_unpack/2_instance_18_send_unpack/2_instance_18_send_unpack.bash create mode 100644 PHP/18_send_unpack/3_instance_18_send_unpack/3_instance_18_send_unpack.bash create mode 100644 PHP/18_send_unpack/docs/description.md create mode 100644 PHP/18_send_unpack/docs/discovery_notes.md rename PHP/19_closures/{1_instance_19_closures/1_instance_19_closures.sc => 19_closures.sc} (100%) create mode 100644 PHP/19_closures/1_instance_19_closures/1_instance_19_closures.bash delete mode 100644 PHP/19_closures/2_instance_19_closures/2_instance_19_closures.sc create mode 100644 PHP/19_closures/docs/description.md create mode 100644 PHP/19_closures/docs/remediation_notes.md create mode 100644 PHP/1_static_variables/1_instance_1_static_variables/docs/discovery_notes.md create mode 100644 PHP/20_use_with_closures/docs/description.md create mode 100644 PHP/21_simple_object/docs/description.md create mode 100644 PHP/22_assign_object/docs/description.md create mode 100644 PHP/22_assign_object/docs/discovery_notes.md create mode 100644 PHP/23_object_argument/docs/description.md create mode 100644 PHP/24_new_self/docs/description.md create mode 100644 PHP/25_clone/README.md create mode 100644 PHP/25_clone/docs/description.md create mode 100644 PHP/26_late_static_binding/README.md create mode 100644 PHP/26_late_static_binding/docs/description.md create mode 100644 PHP/27_get_called_class/README.md create mode 100644 PHP/27_get_called_class/docs/description.md create mode 100644 PHP/28_static_methods/README.md create mode 100644 PHP/28_static_methods/docs/description.md create mode 100644 PHP/29_static_properties/README.md create mode 100644 PHP/29_static_properties/docs/description.md create mode 100644 PHP/30_anonymous_classes/README.md create mode 100644 PHP/30_anonymous_classes/docs/description.md create mode 100644 PHP/31_static_method_variable/1_instance_31_static_method_variable/1_instance_31_static_method_variable.bash create mode 100644 PHP/31_static_method_variable/README.md create mode 100644 PHP/31_static_method_variable/docs/description.md create mode 100644 PHP/32_set_overloading/2_instance_32_set_overloading/2_instance_32_set_overloading.bash create mode 100644 PHP/32_set_overloading/2_instance_32_set_overloading/2_instance_32_set_overloading.json create mode 100644 PHP/32_set_overloading/2_instance_32_set_overloading/2_instance_32_set_overloading.php rename PHP/32_set_overloading/{1_instance_32_set_overloading/1_instance_32_set_overloading.sc => 32_set_overloading.sc} (50%) create mode 100644 PHP/32_set_overloading/README.md create mode 100644 PHP/32_set_overloading/docs/description.md create mode 100644 PHP/32_set_overloading/docs/discovery_notes.md create mode 100644 PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.bash create mode 100644 PHP/33_get_overloading/README.md create mode 100644 PHP/33_get_overloading/docs/description.md create mode 100644 PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.bash delete mode 100644 PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.sc create mode 100644 PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.bash delete mode 100644 PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.sc create mode 100644 PHP/34_isset_overloading/34_isset_overloading.sc create mode 100644 PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.bash create mode 100644 PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.json create mode 100644 PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.php create mode 100644 PHP/34_isset_overloading/4_instance_34_isset_overloading/4_instance_34_isset_overloading.bash create mode 100644 PHP/34_isset_overloading/4_instance_34_isset_overloading/4_instance_34_isset_overloading.json create mode 100644 PHP/34_isset_overloading/4_instance_34_isset_overloading/4_instance_34_isset_overloading.php create mode 100644 PHP/34_isset_overloading/README.md create mode 100644 PHP/34_isset_overloading/docs/description.md create mode 100644 PHP/34_isset_overloading/docs/discovery_notes.md create mode 100644 PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.bash delete mode 100644 PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.sc create mode 100644 PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.bash create mode 100644 PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.json create mode 100644 PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.php create mode 100644 PHP/35_unset_overloading/35_unset_overloading.sc create mode 100644 PHP/35_unset_overloading/3_instance_35_unset_overloading/3_instance_35_unset_overloading.bash create mode 100644 PHP/35_unset_overloading/3_instance_35_unset_overloading/3_instance_35_unset_overloading.json create mode 100644 PHP/35_unset_overloading/3_instance_35_unset_overloading/3_instance_35_unset_overloading.php create mode 100644 PHP/35_unset_overloading/README.md create mode 100644 PHP/35_unset_overloading/docs/description.md create mode 100644 PHP/35_unset_overloading/docs/discovery_notes.md create mode 100644 PHP/36_call_overloading/README.md create mode 100644 PHP/36_call_overloading/docs/description.md create mode 100644 PHP/37_callstatic_overloading/README.md create mode 100644 PHP/37_callstatic_overloading/docs/description.md create mode 100644 PHP/38_invoke/README.md create mode 100644 PHP/38_invoke/docs/description.md create mode 100644 PHP/39_serialize_unserialize/README.md create mode 100644 PHP/39_serialize_unserialize/docs/description.md create mode 100644 PHP/3_global_array/1_instance_3_global_array/1_instance_3_global_array.bash create mode 100644 PHP/3_global_array/2_instance_3_global_array/2_instance_3_global_array.bash create mode 100644 PHP/3_global_array/docs/description.md create mode 100644 PHP/40_trait/README.md create mode 100644 PHP/40_trait/docs/description.md create mode 100644 PHP/41_self_methods/1_instance_41_self_methods/_1_instance_41_self_methods.bash create mode 100644 PHP/41_self_methods/README.md create mode 100644 PHP/41_self_methods/docs/description.md create mode 100644 PHP/42_destructor/README.md create mode 100644 PHP/42_destructor/docs/description.md create mode 100644 PHP/43_tostring_echo_object/README.md create mode 100644 PHP/43_tostring_echo_object/docs/description.md delete mode 100644 PHP/44_verify_return_type/44_verify_return_type.sc create mode 100644 PHP/44_verify_return_type/README.md create mode 100644 PHP/44_verify_return_type/docs/description.md create mode 100644 PHP/46_object_to_array/README.md create mode 100644 PHP/46_object_to_array/docs/description.md delete mode 100644 PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.py create mode 100644 PHP/48_construct_with_inheritance/README.md create mode 100644 PHP/48_construct_with_inheritance/docs/description.md create mode 100644 PHP/49_static_instance/README.md create mode 100644 PHP/49_static_instance/docs/description.md create mode 100644 PHP/4_conditional_assignment/docs/description.md create mode 100644 PHP/50_throw_exception/README.md create mode 100644 PHP/50_throw_exception/docs/description.md create mode 100644 PHP/51_catch_exceptions/1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.bash create mode 100644 PHP/51_catch_exceptions/1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.php create mode 100644 PHP/51_catch_exceptions/README.md create mode 100644 PHP/51_catch_exceptions/docs/description.md create mode 100644 PHP/52_try_catch_finally/52_try_catch_finally.sc create mode 100644 PHP/52_try_catch_finally/README.md create mode 100644 PHP/52_try_catch_finally/docs/description.md create mode 100644 PHP/53_track_error/README.md create mode 100644 PHP/53_track_error/docs/description.md create mode 100644 PHP/54_generators/README.md create mode 100644 PHP/54_generators/docs/description.md create mode 100644 PHP/55_goto/README.md create mode 100644 PHP/55_goto/docs/description.md create mode 100644 PHP/56_exit/README.md create mode 100644 PHP/56_exit/docs/description.md create mode 100644 PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.sc create mode 100644 PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect_0.bash create mode 100644 PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect_0.php create mode 100644 PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect_1.bash create mode 100644 PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect_1.php create mode 100644 PHP/57_js_redirect/README.md create mode 100644 PHP/57_js_redirect/docs/description.md create mode 100644 PHP/58_simple_array/58_simple_array.sc create mode 100644 PHP/58_simple_array/README.md create mode 100644 PHP/58_simple_array/docs/description.md create mode 100644 PHP/59_foreach_with_array/README.md create mode 100644 PHP/59_foreach_with_array/docs/description.md create mode 100644 PHP/5_combined_operator/3_instance_5_combined_operator/3_instance_5_combined_operator.bash create mode 100644 PHP/5_combined_operator/3_instance_5_combined_operator/3_instance_5_combined_operator.sc create mode 100644 PHP/5_combined_operator/docs/description.md create mode 100644 PHP/5_combined_operator/docs/remediation_notes.md create mode 100644 PHP/60_array_walk/1_instance_60_array_walk/1_instance_60_array_walk.bash create mode 100644 PHP/60_array_walk/2_instance_60_array_walk/2_instance_60_array_walk.bash create mode 100644 PHP/60_array_walk/60_array_walk.sc create mode 100644 PHP/60_array_walk/README.md create mode 100644 PHP/60_array_walk/docs/description.md create mode 100644 PHP/61_array_map/1_instance_61_array_map/1_instance_61_array_map.bash create mode 100644 PHP/61_array_map/2_instance_61_array_map/2_instance_61_array_map.bash create mode 100644 PHP/61_array_map/61_array_map.sc create mode 100644 PHP/61_array_map/README.md create mode 100644 PHP/61_array_map/docs/description.md create mode 100644 PHP/62_parse_str_built_in_function/README.md create mode 100644 PHP/62_parse_str_built_in_function/docs/description.md create mode 100644 PHP/63_substring_replace_built_in_function/README.md create mode 100644 PHP/63_substring_replace_built_in_function/docs/description.md create mode 100644 PHP/64_preg_match/README.md create mode 100644 PHP/64_preg_match/docs/description.md create mode 100644 PHP/65_system/README.md create mode 100644 PHP/65_system/docs/description.md create mode 100644 PHP/66_superglobals/2_instance_66_superglobals/2_instance_66_superglobals_0.bash create mode 100644 PHP/66_superglobals/2_instance_66_superglobals/2_instance_66_superglobals_0.php create mode 100644 PHP/66_superglobals/2_instance_66_superglobals/2_instance_66_superglobals_1.bash create mode 100644 PHP/66_superglobals/2_instance_66_superglobals/2_instance_66_superglobals_1.php create mode 100644 PHP/66_superglobals/README.md create mode 100644 PHP/66_superglobals/docs/description.md create mode 100644 PHP/67_odbc/README.md create mode 100644 PHP/67_odbc/docs/description.md create mode 100644 PHP/68_compact/1_instance_68_compact/1_instance_68_compact.bash create mode 100644 PHP/68_compact/68_compact.sc create mode 100644 PHP/68_compact/README.md create mode 100644 PHP/68_compact/docs/description.md create mode 100644 PHP/69_create_function/README.md create mode 100644 PHP/69_create_function/docs/description.md create mode 100644 PHP/70_extract/README.md create mode 100644 PHP/70_extract/docs/description.md create mode 100644 PHP/71_array_functions/README.md create mode 100644 PHP/71_array_functions/docs/description.md create mode 100644 PHP/72_procedural_queries/README.md create mode 100644 PHP/72_procedural_queries/docs/description.md create mode 100644 PHP/73_wrong_sanitizer/README.md create mode 100644 PHP/73_wrong_sanitizer/docs/description.md create mode 100644 PHP/74_dirname/1_instance_74_dirname/1_instance_74_dirname.bash create mode 100644 PHP/74_dirname/1_instance_74_dirname/1_instance_74_dirname.php create mode 100644 PHP/74_dirname/1_instance_74_dirname/1_instance_74_dirname.sc create mode 100644 PHP/74_dirname/1_instance_74_dirname/_code/1_instance_74_dirname_0.bash create mode 100644 PHP/74_dirname/1_instance_74_dirname/_code/1_instance_74_dirname_0.php create mode 100644 PHP/74_dirname/1_instance_74_dirname/_includes/1_instance_74_dirname_1.bash create mode 100644 PHP/74_dirname/1_instance_74_dirname/_includes/1_instance_74_dirname_1.php create mode 100644 PHP/74_dirname/README.md create mode 100644 PHP/74_dirname/docs/description.md create mode 100644 PHP/76_function_variable/76_function_variable.sc create mode 100644 PHP/76_function_variable/README.md create mode 100644 PHP/76_function_variable/docs/description.md create mode 100644 PHP/77_object_callable/README.md create mode 100644 PHP/77_object_callable/docs/description.md create mode 100644 PHP/78_autoloading_classes/README.md create mode 100644 PHP/78_autoloading_classes/docs/description.md create mode 100644 PHP/79_dynamic_include/1_instance_79_dynamic_include/1_instance_79_dynamic_include_0.bash create mode 100644 PHP/79_dynamic_include/1_instance_79_dynamic_include/1_instance_79_dynamic_include_0.php create mode 100644 PHP/79_dynamic_include/1_instance_79_dynamic_include/1_instance_79_dynamic_include_1.bash create mode 100644 PHP/79_dynamic_include/1_instance_79_dynamic_include/1_instance_79_dynamic_include_1.php create mode 100644 PHP/79_dynamic_include/2_instance_79_dynamic_include/2_instance_79_dynamic_include_0.bash create mode 100644 PHP/79_dynamic_include/2_instance_79_dynamic_include/2_instance_79_dynamic_include_0.php create mode 100644 PHP/79_dynamic_include/2_instance_79_dynamic_include/2_instance_79_dynamic_include_1.bash create mode 100644 PHP/79_dynamic_include/2_instance_79_dynamic_include/2_instance_79_dynamic_include_1.php create mode 100644 PHP/79_dynamic_include/2_instance_79_dynamic_include/2_instance_79_dynamic_include_2.bash create mode 100644 PHP/79_dynamic_include/2_instance_79_dynamic_include/2_instance_79_dynamic_include_2.php create mode 100644 PHP/79_dynamic_include/3_instance_79_dynamic_include/3_instance_79_dynamic_include_0.bash create mode 100644 PHP/79_dynamic_include/3_instance_79_dynamic_include/3_instance_79_dynamic_include_0.php create mode 100644 PHP/79_dynamic_include/3_instance_79_dynamic_include/3_instance_79_dynamic_include_1.bash create mode 100644 PHP/79_dynamic_include/3_instance_79_dynamic_include/3_instance_79_dynamic_include_1.php create mode 100644 PHP/79_dynamic_include/4_instance_79_dynamic_include/4_instance_79_dynamic_include_0.bash create mode 100644 PHP/79_dynamic_include/4_instance_79_dynamic_include/4_instance_79_dynamic_include_0.php create mode 100644 PHP/79_dynamic_include/4_instance_79_dynamic_include/4_instance_79_dynamic_include_1.bash create mode 100644 PHP/79_dynamic_include/4_instance_79_dynamic_include/4_instance_79_dynamic_include_1.php create mode 100644 PHP/79_dynamic_include/5_instance_79_dynamic_include/5_instance_79_dynamic_include_0.bash create mode 100644 PHP/79_dynamic_include/5_instance_79_dynamic_include/5_instance_79_dynamic_include_0.php create mode 100644 PHP/79_dynamic_include/5_instance_79_dynamic_include/5_instance_79_dynamic_include_1.bash create mode 100644 PHP/79_dynamic_include/5_instance_79_dynamic_include/5_instance_79_dynamic_include_1.php create mode 100644 PHP/79_dynamic_include/README.md create mode 100644 PHP/79_dynamic_include/docs/description.md create mode 100644 PHP/7_string_arithmetic_operations/10_instance_7_string_arithmetic_operations/10_instance_7_string_arithmetic_operations.bash create mode 100644 PHP/7_string_arithmetic_operations/11_instance_7_string_arithmetic_operations/11_instance_7_string_arithmetic_operations.bash create mode 100644 PHP/7_string_arithmetic_operations/12_instance_7_string_arithmetic_operations/12_instance_7_string_arithmetic_operations.bash create mode 100644 PHP/7_string_arithmetic_operations/1_instance_7_string_arithmetic_operations/1_instance_7_string_arithmetic_operations.bash create mode 100644 PHP/7_string_arithmetic_operations/2_instance_7_string_arithmetic_operations/2_instance_7_string_arithmetic_operations.bash create mode 100644 PHP/7_string_arithmetic_operations/3_instance_7_string_arithmetic_operations/3_instance_7_string_arithmetic_operations.bash create mode 100644 PHP/7_string_arithmetic_operations/4_instance_7_string_arithmetic_operations/4_instance_7_string_arithmetic_operations.bash create mode 100644 PHP/7_string_arithmetic_operations/5_instance_7_string_arithmetic_operations/5_instance_7_string_arithmetic_operations.bash create mode 100644 PHP/7_string_arithmetic_operations/6_instance_7_string_arithmetic_operations/6_instance_7_string_arithmetic_operations.bash create mode 100644 PHP/7_string_arithmetic_operations/7_instance_7_string_arithmetic_operations/7_instance_7_string_arithmetic_operations.bash create mode 100644 PHP/7_string_arithmetic_operations/8_instance_7_string_arithmetic_operations/8_instance_7_string_arithmetic_operations.bash create mode 100644 PHP/7_string_arithmetic_operations/9_instance_7_string_arithmetic_operations/9_instance_7_string_arithmetic_operations.bash create mode 100644 PHP/7_string_arithmetic_operations/docs/description.md create mode 100644 PHP/80_callback_functions/README.md create mode 100644 PHP/80_callback_functions/docs/description.md create mode 100644 PHP/81_new_from_variable/README.md create mode 100644 PHP/81_new_from_variable/docs/description.md create mode 100644 PHP/82_methods_variable/README.md create mode 100644 PHP/82_methods_variable/docs/description.md create mode 100644 PHP/84_variable_variables/README.md create mode 100644 PHP/84_variable_variables/docs/description.md create mode 100644 PHP/85_test_pattern/1_instance_85_test_pattern/1_instance_85_test_pattern.bash create mode 100644 PHP/85_test_pattern/1_instance_85_test_pattern/1_instance_85_test_pattern.json create mode 100644 PHP/85_test_pattern/1_instance_85_test_pattern/1_instance_85_test_pattern.php create mode 100644 PHP/85_test_pattern/1_instance_85_test_pattern/1_instance_85_test_pattern.sc create mode 100644 PHP/85_test_pattern/85_test_pattern.json create mode 100644 PHP/85_test_pattern/docs/description.md create mode 100644 PHP/8_simple_reference/docs/description.md create mode 100644 PHP/9_reference_argument/docs/description.md diff --git a/PHP/10_return_by_reference/10_return_by_reference.json b/PHP/10_return_by_reference/10_return_by_reference.json index 902aedb..6127a1c 100644 --- a/PHP/10_return_by_reference/10_return_by_reference.json +++ b/PHP/10_return_by_reference/10_return_by_reference.json @@ -1,6 +1,6 @@ { "name": "Return By Reference", - "description": "[Return by reference](https://www.php.net/manual/en/language.references.return.php) in PHP, when the variable will be referenced to the returned variable from a specific function. Returning by reference is useful when you want to use a function to find to which variable a reference should be bound. If there are more than one return in the function, the variable will be referenced for the first one.", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_10_return_by_reference/1_instance_10_return_by_reference.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/10_return_by_reference/1_instance_10_return_by_reference/1_instance_10_return_by_reference.bash b/PHP/10_return_by_reference/1_instance_10_return_by_reference/1_instance_10_return_by_reference.bash index 96cc266..1a77258 100644 --- a/PHP/10_return_by_reference/1_instance_10_return_by_reference/1_instance_10_return_by_reference.bash +++ b/PHP/10_return_by_reference/1_instance_10_return_by_reference/1_instance_10_return_by_reference.bash @@ -1,33 +1,30 @@ -$_main: ; (lines=17, args=0, vars=3, tmps=7) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/19_return_by_reference/19_return_by_reference.php:1-18 -L0 (3): NOP -L1 (10): EXT_STMT -L2 (10): ASSIGN CV0($b) string("input") -L3 (11): EXT_STMT -L4 (11): V4 = NEW 0 string("foo") -L5 (11): DO_FCALL -L6 (11): ASSIGN CV1($obj) V4 -L7 (13): EXT_STMT -L8 (13): INIT_METHOD_CALL 0 CV1($obj) string("getValue") -L9 (13): V7 = DO_FCALL -L10 (13): ASSIGN_REF (function) CV2($myValue) V7 -L11 (14): EXT_STMT -L12 (14): ASSIGN_OBJ CV1($obj) string("value") -L13 (14): OP_DATA CV0($b) -L14 (17): EXT_STMT -L15 (17): ECHO CV2($myValue) -L16 (18): RETURN int(1) +$_main: + ; (lines=13, args=0, vars=3, tmps=9) + ; (before optimizer) + ; /.../PHP/10_return_by_reference/1_instance_10_return_by_reference/1_instance_10_return_by_reference.php:1-17 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($a) T4 +0003 V6 = NEW 0 string("foo") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V6 +0006 INIT_METHOD_CALL 0 CV1($obj) string("getValue") +0007 V9 = DO_FCALL +0008 ASSIGN_REF (function) CV2($b) V9 +0009 ASSIGN_OBJ CV1($obj) string("value") +0010 OP_DATA CV0($a) +0011 ECHO CV2($b) +0012 RETURN int(1) LIVE RANGES: - 4: L5 - L6 (new) + 6: 0004 - 0005 (new) -foo::getValue: ; (lines=6, args=0, vars=0, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/19_return_by_reference/19_return_by_reference.php:5-7 -L0 (5): EXT_NOP -L1 (6): EXT_STMT -L2 (6): V0 = FETCH_OBJ_W (ref) THIS string("value") -L3 (6): RETURN_BY_REF V0 -L4 (7): EXT_STMT -L5 (7): RETURN_BY_REF (function) null +foo::getValue: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/10_return_by_reference/1_instance_10_return_by_reference/1_instance_10_return_by_reference.php:5-7 + ; return [] RANGE[0..0] +0000 V0 = FETCH_OBJ_W (ref) THIS string("value") +0001 RETURN_BY_REF V0 +0002 RETURN_BY_REF (function) null diff --git a/PHP/10_return_by_reference/1_instance_10_return_by_reference/1_instance_10_return_by_reference.json b/PHP/10_return_by_reference/1_instance_10_return_by_reference/1_instance_10_return_by_reference.json index 04dddd0..0c7e24b 100644 --- a/PHP/10_return_by_reference/1_instance_10_return_by_reference/1_instance_10_return_by_reference.json +++ b/PHP/10_return_by_reference/1_instance_10_return_by_reference/1_instance_10_return_by_reference.json @@ -1,4 +1,5 @@ { + "description": "This instance target the usage of return values being passed by reference.", "code": { "path": "./1_instance_10_return_by_reference.php", "injection_skeleton_broken": false diff --git a/PHP/10_return_by_reference/1_instance_10_return_by_reference/1_instance_10_return_by_reference.php b/PHP/10_return_by_reference/1_instance_10_return_by_reference/1_instance_10_return_by_reference.php index 4295fcc..50a8330 100644 --- a/PHP/10_return_by_reference/1_instance_10_return_by_reference/1_instance_10_return_by_reference.php +++ b/PHP/10_return_by_reference/1_instance_10_return_by_reference/1_instance_10_return_by_reference.php @@ -7,10 +7,10 @@ public function &getValue() { } } -$a = $_GET["p1"]; +$a = $_GET["p1"]; // source $obj = new foo; // $b is a reference to $obj->value, which is 42. $b = &$obj->getValue(); $obj->value = $a; // prints the new value of $obj->value, which is the source $a (XSS) -echo $b; +echo $b; // sink diff --git a/PHP/10_return_by_reference/README.md b/PHP/10_return_by_reference/README.md index 7fd4a55..c9c4551 100644 --- a/PHP/10_return_by_reference/README.md +++ b/PHP/10_return_by_reference/README.md @@ -1,29 +1,28 @@ -# Pattern: Return by Reference +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) -## Category +# Return By Reference -References +Tags: sast, php, php_v7.4.9 -## Definition +Version: v1.0 -[Return by reference](https://www.php.net/manual/en/language.references.return.php) in PHP, when the variable will be referenced to the returned variable from a specific function. +## Description ->Returning by reference is useful when you want to use a function to find to which variable a reference should be bound. -> ->If there are more than one return in the function, the variable will be referenced for the first one. +[Return by reference](https://www.php.net/manual/en/language.references.return.php) in PHP, when the variable will be referenced to the returned variable from a specific function. Returning by reference is useful when you want to use a function to find to which variable a reference should be bound. If there are more than one return in the function, the variable will be referenced for the first one. -## Instances +## Overview -### Instance 1 +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | -- CATEGORY: S0 -- FEATURE vs INTERNAL API: FEATURE -- INPUT SANITIZERS: NO -- SOURCES AND SINKS: NO -- NEGATIVE TEST CASES: NO -- CODE: +## 1 Instance -```php +This instance target the usage of return values being passed by reference. + +### Code + +```PHP value, which is 42. -$myValue = &$obj->getValue(); -$obj->value = $b; -// prints the new value of $obj->value, which is the value of $b. -// Here there is XSS vulnerability. -echo $myValue; +// $b is a reference to $obj->value, which is 42. +$b = &$obj->getValue(); +$obj->value = $a; +// prints the new value of $obj->value, which is the source $a (XSS) +echo $b; // sink ``` -- MEASUREMENT: +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | -| Tool | RIPS | phpSAFE | WAP | Progpilot | Comm_1 | Comm_2 | Correct | -| ------------- | ---- | ------- | ---- | --------- | ------- | --------- | ------- | -| Vulnerability | NO | NO | NO | NO | NO | NO | YES | -Measurements Date: 8 June 2021 +
+ +More -- OPCODE: +
+ + +### Compile + ```bash -$_main: ; (lines=17, args=0, vars=3, tmps=7) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/19_return_by_reference/19_return_by_reference.php:1-18 -L0 (3): NOP -L1 (10): EXT_STMT -L2 (10): ASSIGN CV0($b) string("input") -L3 (11): EXT_STMT -L4 (11): V4 = NEW 0 string("foo") -L5 (11): DO_FCALL -L6 (11): ASSIGN CV1($obj) V4 -L7 (13): EXT_STMT -L8 (13): INIT_METHOD_CALL 0 CV1($obj) string("getValue") -L9 (13): V7 = DO_FCALL -L10 (13): ASSIGN_REF (function) CV2($myValue) V7 -L11 (14): EXT_STMT -L12 (14): ASSIGN_OBJ CV1($obj) string("value") -L13 (14): OP_DATA CV0($b) -L14 (17): EXT_STMT -L15 (17): ECHO CV2($myValue) -L16 (18): RETURN int(1) +$_main: + ; (lines=13, args=0, vars=3, tmps=9) + ; (before optimizer) + ; /.../PHP/10_return_by_reference/1_instance_10_return_by_reference/1_instance_10_return_by_reference.php:1-17 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($a) T4 +0003 V6 = NEW 0 string("foo") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V6 +0006 INIT_METHOD_CALL 0 CV1($obj) string("getValue") +0007 V9 = DO_FCALL +0008 ASSIGN_REF (function) CV2($b) V9 +0009 ASSIGN_OBJ CV1($obj) string("value") +0010 OP_DATA CV0($a) +0011 ECHO CV2($b) +0012 RETURN int(1) LIVE RANGES: - 4: L5 - L6 (new) - -foo::getValue: ; (lines=6, args=0, vars=0, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/19_return_by_reference/19_return_by_reference.php:5-7 -L0 (5): EXT_NOP -L1 (6): EXT_STMT -L2 (6): V0 = FETCH_OBJ_W (ref) THIS string("value") -L3 (6): RETURN_BY_REF V0 -L4 (7): EXT_STMT -L5 (7): RETURN_BY_REF (function) null + 6: 0004 - 0005 (new) + +foo::getValue: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/10_return_by_reference/1_instance_10_return_by_reference/1_instance_10_return_by_reference.php:5-7 + ; return [] RANGE[0..0] +0000 V0 = FETCH_OBJ_W (ref) THIS string("value") +0001 RETURN_BY_REF V0 +0002 RETURN_BY_REF (function) null ``` -- DISCOVERY: +
-There is a specific opcode for this type of references called RETURN_BY_REF. +
+ -``` -cpg.call(".*RETURN_BY_REF.*").argument.code("function").location.l -``` +### Discovery + -- PRECONDITIONS: - 1. +Question: To be perfect this rule should be combined to search for the assignment of the return by reference function i.e., ASSIGN_REF (function)? -- TRANSFORMATION: +```scala +val x10 = (name, "10_return_by_reference_iall", cpg.call(".*RETURN_BY_REF.*").argument.code("function").location.toJson); +``` -I show that in the pattern [simple references](https://gitlab.eurecom.fr/alkasar/static-tools---latex/issues/26), we need to have a table of variables with the references between them. In this pattern, I need first to detect the first return in the function, then do the connection between the variable and the returned variable from the function. This pattern show the complexity of following the references for the static tools, especially the variable in the function should be [static](https://gitlab.eurecom.fr/alkasar/static-tools---latex/issues/20), global or object property. In addition to that, we face the same difficulties of call graph. +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | -``` +
-``` +
+ + +### Measurement + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | no | no | no | yes | +| 17 May 2023 | no | no | | | | | yes | +
+
diff --git a/PHP/10_return_by_reference/docs/description.md b/PHP/10_return_by_reference/docs/description.md new file mode 100644 index 0000000..4f17c49 --- /dev/null +++ b/PHP/10_return_by_reference/docs/description.md @@ -0,0 +1 @@ +[Return by reference](https://www.php.net/manual/en/language.references.return.php) in PHP, when the variable will be referenced to the returned variable from a specific function. Returning by reference is useful when you want to use a function to find to which variable a reference should be bound. If there are more than one return in the function, the variable will be referenced for the first one. \ No newline at end of file diff --git a/PHP/11_foreach_with_reference/11_foreach_with_reference.json b/PHP/11_foreach_with_reference/11_foreach_with_reference.json index 0b559ff..5cc38db 100644 --- a/PHP/11_foreach_with_reference/11_foreach_with_reference.json +++ b/PHP/11_foreach_with_reference/11_foreach_with_reference.json @@ -1,6 +1,6 @@ { - "name": "ForEach with Reference", - "description": "Foreach is used by high level programming languages to iterate over arrays and objects.\n```php\n + +More -- OPCODE: +
+ + +### Compile + ```bash -$_main: ; (lines=12, args=0, vars=3, tmps=7) - ; (before optimizer) - ; /tp-framework/testability_patterns/PHP/11_foreach_with_reference/2_instance_11_foreach_with_reference/2_instance_11_foreach_with_reference.php:1-11 -L0 (2): ASSIGN CV0($arr) array(...) -L1 (3): T4 = FETCH_R (global) string("_GET") -L2 (3): T5 = FETCH_DIM_R T4 string("p1") -L3 (3): ASSIGN CV1($a) T5 -L4 (4): V7 = FE_RESET_RW CV0($arr) L8 -L5 (4): FE_FETCH_RW V7 CV2($x) L8 -L6 (7): ASSIGN CV2($x) CV1($a) -L7 (4): JMP L5 -L8 (4): FE_FREE V7 -L9 (10): T9 = FETCH_DIM_R CV0($arr) int(0) -L10 (10): ECHO T9 -L11 (11): RETURN int(1) +$_main: + ; (lines=12, args=0, vars=3, tmps=7) + ; (before optimizer) + ; /.../PHP/11_foreach_with_reference/1_instance_11_foreach_with_reference/1_instance_11_foreach_with_reference.php:1-11 + ; return [] RANGE[0..0] +0000 ASSIGN CV0($arr) array(...) +0001 T4 = FETCH_R (global) string("_GET") +0002 T5 = FETCH_DIM_R T4 string("p1") +0003 ASSIGN CV1($a) T5 +0004 V7 = FE_RESET_RW CV0($arr) 0008 +0005 FE_FETCH_RW V7 CV2($x) 0008 +0006 ASSIGN CV2($x) CV1($a) +0007 JMP 0005 +0008 FE_FREE V7 +0009 T9 = FETCH_DIM_R CV0($arr) int(0) +0010 ECHO T9 +0011 RETURN int(1) LIVE RANGES: - 7: L5 - L8 (loop) + 7: 0005 - 0008 (loop) ``` -- DISCOVERY: +
-```bash -cpg.call(".*FE_FETCH_RW.*").location.l +
+ + +### Discovery + + +```scala +val x11 = (name, "11_foreach_with_reference_iall", cpg.call(".*FE_FETCH_RW.*").location.toJson); ``` -- PRECONDITIONS: - 1. +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | -- TRANSFORMATION: +
-``` +
+ -``` +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | no | no | no | yes | +| 17 May 2023 | no | yes | | | | | yes | + +
+ +
+ + +### Remediation + + +If possible, a copy of the array could be created and it could than be looped over the copy of that array. After the loop, the copy could be assigned back to the original array. However, is highly dependent on the content of the loop and can therefor only be done manually. + +
+ diff --git a/PHP/11_foreach_with_reference/docs/description.md b/PHP/11_foreach_with_reference/docs/description.md new file mode 100644 index 0000000..8071df8 --- /dev/null +++ b/PHP/11_foreach_with_reference/docs/description.md @@ -0,0 +1,19 @@ +Foreach is used by high level programming languages to iterate over arrays and objects. + +```php + + + +## 1 Instance + + +This instance shows, that the content of two different array elements can be connected using a reference. If one changes, the other one changes as well. + +### Code + +```PHP + +More -- OPCODE: +
+ + +### Compile + ```bash -$_main: ; (lines=16, args=0, vars=1, tmps=9) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/123_make_ref/first_ex/123_make_ref.php:1-5 -L0 (2): EXT_STMT -L1 (2): ASSIGN CV0($arr) array(...) -L2 (3): EXT_STMT -L3 (3): V3 = FETCH_DIM_W CV0($arr) int(3) -L4 (3): V4 = MAKE_REF V3 -L5 (3): V2 = FETCH_DIM_W CV0($arr) int(1) -L6 (3): ASSIGN_REF V2 V4 -L7 (4): EXT_STMT -L8 (4): T7 = FETCH_R (global) string("_GET") -L9 (4): T8 = FETCH_DIM_R T7 string("p1") -L10 (4): ASSIGN_DIM CV0($arr) int(3) -L11 (4): OP_DATA T8 -L12 (5): EXT_STMT -L13 (5): T9 = FETCH_DIM_R CV0($arr) int(1) -L14 (5): ECHO T9 -L15 (5): RETURN int(1) +$_main: + ; (lines=12, args=0, vars=1, tmps=9) + ; (before optimizer) + ; /.../PHP/12_make_ref/1_instance_12_make_ref/1_instance_12_make_ref.php:1-5 + ; return [] RANGE[0..0] +0000 ASSIGN CV0($arr) array(...) +0001 V3 = FETCH_DIM_W CV0($arr) int(3) +0002 V4 = MAKE_REF V3 +0003 V2 = FETCH_DIM_W CV0($arr) int(1) +0004 ASSIGN_REF V2 V4 +0005 T7 = FETCH_R (global) string("_GET") +0006 T8 = FETCH_DIM_R T7 string("p1") +0007 ASSIGN_DIM CV0($arr) int(3) +0008 OP_DATA T8 +0009 T9 = FETCH_DIM_R CV0($arr) int(1) +0010 ECHO T9 +0011 RETURN int(1) LIVE RANGES: - 4: L5 - L6 (tmp/var) + 4: 0003 - 0004 (tmp/var) ``` -- DISCOVERY: +
-```bash +
+ +### Discovery + + +The rule searches for occurences of `MAKE_REF` and should therefor be perfect. + +```scala +val x12 = (name, "12_make_ref_iall_i1", cpg.call(".*MAKE_REF.*").location.toJson); ``` -- PRECONDITIONS: - 1. +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | -- TRANSFORMATION: +
-``` +
+ -``` +### Measurement + + +| Tool | Comm_1 | Comm_2 | Progpilot | Ground Truth | +|-------------|----------|----------|-------------|----------------| +| 08 Jun 2021 | | yes | no | no | +| 17 May 2023 | no | no | | no | + +
+ + + -### Instance 2 +
+ -- CATEGORY: S0 -- FEATURE vs INTERNAL API: FEATURE -- INPUT SANITIZERS: NO -- SOURCES AND SINKS: NO -- NEGATIVE TEST CASES: NO -- CODE: +## 2 Instance + -```php +This instance does not have a vulnerability. It shows, that only the two referenced values are actually connected. If you output a different value, this is user controlled value. + +### Code + +```PHP + +More -| Tool | RIPS | phpSAFE | WAP | Progpilot | Comm_1 | Comm_2 | Correct | -| ------------- | ---- | ------- | ---- | --------- | ------- | --------- | ------- | -| Vulnerability | NO | NO | NO | YES | NO | YES | YES | -Measurements Date: 8 June 2021 +
+ -- OPCODE: +### Compile + ```bash -$_main: ; (lines=16, args=0, vars=1, tmps=9) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/123_make_ref/second_ex/second_ex.php:1-5 -L0 (2): EXT_STMT -L1 (2): ASSIGN CV0($arr) array(...) -L2 (3): EXT_STMT -L3 (3): V3 = FETCH_DIM_W CV0($arr) int(3) -L4 (3): V4 = MAKE_REF V3 -L5 (3): V2 = FETCH_DIM_W CV0($arr) int(1) -L6 (3): ASSIGN_REF V2 V4 -L7 (4): EXT_STMT -L8 (4): T7 = FETCH_R (global) string("_GET") -L9 (4): T8 = FETCH_DIM_R T7 string("p1") -L10 (4): ASSIGN_DIM CV0($arr) int(3) -L11 (4): OP_DATA T8 -L12 (5): EXT_STMT -L13 (5): T9 = FETCH_DIM_R CV0($arr) int(0) -L14 (5): ECHO T9 -L15 (5): RETURN int(1) +$_main: + ; (lines=12, args=0, vars=1, tmps=9) + ; (before optimizer) + ; /.../PHP/12_make_ref/2_instance_12_make_ref/2_instance_12_make_ref.php:1-5 + ; return [] RANGE[0..0] +0000 ASSIGN CV0($arr) array(...) +0001 T3 = FETCH_R (global) string("_GET") +0002 T4 = FETCH_DIM_R T3 string("p1") +0003 ASSIGN_DIM CV0($arr) int(3) +0004 OP_DATA T4 +0005 V6 = FETCH_DIM_W CV0($arr) int(3) +0006 V7 = MAKE_REF V6 +0007 V5 = FETCH_DIM_W CV0($arr) int(1) +0008 ASSIGN_REF V5 V7 +0009 T9 = FETCH_DIM_R CV0($arr) int(0) +0010 ECHO T9 +0011 RETURN int(1) LIVE RANGES: - 4: L5 - L6 (tmp/var) + 7: 0007 - 0008 (tmp/var) ``` -- DISCOVERY: +
-```bash -cpg.call(".*MAKE_REF.*").location.l -``` +
+ -- PRECONDITIONS: - 1. +### Discovery + -- TRANSFORMATION: +The rule searches for occurences of `MAKE_REF` and should therefor be perfect. +```scala +val x12 = (name, "12_make_ref_iall_i1", cpg.call(".*MAKE_REF.*").location.toJson); ``` -``` +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | yes | no | yes | no | no | no | +| 17 May 2023 | no | no | | | | | no | + +
+ +
+ + diff --git a/PHP/12_make_ref/docs/description.md b/PHP/12_make_ref/docs/description.md new file mode 100644 index 0000000..c66dff1 --- /dev/null +++ b/PHP/12_make_ref/docs/description.md @@ -0,0 +1 @@ +Multiple variables can point to the same object in memory using references. When the value of one variable changes, it changes the value of all the other variables referencing that same value. \ No newline at end of file diff --git a/PHP/13_assign_static_prop_ref/13_assign_static_prop_ref.json b/PHP/13_assign_static_prop_ref/13_assign_static_prop_ref.json index b1f69b0..f8ec0a7 100644 --- a/PHP/13_assign_static_prop_ref/13_assign_static_prop_ref.json +++ b/PHP/13_assign_static_prop_ref/13_assign_static_prop_ref.json @@ -1,6 +1,6 @@ { "name": "Assign Static Prop Ref", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref.bash b/PHP/13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref.bash index 443b794..839d7d9 100644 --- a/PHP/13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref.bash +++ b/PHP/13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref.bash @@ -1,18 +1,15 @@ -$_main: ; (lines=14, args=0, vars=1, tmps=6) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/122_assign_static_prop_ref/122_assign_static_prop_ref.php:1-10 -L0 (3): NOP -L1 (6): EXT_STMT -L2 (6): ASSIGN CV0($y) string("abc") -L3 (7): EXT_STMT -L4 (7): ASSIGN_STATIC_PROP_REF string("sprop") string("myclass") -L5 (7): OP_DATA CV0($y) -L6 (8): EXT_STMT -L7 (8): T3 = FETCH_R (global) string("_GET") -L8 (8): T4 = FETCH_DIM_R T3 string("p1") -L9 (8): ASSIGN CV0($y) T4 -L10 (9): EXT_STMT -L11 (9): T6 = FETCH_STATIC_PROP_R string("sprop") string("myclass") -L12 (9): ECHO T6 -L13 (10): RETURN int(1) +$_main: + ; (lines=9, args=0, vars=1, tmps=6) + ; (before optimizer) + ; /.../PHP/13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref.php:1-9 + ; return [] RANGE[0..0] +0000 ASSIGN CV0($y) string("abc") +0001 ASSIGN_STATIC_PROP_REF string("sprop") string("myclass") +0002 OP_DATA CV0($y) +0003 T3 = FETCH_R (global) string("_GET") +0004 T4 = FETCH_DIM_R T3 string("p1") +0005 ASSIGN CV0($y) T4 +0006 T6 = FETCH_STATIC_PROP_R string("sprop") string("myclass") +0007 ECHO T6 +0008 RETURN int(1) diff --git a/PHP/13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref.json b/PHP/13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref.json index c650e59..4db61c8 100644 --- a/PHP/13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref.json +++ b/PHP/13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref.json @@ -1,4 +1,5 @@ { + "description": "The instance shows the assignement by reference to a static class variable.", "code": { "path": "./1_instance_13_assign_static_prop_ref.php", "injection_skeleton_broken": false @@ -7,7 +8,7 @@ "rule": "./1_instance_13_assign_static_prop_ref.sc", "method": "joern", "rule_accuracy": "Perfect", - "notes": null + "notes": "The rule is searching for `ASSIGN_STATIC_PROP_REF`, which assignes a value by reference to a static property." }, "compile": { "binary": "./1_instance_13_assign_static_prop_ref.bash", diff --git a/PHP/13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref.php b/PHP/13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref.php index 99811ae..6b613b0 100644 --- a/PHP/13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref.php +++ b/PHP/13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref.php @@ -1,9 +1,9 @@ + +More -```bash -$_main: ; (lines=14, args=0, vars=1, tmps=6) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/122_assign_static_prop_ref/122_assign_static_prop_ref.php:1-10 -L0 (3): NOP -L1 (6): EXT_STMT -L2 (6): ASSIGN CV0($y) string("abc") -L3 (7): EXT_STMT -L4 (7): ASSIGN_STATIC_PROP_REF string("sprop") string("myclass") -L5 (7): OP_DATA CV0($y) -L6 (8): EXT_STMT -L7 (8): T3 = FETCH_R (global) string("_GET") -L8 (8): T4 = FETCH_DIM_R T3 string("p1") -L9 (8): ASSIGN CV0($y) T4 -L10 (9): EXT_STMT -L11 (9): T6 = FETCH_STATIC_PROP_R string("sprop") string("myclass") -L12 (9): ECHO T6 -L13 (10): RETURN int(1) -``` +
+ -- DISCOVERY: +### Compile + ```bash -cpg.call(".*ASSIGN_STATIC_PROP_REF.*").location.l +$_main: + ; (lines=9, args=0, vars=1, tmps=6) + ; (before optimizer) + ; /.../PHP/13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref/1_instance_13_assign_static_prop_ref.php:1-9 + ; return [] RANGE[0..0] +0000 ASSIGN CV0($y) string("abc") +0001 ASSIGN_STATIC_PROP_REF string("sprop") string("myclass") +0002 OP_DATA CV0($y) +0003 T3 = FETCH_R (global) string("_GET") +0004 T4 = FETCH_DIM_R T3 string("p1") +0005 ASSIGN CV0($y) T4 +0006 T6 = FETCH_STATIC_PROP_R string("sprop") string("myclass") +0007 ECHO T6 +0008 RETURN int(1) ``` -- PRECONDITIONS: - 1. +
-- TRANSFORMATION: +
+ -``` +### Discovery + +The rule is searching for `ASSIGN_STATIC_PROP_REF`, which assignes a value by reference to a static property. + +```scala +val x13 = (name, "13_assign_static_prop_ref_iall", cpg.call(".*ASSIGN_STATIC_PROP_REF.*").location.toJson); ``` +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | yes | no | no | yes | +| 17 May 2023 | yes | no | | | | | yes | + +
+ + diff --git a/PHP/13_assign_static_prop_ref/docs/description.md b/PHP/13_assign_static_prop_ref/docs/description.md new file mode 100644 index 0000000..157a6df --- /dev/null +++ b/PHP/13_assign_static_prop_ref/docs/description.md @@ -0,0 +1 @@ +A static variable in a class in PHP is associated with that class rather than an instance of the class. \ No newline at end of file diff --git a/PHP/14_object_assigned_by_reference/14_object_assigned_by_reference.json b/PHP/14_object_assigned_by_reference/14_object_assigned_by_reference.json index 7bd9b3d..1acb7a8 100644 --- a/PHP/14_object_assigned_by_reference/14_object_assigned_by_reference.json +++ b/PHP/14_object_assigned_by_reference/14_object_assigned_by_reference.json @@ -1,6 +1,6 @@ { "name": "Object Assigned By Reference", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -12,5 +12,5 @@ "./2_instance_14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference.json", "./3_instance_14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.sc b/PHP/14_object_assigned_by_reference/14_object_assigned_by_reference.sc similarity index 100% rename from PHP/14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.sc rename to PHP/14_object_assigned_by_reference/14_object_assigned_by_reference.sc diff --git a/PHP/14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.bash b/PHP/14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.bash index 7ef0e65..b9e0763 100644 --- a/PHP/14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.bash +++ b/PHP/14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.bash @@ -1,20 +1,20 @@ -$_main: ; (lines=16, args=0, vars=2, tmps=7) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/121_object_assigned_by_reference/121_object_assigned_by_reference.php:1-9 -L0 (3): NOP -L1 (5): EXT_STMT -L2 (5): ASSIGN CV0($x) string("safe") -L3 (6): EXT_STMT -L4 (6): ASSIGN CV1($obj) string("abc") -L5 (7): EXT_STMT -L6 (7): ASSIGN_OBJ_REF CV1($obj) string("prop") -L7 (7): OP_DATA CV0($x) -L8 (8): EXT_STMT -L9 (8): T5 = FETCH_R (global) string("_GET") -L10 (8): T6 = FETCH_DIM_R T5 string("p1") -L11 (8): ASSIGN CV0($x) T6 -L12 (9): EXT_STMT -L13 (9): T8 = FETCH_OBJ_R CV1($obj) string("prop") -L14 (9): ECHO T8 -L15 (9): RETURN int(1) +$_main: + ; (lines=12, args=0, vars=2, tmps=9) + ; (before optimizer) + ; /.../PHP/14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.php:1-9 + ; return [] RANGE[0..0] +0000 ASSIGN CV0($x) string("safe") +0001 V3 = NEW 0 string("myclass") +0002 DO_FCALL +0003 ASSIGN CV1($obj) V3 +0004 ASSIGN_OBJ_REF CV1($obj) string("prop") +0005 OP_DATA CV0($x) +0006 T7 = FETCH_R (global) string("_GET") +0007 T8 = FETCH_DIM_R T7 string("p1") +0008 ASSIGN CV0($x) T8 +0009 T10 = FETCH_OBJ_R CV1($obj) string("prop") +0010 ECHO T10 +0011 RETURN int(1) +LIVE RANGES: + 3: 0002 - 0003 (new) diff --git a/PHP/14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.json b/PHP/14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.json index 0189b0c..7252971 100644 --- a/PHP/14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.json +++ b/PHP/14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.json @@ -1,13 +1,14 @@ { + "description": "The instance shows a variable assigned to an instance variable of an object by reference. The instance variable is first assigned to the other variable and than the other variable is set to a user controlled input.", "code": { "path": "./1_instance_14_object_assigned_by_reference.php", "injection_skeleton_broken": true }, "discovery": { - "rule": "./1_instance_14_object_assigned_by_reference.sc", + "rule": "../14_object_assigned_by_reference.sc", "method": "joern", "rule_accuracy": "Perfect", - "notes": null + "notes": "../docs/discovery_notes.md" }, "compile": { "binary": "./1_instance_14_object_assigned_by_reference.bash", diff --git a/PHP/14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.php b/PHP/14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.php index cd3e3dd..ca899a4 100644 --- a/PHP/14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.php +++ b/PHP/14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.php @@ -1,9 +1,9 @@ prop = &$x; // tarpit $x = $_GET["p1"]; // source echo $obj->prop; // sink \ No newline at end of file diff --git a/PHP/14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference.bash b/PHP/14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference.bash new file mode 100644 index 0000000..07f6411 --- /dev/null +++ b/PHP/14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference.bash @@ -0,0 +1,20 @@ + +$_main: + ; (lines=12, args=0, vars=2, tmps=9) + ; (before optimizer) + ; /.../PHP/14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference.php:1-9 + ; return [] RANGE[0..0] +0000 ASSIGN CV0($x) string("safe") +0001 V3 = NEW 0 string("myclass") +0002 DO_FCALL +0003 ASSIGN CV1($obj) V3 +0004 T6 = FETCH_R (global) string("_GET") +0005 T7 = FETCH_DIM_R T6 string("p1") +0006 ASSIGN CV0($x) T7 +0007 ASSIGN_OBJ_REF CV1($obj) string("prop") +0008 OP_DATA CV0($x) +0009 T10 = FETCH_OBJ_R CV1($obj) string("prop") +0010 ECHO T10 +0011 RETURN int(1) +LIVE RANGES: + 3: 0002 - 0003 (new) diff --git a/PHP/14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference.json b/PHP/14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference.json index 27fcff0..b18bfc2 100644 --- a/PHP/14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference.json +++ b/PHP/14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference.json @@ -1,24 +1,25 @@ { + "description": "The instance shows a variable assigned to an instance variable of an object by reference. The other variable is first set to a user controlled input and than this variable is assigned to an instance variable of an object.", "code": { - "path": "./2_instance__14_object_assigned_by_reference.php", + "path": "./2_instance_14_object_assigned_by_reference.php", "injection_skeleton_broken": false }, "discovery": { - "rule": "./../1_instance__14_object_assigned_by_reference/1_instance__14_object_assigned_by_reference.sc", + "rule": "../14_object_assigned_by_reference.sc", "method": "joern", "rule_accuracy": "Perfect", - "notes": null + "notes": "../docs/discovery_notes.md" }, "compile": { - "binary": null, + "binary": "./2_instance_14_object_assigned_by_reference.bash", "instruction": null, "dependencies": null }, "expectation": { "type": "xss", - "sink_file": "./2_instance__14_object_assigned_by_reference.php", + "sink_file": "./2_instance_14_object_assigned_by_reference.php", "sink_line": 9, - "source_file": "./2_instance__14_object_assigned_by_reference.php", + "source_file": "./2_instance_14_object_assigned_by_reference.php", "source_line": 7, "expectation": true }, diff --git a/PHP/14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference.php b/PHP/14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference.php index ef20f68..cd71119 100644 --- a/PHP/14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference.php +++ b/PHP/14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference.php @@ -1,9 +1,9 @@ prop = &$x; // tarpit echo $obj->prop; // sink \ No newline at end of file diff --git a/PHP/14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference.bash b/PHP/14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference.bash new file mode 100644 index 0000000..57a3c44 --- /dev/null +++ b/PHP/14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference.bash @@ -0,0 +1,21 @@ + +$_main: + ; (lines=13, args=0, vars=3, tmps=10) + ; (before optimizer) + ; /.../PHP/14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference.php:1-10 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($a) T4 +0003 ASSIGN CV1($x) string("safe") +0004 V7 = NEW 0 string("myclass") +0005 DO_FCALL +0006 ASSIGN CV2($obj) V7 +0007 ASSIGN_OBJ_REF CV2($obj) string("prop") +0008 OP_DATA CV1($x) +0009 ASSIGN CV1($x) CV0($a) +0010 T12 = FETCH_OBJ_R CV2($obj) string("prop") +0011 ECHO T12 +0012 RETURN int(1) +LIVE RANGES: + 7: 0005 - 0006 (new) diff --git a/PHP/14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference.json b/PHP/14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference.json index fb345d2..815aef0 100644 --- a/PHP/14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference.json +++ b/PHP/14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference.json @@ -1,24 +1,25 @@ { + "description": "This instance provides another indirection through which the user input reaches the sink. In this instance, it is stored in an intermediate variable, which is assigned to another variable, which itself links to the instance variable, that is used for the output.", "code": { - "path": "./3_instance___14_object_assigned_by_reference.php", + "path": "./3_instance_14_object_assigned_by_reference.php", "injection_skeleton_broken": false }, "discovery": { - "rule": "./../1_instance___14_object_assigned_by_reference/1_instance___14_object_assigned_by_reference.sc", + "rule": "../14_object_assigned_by_reference.sc", "method": "joern", "rule_accuracy": "Perfect", - "notes": null + "notes": "../docs/discovery_notes.md" }, "compile": { - "binary": null, + "binary": "./3_instance_14_object_assigned_by_reference.bash", "instruction": null, "dependencies": null }, "expectation": { "type": "xss", - "sink_file": "./3_instance___14_object_assigned_by_reference.php", + "sink_file": "./3_instance_14_object_assigned_by_reference.php", "sink_line": 10, - "source_file": "./3_instance___14_object_assigned_by_reference.php", + "source_file": "./3_instance_14_object_assigned_by_reference.php", "source_line": 5, "expectation": true }, diff --git a/PHP/14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference.php b/PHP/14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference.php index d14a60a..911b0a7 100644 --- a/PHP/14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference.php +++ b/PHP/14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference.php @@ -1,10 +1,10 @@ prop = &$x; // tarpit $x = $a; echo $obj->prop; // sink \ No newline at end of file diff --git a/PHP/14_object_assigned_by_reference/README.md b/PHP/14_object_assigned_by_reference/README.md index 818cb2b..8db1a8c 100644 --- a/PHP/14_object_assigned_by_reference/README.md +++ b/PHP/14_object_assigned_by_reference/README.md @@ -1,77 +1,309 @@ -# Pattern: Object Assigned By Reference +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) -## Category +# Object Assigned By Reference -Refrences +Tags: sast, php, php_v7.4.9 -## Definition +Version: v1.0 -## Instances +## Description -### Instance 1 +Instance variables can be assigned by reference, every change to a variable referencing an instance variable of an object will be reflected in the instance variable and vice versa. -- CATEGORY: S0 -- FEATURE vs INTERNAL API: FEATURE -- INPUT SANITIZERS: NO -- SOURCES AND SINKS: NO -- NEGATIVE TEST CASES: NO -- CODE: +## Overview -```php +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | +| [2 Instance](#2-instance) | yes | joern | yes | +| [3 Instance](#3-instance) | yes | joern | yes | + +
+ + +## 1 Instance + + +The instance shows a variable assigned to an instance variable of an object by reference. The instance variable is first assigned to the other variable and than the other variable is set to a user controlled input. + +### Code + +```PHP prop = &$x; - $x = $_GET["p1"]; - echo $obj->prop; +class myclass { + public $prop; +}; +$x = "safe"; +$obj = new myclass(); +$obj->prop = &$x; // tarpit +$x = $_GET["p1"]; // source +echo $obj->prop; // sink ``` -- MEASUREMENT: +### Instance Properties -| Tool | RIPS | phpSAFE | WAP | Progpilot | Comm_1 | Comm_2 | Correct | -| ------------- | ---- | ------- | ---- | --------- | ------- | --------- | ------- | -| Vulnerability | NO | NO | NO | NO | YES | NO | YES | -Measurements Date: 8 June 2021 +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | -- OPCODE: +
+ +More + +
+ + +### Compile + ```bash -$_main: ; (lines=16, args=0, vars=2, tmps=7) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/121_object_assigned_by_reference/121_object_assigned_by_reference.php:1-9 -L0 (3): NOP -L1 (5): EXT_STMT -L2 (5): ASSIGN CV0($x) string("safe") -L3 (6): EXT_STMT -L4 (6): ASSIGN CV1($obj) string("abc") -L5 (7): EXT_STMT -L6 (7): ASSIGN_OBJ_REF CV1($obj) string("prop") -L7 (7): OP_DATA CV0($x) -L8 (8): EXT_STMT -L9 (8): T5 = FETCH_R (global) string("_GET") -L10 (8): T6 = FETCH_DIM_R T5 string("p1") -L11 (8): ASSIGN CV0($x) T6 -L12 (9): EXT_STMT -L13 (9): T8 = FETCH_OBJ_R CV1($obj) string("prop") -L14 (9): ECHO T8 -L15 (9): RETURN int(1) +$_main: + ; (lines=12, args=0, vars=2, tmps=9) + ; (before optimizer) + ; /.../PHP/14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference/1_instance_14_object_assigned_by_reference.php:1-9 + ; return [] RANGE[0..0] +0000 ASSIGN CV0($x) string("safe") +0001 V3 = NEW 0 string("myclass") +0002 DO_FCALL +0003 ASSIGN CV1($obj) V3 +0004 ASSIGN_OBJ_REF CV1($obj) string("prop") +0005 OP_DATA CV0($x) +0006 T7 = FETCH_R (global) string("_GET") +0007 T8 = FETCH_DIM_R T7 string("p1") +0008 ASSIGN CV0($x) T8 +0009 T10 = FETCH_OBJ_R CV1($obj) string("prop") +0010 ECHO T10 +0011 RETURN int(1) +LIVE RANGES: + 3: 0002 - 0003 (new) +``` + +
+ +
+ + +### Discovery + + +The rule searches for `ASSIGN_OBJ_REF` which is used to assign objects by reference. The rule is the same for all instances. + +```scala +val x14 = (name, "14_object_assigned_by_reference_iall", cpg.call(".*ASSIGN_OBJ_REF.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | Ground Truth | +|-------------|----------|----------|----------------| +| 17 May 2023 | yes | no | yes | + +
+ +
+ +
+ +
+ + +## 2 Instance + + +The instance shows a variable assigned to an instance variable of an object by reference. The other variable is first set to a user controlled input and than this variable is assigned to an instance variable of an object. + +### Code + +```PHP +prop = &$x; // tarpit +echo $obj->prop; // sink ``` -- DISCOVERY: +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + ```bash -cpg.call(".*ASSIGN_OBJ_REF.*").location.l +$_main: + ; (lines=12, args=0, vars=2, tmps=9) + ; (before optimizer) + ; /.../PHP/14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference/2_instance_14_object_assigned_by_reference.php:1-9 + ; return [] RANGE[0..0] +0000 ASSIGN CV0($x) string("safe") +0001 V3 = NEW 0 string("myclass") +0002 DO_FCALL +0003 ASSIGN CV1($obj) V3 +0004 T6 = FETCH_R (global) string("_GET") +0005 T7 = FETCH_DIM_R T6 string("p1") +0006 ASSIGN CV0($x) T7 +0007 ASSIGN_OBJ_REF CV1($obj) string("prop") +0008 OP_DATA CV0($x) +0009 T10 = FETCH_OBJ_R CV1($obj) string("prop") +0010 ECHO T10 +0011 RETURN int(1) +LIVE RANGES: + 3: 0002 - 0003 (new) +``` + +
+ +
+ + +### Discovery + + +The rule searches for `ASSIGN_OBJ_REF` which is used to assign objects by reference. The rule is the same for all instances. + +```scala +val x14 = (name, "14_object_assigned_by_reference_iall", cpg.call(".*ASSIGN_OBJ_REF.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | Ground Truth | +|-------------|----------|----------|----------------| +| 17 May 2023 | yes | yes | yes | + +
+ +
+ +
+ +
+ + +## 3 Instance + + +This instance provides another indirection through which the user input reaches the sink. In this instance, it is stored in an intermediate variable, which is assigned to another variable, which itself links to the instance variable, that is used for the output. + +### Code + +```PHP +prop = &$x; // tarpit +$x = $a; +echo $obj->prop; // sink ``` -- PRECONDITIONS: - 1. +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ -- TRANSFORMATION: +### Compile + +```bash +$_main: + ; (lines=13, args=0, vars=3, tmps=10) + ; (before optimizer) + ; /.../PHP/14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference/3_instance_14_object_assigned_by_reference.php:1-10 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($a) T4 +0003 ASSIGN CV1($x) string("safe") +0004 V7 = NEW 0 string("myclass") +0005 DO_FCALL +0006 ASSIGN CV2($obj) V7 +0007 ASSIGN_OBJ_REF CV2($obj) string("prop") +0008 OP_DATA CV1($x) +0009 ASSIGN CV1($x) CV0($a) +0010 T12 = FETCH_OBJ_R CV2($obj) string("prop") +0011 ECHO T12 +0012 RETURN int(1) +LIVE RANGES: + 7: 0005 - 0006 (new) ``` +
+ +
+ + +### Discovery + + +The rule searches for `ASSIGN_OBJ_REF` which is used to assign objects by reference. The rule is the same for all instances. + +```scala +val x14 = (name, "14_object_assigned_by_reference_iall", cpg.call(".*ASSIGN_OBJ_REF.*").location.toJson); ``` +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | Ground Truth | +|-------------|----------|----------|----------------| +| 17 May 2023 | yes | no | yes | + +
+ +
+ +
diff --git a/PHP/14_object_assigned_by_reference/docs/description.md b/PHP/14_object_assigned_by_reference/docs/description.md new file mode 100644 index 0000000..12e46a3 --- /dev/null +++ b/PHP/14_object_assigned_by_reference/docs/description.md @@ -0,0 +1 @@ +Instance variables can be assigned by reference, every change to a variable referencing an instance variable of an object will be reflected in the instance variable and vice versa. \ No newline at end of file diff --git a/PHP/14_object_assigned_by_reference/docs/discovery_notes.md b/PHP/14_object_assigned_by_reference/docs/discovery_notes.md new file mode 100644 index 0000000..2ce1236 --- /dev/null +++ b/PHP/14_object_assigned_by_reference/docs/discovery_notes.md @@ -0,0 +1 @@ +The rule searches for `ASSIGN_OBJ_REF` which is used to assign objects by reference. The rule is the same for all instances. \ No newline at end of file diff --git a/PHP/15_nested_function/15_nested_function.json b/PHP/15_nested_function/15_nested_function.json index 6ca130c..423ed4d 100644 --- a/PHP/15_nested_function/15_nested_function.json +++ b/PHP/15_nested_function/15_nested_function.json @@ -1,6 +1,6 @@ { - "name": "Nested Function Declaration", - "description": "Declaring a function inside another function", + "name": "Nested Function", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -11,5 +11,5 @@ "./1_instance_15_nested_function/1_instance_15_nested_function.json", "./2_instance_15_nested_function/2_instance_15_nested_function.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/15_nested_function/15_nested_function.sc b/PHP/15_nested_function/15_nested_function.sc new file mode 100644 index 0000000..190f1a7 --- /dev/null +++ b/PHP/15_nested_function/15_nested_function.sc @@ -0,0 +1,6 @@ +@main def main(name : String): Unit = { + importCpg(name) + val x15 = (name, "15_nested_function_iall", cpg.call(".*DECLARE_FUNCTION.*").location.toJson); + println(x15) + delete; +} \ No newline at end of file diff --git a/PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.bash b/PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.bash index 733559e..99a0de6 100644 --- a/PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.bash +++ b/PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.bash @@ -1,35 +1,32 @@ -$_main: ; (lines=12, args=0, vars=1, tmps=5) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/9_nested_function/9_nested_function.php:1-10 -L0 (8): EXT_STMT -L1 (8): T1 = FETCH_R (global) string("_GET") -L2 (8): T2 = FETCH_DIM_R T1 string("p1") -L3 (8): ASSIGN CV0($b) T2 -L4 (9): EXT_STMT -L5 (9): INIT_FCALL 0 80 string("f") -L6 (9): DO_FCALL -L7 (10): EXT_STMT -L8 (10): INIT_FCALL_BY_NAME 1 string("D") -L9 (10): SEND_VAR_EX CV0($b) 1 -L10 (10): DO_FCALL -L11 (10): RETURN int(1) +$_main: + ; (lines=9, args=0, vars=1, tmps=5) + ; (before optimizer) + ; /.../PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.php:1-9 + ; return [] RANGE[0..0] +0000 T1 = FETCH_R (global) string("_GET") +0001 T2 = FETCH_DIM_R T1 string("p1") +0002 ASSIGN CV0($b) T2 +0003 INIT_FCALL 0 80 string("f") +0004 DO_UCALL +0005 INIT_FCALL_BY_NAME 1 string("D") +0006 SEND_VAR_EX CV0($b) 1 +0007 DO_FCALL_BY_NAME +0008 RETURN int(1) -F: ; (lines=5, args=0, vars=0, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/9_nested_function/9_nested_function.php:3-7 -L0 (3): EXT_NOP -L1 (4): EXT_STMT -L2 (4): DECLARE_FUNCTION string("d") -L3 (7): EXT_STMT -L4 (7): RETURN null +F: + ; (lines=2, args=0, vars=0, tmps=0) + ; (before optimizer) + ; /.../PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.php:2-6 + ; return [] RANGE[0..0] +0000 DECLARE_FUNCTION string("d") 0 +0001 RETURN null -D: ; (lines=6, args=1, vars=1, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/9_nested_function/9_nested_function.php:4-6 -L0 (4): EXT_NOP -L1 (4): CV0($b) = RECV 1 -L2 (5): EXT_STMT -L3 (5): ECHO CV0($b) -L4 (6): EXT_STMT -L5 (6): RETURN null +D: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ECHO CV0($b) +0002 RETURN null diff --git a/PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.json b/PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.json index af8f3dd..1549cb7 100644 --- a/PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.json +++ b/PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.json @@ -1,13 +1,14 @@ { + "description": "This instance defines a function within another function. The sink can be found within the inner function.", "code": { "path": "./1_instance_15_nested_function.php", "injection_skeleton_broken": true }, "discovery": { - "rule": "./1_instance_15_nested_function.sc", + "rule": "../15_nested_function.sc", "method": "joern", "rule_accuracy": "Perfect", - "notes": null + "notes": "The rule searches for `DECLARE_FUNCTION`." }, "compile": { "binary": "./1_instance_15_nested_function.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_15_nested_function.php", - "sink_line": 5, + "sink_line": 4, "source_file": "./1_instance_15_nested_function.php", - "source_line": 8, + "source_line": 7, "expectation": true }, "properties": { @@ -30,7 +31,7 @@ "negative_test_case": false }, "remediation": { - "notes": "", + "notes": "If possible, the inner function should be declared outside of the scope of the outer function. Are there any performance related or other issues with that? If not, this could be automated.", "transformation": null, "modeling_rule": null } diff --git a/PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.php b/PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.php index 65be58c..9ac91ff 100644 --- a/PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.php +++ b/PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.php @@ -1,7 +1,6 @@ + + +## 1 Instance + + +This instance defines a function within another function. The sink can be found within the inner function. -function F(){ - function D($b){ - echo $b; +### Code + +```PHP + + +More -- OPCODE: +
+ + +### Compile + ```bash -$_main: ; (lines=12, args=0, vars=1, tmps=5) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/9_nested_function/9_nested_function.php:1-10 -L0 (8): EXT_STMT -L1 (8): T1 = FETCH_R (global) string("_GET") -L2 (8): T2 = FETCH_DIM_R T1 string("p1") -L3 (8): ASSIGN CV0($b) T2 -L4 (9): EXT_STMT -L5 (9): INIT_FCALL 0 80 string("f") -L6 (9): DO_FCALL -L7 (10): EXT_STMT -L8 (10): INIT_FCALL_BY_NAME 1 string("D") -L9 (10): SEND_VAR_EX CV0($b) 1 -L10 (10): DO_FCALL -L11 (10): RETURN int(1) - -F: ; (lines=5, args=0, vars=0, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/9_nested_function/9_nested_function.php:3-7 -L0 (3): EXT_NOP -L1 (4): EXT_STMT -L2 (4): DECLARE_FUNCTION string("d") -L3 (7): EXT_STMT -L4 (7): RETURN null - -D: ; (lines=6, args=1, vars=1, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/9_nested_function/9_nested_function.php:4-6 -L0 (4): EXT_NOP -L1 (4): CV0($b) = RECV 1 -L2 (5): EXT_STMT -L3 (5): ECHO CV0($b) -L4 (6): EXT_STMT -L5 (6): RETURN null +$_main: + ; (lines=9, args=0, vars=1, tmps=5) + ; (before optimizer) + ; /.../PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.php:1-9 + ; return [] RANGE[0..0] +0000 T1 = FETCH_R (global) string("_GET") +0001 T2 = FETCH_DIM_R T1 string("p1") +0002 ASSIGN CV0($b) T2 +0003 INIT_FCALL 0 80 string("f") +0004 DO_UCALL +0005 INIT_FCALL_BY_NAME 1 string("D") +0006 SEND_VAR_EX CV0($b) 1 +0007 DO_FCALL_BY_NAME +0008 RETURN int(1) + +F: + ; (lines=2, args=0, vars=0, tmps=0) + ; (before optimizer) + ; /.../PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.php:2-6 + ; return [] RANGE[0..0] +0000 DECLARE_FUNCTION string("d") 0 +0001 RETURN null + +D: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/15_nested_function/1_instance_15_nested_function/1_instance_15_nested_function.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ECHO CV0($b) +0002 RETURN null ``` -- DISCOVERY: +
-```bash -cpg.call(".*DECLARE_FUNCTION.*").location.l +
+ + +### Discovery + + +The rule searches for `DECLARE_FUNCTION`. + +```scala +val x15 = (name, "15_nested_function_iall", cpg.call(".*DECLARE_FUNCTION.*").location.toJson); ``` -- PRECONDITIONS: - 1. +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | yes | yes | no | yes | yes | +| 17 May 2023 | yes | no | | | | | yes | + +
+ +
+ + +### Remediation + + +If possible, the inner function should be declared outside of the scope of the outer function. Are there any performance related or other issues with that? If not, this could be automated. + +
+ + + + + +
+ -- TRANSFORMATION: +## 2 Instance + +This instance defines a function within another function. The sink is moved out of the inner function to provide the standard skeleton. Why does this make a difference for some SAST tools? + +### Code + +```PHP + + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=11, args=0, vars=2, tmps=6) + ; (before optimizer) + ; /.../PHP/15_nested_function/2_instance_15_nested_function/2_instance_15_nested_function.php:1-10 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($a) T3 +0003 INIT_FCALL 0 80 string("f") +0004 DO_UCALL +0005 INIT_FCALL_BY_NAME 1 string("D") +0006 SEND_VAR_EX CV0($a) 1 +0007 V6 = DO_FCALL_BY_NAME +0008 ASSIGN CV1($b) V6 +0009 ECHO CV1($b) +0010 RETURN int(1) + +F: + ; (lines=2, args=0, vars=0, tmps=0) + ; (before optimizer) + ; /.../PHP/15_nested_function/2_instance_15_nested_function/2_instance_15_nested_function.php:2-6 + ; return [] RANGE[0..0] +0000 DECLARE_FUNCTION string("d") 0 +0001 RETURN null + +D: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/15_nested_function/2_instance_15_nested_function/2_instance_15_nested_function.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($c) = RECV 1 +0001 RETURN CV0($c) +0002 RETURN null ``` +
+ +
+ + +### Discovery + + +The rule searches for `DECLARE_FUNCTION`. + +```scala +val x15 = (name, "15_nested_function_iall", cpg.call(".*DECLARE_FUNCTION.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | Ground Truth | +|-------------|----------|----------|----------------| +| 17 May 2023 | yes | yes | yes | + +
+ +
+ +### Remediation + +If possible, the inner function should be declared outside of the scope of the outer function. Are there any performance related or other issues with that? If not, this could be automated. +
+
+ diff --git a/PHP/15_nested_function/docs/description.md b/PHP/15_nested_function/docs/description.md new file mode 100644 index 0000000..017e699 --- /dev/null +++ b/PHP/15_nested_function/docs/description.md @@ -0,0 +1 @@ +PHP allows declaring a function inside another function. \ No newline at end of file diff --git a/PHP/16_variadic_functions/16_variadic_functions.json b/PHP/16_variadic_functions/16_variadic_functions.json index 4f6d9be..e30e166 100644 --- a/PHP/16_variadic_functions/16_variadic_functions.json +++ b/PHP/16_variadic_functions/16_variadic_functions.json @@ -1,6 +1,6 @@ { "name": "Variadic Functions", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -12,5 +12,5 @@ "./2_instance_16_variadic_functions/2_instance_16_variadic_functions.json", "./3_instance_16_variadic_functions/3_instance_16_variadic_functions.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.sc b/PHP/16_variadic_functions/16_variadic_functions.sc similarity index 100% rename from PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.sc rename to PHP/16_variadic_functions/16_variadic_functions.sc diff --git a/PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.bash b/PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.bash index 62cea8c..08ff924 100644 --- a/PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.bash +++ b/PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.bash @@ -1,33 +1,31 @@ -$_main: ; (lines=12, args=0, vars=1, tmps=4) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/10_variadic_functions/10_variadic_functions.php:1-12 -L0 (11): EXT_STMT -L1 (11): T1 = FETCH_R (global) string("_GET") -L2 (11): T2 = FETCH_DIM_R T1 string("p1") -L3 (11): ASSIGN CV0($b) T2 -L4 (12): EXT_STMT -L5 (12): INIT_FCALL 4 192 string("sum") -L6 (12): SEND_VAL int(1) 1 -L7 (12): SEND_VAL int(2) 2 -L8 (12): SEND_VAL int(3) 3 -L9 (12): SEND_VAR CV0($b) 4 -L10 (12): DO_FCALL -L11 (12): RETURN int(1) +$_main: + ; (lines=10, args=0, vars=1, tmps=4) + ; (before optimizer) + ; /.../PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.php:1-11 + ; return [] RANGE[0..0] +0000 T1 = FETCH_R (global) string("_GET") +0001 T2 = FETCH_DIM_R T1 string("p1") +0002 ASSIGN CV0($a) T2 +0003 INIT_FCALL 4 192 string("sum") +0004 SEND_VAL int(1) 1 +0005 SEND_VAL int(2) 2 +0006 SEND_VAL int(3) 3 +0007 SEND_VAR CV0($a) 4 +0008 DO_UCALL +0009 RETURN int(1) -sum: ; (lines=11, args=0, vars=2, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/10_variadic_functions/10_variadic_functions.php:4-9 -L0 (4): EXT_NOP -L1 (4): CV0($numbers) = RECV_VARIADIC 1 -L2 (5): EXT_STMT -L3 (5): V2 = FE_RESET_R CV0($numbers) L8 -L4 (5): FE_FETCH_R V2 CV1($n) L8 -L5 (7): EXT_STMT -L6 (7): ECHO CV1($n) -L7 (5): JMP L4 -L8 (5): FE_FREE V2 -L9 (9): EXT_STMT -L10 (9): RETURN null +sum: + ; (lines=7, args=0, vars=2, tmps=1) + ; (before optimizer) + ; /.../PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.php:3-8 + ; return [] RANGE[0..0] +0000 CV0($numbers) = RECV_VARIADIC 1 +0001 V2 = FE_RESET_R CV0($numbers) 0005 +0002 FE_FETCH_R V2 CV1($n) 0005 +0003 ECHO CV1($n) +0004 JMP 0002 +0005 FE_FREE V2 +0006 RETURN null LIVE RANGES: - 2: L4 - L8 (loop) \ No newline at end of file + 2: 0002 - 0005 (loop) diff --git a/PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.json b/PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.json index 4c66fba..32eaa77 100644 --- a/PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.json +++ b/PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.json @@ -1,13 +1,14 @@ { + "description": "This instance shows a function, that takes an arbitrary number of variables and outputs each of them. The sink is within the function.", "code": { "path": "./1_instance_16_variadic_functions.php", "injection_skeleton_broken": true }, "discovery": { - "rule": "./1_instance_16_variadic_functions.sc", + "rule": "../16_variadic_functions.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "Perfect", + "notes": "The rule searches for `RECV_VARIADIC`." }, "compile": { "binary": "./1_instance_16_variadic_functions.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_16_variadic_functions.php", - "sink_line": 7, + "sink_line": 6, "source_file": "./1_instance_16_variadic_functions.php", - "source_line": 11, + "source_line": 10, "expectation": true }, "properties": { diff --git a/PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.php b/PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.php index 5460d67..128c7fd 100644 --- a/PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.php +++ b/PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.php @@ -1,12 +1,11 @@ + + +## 1 Instance + + +This instance shows a function, that takes an arbitrary number of variables and outputs each of them. The sink is within the function. + +### Code +```PHP + + +More -| Tool | RIPS | phpSAFE | WAP | Progpilot | Comm_1 | Comm_2 | Correct | -| ------------- | ---- | ------- | ---- | --------- | ------- | --------- | ------- | -| Vulnerability | NO | NO | NO | NO | YES | YES | YES | -Measurements Date: 8 June 2021 +
+ -- OPCODE: +### Compile + ```bash -$_main: ; (lines=12, args=0, vars=1, tmps=4) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/10_variadic_functions/10_variadic_functions.php:1-12 -L0 (11): EXT_STMT -L1 (11): T1 = FETCH_R (global) string("_GET") -L2 (11): T2 = FETCH_DIM_R T1 string("p1") -L3 (11): ASSIGN CV0($b) T2 -L4 (12): EXT_STMT -L5 (12): INIT_FCALL 4 192 string("sum") -L6 (12): SEND_VAL int(1) 1 -L7 (12): SEND_VAL int(2) 2 -L8 (12): SEND_VAL int(3) 3 -L9 (12): SEND_VAR CV0($b) 4 -L10 (12): DO_FCALL -L11 (12): RETURN int(1) - -sum: ; (lines=11, args=0, vars=2, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/10_variadic_functions/10_variadic_functions.php:4-9 -L0 (4): EXT_NOP -L1 (4): CV0($numbers) = RECV_VARIADIC 1 -L2 (5): EXT_STMT -L3 (5): V2 = FE_RESET_R CV0($numbers) L8 -L4 (5): FE_FETCH_R V2 CV1($n) L8 -L5 (7): EXT_STMT -L6 (7): ECHO CV1($n) -L7 (5): JMP L4 -L8 (5): FE_FREE V2 -L9 (9): EXT_STMT -L10 (9): RETURN null +$_main: + ; (lines=10, args=0, vars=1, tmps=4) + ; (before optimizer) + ; /.../PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.php:1-11 + ; return [] RANGE[0..0] +0000 T1 = FETCH_R (global) string("_GET") +0001 T2 = FETCH_DIM_R T1 string("p1") +0002 ASSIGN CV0($a) T2 +0003 INIT_FCALL 4 192 string("sum") +0004 SEND_VAL int(1) 1 +0005 SEND_VAL int(2) 2 +0006 SEND_VAL int(3) 3 +0007 SEND_VAR CV0($a) 4 +0008 DO_UCALL +0009 RETURN int(1) + +sum: + ; (lines=7, args=0, vars=2, tmps=1) + ; (before optimizer) + ; /.../PHP/16_variadic_functions/1_instance_16_variadic_functions/1_instance_16_variadic_functions.php:3-8 + ; return [] RANGE[0..0] +0000 CV0($numbers) = RECV_VARIADIC 1 +0001 V2 = FE_RESET_R CV0($numbers) 0005 +0002 FE_FETCH_R V2 CV1($n) 0005 +0003 ECHO CV1($n) +0004 JMP 0002 +0005 FE_FREE V2 +0006 RETURN null LIVE RANGES: - 2: L4 - L8 (loop) + 2: 0002 - 0005 (loop) +``` + +
+ +
+ + +### Discovery + + +The rule searches for `RECV_VARIADIC`. + +```scala +val x16 = (name, "16_variadic_functions_iall", cpg.call(".*RECV_VARIADIC.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | yes | no | no | no | no | yes | +| 17 May 2023 | yes | yes | | | | | yes | + +
+ + + + + +
+ + +## 2 Instance + + +The instance shows a function, that takes an arbitrary number of arguments and returns the fourth, which contains a user controlled value. + +### Code + +```PHP + + +More + +
+ + +### Compile + ```bash -cpg.call(".*RECV_VARIADIC.*").location.l +$_main: + ; (lines=12, args=0, vars=2, tmps=5) + ; (before optimizer) + ; /.../PHP/16_variadic_functions/2_instance_16_variadic_functions/2_instance_16_variadic_functions.php:1-8 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($a) T3 +0003 INIT_FCALL 4 176 string("sum") +0004 SEND_VAL int(1) 1 +0005 SEND_VAL int(2) 2 +0006 SEND_VAL int(3) 3 +0007 SEND_VAR CV0($a) 4 +0008 V5 = DO_UCALL +0009 ASSIGN CV1($b) V5 +0010 ECHO CV1($b) +0011 RETURN int(1) + +sum: + ; (lines=4, args=0, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/16_variadic_functions/2_instance_16_variadic_functions/2_instance_16_variadic_functions.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($numbers) = RECV_VARIADIC 1 +0001 T1 = FETCH_DIM_R CV0($numbers) int(3) +0002 RETURN T1 +0003 RETURN null ``` -- PRECONDITIONS: - 1. +
+ +
+ -- TRANSFORMATION: +### Discovery + +The rule searches for `RECV_VARIADIC`. + +```scala +val x16 = (name, "16_variadic_functions_iall", cpg.call(".*RECV_VARIADIC.*").location.toJson); ``` +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | Ground Truth | +|-------------|----------|----------|----------------| +| 17 May 2023 | yes | yes | yes | + +
+ +
+ + + +
+ + +## 3 Instance + + +The instance shows a function, that takes an arbitrary number of arguments and returns the first argument, that is not 1, so if the user controlled value is something different than 1, it ends up in the sink. + +### Code + +```PHP + + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=12, args=0, vars=2, tmps=5) + ; (before optimizer) + ; /.../PHP/16_variadic_functions/3_instance_16_variadic_functions/3_instance_16_variadic_functions.php:1-14 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($a) T3 +0003 INIT_FCALL 4 208 string("sum") +0004 SEND_VAL int(1) 1 +0005 SEND_VAL int(1) 2 +0006 SEND_VAL int(1) 3 +0007 SEND_VAR CV0($a) 4 +0008 V5 = DO_UCALL +0009 ASSIGN CV1($b) V5 +0010 ECHO CV1($b) +0011 RETURN int(1) + +sum: + ; (lines=11, args=0, vars=2, tmps=2) + ; (before optimizer) + ; /.../PHP/16_variadic_functions/3_instance_16_variadic_functions/3_instance_16_variadic_functions.php:3-10 + ; return [] RANGE[0..0] +0000 CV0($numbers) = RECV_VARIADIC 1 +0001 V2 = FE_RESET_R CV0($numbers) 0008 +0002 FE_FETCH_R V2 CV1($n) 0008 +0003 T3 = IS_NOT_EQUAL CV1($n) int(1) +0004 JMPZ T3 0007 +0005 FE_FREE V2 +0006 RETURN CV1($n) +0007 JMP 0002 +0008 FE_FREE V2 +0009 RETURN string("safe") +0010 RETURN null +LIVE RANGES: + 2: 0002 - 0008 (loop) +``` + +
+ +
+ + +### Discovery + + +The rule searches for `RECV_VARIADIC`. + +```scala +val x16 = (name, "16_variadic_functions_iall", cpg.call(".*RECV_VARIADIC.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | Ground Truth | +|-------------|----------|----------|----------------| +| 17 May 2023 | yes | yes | yes | + +
+ +
+ + diff --git a/PHP/16_variadic_functions/docs/description.md b/PHP/16_variadic_functions/docs/description.md new file mode 100644 index 0000000..b89e757 --- /dev/null +++ b/PHP/16_variadic_functions/docs/description.md @@ -0,0 +1 @@ +Variadic functions in PHP allow a function to accept an arbitrary number of arguments, which are automatically collected into an array, using the ... (ellipsis) operator. \ No newline at end of file diff --git a/PHP/17_get_arguments/17_get_arguments.json b/PHP/17_get_arguments/17_get_arguments.json index 9042832..163c84b 100644 --- a/PHP/17_get_arguments/17_get_arguments.json +++ b/PHP/17_get_arguments/17_get_arguments.json @@ -1,6 +1,6 @@ { "name": "Get Arguments", - "description": "In PHP it is not possible to define more than one function with the same name, even if the number of arguments are different between the two functions. \n```php\n + -- CATEGORY: S0 -- FEATURE vs INTERNAL API: FEATURE -- INPUT SANITIZERS: NO -- SOURCES AND SINKS: NO -- NEGATIVE TEST CASES: NO -- CODE: +## 1 Instance + -```php +This instance uses `func_get_args` and iterates over all the arguments passed to the function and outputs those. The sink is within this for loop. + +### Code + +```PHP + +More -- OPCODE: +
+ + +### Compile + ```bash -$_main: ; (lines=12, args=0, vars=1, tmps=4) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/12_get_arguments/12_get_arguments.php:1-11 -L0 (10): EXT_STMT -L1 (10): T1 = FETCH_R (global) string("_GET") -L2 (10): T2 = FETCH_DIM_R T1 string("p1") -L3 (10): ASSIGN CV0($b) T2 -L4 (11): EXT_STMT -L5 (11): INIT_FCALL 4 192 string("sum") -L6 (11): SEND_VAL int(1) 1 -L7 (11): SEND_VAL int(2) 2 -L8 (11): SEND_VAL int(3) 3 -L9 (11): SEND_VAR CV0($b) 4 -L10 (11): DO_FCALL -L11 (11): RETURN int(1) - -sum: ; (lines=11, args=0, vars=1, tmps=2) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/12_get_arguments/12_get_arguments.php:2-8 -L0 (2): EXT_NOP -L1 (5): EXT_STMT -L2 (5): T1 = FUNC_GET_ARGS -L3 (5): V2 = FE_RESET_R T1 L8 -L4 (5): FE_FETCH_R V2 CV0($n) L8 -L5 (6): EXT_STMT -L6 (6): ECHO CV0($n) -L7 (5): JMP L4 -L8 (5): FE_FREE V2 -L9 (8): EXT_STMT -L10 (8): RETURN null +$_main: + ; (lines=10, args=0, vars=1, tmps=4) + ; (before optimizer) + ; /.../PHP/17_get_arguments/1_instance_17_get_arguments/1_instance_17_get_arguments.php:1-11 + ; return [] RANGE[0..0] +0000 T1 = FETCH_R (global) string("_GET") +0001 T2 = FETCH_DIM_R T1 string("p1") +0002 ASSIGN CV0($b) T2 +0003 INIT_FCALL 4 192 string("sum") +0004 SEND_VAL int(1) 1 +0005 SEND_VAL int(2) 2 +0006 SEND_VAL int(3) 3 +0007 SEND_VAR CV0($b) 4 +0008 DO_UCALL +0009 RETURN int(1) + +sum: + ; (lines=7, args=0, vars=1, tmps=2) + ; (before optimizer) + ; /.../PHP/17_get_arguments/1_instance_17_get_arguments/1_instance_17_get_arguments.php:2-8 + ; return [] RANGE[0..0] +0000 T1 = FUNC_GET_ARGS +0001 V2 = FE_RESET_R T1 0005 +0002 FE_FETCH_R V2 CV0($n) 0005 +0003 ECHO CV0($n) +0004 JMP 0002 +0005 FE_FREE V2 +0006 RETURN null LIVE RANGES: - 2: L4 - L8 (loop) + 2: 0002 - 0005 (loop) ``` -- DISCOVERY: +
-I can find the pattern by searching for the name of the function (func_get_args) as keyword in regex. While in Opcode there is a special opcode for this function FUNC_GET_ARGS. +
+ -```bash -cpg.call(".*FUNC_GET_ARGS.*").location.l +### Discovery + + +In opcode there is a special opcode for this function `FUNC_GET_ARGS`. + +```scala +val x17 = (name, "17_get_arguments_iall", cpg.call(".*FUNC_GET_ARGS.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | yes | no | no | yes | no | yes | +| 17 May 2023 | no | yes | | | | | yes | + +
+ + + + + +
+ + +## 2 Instance + + +This instance uses `func_get_args` to output the fourth element, which contains user controlled input. + +### Code + +```PHP + + +More +
+ + +### Compile + + +```bash +$_main: + ; (lines=12, args=0, vars=2, tmps=5) + ; (before optimizer) + ; /.../PHP/17_get_arguments/2_instance_17_get_arguments/2_instance_17_get_arguments.php:1-7 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($a) T3 +0003 INIT_FCALL 4 176 string("fourth") +0004 SEND_VAL int(1) 1 +0005 SEND_VAL int(2) 2 +0006 SEND_VAL int(3) 3 +0007 SEND_VAR CV0($a) 4 +0008 V5 = DO_UCALL +0009 ASSIGN CV1($b) V5 +0010 ECHO CV1($b) +0011 RETURN int(1) + +fourth: + ; (lines=4, args=0, vars=0, tmps=2) + ; (before optimizer) + ; /.../PHP/17_get_arguments/2_instance_17_get_arguments/2_instance_17_get_arguments.php:2-4 + ; return [] RANGE[0..0] +0000 T0 = FUNC_GET_ARGS +0001 T1 = FETCH_DIM_R T0 int(3) +0002 RETURN T1 +0003 RETURN null ``` +
+ +
+ + +### Discovery + + +In opcode there is a special opcode for this function `FUNC_GET_ARGS`. + +```scala +val x17 = (name, "17_get_arguments_iall", cpg.call(".*FUNC_GET_ARGS.*").location.toJson); ``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | Ground Truth | +|-------------|----------|----------|----------------| +| 17 May 2023 | no | yes | yes | + +
+ +
+ + diff --git a/PHP/17_get_arguments/docs/description.md b/PHP/17_get_arguments/docs/description.md new file mode 100644 index 0000000..34662c2 --- /dev/null +++ b/PHP/17_get_arguments/docs/description.md @@ -0,0 +1,30 @@ +In PHP it is not possible to define more than one function with the same name, even if the number of arguments are different between the two functions. + +```php + + + +## 1 Instance + + +The instance uses the unpack operator for calling the `add` function. The sink is within this function. + +### Code + +```PHP + +More + +
+ + +### Compile + ```bash -$_main: ; (lines=13, args=0, vars=2, tmps=6) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/11_send_unpack/11_send_unpack.php:1-11 -L0 (9): EXT_STMT -L1 (9): T2 = FETCH_R (global) string("_GET") -L2 (9): T3 = FETCH_DIM_R T2 string("p1") -L3 (9): ASSIGN CV0($b) T3 -L4 (10): EXT_STMT -L5 (10): T5 = INIT_ARRAY 2 (packed) int(1) NEXT -L6 (10): T5 = ADD_ARRAY_ELEMENT CV0($b) NEXT -L7 (10): ASSIGN CV1($a) T5 -L8 (11): EXT_STMT -L9 (11): INIT_FCALL 0 112 string("add") -L10 (11): SEND_UNPACK CV1($a) -L11 (11): DO_FCALL -L12 (11): RETURN int(1) +$_main: + ; (lines=11, args=0, vars=2, tmps=6) + ; (before optimizer) + ; /.../PHP/18_send_unpack/1_instance_18_send_unpack/1_instance_18_send_unpack.php:1-11 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 T5 = INIT_ARRAY 2 (packed) int(1) NEXT +0004 T5 = ADD_ARRAY_ELEMENT CV0($b) NEXT +0005 ASSIGN CV1($a) T5 +0006 INIT_FCALL 0 112 string("add") +0007 SEND_UNPACK CV1($a) +0008 CHECK_UNDEF_ARGS +0009 DO_UCALL +0010 RETURN int(1) LIVE RANGES: - 5: L6 - L7 (tmp/var) - -add: ; (lines=9, args=2, vars=2, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/11_send_unpack/11_send_unpack.php:3-7 -L0 (3): EXT_NOP -L1 (3): CV0($a) = RECV 1 -L2 (3): CV1($b) = RECV 2 -L3 (4): EXT_STMT -L4 (4): ECHO CV0($a) -L5 (6): EXT_STMT -L6 (6): ECHO CV1($b) -L7 (7): EXT_STMT -L8 (7): RETURN null + 5: 0004 - 0005 (tmp/var) + +add: + ; (lines=5, args=2, vars=2, tmps=0) + ; (before optimizer) + ; /.../PHP/18_send_unpack/1_instance_18_send_unpack/1_instance_18_send_unpack.php:3-7 + ; return [] RANGE[0..0] +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV 2 +0002 ECHO CV0($a) +0003 ECHO CV1($b) +0004 RETURN null +``` + +
+ +
+ + +### Discovery + + +The unpack operator has an equivalent opcode instruction `SEND_UNPACK`. This rule searches for that. + +```scala +val x18 = (name, "18_send_unpack_iall", cpg.call(".*SEND_UNPACK.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | yes | no | yes | no | yes | +| 17 May 2023 | yes | yes | | | | | yes | + +
+ + + + + +
+ + +## 2 Instance + + +The instance uses the unpack operator to call the `add` function, but this time, one + +### Code + +```PHP + + +More + +
+ + +### Compile + ```bash -cpg.call(".*SEND_UNPACK.*").location.l +$_main: + ; (lines=13, args=0, vars=3, tmps=7) + ; (before optimizer) + ; /.../PHP/18_send_unpack/2_instance_18_send_unpack/2_instance_18_send_unpack.php:1-10 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($b) T4 +0003 T6 = INIT_ARRAY 2 (packed) int(1) NEXT +0004 T6 = ADD_ARRAY_ELEMENT CV0($b) NEXT +0005 ASSIGN CV1($a) T6 +0006 INIT_FCALL 0 112 string("add") +0007 SEND_UNPACK CV1($a) +0008 CHECK_UNDEF_ARGS +0009 V8 = DO_UCALL +0010 ASSIGN CV2($c) V8 +0011 ECHO CV2($c) +0012 RETURN int(1) +LIVE RANGES: + 6: 0004 - 0005 (tmp/var) + +add: + ; (lines=4, args=2, vars=2, tmps=0) + ; (before optimizer) + ; /.../PHP/18_send_unpack/2_instance_18_send_unpack/2_instance_18_send_unpack.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV 2 +0002 RETURN CV1($b) +0003 RETURN null ``` -- PRECONDITIONS: - 1. +
-- TRANSFORMATION: +
+ +### Discovery + + +The unpack operator has an equivalent opcode instruction `SEND_UNPACK`. This rule searches for that. + +```scala +val x18 = (name, "18_send_unpack_iall", cpg.call(".*SEND_UNPACK.*").location.toJson); ``` +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | Ground Truth | +|-------------|----------|----------|----------------| +| 17 May 2023 | yes | no | yes | + +
+ +
+ + + +
+ + +## 3 Instance + + +This instance shows the opposite and does not use the unpack operator on the `add` function. + +### Code + +```PHP + + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=10, args=0, vars=2, tmps=5) + ; (before optimizer) + ; /.../PHP/18_send_unpack/3_instance_18_send_unpack/3_instance_18_send_unpack.php:1-9 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 INIT_FCALL 2 112 string("add") +0004 SEND_VAL int(1) 1 +0005 SEND_VAR CV0($b) 2 +0006 V5 = DO_UCALL +0007 ASSIGN CV1($c) V5 +0008 ECHO CV1($c) +0009 RETURN int(1) + +add: + ; (lines=4, args=2, vars=2, tmps=0) + ; (before optimizer) + ; /.../PHP/18_send_unpack/3_instance_18_send_unpack/3_instance_18_send_unpack.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV 2 +0002 RETURN CV1($b) +0003 RETURN null +``` + +
+ +
+ + +### Discovery + + +This pattern does not use the unpack operator, so this rule will never be successfull + +```scala +val x18 = (name, "18_send_unpack_iall", cpg.call(".*SEND_UNPACK.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | Ground Truth | +|-------------|----------|----------|----------------| +| 17 May 2023 | yes | yes | yes | + +
+
+ diff --git a/PHP/18_send_unpack/docs/description.md b/PHP/18_send_unpack/docs/description.md new file mode 100644 index 0000000..5d9f307 --- /dev/null +++ b/PHP/18_send_unpack/docs/description.md @@ -0,0 +1 @@ +The ellipsis (...) operator in PHP allows you to expand an array or iterable object into a list of arguments that can than be passed to a function. \ No newline at end of file diff --git a/PHP/18_send_unpack/docs/discovery_notes.md b/PHP/18_send_unpack/docs/discovery_notes.md new file mode 100644 index 0000000..73908b1 --- /dev/null +++ b/PHP/18_send_unpack/docs/discovery_notes.md @@ -0,0 +1 @@ +The unpack operator has an equivalent opcode instruction `SEND_UNPACK`. This rule searches for that. \ No newline at end of file diff --git a/PHP/19_closures/19_closures.json b/PHP/19_closures/19_closures.json index a248e64..d3fc0b8 100644 --- a/PHP/19_closures/19_closures.json +++ b/PHP/19_closures/19_closures.json @@ -1,6 +1,6 @@ { "name": "Closures", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -11,5 +11,5 @@ "./1_instance_19_closures/1_instance_19_closures.json", "./2_instance_19_closures/2_instance_19_closures.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/19_closures/1_instance_19_closures/1_instance_19_closures.sc b/PHP/19_closures/19_closures.sc similarity index 100% rename from PHP/19_closures/1_instance_19_closures/1_instance_19_closures.sc rename to PHP/19_closures/19_closures.sc diff --git a/PHP/19_closures/1_instance_19_closures/1_instance_19_closures.bash b/PHP/19_closures/1_instance_19_closures/1_instance_19_closures.bash new file mode 100644 index 0000000..e23a5d4 --- /dev/null +++ b/PHP/19_closures/1_instance_19_closures/1_instance_19_closures.bash @@ -0,0 +1,26 @@ + +$_main: + ; (lines=11, args=0, vars=3, tmps=7) + ; (before optimizer) + ; /.../PHP/19_closures/1_instance_19_closures/1_instance_19_closures.php:1-7 + ; return [] RANGE[0..0] +0000 T3 = DECLARE_LAMBDA_FUNCTION 0 +0001 ASSIGN CV0($greet) T3 +0002 T5 = FETCH_R (global) string("_GET") +0003 T6 = FETCH_DIM_R T5 string("p1") +0004 ASSIGN CV1($a) T6 +0005 INIT_DYNAMIC_CALL 1 CV0($greet) +0006 SEND_VAR_EX CV1($a) 1 +0007 V8 = DO_FCALL +0008 ASSIGN CV2($b) V8 +0009 ECHO CV2($b) +0010 RETURN int(1) + +{closure}: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/19_closures/1_instance_19_closures/1_instance_19_closures.php:2-4 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 RETURN CV0($name) +0002 RETURN null diff --git a/PHP/19_closures/1_instance_19_closures/1_instance_19_closures.json b/PHP/19_closures/1_instance_19_closures/1_instance_19_closures.json index c88386a..07a05ca 100644 --- a/PHP/19_closures/1_instance_19_closures/1_instance_19_closures.json +++ b/PHP/19_closures/1_instance_19_closures/1_instance_19_closures.json @@ -1,26 +1,27 @@ { + "description": "This instance captures the declaration of an unnamed function.", "code": { "path": "./1_instance_19_closures.php", "injection_skeleton_broken": false }, "discovery": { - "rule": "./1_instance_19_closures.sc", + "rule": "../19_closures.sc", "method": "joern", "rule_accuracy": "Perfect", - "notes": null + "notes": "Declaring unnamed functions has an opcode statement `DECLARE_LAMBDA_FUNCTION`, which this rule searches for." }, "compile": { - "binary": null, + "binary": "./1_instance_19_closures.bash", "instruction": null, "dependencies": null }, "expectation": { "type": "xss", "sink_file": "./1_instance_19_closures.php", - "sink_line": 8, + "sink_line": 7, "source_file": "./1_instance_19_closures.php", - "source_line": 6, - "expectation": false + "source_line": 5, + "expectation": true }, "properties": { "category": "D2", @@ -30,7 +31,7 @@ "negative_test_case": true }, "remediation": { - "notes": "", + "notes": "../docs/remediation_notes.md", "transformation": null, "modeling_rule": null } diff --git a/PHP/19_closures/1_instance_19_closures/1_instance_19_closures.php b/PHP/19_closures/1_instance_19_closures/1_instance_19_closures.php index ad68ba8..b9f8509 100644 --- a/PHP/19_closures/1_instance_19_closures/1_instance_19_closures.php +++ b/PHP/19_closures/1_instance_19_closures/1_instance_19_closures.php @@ -1,8 +1,7 @@ fn($y) => $x . $y; -echo $fn1("safe")($b); -?> \ No newline at end of file +$a = $fn1("safe")($b); +echo a; // sink \ No newline at end of file diff --git a/PHP/19_closures/2_instance_19_closures/2_instance_19_closures.sc b/PHP/19_closures/2_instance_19_closures/2_instance_19_closures.sc deleted file mode 100644 index 55899f8..0000000 --- a/PHP/19_closures/2_instance_19_closures/2_instance_19_closures.sc +++ /dev/null @@ -1,6 +0,0 @@ -@main def main(name : String): Unit = { - importCpg(name) - val x19 = (name, "19_closures_iall", cpg.call(".*DECLARE_LAMBDA_FUNCTION.*").location.toJson); - println(x19) - delete; -} \ No newline at end of file diff --git a/PHP/19_closures/README.md b/PHP/19_closures/README.md index 240811e..ce18b99 100644 --- a/PHP/19_closures/README.md +++ b/PHP/19_closures/README.md @@ -1,183 +1,263 @@ -# Pattern: Closures +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) -## Category +# Closures -Functions +Tags: sast, php, php_v7.4.9 -## Definition +Version: v1.0 -## Instances +## Description -### Instance 1 +[Closures or anonymous functions](https://www.php.net/manual/en/functions.anonymous.php) allow the creation of functions, that have no specific name. In PHP, a closure does not inherit the scope it was defined in. It rather encapsulates its scope and any variable that you want to access must be bind to the function manually. -- CATEGORY: D2 -- FEATURE vs INTERNAL API: FEATURE -- INPUT SANITIZERS: NO -- SOURCES AND SINKS: NO -- NEGATIVE TEST CASES: NO -- CODE: +Instance 2 targets the usage of [arrow functions](https://www.php.net/manual/en/functions.arrow.php). In PHP the implementation of arrow function uses the closure class as well, they both have the same features. Except arrow functions capture variables from the parent scope by value automatically. -```php +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | +| [2 Instance](#2-instance) | yes | joern | error | + +
+ + +## 1 Instance + + +This instance captures the declaration of an unnamed function. + +### Code + +```PHP + +More -```bash -$_main: ; (lines=12, args=0, vars=2, tmps=6) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/13_closures/first_ex/13_closures.php:1-7 -L0 (2): EXT_STMT -L1 (2): T2 = DECLARE_LAMBDA_FUNCTION string("") -L2 (5): ASSIGN CV0($greet) T2 -L3 (6): EXT_STMT -L4 (6): T4 = FETCH_R (global) string("_GET") -L5 (6): T5 = FETCH_DIM_R T4 string("p1") -L6 (6): ASSIGN CV1($b) T5 -L7 (7): EXT_STMT -L8 (7): INIT_DYNAMIC_CALL 1 CV0($greet) -L9 (7): SEND_VAR_EX CV1($b) 1 -L10 (7): DO_FCALL -L11 (7): RETURN int(1) - -{closure}: ; (lines=9, args=1, vars=1, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/13_closures/first_ex/13_closures.php:2-5 -L0 (2): EXT_NOP -L1 (2): CV0($name) = RECV 1 -L2 (4): EXT_STMT -L3 (4): INIT_FCALL 2 112 string("printf") -L4 (4): SEND_VAL string("Hello %s -") 1 -L5 (4): SEND_VAR CV0($name) 2 -L6 (4): DO_FCALL -L7 (5): EXT_STMT -L8 (5): RETURN null -``` +
+ -- DISCOVERY: +### Compile + ```bash -cpg.call(".*DECLARE_LAMBDA_FUNCTION.*").location.l +$_main: + ; (lines=11, args=0, vars=3, tmps=7) + ; (before optimizer) + ; /.../PHP/19_closures/1_instance_19_closures/1_instance_19_closures.php:1-7 + ; return [] RANGE[0..0] +0000 T3 = DECLARE_LAMBDA_FUNCTION 0 +0001 ASSIGN CV0($greet) T3 +0002 T5 = FETCH_R (global) string("_GET") +0003 T6 = FETCH_DIM_R T5 string("p1") +0004 ASSIGN CV1($a) T6 +0005 INIT_DYNAMIC_CALL 1 CV0($greet) +0006 SEND_VAR_EX CV1($a) 1 +0007 V8 = DO_FCALL +0008 ASSIGN CV2($b) V8 +0009 ECHO CV2($b) +0010 RETURN int(1) + +{closure}: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/19_closures/1_instance_19_closures/1_instance_19_closures.php:2-4 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 RETURN CV0($name) +0002 RETURN null ``` -- PRECONDITIONS: - 1. +
-- TRANSFORMATION: +
+ -``` +### Discovery + + +Declaring unnamed functions has an opcode statement `DECLARE_LAMBDA_FUNCTION`, which this rule searches for. +```scala +val x19 = (name, "19_closures_iall", cpg.call(".*DECLARE_LAMBDA_FUNCTION.*").location.toJson); ``` -### Instance 2 +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | -- CATEGORY: D2 -- FEATURE vs INTERNAL API: FEATURE -- INPUT SANITIZERS: NO -- SOURCES AND SINKS: NO -- NEGATIVE TEST CASES: NO -- CODE: +
-```php - + -$fn1 = fn($x) => fn($y) => $x . $y; +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | yes | no | no | no | no | yes | +| 17 May 2023 | no | no | | | | | yes | + +
+ +
+ + +### Remediation + + +When it is easier for a SAST tool, to capture named functions, can one just rewrite an unnamed function and name it? + +
+ + + + -echo $fn1("safe")($b); -?> +
+ + +## 2 Instance + + +This instance captures another possibility of declaring an unnamed function in php, using arrow functions. + +### Code + +```PHP + fn($y) => $x . $y; +$a = $fn1("safe")($b); +echo a; // sink ``` -- MEASUREMENT: +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| D2 | FEATURE | no | no | no | + +
+ +More -| Tool | RIPS | phpSAFE | WAP | Progpilot | Comm_1 | Comm_2 | Correct | -| --------------- | ---- | ------- | ---- | --------- | ------- | --------- | ------- | -| VulnerabilityNO | YES | NO | NO | NO | NO | YES | YES | -Measurements Date: 8 June 2021 +
+ -- OPCODE: +### Compile + ```bash -$_main: ; (lines=17, args=0, vars=3, tmps=7) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/13_closures/second_ex/second_ex.php:1-8 -L0 (2): EXT_STMT -L1 (2): T3 = FETCH_R (global) string("_GET") -L2 (2): T4 = FETCH_DIM_R T3 string("p1") -L3 (2): ASSIGN CV0($b) T4 -L4 (5): EXT_STMT -L5 (5): T6 = DECLARE_LAMBDA_FUNCTION string("") -L6 (5): BIND_LEXICAL T6 CV2($y) -L7 (5): ASSIGN CV1($fn1) T6 -L8 (7): EXT_STMT -L9 (7): INIT_DYNAMIC_CALL 1 CV1($fn1) -L10 (7): SEND_VAL_EX string("safe") 1 -L11 (7): V8 = DO_FCALL -L12 (7): INIT_DYNAMIC_CALL 1 V8 -L13 (7): SEND_VAR_EX CV0($b) 1 -L14 (7): V9 = DO_FCALL -L15 (7): ECHO V9 -L16 (8): RETURN int(1) +$_main: + ; (lines=16, args=0, vars=4, tmps=9) + ; (before optimizer) + ; /.../PHP/19_closures/2_instance_19_closures/2_instance_19_closures.php:1-5 + ; return [] RANGE[0..0] +0000 T4 = FETCH_R (global) string("_GET") +0001 T5 = FETCH_DIM_R T4 string("p1") +0002 ASSIGN CV0($b) T5 +0003 T7 = DECLARE_LAMBDA_FUNCTION 0 +0004 BIND_LEXICAL T7 CV2($y) +0005 ASSIGN CV1($fn1) T7 +0006 INIT_DYNAMIC_CALL 1 CV1($fn1) +0007 SEND_VAL_EX string("safe") 1 +0008 V9 = DO_FCALL +0009 INIT_DYNAMIC_CALL 1 V9 +0010 SEND_VAR_EX CV0($b) 1 +0011 V10 = DO_FCALL +0012 ASSIGN CV3($a) V10 +0013 T12 = FETCH_CONSTANT string("a") +0014 ECHO T12 +0015 RETURN int(1) LIVE RANGES: - 6: L6 - L7 (tmp/var) - -{closure}: ; (lines=9, args=1, vars=2, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/13_closures/second_ex/second_ex.php:5-5 -L0 (5): EXT_NOP -L1 (5): CV0($x) = RECV 1 -L2 (5): BIND_STATIC CV1($y) -L3 (5): EXT_STMT -L4 (5): T2 = DECLARE_LAMBDA_FUNCTION string("") -L5 (5): BIND_LEXICAL T2 CV0($x) -L6 (5): RETURN T2 -L7 (5): EXT_STMT -L8 (5): RETURN null + 7: 0004 - 0005 (tmp/var) + +{closure}: + ; (lines=6, args=1, vars=2, tmps=1) + ; (before optimizer) + ; /.../PHP/19_closures/2_instance_19_closures/2_instance_19_closures.php:3-3 + ; return [] RANGE[0..0] +0000 CV0($x) = RECV 1 +0001 BIND_STATIC CV1($y) +0002 T2 = DECLARE_LAMBDA_FUNCTION 0 +0003 BIND_LEXICAL T2 CV0($x) +0004 RETURN T2 +0005 RETURN null LIVE RANGES: - 2: L5 - L6 (tmp/var) - -{closure}: ; (lines=8, args=1, vars=2, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/13_closures/second_ex/second_ex.php:5-5 -L0 (5): EXT_NOP -L1 (5): CV0($y) = RECV 1 -L2 (5): BIND_STATIC CV1($x) -L3 (5): EXT_STMT -L4 (5): T2 = CONCAT CV1($x) CV0($y) -L5 (5): RETURN T2 -L6 (5): EXT_STMT -L7 (5): RETURN null + 2: 0003 - 0004 (tmp/var) + +{closure}: + ; (lines=5, args=1, vars=2, tmps=1) + ; (before optimizer) + ; /.../PHP/19_closures/2_instance_19_closures/2_instance_19_closures.php:3-3 + ; return [] RANGE[0..0] +0000 CV0($y) = RECV 1 +0001 BIND_STATIC CV1($x) +0002 T2 = CONCAT CV1($x) CV0($y) +0003 RETURN T2 +0004 RETURN null ``` -- DISCOVERY: +
-```bash -cpg.call(".*DECLARE_LAMBDA_FUNCTION.*").location.l -``` +
+ +### Discovery + -- PRECONDITIONS: - 1. -- TRANSFORMATION: +In May 2023, this instance throws an error while trying to generate the CPG using Joern. +```scala +val x19 = (name, "19_closures_iall", cpg.call(".*DECLARE_LAMBDA_FUNCTION.*").location.toJson); ``` -``` +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | yes | no | no | yes | no | yes | +| 17 May 2023 | no | yes | | | | | yes | + +
+ +
+ + +### Remediation + + +When it is easier for a SAST tool, to capture named functions, can one just rewrite an unnamed function and name it? +
+
+
diff --git a/PHP/19_closures/docs/description.md b/PHP/19_closures/docs/description.md new file mode 100644 index 0000000..1a216a4 --- /dev/null +++ b/PHP/19_closures/docs/description.md @@ -0,0 +1,3 @@ +[Closures or anonymous functions](https://www.php.net/manual/en/functions.anonymous.php) allow the creation of functions, that have no specific name. In PHP, a closure does not inherit the scope it was defined in. It rather encapsulates its scope and any variable that you want to access must be bind to the function manually. + +Instance 2 targets the usage of [arrow functions](https://www.php.net/manual/en/functions.arrow.php). In PHP the implementation of arrow function uses the closure class as well, they both have the same features. Except arrow functions capture variables from the parent scope by value automatically. diff --git a/PHP/19_closures/docs/remediation_notes.md b/PHP/19_closures/docs/remediation_notes.md new file mode 100644 index 0000000..fcc1af7 --- /dev/null +++ b/PHP/19_closures/docs/remediation_notes.md @@ -0,0 +1 @@ +When it is easier for a SAST tool, to capture named functions, can one just rewrite an unnamed function and name it? \ No newline at end of file diff --git a/PHP/1_static_variables/1_instance_1_static_variables/1_instance_1_static_variables.bash b/PHP/1_static_variables/1_instance_1_static_variables/1_instance_1_static_variables.bash index d5d90d5..d5ebc10 100644 --- a/PHP/1_static_variables/1_instance_1_static_variables/1_instance_1_static_variables.bash +++ b/PHP/1_static_variables/1_instance_1_static_variables/1_instance_1_static_variables.bash @@ -1,31 +1,27 @@ -$_main: ; (lines=13, args=0, vars=1, tmps=5) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/1_static_variables/1_static_variables.php:1-11 -L0 (9): EXT_STMT -L1 (9): T1 = FETCH_R (global) string("_GET") -L2 (9): T2 = FETCH_DIM_R T1 string("p1") -L3 (9): ASSIGN CV0($a) T2 -L4 (10): EXT_STMT -L5 (10): INIT_FCALL 1 128 string("f") -L6 (10): SEND_VAR CV0($a) 1 -L7 (10): DO_FCALL -L8 (11): EXT_STMT -L9 (11): INIT_FCALL 1 128 string("f") -L10 (11): SEND_VAL string("abc") 1 -L11 (11): DO_FCALL -L12 (11): RETURN int(1) +$_main: + ; (lines=10, args=0, vars=1, tmps=5) + ; (before optimizer) + ; /.../PHP/1_static_variables/1_instance_1_static_variables/1_instance_1_static_variables.php:1-11 + ; return [] RANGE[0..0] +0000 T1 = FETCH_R (global) string("_GET") +0001 T2 = FETCH_DIM_R T1 string("p1") +0002 ASSIGN CV0($a) T2 +0003 INIT_FCALL 1 128 string("f") +0004 SEND_VAR CV0($a) 1 +0005 DO_UCALL +0006 INIT_FCALL 1 128 string("f") +0007 SEND_VAL string("abc") 1 +0008 DO_UCALL +0009 RETURN int(1) -F: ; (lines=10, args=1, vars=2, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/1_static_variables/1_static_variables.php:3-7 -L0 (3): EXT_NOP -L1 (3): CV0($a) = RECV 1 -L2 (4): EXT_STMT -L3 (4): BIND_STATIC (ref) CV1($b) -L4 (5): EXT_STMT -L5 (5): ECHO CV1($b) -L6 (6): EXT_STMT -L7 (6): ASSIGN CV1($b) CV0($a) -L8 (7): EXT_STMT -L9 (7): RETURN null \ No newline at end of file +F: + ; (lines=5, args=1, vars=2, tmps=1) + ; (before optimizer) + ; /.../PHP/1_static_variables/1_instance_1_static_variables/1_instance_1_static_variables.php:3-7 + ; return [] RANGE[0..0] +0000 CV0($a) = RECV 1 +0001 BIND_STATIC (ref) CV1($b) +0002 ECHO CV1($b) +0003 ASSIGN CV1($b) CV0($a) +0004 RETURN null diff --git a/PHP/1_static_variables/1_instance_1_static_variables/1_instance_1_static_variables.json b/PHP/1_static_variables/1_instance_1_static_variables/1_instance_1_static_variables.json index 71ac204..347ad4e 100644 --- a/PHP/1_static_variables/1_instance_1_static_variables/1_instance_1_static_variables.json +++ b/PHP/1_static_variables/1_instance_1_static_variables/1_instance_1_static_variables.json @@ -1,4 +1,5 @@ { + "description": "This instance, focuses on the static variables in functions not the static properties in objects nor static methods.", "code": { "path": "./1_instance_1_static_variables.php", "injection_skeleton_broken": true @@ -7,7 +8,7 @@ "rule": "./1_instance_1_static_variables.sc", "method": "joern", "rule_accuracy": "Perfect", - "notes": "The `BIND_STATIC` opcode is only for static variables that are normally used inside code blocks. The SAST tools may not able to keep the proper values for these static variables. As such the discovery rule should be accurate as it is" + "notes": "./docs/discovery_notes.md" }, "remediation": { "notes": "./docs/remediation_notes.md", diff --git a/PHP/1_static_variables/1_instance_1_static_variables/1_instance_1_static_variables.php b/PHP/1_static_variables/1_instance_1_static_variables/1_instance_1_static_variables.php index e8f9a9f..33d7a99 100644 --- a/PHP/1_static_variables/1_instance_1_static_variables/1_instance_1_static_variables.php +++ b/PHP/1_static_variables/1_instance_1_static_variables/1_instance_1_static_variables.php @@ -1,6 +1,6 @@ + +More -```bash -$_main: ; (lines=13, args=0, vars=1, tmps=5) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/1_static_variables/1_static_variables.php:1-11 -L0 (9): EXT_STMT -L1 (9): T1 = FETCH_R (global) string("_GET") -L2 (9): T2 = FETCH_DIM_R T1 string("p1") -L3 (9): ASSIGN CV0($a) T2 -L4 (10): EXT_STMT -L5 (10): INIT_FCALL 1 128 string("f") -L6 (10): SEND_VAR CV0($a) 1 -L7 (10): DO_FCALL -L8 (11): EXT_STMT -L9 (11): INIT_FCALL 1 128 string("f") -L10 (11): SEND_VAL string("abc") 1 -L11 (11): DO_FCALL -L12 (11): RETURN int(1) - -F: ; (lines=10, args=1, vars=2, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/1_static_variables/1_static_variables.php:3-7 -L0 (3): EXT_NOP -L1 (3): CV0($a) = RECV 1 -L2 (4): EXT_STMT -L3 (4): BIND_STATIC (ref) CV1($b) -L4 (5): EXT_STMT -L5 (5): ECHO CV1($b) -L6 (6): EXT_STMT -L7 (6): ASSIGN CV1($b) CV0($a) -L8 (7): EXT_STMT -L9 (7): RETURN null -``` +
+ -- DISCOVERY: +### Compile + -In this pattern, I focus on the static variables in functions not the static properties in objects nor static methods. To discover the static variables in opcode, I search for the opcode BIND_STATIC. ```bash -cpg.call(".*BIND_STATIC.*").location.l +$_main: + ; (lines=10, args=0, vars=1, tmps=5) + ; (before optimizer) + ; /.../PHP/1_static_variables/1_instance_1_static_variables/1_instance_1_static_variables.php:1-11 + ; return [] RANGE[0..0] +0000 T1 = FETCH_R (global) string("_GET") +0001 T2 = FETCH_DIM_R T1 string("p1") +0002 ASSIGN CV0($a) T2 +0003 INIT_FCALL 1 128 string("f") +0004 SEND_VAR CV0($a) 1 +0005 DO_UCALL +0006 INIT_FCALL 1 128 string("f") +0007 SEND_VAL string("abc") 1 +0008 DO_UCALL +0009 RETURN int(1) + +F: + ; (lines=5, args=1, vars=2, tmps=1) + ; (before optimizer) + ; /.../PHP/1_static_variables/1_instance_1_static_variables/1_instance_1_static_variables.php:3-7 + ; return [] RANGE[0..0] +0000 CV0($a) = RECV 1 +0001 BIND_STATIC (ref) CV1($b) +0002 ECHO CV1($b) +0003 ASSIGN CV1($b) CV0($a) +0004 RETURN null ``` -For regex, I can search for the keyword but I cannot distinguish between static variables and static properties. -- PRECONDITIONS: - 1. -- TRANSFORMATION: + +
+ +
+ + +### Discovery + + +To discover the static variables in opcode, I search for the opcode BIND_STATIC. +The `BIND_STATIC` opcode is only for static variables that are normally used inside code blocks. The SAST tools may not able to keep the proper values for these static variables. +As such the discovery rule should be accurate as it is. + +```scala +val x1 = (name, "1_static_variables_iall", cpg.call(".*BIND_STATIC.*").location.toJson); ``` -``` \ No newline at end of file +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | no | no | no | yes | +| 17 May 2023 | no | no | | | | | yes | + +
+ +
+ + +### Remediation + + +Likely this tarpit should be solved at the SAST tool side. Transforming a static variable into a non-static one is unfeasible. It is unclear how to create a modeling rule for the static keyword. + +
+ + diff --git a/PHP/20_use_with_closures/1_instance_20_use_with_closures/1_instance_20_use_with_closures.bash b/PHP/20_use_with_closures/1_instance_20_use_with_closures/1_instance_20_use_with_closures.bash index 0c08886..1d90fa2 100644 --- a/PHP/20_use_with_closures/1_instance_20_use_with_closures/1_instance_20_use_with_closures.bash +++ b/PHP/20_use_with_closures/1_instance_20_use_with_closures/1_instance_20_use_with_closures.bash @@ -1,32 +1,30 @@ -$_main: ; (lines=16, args=0, vars=3, tmps=8) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/14_use_with_closures/first_ex/first_ex.php:1-13 -L0 (2): EXT_STMT -L1 (2): T3 = FETCH_R (global) string("_GET") -L2 (2): T4 = FETCH_DIM_R T3 string("p1") -L3 (2): ASSIGN CV0($b) T4 -L4 (3): EXT_STMT -L5 (3): ASSIGN CV1($message) string("safe") -L6 (5): EXT_STMT -L7 (5): T7 = DECLARE_LAMBDA_FUNCTION string("") -L8 (5): BIND_LEXICAL T7 CV1($message) -L9 (10): ASSIGN CV2($example) T7 -L10 (11): EXT_STMT -L11 (11): ASSIGN CV1($message) CV0($b) -L12 (12): EXT_STMT -L13 (12): INIT_DYNAMIC_CALL 0 CV2($example) -L14 (12): DO_FCALL -L15 (13): RETURN int(1) +$_main: + ; (lines=13, args=0, vars=4, tmps=9) + ; (before optimizer) + ; /.../PHP/20_use_with_closures/1_instance_20_use_with_closures/1_instance_20_use_with_closures.php:1-14 + ; return [] RANGE[0..0] +0000 T4 = FETCH_R (global) string("_GET") +0001 T5 = FETCH_DIM_R T4 string("p1") +0002 ASSIGN CV0($a) T5 +0003 ASSIGN CV1($message) string("safe") +0004 T8 = DECLARE_LAMBDA_FUNCTION 0 +0005 BIND_LEXICAL T8 CV1($message) +0006 ASSIGN CV2($example) T8 +0007 ASSIGN CV1($message) CV0($a) +0008 INIT_DYNAMIC_CALL 0 CV2($example) +0009 V11 = DO_FCALL +0010 ASSIGN CV3($b) V11 +0011 ECHO CV3($b) +0012 RETURN int(1) LIVE RANGES: - 7: L8 - L9 (tmp/var) + 8: 0005 - 0006 (tmp/var) -{closure}: ; (lines=6, args=0, vars=1, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/14_use_with_closures/first_ex/first_ex.php:5-10 -L0 (5): EXT_NOP -L1 (5): BIND_STATIC CV0($message) -L2 (9): EXT_STMT -L3 (9): ECHO CV0($message) -L4 (10): EXT_STMT -L5 (10): RETURN null \ No newline at end of file +{closure}: + ; (lines=3, args=0, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/20_use_with_closures/1_instance_20_use_with_closures/1_instance_20_use_with_closures.php:5-10 + ; return [] RANGE[0..0] +0000 BIND_STATIC CV0($message) +0001 RETURN CV0($message) +0002 RETURN null diff --git a/PHP/20_use_with_closures/1_instance_20_use_with_closures/1_instance_20_use_with_closures.json b/PHP/20_use_with_closures/1_instance_20_use_with_closures/1_instance_20_use_with_closures.json index 36197a2..7e62162 100644 --- a/PHP/20_use_with_closures/1_instance_20_use_with_closures/1_instance_20_use_with_closures.json +++ b/PHP/20_use_with_closures/1_instance_20_use_with_closures/1_instance_20_use_with_closures.json @@ -1,4 +1,5 @@ { + "description": "This instance captures the use of the keyword `use` in closures without reference, so any changes made to the value captured by the closure will not affect the captured value within the closure. Therefor this instance is not vulnerable", "code": { "path": "./1_instance_20_use_with_closures.php", "injection_skeleton_broken": false diff --git a/PHP/20_use_with_closures/1_instance_20_use_with_closures/1_instance_20_use_with_closures.php b/PHP/20_use_with_closures/1_instance_20_use_with_closures/1_instance_20_use_with_closures.php index 66092c2..d8745c9 100644 --- a/PHP/20_use_with_closures/1_instance_20_use_with_closures/1_instance_20_use_with_closures.php +++ b/PHP/20_use_with_closures/1_instance_20_use_with_closures/1_instance_20_use_with_closures.php @@ -1,5 +1,5 @@ Closures may also inherit variables from the parent scope. Any such variables must be passed to the use language construct. +In PHP `use` can be used in the definition of a [closure](https://www.php.net/manual/en/functions.anonymous.php). It allows for variables of the parent scope to be accessed within the body of the function. Variables that are bind to the function using the `use` keyword are passed by value. -## Instances +## Overview -### Instance 1 +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | +| [2 Instance](#2-instance) | yes | joern | yes | -- CATEGORY: D2 -- FEATURE vs INTERNAL API: FEATURE -- INPUT SANITIZERS: NO -- SOURCES AND SINKS: NO -- NEGATIVE TEST CASES: YES -- CODE: +
+ -```php +## 1 Instance + + +This instance captures the use of the keyword `use` in closures without reference, so any changes made to the value captured by the closure will not affect the captured value within the closure. Therefor this instance is not vulnerable + +### Code + +```PHP + +More -| Tool | RIPS | phpSAFE | WAP | Progpilot | Comm_1 | Comm_2 | Correct | -| ------------- | ---- | ------- | ---- | --------- | ------- | --------- | ------- | -| Vulnerability | - | - | - | - | NO | YES | NO | -Measurements Date: 8 June 2021 +
+ -- OPCODE: +### Compile + ```bash -$_main: ; (lines=16, args=0, vars=3, tmps=8) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/14_use_with_closures/first_ex/first_ex.php:1-13 -L0 (2): EXT_STMT -L1 (2): T3 = FETCH_R (global) string("_GET") -L2 (2): T4 = FETCH_DIM_R T3 string("p1") -L3 (2): ASSIGN CV0($b) T4 -L4 (3): EXT_STMT -L5 (3): ASSIGN CV1($message) string("safe") -L6 (5): EXT_STMT -L7 (5): T7 = DECLARE_LAMBDA_FUNCTION string("") -L8 (5): BIND_LEXICAL T7 CV1($message) -L9 (10): ASSIGN CV2($example) T7 -L10 (11): EXT_STMT -L11 (11): ASSIGN CV1($message) CV0($b) -L12 (12): EXT_STMT -L13 (12): INIT_DYNAMIC_CALL 0 CV2($example) -L14 (12): DO_FCALL -L15 (13): RETURN int(1) +$_main: + ; (lines=13, args=0, vars=4, tmps=9) + ; (before optimizer) + ; /.../PHP/20_use_with_closures/1_instance_20_use_with_closures/1_instance_20_use_with_closures.php:1-14 + ; return [] RANGE[0..0] +0000 T4 = FETCH_R (global) string("_GET") +0001 T5 = FETCH_DIM_R T4 string("p1") +0002 ASSIGN CV0($a) T5 +0003 ASSIGN CV1($message) string("safe") +0004 T8 = DECLARE_LAMBDA_FUNCTION 0 +0005 BIND_LEXICAL T8 CV1($message) +0006 ASSIGN CV2($example) T8 +0007 ASSIGN CV1($message) CV0($a) +0008 INIT_DYNAMIC_CALL 0 CV2($example) +0009 V11 = DO_FCALL +0010 ASSIGN CV3($b) V11 +0011 ECHO CV3($b) +0012 RETURN int(1) LIVE RANGES: - 7: L8 - L9 (tmp/var) - -{closure}: ; (lines=6, args=0, vars=1, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/14_use_with_closures/first_ex/first_ex.php:5-10 -L0 (5): EXT_NOP -L1 (5): BIND_STATIC CV0($message) -L2 (9): EXT_STMT -L3 (9): ECHO CV0($message) -L4 (10): EXT_STMT -L5 (10): RETURN null + 8: 0005 - 0006 (tmp/var) + +{closure}: + ; (lines=3, args=0, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/20_use_with_closures/1_instance_20_use_with_closures/1_instance_20_use_with_closures.php:5-10 + ; return [] RANGE[0..0] +0000 BIND_STATIC CV0($message) +0001 RETURN CV0($message) +0002 RETURN null ``` -- DISCOVERY: +
-```bash - cpg.call(".*BIND_LEXICAL.*").location.l -``` +
+ -- PRECONDITIONS: - 1. +### Discovery + -- TRANSFORMATION: +To be perfect this rule could check that the BIND_LEXICAL is not associated to the reference of the variable used. +```scala +val x20 = (name, "20_use_with_closures_i1", cpg.call(".*BIND_LEXICAL.*").location.toJson); ``` -``` +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | Ground Truth | +|-------------|----------|----------|----------------| +| 08 Jun 2021 | no | yes | no | +| 17 May 2023 | no | yes | no | + +
+ +
-### Instance 2 + -- CATEGORY: D2 -- FEATURE vs INTERNAL API: FEATURE -- INPUT SANITIZERS: NO -- SOURCES AND SINKS: NO -- NEGATIVE TEST CASES: NO -- CODE: +
+ -```php +## 2 Instance + + +This instance shows what happens, when the value captured by the `use` keyword is passed by reference. Any changes made to the value will also be reflected in the scope of the closure. Therefor, this instance is vulnerable + +### Code + +```PHP + +More + +
+ + +### Compile + ```bash -$_main: ; (lines=16, args=0, vars=3, tmps=8) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/14_use_with_closures/second_ex/second_ex.php:1-12 -L0 (2): EXT_STMT -L1 (2): T3 = FETCH_R (global) string("_GET") -L2 (2): T4 = FETCH_DIM_R T3 string("p1") -L3 (2): ASSIGN CV0($b) T4 -L4 (3): EXT_STMT -L5 (3): ASSIGN CV1($message) string("safe") -L6 (5): EXT_STMT -L7 (5): T7 = DECLARE_LAMBDA_FUNCTION string("") -L8 (5): BIND_LEXICAL (ref) T7 CV1($message) -L9 (9): ASSIGN CV2($example) T7 -L10 (10): EXT_STMT -L11 (10): ASSIGN CV1($message) CV0($b) -L12 (11): EXT_STMT -L13 (11): INIT_DYNAMIC_CALL 0 CV2($example) -L14 (11): DO_FCALL -L15 (12): RETURN int(1) +$_main: + ; (lines=13, args=0, vars=4, tmps=9) + ; (before optimizer) + ; /.../PHP/20_use_with_closures/2_instance_20_use_with_closures/2_instance_20_use_with_closures.php:1-13 + ; return [] RANGE[0..0] +0000 T4 = FETCH_R (global) string("_GET") +0001 T5 = FETCH_DIM_R T4 string("p1") +0002 ASSIGN CV0($a) T5 +0003 ASSIGN CV1($message) string("safe") +0004 T8 = DECLARE_LAMBDA_FUNCTION 0 +0005 BIND_LEXICAL (ref) T8 CV1($message) +0006 ASSIGN CV2($example) T8 +0007 ASSIGN CV1($message) CV0($a) +0008 INIT_DYNAMIC_CALL 0 CV2($example) +0009 V11 = DO_FCALL +0010 ASSIGN CV3($b) V11 +0011 ECHO CV3($b) +0012 RETURN int(1) LIVE RANGES: - 7: L8 - L9 (tmp/var) - -{closure}: ; (lines=6, args=0, vars=1, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/14_use_with_closures/second_ex/second_ex.php:5-9 -L0 (5): EXT_NOP -L1 (5): BIND_STATIC (ref) CV0($message) -L2 (8): EXT_STMT -L3 (8): ECHO CV0($message) -L4 (9): EXT_STMT -L5 (9): RETURN null + 8: 0005 - 0006 (tmp/var) + +{closure}: + ; (lines=3, args=0, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/20_use_with_closures/2_instance_20_use_with_closures/2_instance_20_use_with_closures.php:5-9 + ; return [] RANGE[0..0] +0000 BIND_STATIC (ref) CV0($message) +0001 RETURN CV0($message) +0002 RETURN null ``` -- DISCOVERY: +
-```bash - cpg.call(".*BIND_LEXICAL.*").location.l -``` +
+ -- PRECONDITIONS: - 1. +### Discovery + -- TRANSFORMATION: +To be perfect this rule could check that the BIND_LEXICAL is associated to the reference of the variable used. +```scala +val x20 = (name, "20_use_with_closures_i2", cpg.call(".*BIND_LEXICAL.*").location.toJson); ``` -``` +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | no | no | no | yes | +| 17 May 2023 | yes | no | | | | | yes | +
+
+ diff --git a/PHP/20_use_with_closures/docs/description.md b/PHP/20_use_with_closures/docs/description.md new file mode 100644 index 0000000..674f412 --- /dev/null +++ b/PHP/20_use_with_closures/docs/description.md @@ -0,0 +1 @@ +In PHP `use` can be used in the definition of a [closure](https://www.php.net/manual/en/functions.anonymous.php). It allows for variables of the parent scope to be accessed within the body of the function. Variables that are bind to the function using the `use` keyword are passed by value. \ No newline at end of file diff --git a/PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.bash b/PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.bash index 0c13c40..0e56c52 100644 --- a/PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.bash +++ b/PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.bash @@ -1,42 +1,38 @@ -$_main: ; (lines=15, args=0, vars=2, tmps=7) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/66_simple_object/66_simple_object.php:1-19 -L0 (4): NOP -L1 (16): EXT_STMT -L2 (16): T2 = FETCH_R (global) string("_GET") -L3 (16): T3 = FETCH_DIM_R T2 string("p1") -L4 (16): ASSIGN CV0($b) T3 -L5 (17): EXT_STMT -L6 (17): V5 = NEW 1 string("Test") -L7 (17): SEND_VAR_EX CV0($b) 1 -L8 (17): DO_FCALL -L9 (17): ASSIGN CV1($test) V5 -L10 (19): EXT_STMT -L11 (19): INIT_METHOD_CALL 0 CV1($test) string("getfoo") -L12 (19): V8 = DO_FCALL -L13 (19): ECHO V8 -L14 (19): RETURN int(1) +$_main: + ; (lines=11, args=0, vars=2, tmps=7) + ; (before optimizer) + ; /.../PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.php:1-17 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 1 string("Test") +0004 SEND_VAR_EX CV0($b) 1 +0005 DO_FCALL +0006 ASSIGN CV1($test) V5 +0007 INIT_METHOD_CALL 0 CV1($test) string("getfoo") +0008 V8 = DO_FCALL +0009 ECHO V8 +0010 RETURN int(1) LIVE RANGES: - 5: L7 - L9 (new) + 5: 0004 - 0006 (new) -Test::__construct: ; (lines=7, args=1, vars=1, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/66_simple_object/66_simple_object.php:6-9 -L0 (6): EXT_NOP -L1 (6): CV0($foo) = RECV 1 -L2 (8): EXT_STMT -L3 (8): ASSIGN_OBJ THIS string("foo") -L4 (8): OP_DATA CV0($foo) -L5 (9): EXT_STMT -L6 (9): RETURN null +Test::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($foo) = RECV 1 +0001 ASSIGN_OBJ THIS string("foo") +0002 OP_DATA CV0($foo) +0003 RETURN null -Test::getfoo: ; (lines=6, args=0, vars=0, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/66_simple_object/66_simple_object.php:11-13 -L0 (11): EXT_NOP -L1 (12): EXT_STMT -L2 (12): T0 = FETCH_OBJ_R THIS string("foo") -L3 (12): RETURN T0 -L4 (13): EXT_STMT -L5 (13): RETURN null +Test::getfoo: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.php:9-11 + ; return [] RANGE[0..0] +0000 T0 = FETCH_OBJ_R THIS string("foo") +0001 RETURN T0 +0002 RETURN null diff --git a/PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.json b/PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.json index 345b3a4..fb44743 100644 --- a/PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.json +++ b/PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.json @@ -1,4 +1,5 @@ { + "description": "This instance targets the use of a simple object, where an argument is passed to the constructor of that object.", "code": { "path": "./1_instance_21_simple_object.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_21_simple_object.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "FP", + "notes": "The rule could be more accurate, if we could check if there was an argument passed to the constructor." }, "compile": { "binary": "./1_instance_21_simple_object.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_21_simple_object.php", - "sink_line": 19, + "sink_line": 17, "source_file": "./1_instance_21_simple_object.php", - "source_line": 16, + "source_line": 14, "expectation": true }, "properties": { diff --git a/PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.php b/PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.php index 98f017e..9a55f09 100644 --- a/PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.php +++ b/PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.php @@ -1,19 +1,17 @@ foo = $foo; } - public function getfoo(){ + public function getfoo() { return $this->foo; } } -$b = $_GET["p1"]; -$test = new Test($b); +$b = $_GET["p1"]; // source +$test = new Test($b); // tarpit // XSS vulnerability -echo $test->getfoo(); \ No newline at end of file +echo $test->getfoo(); // sink \ No newline at end of file diff --git a/PHP/21_simple_object/21_simple_object.json b/PHP/21_simple_object/21_simple_object.json index 5c5f1f1..65f5489 100644 --- a/PHP/21_simple_object/21_simple_object.json +++ b/PHP/21_simple_object/21_simple_object.json @@ -1,6 +1,6 @@ { "name": "Simple Object", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_21_simple_object/1_instance_21_simple_object.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/21_simple_object/README.md b/PHP/21_simple_object/README.md index 99a4d81..56e9845 100644 --- a/PHP/21_simple_object/README.md +++ b/PHP/21_simple_object/README.md @@ -1,109 +1,134 @@ -# Pattern: Simple Object +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) -## Category +# Simple Object -Objects +Tags: sast, php, php_v7.4.9 -## Definition +Version: v1.0 -## Instances +## Description -### Instance 1 +This pattern should target the creation and usage of simple objects. -- CATEGORY: S0 -- FEATURE vs INTERNAL API: FEATURE -- INPUT SANITIZERS: NO -- SOURCES AND SINKS: NO -- NEGATIVE TEST CASES: NO -- CODE: +## Overview -```php +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +This instance targets the use of a simple object, where an argument is passed to the constructor of that object. + +### Code + +```PHP foo = $foo; } - public function getfoo(){ + public function getfoo() { return $this->foo; } } -$b = $_GET["p1"]; -$test = new Test($b); +$b = $_GET["p1"]; // source +$test = new Test($b); // tarpit // XSS vulnerability -echo $test->getfoo(); +echo $test->getfoo(); // sink ``` -- MEASUREMENT: +### Instance Properties -| Tool | RIPS | phpSAFE | WAP | Progpilot | Comm_1 | Comm_2 | Correct | -| ------------- | ---- | ------- | ---- | --------- | ------- | --------- | ------- | -| Vulnerability | NO | NO | NO | YES | YES | YES | YES | -Measurements Date: 8 June 2021 +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | -- OPCODE: +
+ +More + +
+ + +### Compile + ```bash -$_main: ; (lines=15, args=0, vars=2, tmps=7) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/66_simple_object/66_simple_object.php:1-19 -L0 (4): NOP -L1 (16): EXT_STMT -L2 (16): T2 = FETCH_R (global) string("_GET") -L3 (16): T3 = FETCH_DIM_R T2 string("p1") -L4 (16): ASSIGN CV0($b) T3 -L5 (17): EXT_STMT -L6 (17): V5 = NEW 1 string("Test") -L7 (17): SEND_VAR_EX CV0($b) 1 -L8 (17): DO_FCALL -L9 (17): ASSIGN CV1($test) V5 -L10 (19): EXT_STMT -L11 (19): INIT_METHOD_CALL 0 CV1($test) string("getfoo") -L12 (19): V8 = DO_FCALL -L13 (19): ECHO V8 -L14 (19): RETURN int(1) +$_main: + ; (lines=11, args=0, vars=2, tmps=7) + ; (before optimizer) + ; /.../PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.php:1-17 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 1 string("Test") +0004 SEND_VAR_EX CV0($b) 1 +0005 DO_FCALL +0006 ASSIGN CV1($test) V5 +0007 INIT_METHOD_CALL 0 CV1($test) string("getfoo") +0008 V8 = DO_FCALL +0009 ECHO V8 +0010 RETURN int(1) LIVE RANGES: - 5: L7 - L9 (new) - -Test::__construct: ; (lines=7, args=1, vars=1, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/66_simple_object/66_simple_object.php:6-9 -L0 (6): EXT_NOP -L1 (6): CV0($foo) = RECV 1 -L2 (8): EXT_STMT -L3 (8): ASSIGN_OBJ THIS string("foo") -L4 (8): OP_DATA CV0($foo) -L5 (9): EXT_STMT -L6 (9): RETURN null - -Test::getfoo: ; (lines=6, args=0, vars=0, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/66_simple_object/66_simple_object.php:11-13 -L0 (11): EXT_NOP -L1 (12): EXT_STMT -L2 (12): T0 = FETCH_OBJ_R THIS string("foo") -L3 (12): RETURN T0 -L4 (13): EXT_STMT -L5 (13): RETURN null + 5: 0004 - 0006 (new) + +Test::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($foo) = RECV 1 +0001 ASSIGN_OBJ THIS string("foo") +0002 OP_DATA CV0($foo) +0003 RETURN null + +Test::getfoo: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/21_simple_object/1_instance_21_simple_object/1_instance_21_simple_object.php:9-11 + ; return [] RANGE[0..0] +0000 T0 = FETCH_OBJ_R THIS string("foo") +0001 RETURN T0 +0002 RETURN null ``` -- DISCOVERY: +
-```bash -cpg.call(".*OBJ.*|.*NEW.*|.*CLONE.*|.*METHOD.*").location.l -``` +
+ -- PRECONDITIONS: - 1. +### Discovery + -- TRANSFORMATION: +The rule could be more accurate, if we could check if there was an argument passed to the constructor. +```scala +val x21 = (name, "21_simple_object_iall", cpg.call(".*OBJ.*|.*NEW.*|.*CLONE.*|.*METHOD.*").location.toJson); ``` -``` +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | yes | no | yes | no | no | yes | +| 17 May 2023 | yes | yes | | | | | yes | + +
+
diff --git a/PHP/21_simple_object/docs/description.md b/PHP/21_simple_object/docs/description.md new file mode 100644 index 0000000..e768102 --- /dev/null +++ b/PHP/21_simple_object/docs/description.md @@ -0,0 +1 @@ +This pattern should target the creation and usage of simple objects. diff --git a/PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.bash b/PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.bash index a970ae3..495e796 100644 --- a/PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.bash +++ b/PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.bash @@ -1,25 +1,21 @@ -$_main: ; (lines=19, args=0, vars=2, tmps=9) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/24_assign_object/24_assign_object.php:1-10 -L0 (3): NOP -L1 (5): EXT_STMT -L2 (5): V2 = NEW 0 string("myclass") -L3 (5): DO_FCALL -L4 (5): ASSIGN CV0($obj1) V2 -L5 (6): EXT_STMT -L6 (6): ASSIGN_OBJ CV0($obj1) string("b") -L7 (6): OP_DATA string("safe2") -L8 (7): EXT_STMT -L9 (7): ASSIGN CV1($obj2) CV0($obj1) -L10 (8): EXT_STMT -L11 (8): T8 = FETCH_R (global) string("_GET") -L12 (8): T9 = FETCH_DIM_R T8 string("p1") -L13 (8): ASSIGN_OBJ CV1($obj2) string("b") -L14 (8): OP_DATA T9 -L15 (10): EXT_STMT -L16 (10): T10 = FETCH_OBJ_R CV0($obj1) string("b") -L17 (10): ECHO T10 -L18 (10): RETURN int(1) +$_main: + ; (lines=13, args=0, vars=2, tmps=9) + ; (before optimizer) + ; /.../PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.php:1-10 + ; return [] RANGE[0..0] +0000 V2 = NEW 0 string("myclass") +0001 DO_FCALL +0002 ASSIGN CV0($obj1) V2 +0003 ASSIGN_OBJ CV0($obj1) string("b") +0004 OP_DATA string("safe2") +0005 ASSIGN CV1($obj2) CV0($obj1) +0006 T8 = FETCH_R (global) string("_GET") +0007 T9 = FETCH_DIM_R T8 string("p1") +0008 ASSIGN_OBJ CV1($obj2) string("b") +0009 OP_DATA T9 +0010 T10 = FETCH_OBJ_R CV0($obj1) string("b") +0011 ECHO T10 +0012 RETURN int(1) LIVE RANGES: - 2: L3 - L4 (new) + 2: 0001 - 0002 (new) diff --git a/PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.json b/PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.json index 67e7db9..9a76e25 100644 --- a/PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.json +++ b/PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.json @@ -1,4 +1,5 @@ { + "description": "This instance shows, then when assigning one object to another object, they both point to the same object in memory, so they have the same attributes.", "code": { "path": "./1_instance_22_assign_object.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_22_assign_object.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "Perfect", + "notes": "../docs/discovery_notes.md" }, "compile": { "binary": "./1_instance_22_assign_object.bash", diff --git a/PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.php b/PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.php index ea287fc..fb22dc6 100644 --- a/PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.php +++ b/PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.php @@ -1,10 +1,10 @@ b = "safe2"; $obj2 = $obj1; -$obj2->b = $_GET["p1"]; +$obj2->b = $_GET["p1"]; // source // XSS vulnerability -echo $obj1->b; \ No newline at end of file +echo $obj1->b; // sink \ No newline at end of file diff --git a/PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.sc b/PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.sc index af9a4a3..839f7c5 100644 --- a/PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.sc +++ b/PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.sc @@ -5,4 +5,4 @@ val x22 = (name, "22_assign_object_iall", R1.filter{ call => G1.exists{ h => call.argument.order(1).code.l.contains("CV($" + h + ")")} }.location.toJson); println(x22) delete; -} \ No newline at end of file +} \ No newline at end of file diff --git a/PHP/22_assign_object/22_assign_object.json b/PHP/22_assign_object/22_assign_object.json index f31dcf8..2759c7d 100644 --- a/PHP/22_assign_object/22_assign_object.json +++ b/PHP/22_assign_object/22_assign_object.json @@ -1,6 +1,6 @@ { "name": "Assign Object", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_22_assign_object/1_instance_22_assign_object.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/22_assign_object/README.md b/PHP/22_assign_object/README.md index b0cf89b..a7e3c23 100644 --- a/PHP/22_assign_object/README.md +++ b/PHP/22_assign_object/README.md @@ -1,85 +1,114 @@ -# Pattern: Assign Object +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) -## Category +# Assign Object -Objects +Tags: sast, php, php_v7.4.9 -## Definition +Version: v1.0 -## Instances +## Description -### Instance 1 +Object assignment in PHP creates a reference to the same object in memory, rather than a new copy, which means that any changes made to the object through one variable or function parameter will be reflected in all other variables or parameters that reference the same object. -- CATEGORY: S0 -- FEATURE vs INTERNAL API: FEATURE -- INPUT SANITIZERS: NO -- SOURCES AND SINKS: NO -- NEGATIVE TEST CASES: NO -- CODE: +## Overview -```php +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +This instance shows, then when assigning one object to another object, they both point to the same object in memory, so they have the same attributes. + +### Code + +```PHP b = "safe2"; $obj2 = $obj1; -$obj2->b = $_GET["p1"]; +$obj2->b = $_GET["p1"]; // source // XSS vulnerability -echo $obj1->b; +echo $obj1->b; // sink ``` -- MEASUREMENT: +### Instance Properties -| Tool | RIPS | phpSAFE | WAP | Progpilot | Comm_1 | Comm_2 | Correct | -| ------------- | ---- | ------- | ---- | --------- | ------- | --------- | ------- | -| Vulnerability | NO | NO |YES | NO | YES | NO | YES | -Measurements Date: 8 June 2021 +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | -- OPCODE: +
+ +More + +
+ + +### Compile + ```bash -$_main: ; (lines=19, args=0, vars=2, tmps=9) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/24_assign_object/24_assign_object.php:1-10 -L0 (3): NOP -L1 (5): EXT_STMT -L2 (5): V2 = NEW 0 string("myclass") -L3 (5): DO_FCALL -L4 (5): ASSIGN CV0($obj1) V2 -L5 (6): EXT_STMT -L6 (6): ASSIGN_OBJ CV0($obj1) string("b") -L7 (6): OP_DATA string("safe2") -L8 (7): EXT_STMT -L9 (7): ASSIGN CV1($obj2) CV0($obj1) -L10 (8): EXT_STMT -L11 (8): T8 = FETCH_R (global) string("_GET") -L12 (8): T9 = FETCH_DIM_R T8 string("p1") -L13 (8): ASSIGN_OBJ CV1($obj2) string("b") -L14 (8): OP_DATA T9 -L15 (10): EXT_STMT -L16 (10): T10 = FETCH_OBJ_R CV0($obj1) string("b") -L17 (10): ECHO T10 -L18 (10): RETURN int(1) +$_main: + ; (lines=13, args=0, vars=2, tmps=9) + ; (before optimizer) + ; /.../PHP/22_assign_object/1_instance_22_assign_object/1_instance_22_assign_object.php:1-10 + ; return [] RANGE[0..0] +0000 V2 = NEW 0 string("myclass") +0001 DO_FCALL +0002 ASSIGN CV0($obj1) V2 +0003 ASSIGN_OBJ CV0($obj1) string("b") +0004 OP_DATA string("safe2") +0005 ASSIGN CV1($obj2) CV0($obj1) +0006 T8 = FETCH_R (global) string("_GET") +0007 T9 = FETCH_DIM_R T8 string("p1") +0008 ASSIGN_OBJ CV1($obj2) string("b") +0009 OP_DATA T9 +0010 T10 = FETCH_OBJ_R CV0($obj1) string("b") +0011 ECHO T10 +0012 RETURN int(1) LIVE RANGES: - 2: L3 - L4 (new) + 2: 0001 - 0002 (new) ``` -- DISCOVERY: +
-```bash +
+ + +### Discovery + + +This rules first collects all `ASSIGN` calls, which are reachable by a `NEW` call in `G1`. +In `R1` it collects all `ASSIGN` calls where one variable is assigned to another variable in a list. +Finally, the rule filters out all `ASSIGN` calls from `R1`, where any call from `G1` is invoked in. + +```scala val G1 = cpg.call("ASSIGN").reachableByFlows(cpg.call.code(".*NEW.*")).map(_.elements.last).collect{ case c : nodes.Call => c}.argument.order(0).isIdentifier.name.l.distinct val R1 = cpg.call("ASSIGN").code(".*CV.*CV.*").l -R1.filter{ call => G1.exists{ h => call.argument.order(1).code.l.contains("CV($" + h + ")")} }.size; +val x22 = (name, "22_assign_object_iall", R1.filter{ call => G1.exists{ h => call.argument.order(1).code.l.contains("CV($" + h + ")")} }.location.toJson); ``` -- PRECONDITIONS: - 1. +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | -- TRANSFORMATION: +
-``` +
+ -``` +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | no | no | yes | yes | +| 17 May 2023 | yes | no | | | | | yes | + +
+
diff --git a/PHP/22_assign_object/docs/description.md b/PHP/22_assign_object/docs/description.md new file mode 100644 index 0000000..ed4e3ca --- /dev/null +++ b/PHP/22_assign_object/docs/description.md @@ -0,0 +1 @@ +Object assignment in PHP creates a reference to the same object in memory, rather than a new copy, which means that any changes made to the object through one variable or function parameter will be reflected in all other variables or parameters that reference the same object. \ No newline at end of file diff --git a/PHP/22_assign_object/docs/discovery_notes.md b/PHP/22_assign_object/docs/discovery_notes.md new file mode 100644 index 0000000..b236eb6 --- /dev/null +++ b/PHP/22_assign_object/docs/discovery_notes.md @@ -0,0 +1,3 @@ +This rules first collects all `ASSIGN` calls, which are reachable by a `NEW` call in `G1`. +In `R1` it collects all `ASSIGN` calls where one variable is assigned to another variable in a list. +Finally, the rule filters out all `ASSIGN` calls from `R1`, where any call from `G1` is invoked in. \ No newline at end of file diff --git a/PHP/23_object_argument/1_instance_23_object_argument/1_instance_23_object_argument.bash b/PHP/23_object_argument/1_instance_23_object_argument/1_instance_23_object_argument.bash index a5acf70..930356a 100644 --- a/PHP/23_object_argument/1_instance_23_object_argument/1_instance_23_object_argument.bash +++ b/PHP/23_object_argument/1_instance_23_object_argument/1_instance_23_object_argument.bash @@ -1,38 +1,34 @@ -$_main: ; (lines=20, args=0, vars=2, tmps=9) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/25_object_argument/25_object_argument.php:1-13 -L0 (2): EXT_STMT -L1 (2): V2 = NEW 0 string("stdClass") -L2 (2): DO_FCALL -L3 (2): ASSIGN CV0($x) V2 -L4 (3): EXT_STMT -L5 (3): ASSIGN_OBJ CV0($x) string("prop") -L6 (3): OP_DATA string("abc") -L7 (10): EXT_STMT -L8 (10): T6 = FETCH_R (global) string("_GET") -L9 (10): T7 = FETCH_DIM_R T6 string("p1") -L10 (10): ASSIGN CV1($b) T7 -L11 (11): EXT_STMT -L12 (11): INIT_FCALL 2 128 string("f") -L13 (11): SEND_VAR CV0($x) 1 -L14 (11): SEND_VAR CV1($b) 2 -L15 (11): DO_FCALL -L16 (13): EXT_STMT -L17 (13): T10 = FETCH_OBJ_R CV0($x) string("prop") -L18 (13): ECHO T10 -L19 (13): RETURN int(1) +$_main: + ; (lines=15, args=0, vars=2, tmps=9) + ; (before optimizer) + ; /.../PHP/23_object_argument/1_instance_23_object_argument/1_instance_23_object_argument.php:1-13 + ; return [] RANGE[0..0] +0000 V2 = NEW 0 string("stdClass") +0001 DO_FCALL +0002 ASSIGN CV0($x) V2 +0003 ASSIGN_OBJ CV0($x) string("prop") +0004 OP_DATA string("abc") +0005 T6 = FETCH_R (global) string("_GET") +0006 T7 = FETCH_DIM_R T6 string("p1") +0007 ASSIGN CV1($b) T7 +0008 INIT_FCALL 2 128 string("f") +0009 SEND_VAR CV0($x) 1 +0010 SEND_VAR CV1($b) 2 +0011 DO_UCALL +0012 T10 = FETCH_OBJ_R CV0($x) string("prop") +0013 ECHO T10 +0014 RETURN int(1) LIVE RANGES: - 2: L2 - L3 (new) + 2: 0001 - 0002 (new) -f: ; (lines=8, args=2, vars=2, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/25_object_argument/25_object_argument.php:6-8 -L0 (6): EXT_NOP -L1 (6): CV0($o) = RECV 1 -L2 (6): CV1($b) = RECV 2 -L3 (7): EXT_STMT -L4 (7): ASSIGN_OBJ CV0($o) string("prop") -L5 (7): OP_DATA CV1($b) -L6 (8): EXT_STMT -L7 (8): RETURN null +f: + ; (lines=5, args=2, vars=2, tmps=1) + ; (before optimizer) + ; /.../PHP/23_object_argument/1_instance_23_object_argument/1_instance_23_object_argument.php:6-8 + ; return [] RANGE[0..0] +0000 CV0($o) = RECV 1 +0001 CV1($b) = RECV 2 +0002 ASSIGN_OBJ CV0($o) string("prop") +0003 OP_DATA CV1($b) +0004 RETURN null diff --git a/PHP/23_object_argument/1_instance_23_object_argument/1_instance_23_object_argument.json b/PHP/23_object_argument/1_instance_23_object_argument/1_instance_23_object_argument.json index 9168bbd..bde8f72 100644 --- a/PHP/23_object_argument/1_instance_23_object_argument/1_instance_23_object_argument.json +++ b/PHP/23_object_argument/1_instance_23_object_argument/1_instance_23_object_argument.json @@ -1,4 +1,5 @@ { + "description": "This instance passes an object to a function, the function modifies the object itself.", "code": { "path": "./1_instance_23_object_argument.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_23_object_argument.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "FP", + "notes": "The rule first collects all `ASSIGN` calls, that are reachable by a `NEW` call in `G1`.\nIn `R2` all calls to `SEND` using a variable are gathered.\nIn the end all of the `SEND` calls are filtered and only those taken, where any element of `G1` is included." }, "compile": { "binary": "./1_instance_23_object_argument.bash", diff --git a/PHP/23_object_argument/1_instance_23_object_argument/1_instance_23_object_argument.php b/PHP/23_object_argument/1_instance_23_object_argument/1_instance_23_object_argument.php index 03103ed..5b0a5e2 100644 --- a/PHP/23_object_argument/1_instance_23_object_argument/1_instance_23_object_argument.php +++ b/PHP/23_object_argument/1_instance_23_object_argument/1_instance_23_object_argument.php @@ -7,7 +7,7 @@ function f ( $o, $b ) { $o->prop = $b; } -$b = $_GET["p1"]; +$b = $_GET["p1"]; // source f($x,$b); // XSS vulnerability, it will print $b -echo $x->prop; \ No newline at end of file +echo $x->prop; // sink \ No newline at end of file diff --git a/PHP/23_object_argument/23_object_argument.json b/PHP/23_object_argument/23_object_argument.json index 4854913..22d958d 100644 --- a/PHP/23_object_argument/23_object_argument.json +++ b/PHP/23_object_argument/23_object_argument.json @@ -1,6 +1,6 @@ { "name": "Object Argument", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_23_object_argument/1_instance_23_object_argument.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/23_object_argument/README.md b/PHP/23_object_argument/README.md index f0c6fff..fca48ef 100644 --- a/PHP/23_object_argument/README.md +++ b/PHP/23_object_argument/README.md @@ -1,23 +1,28 @@ -# Pattern: Object Argument +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) -## Category +# Object Argument -Objects +Tags: sast, php, php_v7.4.9 -## Definition +Version: v1.0 -## Instances +## Description -### Instance 1 +When an object is passed to a function as an argument, PHP wil pass it as reference, so every change made to the object inside the function will also affect the object itself. -- CATEGORY: S0 -- FEATURE vs INTERNAL API: FEATURE -- INPUT SANITIZERS: NO -- SOURCES AND SINKS: NO -- NEGATIVE TEST CASES: NO -- CODE: +## Overview -```php +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +This instance passes an object to a function, the function modifies the object itself. + +### Code + +```PHP prop = 'abc'; @@ -27,75 +32,99 @@ function f ( $o, $b ) { $o->prop = $b; } -$b = $_GET["p1"]; +$b = $_GET["p1"]; // source f($x,$b); // XSS vulnerability, it will print $b -echo $x->prop; +echo $x->prop; // sink ``` -- MEASUREMENT: +### Instance Properties -| Tool | RIPS | phpSAFE | WAP | Progpilot | Comm_1 | Comm_2 | Correct | -| ------------- | ---- | ------- | ---- | --------- | ------- | --------- | ------- | -| Vulnerability | NO | NO | NO | NO | YES | NO | YES | -Measurements Date: 8 June 2021 +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | -- OPCODE: +
+ +More + +
+ + +### Compile + ```bash -$_main: ; (lines=20, args=0, vars=2, tmps=9) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/25_object_argument/25_object_argument.php:1-13 -L0 (2): EXT_STMT -L1 (2): V2 = NEW 0 string("stdClass") -L2 (2): DO_FCALL -L3 (2): ASSIGN CV0($x) V2 -L4 (3): EXT_STMT -L5 (3): ASSIGN_OBJ CV0($x) string("prop") -L6 (3): OP_DATA string("abc") -L7 (10): EXT_STMT -L8 (10): T6 = FETCH_R (global) string("_GET") -L9 (10): T7 = FETCH_DIM_R T6 string("p1") -L10 (10): ASSIGN CV1($b) T7 -L11 (11): EXT_STMT -L12 (11): INIT_FCALL 2 128 string("f") -L13 (11): SEND_VAR CV0($x) 1 -L14 (11): SEND_VAR CV1($b) 2 -L15 (11): DO_FCALL -L16 (13): EXT_STMT -L17 (13): T10 = FETCH_OBJ_R CV0($x) string("prop") -L18 (13): ECHO T10 -L19 (13): RETURN int(1) +$_main: + ; (lines=15, args=0, vars=2, tmps=9) + ; (before optimizer) + ; /.../PHP/23_object_argument/1_instance_23_object_argument/1_instance_23_object_argument.php:1-13 + ; return [] RANGE[0..0] +0000 V2 = NEW 0 string("stdClass") +0001 DO_FCALL +0002 ASSIGN CV0($x) V2 +0003 ASSIGN_OBJ CV0($x) string("prop") +0004 OP_DATA string("abc") +0005 T6 = FETCH_R (global) string("_GET") +0006 T7 = FETCH_DIM_R T6 string("p1") +0007 ASSIGN CV1($b) T7 +0008 INIT_FCALL 2 128 string("f") +0009 SEND_VAR CV0($x) 1 +0010 SEND_VAR CV1($b) 2 +0011 DO_UCALL +0012 T10 = FETCH_OBJ_R CV0($x) string("prop") +0013 ECHO T10 +0014 RETURN int(1) LIVE RANGES: - 2: L2 - L3 (new) - -f: ; (lines=8, args=2, vars=2, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/25_object_argument/25_object_argument.php:6-8 -L0 (6): EXT_NOP -L1 (6): CV0($o) = RECV 1 -L2 (6): CV1($b) = RECV 2 -L3 (7): EXT_STMT -L4 (7): ASSIGN_OBJ CV0($o) string("prop") -L5 (7): OP_DATA CV1($b) -L6 (8): EXT_STMT -L7 (8): RETURN null + 2: 0001 - 0002 (new) + +f: + ; (lines=5, args=2, vars=2, tmps=1) + ; (before optimizer) + ; /.../PHP/23_object_argument/1_instance_23_object_argument/1_instance_23_object_argument.php:6-8 + ; return [] RANGE[0..0] +0000 CV0($o) = RECV 1 +0001 CV1($b) = RECV 2 +0002 ASSIGN_OBJ CV0($o) string("prop") +0003 OP_DATA CV1($b) +0004 RETURN null ``` -- DISCOVERY: +
-```bash +
+ + +### Discovery + + +The rule first collects all `ASSIGN` calls, that are reachable by a `NEW` call in `G1`. +In `R2` all calls to `SEND` using a variable are gathered. +In the end all of the `SEND` calls are filtered and only those taken, where any element of `G1` is included. + +```scala val G1 = cpg.call("ASSIGN").reachableByFlows(cpg.call.code(".*NEW.*")).map(_.elements.last).collect{ case c : nodes.Call => c}.argument.order(0).isIdentifier.name.l.distinct val R2 = cpg.call("SEND.*").code(".*CV.*").l -R2.filter{ call => G1.exists{ h => call.argument.order(0).code.l.contains("CV($" + h + ")")} }.size; +val x23 = (name, "23_object_argument_iall", R2.filter{ call => G1.exists{ h => call.argument.order(0).code.l.contains("CV($" + h + ")")} }.location.toJson); ``` -- PRECONDITIONS: - 1. +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | -- TRANSFORMATION: +
-``` +
+ -``` +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | no | no | no | yes | +| 17 May 2023 | yes | no | | | | | yes | + +
+
diff --git a/PHP/23_object_argument/docs/description.md b/PHP/23_object_argument/docs/description.md new file mode 100644 index 0000000..7d87a6a --- /dev/null +++ b/PHP/23_object_argument/docs/description.md @@ -0,0 +1 @@ +When an object is passed to a function as an argument, PHP wil pass it as reference, so every change made to the object inside the function will also affect the object itself. \ No newline at end of file diff --git a/PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.bash b/PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.bash index 57738d9..72355cd 100644 --- a/PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.bash +++ b/PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.bash @@ -1,53 +1,51 @@ -$_main: ; (lines=9, args=0, vars=2, tmps=5) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/23_new_self/23_new_self.php:1-23 -L0 (21): EXT_STMT -L1 (21): V2 = NEW 0 string("myclass") -L2 (21): DO_FCALL -L3 (21): ASSIGN CV0($obj) V2 -L4 (22): EXT_STMT -L5 (22): INIT_METHOD_CALL 0 CV0($obj) string("F") -L6 (22): V5 = DO_FCALL -L7 (22): ASSIGN CV1($obj2) V5 -L8 (23): RETURN int(1) +$_main: + ; (lines=8, args=0, vars=2, tmps=5) + ; (before optimizer) + ; /.../PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.php:1-22 + ; return [] RANGE[0..0] +0000 V2 = NEW 0 string("myclass") +0001 DO_FCALL +0002 ASSIGN CV0($obj) V2 +0003 INIT_METHOD_CALL 0 CV0($obj) string("F") +0004 V5 = DO_FCALL +0005 ASSIGN CV1($a) V5 +0006 ECHO CV1($a) +0007 RETURN int(1) LIVE RANGES: - 2: L2 - L3 (new) + 2: 0001 - 0002 (new) -myclass::__construct: ; (lines=8, args=0, vars=0, tmps=3) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/23_new_self/23_new_self.php:5-8 -L0 (5): EXT_NOP -L1 (6): EXT_STMT -L2 (6): T1 = FETCH_R (global) string("_GET") -L3 (6): T2 = FETCH_DIM_R T1 string("p1") -L4 (6): ASSIGN_OBJ THIS string("b") -L5 (6): OP_DATA T2 -L6 (8): EXT_STMT -L7 (8): RETURN null +myclass::__construct: + ; (lines=5, args=0, vars=0, tmps=3) + ; (before optimizer) + ; /.../PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.php:4-6 + ; return [] RANGE[0..0] +0000 T1 = FETCH_R (global) string("_GET") +0001 T2 = FETCH_DIM_R T1 string("p1") +0002 ASSIGN_OBJ THIS string("b") +0003 OP_DATA T2 +0004 RETURN null -myclass::F: ; (lines=10, args=0, vars=1, tmps=4) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/23_new_self/23_new_self.php:10-13 -L0 (10): EXT_NOP -L1 (11): EXT_STMT -L2 (11): V1 = NEW 0 (self) (exception) -L3 (11): DO_FCALL -L4 (11): ASSIGN CV0($obj2) V1 -L5 (12): EXT_STMT -L6 (12): INIT_METHOD_CALL 0 CV0($obj2) string("T") -L7 (12): DO_FCALL -L8 (13): EXT_STMT -L9 (13): RETURN null +myclass::F: + ; (lines=7, args=0, vars=1, tmps=4) + ; (before optimizer) + ; /.../PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.php:8-11 + ; return [] RANGE[0..0] +0000 V1 = NEW 0 (self) (exception) +0001 DO_FCALL +0002 ASSIGN CV0($obj2) V1 +0003 INIT_METHOD_CALL 0 CV0($obj2) string("T") +0004 V4 = DO_FCALL +0005 RETURN V4 +0006 RETURN null LIVE RANGES: - 1: L3 - L4 (new) + 1: 0001 - 0002 (new) -myclass::T: ; (lines=6, args=0, vars=0, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/23_new_self/23_new_self.php:15-17 -L0 (15): EXT_NOP -L1 (16): EXT_STMT -L2 (16): T0 = FETCH_OBJ_R THIS string("b") -L3 (16): ECHO T0 -L4 (17): EXT_STMT -L5 (17): RETURN null +myclass::T: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.php:13-15 + ; return [] RANGE[0..0] +0000 T0 = FETCH_OBJ_R THIS string("b") +0001 RETURN T0 +0002 RETURN null diff --git a/PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.json b/PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.json index 59e2ac1..eb7ab25 100644 --- a/PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.json +++ b/PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.json @@ -1,13 +1,14 @@ { + "description": "The instance demonstrates the use of `new self`, with a source in the `__construct()` call.", "code": { "path": "./1_instance_24_new_self.php", - "injection_skeleton_broken": false + "injection_skeleton_broken": true }, "discovery": { "rule": "./1_instance_24_new_self.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "Perfect", + "notes": "The rule searches for calles to `NEW`, which have `self` as an argument." }, "compile": { "binary": "./1_instance_24_new_self.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_24_new_self.php", - "sink_line": 16, + "sink_line": 21, "source_file": "./1_instance_24_new_self.php", - "source_line": 6, + "source_line": 5, "expectation": true }, "properties": { diff --git a/PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.php b/PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.php index 4da9768..fdc3410 100644 --- a/PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.php +++ b/PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.php @@ -1,22 +1,21 @@ b = $_GET['p1']; // source + } -function __construct(){ - $this->b = $_GET['p1']; - //$this->b = "abc"; -} - -function F(){ - $obj2 = new self; - $obj2->T(); -} + function F() { + $obj2 = new self; + return $obj2->T(); + } -function T(){ - echo $this->b; -} + function T() { + return $this->b; + } } $obj = new myclass(); -$obj2 = $obj->F(); +$a = $obj->F(); +echo $a; // sink diff --git a/PHP/24_new_self/24_new_self.json b/PHP/24_new_self/24_new_self.json index c18f87c..d966df5 100644 --- a/PHP/24_new_self/24_new_self.json +++ b/PHP/24_new_self/24_new_self.json @@ -1,6 +1,6 @@ { "name": "New Self", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_24_new_self/1_instance_24_new_self.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/24_new_self/README.md b/PHP/24_new_self/README.md index 2e7dcf0..4e42e27 100644 --- a/PHP/24_new_self/README.md +++ b/PHP/24_new_self/README.md @@ -1,144 +1,150 @@ -# Pattern: New Self +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) -## Category +# New Self -Objects +Tags: sast, php, php_v7.4.9 -## Definition +Version: v1.0 -## Instances +## Description -### Instance 1 +In PHP `new self` is used to create a new instance of the same class in which it appears. -- CATEGORY: S0 -- FEATURE vs INTERNAL API: FEATURE -- INPUT SANITIZERS: NO -- SOURCES AND SINKS: NO -- NEGATIVE TEST CASES: NO -- CODE: +## Overview -```php -b = $_GET['p1']; - //$this->b = "abc"; + function __construct() { + $this->b = $_GET['p1']; // source } - function F(){ - $obj2 = new self; - $obj2->T(); + function F() { + $obj2 = new self; + return $obj2->T(); } - function T(){ - echo $this->b; + function T() { + return $this->b; } } - $obj = new myclass(); -$obj2 = $obj->F(); +$a = $obj->F(); +echo $a; // sink ``` -- MEASUREMENT: +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | -| Tool | RIPS | phpSAFE | WAP | Progpilot | Comm_1 | Comm_2 | Correct | -| ------------- | ---- | ------- | ---- | --------- | ------- | --------- | ------- | -| Vulnerability | NO | NO |NO | NO | YES | NO | YES | -Measurements Date: 8 June 2021 +
+ +More -- OPCODE: +
+ + +### Compile + ```bash -$_main: ; (lines=9, args=0, vars=2, tmps=5) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/23_new_self/23_new_self.php:1-23 -L0 (21): EXT_STMT -L1 (21): V2 = NEW 0 string("myclass") -L2 (21): DO_FCALL -L3 (21): ASSIGN CV0($obj) V2 -L4 (22): EXT_STMT -L5 (22): INIT_METHOD_CALL 0 CV0($obj) string("F") -L6 (22): V5 = DO_FCALL -L7 (22): ASSIGN CV1($obj2) V5 -L8 (23): RETURN int(1) +$_main: + ; (lines=8, args=0, vars=2, tmps=5) + ; (before optimizer) + ; /.../PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.php:1-22 + ; return [] RANGE[0..0] +0000 V2 = NEW 0 string("myclass") +0001 DO_FCALL +0002 ASSIGN CV0($obj) V2 +0003 INIT_METHOD_CALL 0 CV0($obj) string("F") +0004 V5 = DO_FCALL +0005 ASSIGN CV1($a) V5 +0006 ECHO CV1($a) +0007 RETURN int(1) LIVE RANGES: - 2: L2 - L3 (new) - -myclass::__construct: ; (lines=8, args=0, vars=0, tmps=3) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/23_new_self/23_new_self.php:5-8 -L0 (5): EXT_NOP -L1 (6): EXT_STMT -L2 (6): T1 = FETCH_R (global) string("_GET") -L3 (6): T2 = FETCH_DIM_R T1 string("p1") -L4 (6): ASSIGN_OBJ THIS string("b") -L5 (6): OP_DATA T2 -L6 (8): EXT_STMT -L7 (8): RETURN null - -myclass::F: ; (lines=10, args=0, vars=1, tmps=4) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/23_new_self/23_new_self.php:10-13 -L0 (10): EXT_NOP -L1 (11): EXT_STMT -L2 (11): V1 = NEW 0 (self) (exception) -L3 (11): DO_FCALL -L4 (11): ASSIGN CV0($obj2) V1 -L5 (12): EXT_STMT -L6 (12): INIT_METHOD_CALL 0 CV0($obj2) string("T") -L7 (12): DO_FCALL -L8 (13): EXT_STMT -L9 (13): RETURN null + 2: 0001 - 0002 (new) + +myclass::__construct: + ; (lines=5, args=0, vars=0, tmps=3) + ; (before optimizer) + ; /.../PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.php:4-6 + ; return [] RANGE[0..0] +0000 T1 = FETCH_R (global) string("_GET") +0001 T2 = FETCH_DIM_R T1 string("p1") +0002 ASSIGN_OBJ THIS string("b") +0003 OP_DATA T2 +0004 RETURN null + +myclass::F: + ; (lines=7, args=0, vars=1, tmps=4) + ; (before optimizer) + ; /.../PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.php:8-11 + ; return [] RANGE[0..0] +0000 V1 = NEW 0 (self) (exception) +0001 DO_FCALL +0002 ASSIGN CV0($obj2) V1 +0003 INIT_METHOD_CALL 0 CV0($obj2) string("T") +0004 V4 = DO_FCALL +0005 RETURN V4 +0006 RETURN null LIVE RANGES: - 1: L3 - L4 (new) - -myclass::T: ; (lines=6, args=0, vars=0, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/23_new_self/23_new_self.php:15-17 -L0 (15): EXT_NOP -L1 (16): EXT_STMT -L2 (16): T0 = FETCH_OBJ_R THIS string("b") -L3 (16): ECHO T0 -L4 (17): EXT_STMT -L5 (17): RETURN null + 1: 0001 - 0002 (new) + +myclass::T: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/24_new_self/1_instance_24_new_self/1_instance_24_new_self.php:13-15 + ; return [] RANGE[0..0] +0000 T0 = FETCH_OBJ_R THIS string("b") +0001 RETURN T0 +0002 RETURN null ``` -- DISCOVERY: +
-```bash -cpg.call(".*NEW.*").argument.order(1).code("self").location.l -``` +
+ -- PRECONDITIONS: - 1. +### Discovery + -- TRANSFORMATION: +The rule searches for calles to `NEW`, which have `self` as an argument. -```php -b = $_GET['p1']; - //$this->b = "abc"; - } +
- function F(){ - $obj2 = new myclass(); - $obj2->T(); - } +
+ - function T(){ - echo $this->b; - } -} +### Measurement + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | no | no | no | yes | +| 17 May 2023 | yes | no | | | | | yes | -$obj = new myclass(); -$obj2 = $obj->F(); -``` +
+
diff --git a/PHP/24_new_self/docs/description.md b/PHP/24_new_self/docs/description.md new file mode 100644 index 0000000..3b89cf8 --- /dev/null +++ b/PHP/24_new_self/docs/description.md @@ -0,0 +1 @@ +In PHP `new self` is used to create a new instance of the same class in which it appears. \ No newline at end of file diff --git a/PHP/25_clone/1_instance_25_clone/1_instance_25_clone.bash b/PHP/25_clone/1_instance_25_clone/1_instance_25_clone.bash index 98b5c0f..e1c2495 100644 --- a/PHP/25_clone/1_instance_25_clone/1_instance_25_clone.bash +++ b/PHP/25_clone/1_instance_25_clone/1_instance_25_clone.bash @@ -1,44 +1,41 @@ -$_main: ; (lines=17, args=0, vars=3, tmps=9) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/26_clone/26_clone.php:1-19 -L0 (4): NOP -L1 (14): EXT_STMT -L2 (14): T3 = FETCH_R (global) string("_GET") -L3 (14): T4 = FETCH_DIM_R T3 string("p1") -L4 (14): ASSIGN CV0($b) T4 -L5 (15): EXT_STMT -L6 (15): V6 = NEW 1 string("Foo") -L7 (15): SEND_VAR_EX CV0($b) 1 -L8 (15): DO_FCALL -L9 (15): ASSIGN CV1($ob1) V6 -L10 (16): EXT_STMT -L11 (16): T9 = CLONE CV1($ob1) -L12 (16): ASSIGN CV2($ob2) T9 -L13 (17): EXT_STMT -L14 (17): INIT_METHOD_CALL 0 CV2($ob2) string("baz") -L15 (17): DO_FCALL -L16 (19): RETURN int(1) +$_main: + ; (lines=14, args=0, vars=4, tmps=10) + ; (before optimizer) + ; /.../PHP/25_clone/1_instance_25_clone/1_instance_25_clone.php:1-16 + ; return [] RANGE[0..0] +0000 T4 = FETCH_R (global) string("_GET") +0001 T5 = FETCH_DIM_R T4 string("p1") +0002 ASSIGN CV0($b) T5 +0003 V7 = NEW 1 string("Foo") +0004 SEND_VAR_EX CV0($b) 1 +0005 DO_FCALL +0006 ASSIGN CV1($ob1) V7 +0007 T10 = CLONE CV1($ob1) +0008 ASSIGN CV2($ob2) T10 +0009 INIT_METHOD_CALL 0 CV2($ob2) string("baz") +0010 V12 = DO_FCALL +0011 ASSIGN CV3($a) V12 +0012 ECHO CV3($a) +0013 RETURN int(1) LIVE RANGES: - 6: L7 - L9 (new) + 7: 0004 - 0006 (new) -Foo::__construct: ; (lines=7, args=1, vars=1, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/26_clone/26_clone.php:5-7 -L0 (5): EXT_NOP -L1 (5): CV0($b) = RECV 1 -L2 (6): EXT_STMT -L3 (6): ASSIGN_OBJ THIS string("b") -L4 (6): OP_DATA CV0($b) -L5 (7): EXT_STMT -L6 (7): RETURN null +Foo::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/25_clone/1_instance_25_clone/1_instance_25_clone.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("b") +0002 OP_DATA CV0($b) +0003 RETURN null -Foo::baz: ; (lines=6, args=0, vars=0, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/26_clone/26_clone.php:8-12 -L0 (8): EXT_NOP -L1 (11): EXT_STMT -L2 (11): T0 = FETCH_OBJ_R THIS string("b") -L3 (11): ECHO T0 -L4 (12): EXT_STMT -L5 (12): RETURN null +Foo::baz: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/25_clone/1_instance_25_clone/1_instance_25_clone.php:7-10 + ; return [] RANGE[0..0] +0000 T0 = FETCH_OBJ_R THIS string("b") +0001 RETURN T0 +0002 RETURN null diff --git a/PHP/25_clone/1_instance_25_clone/1_instance_25_clone.json b/PHP/25_clone/1_instance_25_clone/1_instance_25_clone.json index bb05015..f9dfa70 100644 --- a/PHP/25_clone/1_instance_25_clone/1_instance_25_clone.json +++ b/PHP/25_clone/1_instance_25_clone/1_instance_25_clone.json @@ -1,4 +1,5 @@ { + "description": "This instance demonstrates, that when you clone an object, both the cloned object and the original object have the same value.", "code": { "path": "./1_instance_25_clone.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_25_clone.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "Perfect", + "notes": "The rule searches for the opcode `CLONE`." }, "compile": { "binary": "./1_instance_25_clone.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_25_clone.php", - "sink_line": 11, + "sink_line": 16, "source_file": "./1_instance_25_clone.php", - "source_line": 14, + "source_line": 12, "expectation": true }, "properties": { diff --git a/PHP/25_clone/1_instance_25_clone/1_instance_25_clone.php b/PHP/25_clone/1_instance_25_clone/1_instance_25_clone.php index 6697cbb..83dbbae 100644 --- a/PHP/25_clone/1_instance_25_clone/1_instance_25_clone.php +++ b/PHP/25_clone/1_instance_25_clone/1_instance_25_clone.php @@ -1,19 +1,16 @@ b = $b; } - public function baz() - { + public function baz() { // $b has the input, XSS Vulnerability - echo $this->b; + return $this->b; } } -$b = $_GET["p1"]; +$b = $_GET["p1"]; // source $ob1 = new Foo($b); -$ob2 = clone $ob1; -$ob2->baz(); -//$ob->baz(); -//array(new Foo($b), "baz")(); \ No newline at end of file +$ob2 = clone $ob1; // tarpit +$a = $ob2->baz(); +echo $a; // sink \ No newline at end of file diff --git a/PHP/25_clone/25_clone.json b/PHP/25_clone/25_clone.json index 427bb71..b30fe87 100644 --- a/PHP/25_clone/25_clone.json +++ b/PHP/25_clone/25_clone.json @@ -1,6 +1,6 @@ { "name": "Clone", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_25_clone/1_instance_25_clone.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/25_clone/README.md b/PHP/25_clone/README.md new file mode 100644 index 0000000..74fd84e --- /dev/null +++ b/PHP/25_clone/README.md @@ -0,0 +1,136 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Clone + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +In PHP, clone is used to create a copy of an existing object, and it can be used to create a new instance with the same properties and values as the original one. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +This instance demonstrates, that when you clone an object, both the cloned object and the original object have the same value. + +### Code + +```PHP +b = $b; + } + public function baz() { + // $b has the input, XSS Vulnerability + return $this->b; + } +} +$b = $_GET["p1"]; // source +$ob1 = new Foo($b); +$ob2 = clone $ob1; // tarpit +$a = $ob2->baz(); +echo $a; // sink +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=14, args=0, vars=4, tmps=10) + ; (before optimizer) + ; /.../PHP/25_clone/1_instance_25_clone/1_instance_25_clone.php:1-16 + ; return [] RANGE[0..0] +0000 T4 = FETCH_R (global) string("_GET") +0001 T5 = FETCH_DIM_R T4 string("p1") +0002 ASSIGN CV0($b) T5 +0003 V7 = NEW 1 string("Foo") +0004 SEND_VAR_EX CV0($b) 1 +0005 DO_FCALL +0006 ASSIGN CV1($ob1) V7 +0007 T10 = CLONE CV1($ob1) +0008 ASSIGN CV2($ob2) T10 +0009 INIT_METHOD_CALL 0 CV2($ob2) string("baz") +0010 V12 = DO_FCALL +0011 ASSIGN CV3($a) V12 +0012 ECHO CV3($a) +0013 RETURN int(1) +LIVE RANGES: + 7: 0004 - 0006 (new) + +Foo::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/25_clone/1_instance_25_clone/1_instance_25_clone.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("b") +0002 OP_DATA CV0($b) +0003 RETURN null + +Foo::baz: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/25_clone/1_instance_25_clone/1_instance_25_clone.php:7-10 + ; return [] RANGE[0..0] +0000 T0 = FETCH_OBJ_R THIS string("b") +0001 RETURN T0 +0002 RETURN null +``` + +
+ +
+ + +### Discovery + + +The rule searches for the opcode `CLONE`. + +```scala +val x25 = (name, "25_clone_iall", cpg.call(".*CLONE.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | yes | no | no | yes | +| 17 May 2023 | yes | yes | | | | | yes | + +
+ +
diff --git a/PHP/25_clone/docs/description.md b/PHP/25_clone/docs/description.md new file mode 100644 index 0000000..9a29a24 --- /dev/null +++ b/PHP/25_clone/docs/description.md @@ -0,0 +1 @@ +In PHP, clone is used to create a copy of an existing object, and it can be used to create a new instance with the same properties and values as the original one. \ No newline at end of file diff --git a/PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.bash b/PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.bash index 3d77ba5..8287b5c 100644 --- a/PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.bash +++ b/PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.bash @@ -1,45 +1,45 @@ -$_main: ; (lines=9, args=0, vars=1, tmps=4) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/36_late_static_binding/36_late_static_binding.php:1-18 -L0 (17): EXT_STMT -L1 (17): T1 = FETCH_R (global) string("_GET") -L2 (17): T2 = FETCH_DIM_R T1 string("p1") -L3 (17): ASSIGN CV0($b) T2 -L4 (18): EXT_STMT -L5 (18): INIT_STATIC_METHOD_CALL 1 string("B") string("test") -L6 (18): SEND_VAR CV0($b) 1 -L7 (18): DO_FCALL -L8 (18): RETURN int(1) +$_main: + ; (lines=9, args=0, vars=2, tmps=5) + ; (before optimizer) + ; /.../PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.php:1-19 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 INIT_STATIC_METHOD_CALL 1 string("B") string("test") +0004 SEND_VAR CV0($b) 1 +0005 V5 = DO_UCALL +0006 ASSIGN CV1($a) V5 +0007 ECHO CV1($a) +0008 RETURN int(1) -A::who: ; (lines=6, args=1, vars=1, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/36_late_static_binding/36_late_static_binding.php:3-5 -L0 (3): EXT_NOP -L1 (3): CV0($b) = RECV 1 -L2 (4): EXT_STMT -L3 (4): ECHO string("safe") -L4 (5): EXT_STMT -L5 (5): RETURN null +A::who: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN string("safe") +0002 RETURN null -A::test: ; (lines=8, args=1, vars=1, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/36_late_static_binding/36_late_static_binding.php:6-8 -L0 (6): EXT_NOP -L1 (6): CV0($b) = RECV 1 -L2 (7): EXT_STMT -L3 (7): INIT_STATIC_METHOD_CALL 1 (static) (exception) string("who") -L4 (7): SEND_VAR_EX CV0($b) 1 -L5 (7): DO_FCALL -L6 (8): EXT_STMT -L7 (8): RETURN null +A::test: + ; (lines=6, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.php:6-8 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 INIT_STATIC_METHOD_CALL 1 (static) (exception) string("who") +0002 SEND_VAR_EX CV0($b) 1 +0003 V1 = DO_FCALL +0004 RETURN V1 +0005 RETURN null -B::who: ; (lines=6, args=1, vars=1, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/36_late_static_binding/36_late_static_binding.php:12-14 -L0 (12): EXT_NOP -L1 (12): CV0($b) = RECV 1 -L2 (13): EXT_STMT -L3 (13): ECHO CV0($b) -L4 (14): EXT_STMT -L5 (14): RETURN null +B::who: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.php:12-14 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN CV0($b) +0002 RETURN null diff --git a/PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.json b/PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.json index 88c3b0f..3a369dc 100644 --- a/PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.json +++ b/PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.json @@ -1,4 +1,5 @@ { + "description": "This instance binds the method `test` to the class `B`. This is why the function `who` from class `B` will be called, which is vulnerable.", "code": { "path": "./1_instance_26_late_static_binding.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "../26_late_static_binding.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "FP", + "notes": "The rule searches for an `INIT_STATIC_METHOD_CALL`, where the first argument is static." }, "compile": { "binary": "./1_instance_26_late_static_binding.bash", @@ -17,7 +18,7 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_26_late_static_binding.php", - "sink_line": 13, + "sink_line": 19, "source_file": "./1_instance_26_late_static_binding.php", "source_line": 17, "expectation": true diff --git a/PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.php b/PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.php index 40574a3..a5a7513 100644 --- a/PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.php +++ b/PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.php @@ -1,18 +1,19 @@ + + +## 1 Instance + + +This instance binds the method `test` to the class `B`. This is why the function `who` from class `B` will be called, which is vulnerable. + +### Code + +```PHP + + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=9, args=0, vars=2, tmps=5) + ; (before optimizer) + ; /.../PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.php:1-19 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 INIT_STATIC_METHOD_CALL 1 string("B") string("test") +0004 SEND_VAR CV0($b) 1 +0005 V5 = DO_UCALL +0006 ASSIGN CV1($a) V5 +0007 ECHO CV1($a) +0008 RETURN int(1) + +A::who: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN string("safe") +0002 RETURN null + +A::test: + ; (lines=6, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.php:6-8 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 INIT_STATIC_METHOD_CALL 1 (static) (exception) string("who") +0002 SEND_VAR_EX CV0($b) 1 +0003 V1 = DO_FCALL +0004 RETURN V1 +0005 RETURN null + +B::who: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/26_late_static_binding/1_instance_26_late_static_binding/1_instance_26_late_static_binding.php:12-14 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN CV0($b) +0002 RETURN null +``` + +
+ +
+ + +### Discovery + + +The rule searches for an `INIT_STATIC_METHOD_CALL`, where the first argument is static. + +```scala +val x26 = (name, "26_late_static_binding_iall", cpg.call(".*INIT_STATIC_METHOD_CALL.*").argument.order(1).code("static").astParent.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | no | no | no | yes | +| 17 May 2023 | yes | yes | | | | | yes | + +
+ + + + + +
+ + +## 2 Instance + + +This instance binds the method `test` to the class `A`. This is why the function `who` from class `A` will be called, which is returns 'save'. The instance is not vulnerable. + +### Code + +```PHP + + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=9, args=0, vars=2, tmps=5) + ; (before optimizer) + ; /.../PHP/26_late_static_binding/2_instance_26_late_static_binding/2_instance_26_late_static_binding.php:1-19 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 INIT_STATIC_METHOD_CALL 1 string("A") string("test") +0004 SEND_VAR CV0($b) 1 +0005 V5 = DO_UCALL +0006 ASSIGN CV1($a) V5 +0007 ECHO CV1($a) +0008 RETURN int(1) + +A::who: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/26_late_static_binding/2_instance_26_late_static_binding/2_instance_26_late_static_binding.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN string("safe") +0002 RETURN null + +A::test: + ; (lines=6, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/26_late_static_binding/2_instance_26_late_static_binding/2_instance_26_late_static_binding.php:6-8 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 INIT_STATIC_METHOD_CALL 1 (static) (exception) string("who") +0002 SEND_VAR_EX CV0($b) 1 +0003 V1 = DO_FCALL +0004 RETURN V1 +0005 RETURN null + +B::who: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/26_late_static_binding/2_instance_26_late_static_binding/2_instance_26_late_static_binding.php:12-14 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN CV0($b) +0002 RETURN null +``` + +
+ +
+ + +### Discovery + + +The rule searches for an `INIT_STATIC_METHOD_CALL`, where the first argument is static. + +```scala +val x26 = (name, "26_late_static_binding_iall", cpg.call(".*INIT_STATIC_METHOD_CALL.*").argument.order(1).code("static").astParent.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | Ground Truth | +|-------------|----------|----------|----------------| +| 08 Jun 2021 | yes | | no | +| 17 May 2023 | yes | yes | no | + +
+ +
+ + diff --git a/PHP/26_late_static_binding/docs/description.md b/PHP/26_late_static_binding/docs/description.md new file mode 100644 index 0000000..08b8bc2 --- /dev/null +++ b/PHP/26_late_static_binding/docs/description.md @@ -0,0 +1 @@ +In PHP the keyword `self` does not follow inheritance. For example if you have a method defined in parent class and call it from the child class `self` will not resolve to the child class. To address this, [late static binding](https://www.php.net/manual/en/language.oop5.late-static-bindings.php) introduces a new use for the `static` keyword. When using `static` it binds the function to the class where it is first used. \ No newline at end of file diff --git a/PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.bash b/PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.bash index 89a475b..b34e869 100644 --- a/PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.bash +++ b/PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.bash @@ -1,47 +1,47 @@ -$_main: ; (lines=9, args=0, vars=1, tmps=4) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/37_get_called_class/37_get_called_class.php:1-18 -L0 (17): EXT_STMT -L1 (17): T1 = FETCH_R (global) string("_GET") -L2 (17): T2 = FETCH_DIM_R T1 string("p1") -L3 (17): ASSIGN CV0($b) T2 -L4 (18): EXT_STMT -L5 (18): INIT_STATIC_METHOD_CALL 1 string("B") string("test") -L6 (18): SEND_VAR CV0($b) 1 -L7 (18): DO_FCALL -L8 (18): RETURN int(1) +$_main: + ; (lines=9, args=0, vars=2, tmps=5) + ; (before optimizer) + ; /.../PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.php:1-19 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 INIT_STATIC_METHOD_CALL 1 string("B") string("test") +0004 SEND_VAR CV0($b) 1 +0005 V5 = DO_UCALL +0006 ASSIGN CV1($a) V5 +0007 ECHO CV1($a) +0008 RETURN int(1) -A::who: ; (lines=6, args=1, vars=1, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/37_get_called_class/37_get_called_class.php:3-5 -L0 (3): EXT_NOP -L1 (3): CV0($b) = RECV 1 -L2 (4): EXT_STMT -L3 (4): ECHO string("safe") -L4 (5): EXT_STMT -L5 (5): RETURN null +A::who: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN string("safe") +0002 RETURN null -A::test: ; (lines=10, args=1, vars=1, tmps=3) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/37_get_called_class/37_get_called_class.php:6-8 -L0 (6): EXT_NOP -L1 (6): CV0($b) = RECV 1 -L2 (7): EXT_STMT -L3 (7): T1 = GET_CALLED_CLASS -L4 (7): V2 = FETCH_CLASS (exception) T1 -L5 (7): INIT_STATIC_METHOD_CALL 1 V2 string("who") -L6 (7): SEND_VAR_EX CV0($b) 1 -L7 (7): DO_FCALL -L8 (8): EXT_STMT -L9 (8): RETURN null +A::test: + ; (lines=8, args=1, vars=1, tmps=3) + ; (before optimizer) + ; /.../PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.php:6-8 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 T1 = GET_CALLED_CLASS +0002 V2 = FETCH_CLASS (exception) T1 +0003 INIT_STATIC_METHOD_CALL 1 V2 string("who") +0004 SEND_VAR_EX CV0($b) 1 +0005 V3 = DO_FCALL +0006 RETURN V3 +0007 RETURN null -B::who: ; (lines=6, args=1, vars=1, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/37_get_called_class/37_get_called_class.php:12-14 -L0 (12): EXT_NOP -L1 (12): CV0($b) = RECV 1 -L2 (13): EXT_STMT -L3 (13): ECHO CV0($b) -L4 (14): EXT_STMT -L5 (14): RETURN null +B::who: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.php:12-14 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN CV0($b) +0002 RETURN null diff --git a/PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.json b/PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.json index f3576df..984687f 100644 --- a/PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.json +++ b/PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.json @@ -1,4 +1,5 @@ { + "description": "The instance demonstrates how you can get the class from the object, that called the static method.", "code": { "path": "./1_instance_27_get_called_class.php", "injection_skeleton_broken": false @@ -7,7 +8,7 @@ "rule": "./1_instance_27_get_called_class.sc", "method": "joern", "rule_accuracy": "Perfect", - "notes": null + "notes": "The rule searches for the opcode `GET_CALLED_CLASS`." }, "compile": { "binary": "./1_instance_27_get_called_class.bash", @@ -17,7 +18,7 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_27_get_called_class.php", - "sink_line": 13, + "sink_line": 19, "source_file": "./1_instance_27_get_called_class.php", "source_line": 17, "expectation": true diff --git a/PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.php b/PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.php index fea0bb4..ae7e586 100644 --- a/PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.php +++ b/PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.php @@ -1,18 +1,19 @@ + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=9, args=0, vars=2, tmps=5) + ; (before optimizer) + ; /.../PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.php:1-19 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 INIT_STATIC_METHOD_CALL 1 string("B") string("test") +0004 SEND_VAR CV0($b) 1 +0005 V5 = DO_UCALL +0006 ASSIGN CV1($a) V5 +0007 ECHO CV1($a) +0008 RETURN int(1) + +A::who: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN string("safe") +0002 RETURN null + +A::test: + ; (lines=8, args=1, vars=1, tmps=3) + ; (before optimizer) + ; /.../PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.php:6-8 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 T1 = GET_CALLED_CLASS +0002 V2 = FETCH_CLASS (exception) T1 +0003 INIT_STATIC_METHOD_CALL 1 V2 string("who") +0004 SEND_VAR_EX CV0($b) 1 +0005 V3 = DO_FCALL +0006 RETURN V3 +0007 RETURN null + +B::who: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/27_get_called_class/1_instance_27_get_called_class/1_instance_27_get_called_class.php:12-14 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN CV0($b) +0002 RETURN null +``` + +
+ +
+ + +### Discovery + + +The rule searches for the opcode `GET_CALLED_CLASS`. + +```scala +val x27 = (name, "27_get_called_class_iall", cpg.call(".*GET_CALLED_CLASS.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | no | no | no | yes | +| 17 May 2023 | no | | | | | | yes | + +
+ + diff --git a/PHP/27_get_called_class/docs/description.md b/PHP/27_get_called_class/docs/description.md new file mode 100644 index 0000000..3a9c7e8 --- /dev/null +++ b/PHP/27_get_called_class/docs/description.md @@ -0,0 +1 @@ +In PHP `get_called_class` gets the class the static method is called in. \ No newline at end of file diff --git a/PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.bash b/PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.bash index f463ea5..ec80e1b 100644 --- a/PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.bash +++ b/PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.bash @@ -1,36 +1,34 @@ -$_main: ; (lines=11, args=0, vars=0, tmps=4) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/46_static_methods/46_static_methods.php:1-16 -L0 (4): NOP -L1 (14): EXT_STMT -L2 (14): T1 = FETCH_R (global) string("_GET") -L3 (14): T2 = FETCH_DIM_R T1 string("p1") -L4 (14): ASSIGN_STATIC_PROP string("b") string("Foo") -L5 (14): OP_DATA T2 -L6 (15): EXT_STMT -L7 (15): INIT_STATIC_METHOD_CALL 0 string("Foo") string("baz") -L8 (15): V3 = DO_FCALL -L9 (15): ECHO V3 -L10 (16): RETURN int(1) +$_main: + ; (lines=9, args=0, vars=1, tmps=5) + ; (before optimizer) + ; /.../PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.php:1-15 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN_STATIC_PROP string("b") string("Foo") +0003 OP_DATA T3 +0004 INIT_STATIC_METHOD_CALL 0 string("Foo") string("baz") +0005 V4 = DO_UCALL +0006 ASSIGN CV0($a) V4 +0007 ECHO CV0($a) +0008 RETURN int(1) -Foo::__construct: ; (lines=7, args=1, vars=1, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/46_static_methods/46_static_methods.php:5-7 -L0 (5): EXT_NOP -L1 (5): CV0($b) = RECV 1 -L2 (6): EXT_STMT -L3 (6): ASSIGN_STATIC_PROP string("b") -L4 (6): OP_DATA CV0($b) -L5 (7): EXT_STMT -L6 (7): RETURN null +Foo::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_STATIC_PROP string("b") +0002 OP_DATA CV0($b) +0003 RETURN null -Foo::baz: ; (lines=6, args=0, vars=0, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/46_static_methods/46_static_methods.php:8-12 -L0 (8): EXT_NOP -L1 (11): EXT_STMT -L2 (11): T0 = FETCH_STATIC_PROP_R string("b") (self) (exception) -L3 (11): ECHO T0 -L4 (12): EXT_STMT -L5 (12): RETURN null +Foo::baz: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.php:7-10 + ; return [] RANGE[0..0] +0000 T0 = FETCH_STATIC_PROP_R string("b") (self) (exception) +0001 RETURN T0 +0002 RETURN null diff --git a/PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.json b/PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.json index f5ece33..240baac 100644 --- a/PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.json +++ b/PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.json @@ -1,4 +1,5 @@ { + "description": "The instance demonstrates the use of a static function in PHP.", "code": { "path": "./1_instance_28_static_methods.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_28_static_methods.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "FP", + "notes": "The rule searches for `INIT_STATIC_METHOD_CALL` in the opcode." }, "compile": { "binary": "./1_instance_28_static_methods.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_28_static_methods.php", - "sink_line": 11, + "sink_line": 14, "source_file": "./1_instance_28_static_methods.php", - "source_line": 14, + "source_line": 12, "expectation": true }, "properties": { diff --git a/PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.php b/PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.php index 6e1ae20..8a12948 100644 --- a/PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.php +++ b/PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.php @@ -1,15 +1,14 @@ + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=9, args=0, vars=1, tmps=5) + ; (before optimizer) + ; /.../PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.php:1-15 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN_STATIC_PROP string("b") string("Foo") +0003 OP_DATA T3 +0004 INIT_STATIC_METHOD_CALL 0 string("Foo") string("baz") +0005 V4 = DO_UCALL +0006 ASSIGN CV0($a) V4 +0007 ECHO CV0($a) +0008 RETURN int(1) + +Foo::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_STATIC_PROP string("b") +0002 OP_DATA CV0($b) +0003 RETURN null + +Foo::baz: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/28_static_methods/1_instance_28_static_methods/1_instance_28_static_methods.php:7-10 + ; return [] RANGE[0..0] +0000 T0 = FETCH_STATIC_PROP_R string("b") (self) (exception) +0001 RETURN T0 +0002 RETURN null +``` + +
+ +
+ + +### Discovery + + +The rule searches for `INIT_STATIC_METHOD_CALL` in the opcode. + +```scala +val x28 = (name, "28_static_methods_iall", cpg.call(".*INIT_STATIC_METHOD_CALL.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | yes | no | no | yes | +| 17 May 2023 | yes | no | | | | | yes | + +
+ + diff --git a/PHP/28_static_methods/docs/description.md b/PHP/28_static_methods/docs/description.md new file mode 100644 index 0000000..3b428ac --- /dev/null +++ b/PHP/28_static_methods/docs/description.md @@ -0,0 +1 @@ +In PHP the Scope Resolution Operator (`::`) can be used to access static methods or variables. This pattern targets to capture static methods. \ No newline at end of file diff --git a/PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.bash b/PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.bash index aaf47d8..e59d214 100644 --- a/PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.bash +++ b/PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.bash @@ -1,41 +1,39 @@ -$_main: ; (lines=14, args=0, vars=2, tmps=7) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/47_static_properties/first_ex/first_ex.php:1-16 -L0 (4): NOP -L1 (14): EXT_STMT -L2 (14): T2 = FETCH_R (global) string("_GET") -L3 (14): T3 = FETCH_DIM_R T2 string("p1") -L4 (14): ASSIGN CV0($b) T3 -L5 (15): EXT_STMT -L6 (15): V5 = NEW 1 string("Foo") -L7 (15): SEND_VAR_EX CV0($b) 1 -L8 (15): DO_FCALL -L9 (15): ASSIGN CV1($ob) V5 -L10 (16): EXT_STMT -L11 (16): INIT_METHOD_CALL 0 CV1($ob) string("baz") -L12 (16): DO_FCALL -L13 (16): RETURN int(1) +$_main: + ; (lines=12, args=0, vars=3, tmps=8) + ; (before optimizer) + ; /.../PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.php:1-15 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($b) T4 +0003 V6 = NEW 1 string("Foo") +0004 SEND_VAR_EX CV0($b) 1 +0005 DO_FCALL +0006 ASSIGN CV1($ob) V6 +0007 INIT_METHOD_CALL 0 CV1($ob) string("baz") +0008 V9 = DO_FCALL +0009 ASSIGN CV2($a) V9 +0010 ECHO CV2($a) +0011 RETURN int(1) LIVE RANGES: - 5: L7 - L9 (new) + 6: 0004 - 0006 (new) -Foo::__construct: ; (lines=7, args=1, vars=1, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/47_static_properties/first_ex/first_ex.php:5-7 -L0 (5): EXT_NOP -L1 (5): CV0($b) = RECV 1 -L2 (6): EXT_STMT -L3 (6): ASSIGN_STATIC_PROP string("b") -L4 (6): OP_DATA CV0($b) -L5 (7): EXT_STMT -L6 (7): RETURN null +Foo::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_STATIC_PROP string("b") +0002 OP_DATA CV0($b) +0003 RETURN null -Foo::baz: ; (lines=6, args=0, vars=0, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/47_static_properties/first_ex/first_ex.php:8-12 -L0 (8): EXT_NOP -L1 (11): EXT_STMT -L2 (11): T0 = FETCH_STATIC_PROP_R string("b") (self) (exception) -L3 (11): ECHO T0 -L4 (12): EXT_STMT -L5 (12): RETURN null +Foo::baz: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.php:7-10 + ; return [] RANGE[0..0] +0000 T0 = FETCH_STATIC_PROP_R string("b") (self) (exception) +0001 RETURN T0 +0002 RETURN null diff --git a/PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.json b/PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.json index fdcad25..93b3675 100644 --- a/PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.json +++ b/PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.json @@ -1,4 +1,5 @@ { + "description": "This instance uses static properties.", "code": { "path": "./1_instance_29_static_properties.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_29_static_properties.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "FP", + "notes": "The rule searches for different posibilities one has to initialize static properties." }, "compile": { "binary": "./1_instance_29_static_properties.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_29_static_properties.php", - "sink_line": 11, + "sink_line": 15, "source_file": "./1_instance_29_static_properties.php", - "source_line": 14, + "source_line": 12, "expectation": true }, "properties": { diff --git a/PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.php b/PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.php index d4015ea..120df5e 100644 --- a/PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.php +++ b/PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.php @@ -1,16 +1,15 @@ baz(); \ No newline at end of file +$a = $ob->baz(); +echo $a; // sink \ No newline at end of file diff --git a/PHP/29_static_properties/29_static_properties.json b/PHP/29_static_properties/29_static_properties.json index 1163116..b68cda0 100644 --- a/PHP/29_static_properties/29_static_properties.json +++ b/PHP/29_static_properties/29_static_properties.json @@ -1,6 +1,6 @@ { "name": "Static Properties", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_29_static_properties/1_instance_29_static_properties.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/29_static_properties/README.md b/PHP/29_static_properties/README.md new file mode 100644 index 0000000..1c4cb3c --- /dev/null +++ b/PHP/29_static_properties/README.md @@ -0,0 +1,133 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Static Properties + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +In PHP Scope Resolution Operator (`::`) can be used to access static methods or variables. This pattern targets to capture static variables. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +This instance uses static properties. + +### Code + +```PHP +baz(); +echo $a; // sink +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=12, args=0, vars=3, tmps=8) + ; (before optimizer) + ; /.../PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.php:1-15 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($b) T4 +0003 V6 = NEW 1 string("Foo") +0004 SEND_VAR_EX CV0($b) 1 +0005 DO_FCALL +0006 ASSIGN CV1($ob) V6 +0007 INIT_METHOD_CALL 0 CV1($ob) string("baz") +0008 V9 = DO_FCALL +0009 ASSIGN CV2($a) V9 +0010 ECHO CV2($a) +0011 RETURN int(1) +LIVE RANGES: + 6: 0004 - 0006 (new) + +Foo::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_STATIC_PROP string("b") +0002 OP_DATA CV0($b) +0003 RETURN null + +Foo::baz: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/29_static_properties/1_instance_29_static_properties/1_instance_29_static_properties.php:7-10 + ; return [] RANGE[0..0] +0000 T0 = FETCH_STATIC_PROP_R string("b") (self) (exception) +0001 RETURN T0 +0002 RETURN null +``` + +
+ +
+ + +### Discovery + + +The rule searches for different posibilities one has to initialize static properties. + +```scala +val x29 = (name, "29_static_properties_iall", cpg.call(".*ASSIGN_STATIC_PROP.*|.*FETCH_STATIC_PROP_R.*|.*FETCH_STATIC_PROP_W.*|.*FETCH_STATIC_PROP_RW.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | yes | no | no | yes | +| 17 May 2023 | yes | no | | | | | yes | + +
+ +
diff --git a/PHP/29_static_properties/docs/description.md b/PHP/29_static_properties/docs/description.md new file mode 100644 index 0000000..d7417b9 --- /dev/null +++ b/PHP/29_static_properties/docs/description.md @@ -0,0 +1 @@ +In PHP Scope Resolution Operator (`::`) can be used to access static methods or variables. This pattern targets to capture static variables. \ No newline at end of file diff --git a/PHP/2_global_variables/1_instance_2_global_variables/1_instance_2_global_variables.bash b/PHP/2_global_variables/1_instance_2_global_variables/1_instance_2_global_variables.bash index 873be5f..d390268 100644 --- a/PHP/2_global_variables/1_instance_2_global_variables/1_instance_2_global_variables.bash +++ b/PHP/2_global_variables/1_instance_2_global_variables/1_instance_2_global_variables.bash @@ -1,29 +1,25 @@ -$_main: ; (lines=13, args=0, vars=2, tmps=5) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/3_global_variables/3_global_variables.php:1-11 -L0 (2): EXT_STMT -L1 (2): ASSIGN CV0($result) string("") -L2 (8): EXT_STMT -L3 (8): T3 = FETCH_R (global) string("_GET") -L4 (8): T4 = FETCH_DIM_R T3 string("p1") -L5 (8): ASSIGN CV1($words) T4 -L6 (9): EXT_STMT -L7 (9): INIT_FCALL 1 128 string("f") -L8 (9): SEND_VAR CV1($words) 1 -L9 (9): DO_FCALL -L10 (11): EXT_STMT -L11 (11): ECHO CV0($result) -L12 (11): RETURN int(1) +$_main: + ; (lines=9, args=0, vars=2, tmps=5) + ; (before optimizer) + ; /.../PHP/2_global_variables/1_instance_2_global_variables/1_instance_2_global_variables.php:1-11 + ; return [] RANGE[0..0] +0000 ASSIGN CV0($result) string("") +0001 T3 = FETCH_R (global) string("_GET") +0002 T4 = FETCH_DIM_R T3 string("p1") +0003 ASSIGN CV1($words) T4 +0004 INIT_FCALL 1 128 string("f") +0005 SEND_VAR CV1($words) 1 +0006 DO_UCALL +0007 ECHO CV0($result) +0008 RETURN int(1) -F: ; (lines=8, args=1, vars=2, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/3_global_variables/3_global_variables.php:3-7 -L0 (3): EXT_NOP -L1 (3): CV0($word) = RECV 1 -L2 (4): EXT_STMT -L3 (4): BIND_GLOBAL CV1($result) string("result") -L4 (6): EXT_STMT -L5 (6): ASSIGN CV1($result) CV0($word) -L6 (7): EXT_STMT -L7 (7): RETURN null +F: + ; (lines=4, args=1, vars=2, tmps=1) + ; (before optimizer) + ; /.../PHP/2_global_variables/1_instance_2_global_variables/1_instance_2_global_variables.php:3-7 + ; return [] RANGE[0..0] +0000 CV0($word) = RECV 1 +0001 BIND_GLOBAL CV1($result) string("result") +0002 ASSIGN CV1($result) CV0($word) +0003 RETURN null diff --git a/PHP/2_global_variables/1_instance_2_global_variables/1_instance_2_global_variables.json b/PHP/2_global_variables/1_instance_2_global_variables/1_instance_2_global_variables.json index 374f154..9d41c6a 100644 --- a/PHP/2_global_variables/1_instance_2_global_variables/1_instance_2_global_variables.json +++ b/PHP/2_global_variables/1_instance_2_global_variables/1_instance_2_global_variables.json @@ -1,4 +1,5 @@ { + "description": "This instance should capture the use of global variables in a function.", "code": { "path": "./1_instance_2_global_variables.php", "injection_skeleton_broken": false diff --git a/PHP/2_global_variables/README.md b/PHP/2_global_variables/README.md index 59fe586..b26474e 100644 --- a/PHP/2_global_variables/README.md +++ b/PHP/2_global_variables/README.md @@ -1,89 +1,115 @@ -# Pattern: Global Variables -This pattern targets `global` variables. Global variables may be challenging for SAST tools: if an attacker controlled value ends-up in a global variable in a program scope, is a SAST tool able to properly propagate that information to other scopes? +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Global Variables + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 -## Category +## Description -Variables +This pattern targets `global` variables. Global variables may be challenging for SAST tools: if an attacker controlled value ends-up in a global variable in a program scope, is a SAST tool able to properly propagate that information to other scopes? + +## Overview -## Definition +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | -## Instances +## 1 Instance -### Instance 1 +This instance should capture the use of global variables in a function. -- CATEGORY: S0 -- FEATURE vs INTERNAL API: FEATURE -- INPUT SANITIZERS: NO -- SOURCES AND SINKS: NO -- NEGATIVE TEST CASES: NO -- CODE: +### Code -```php +```PHP + +More -```bash -$_main: ; (lines=13, args=0, vars=2, tmps=5) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/3_global_variables/3_global_variables.php:1-11 -L0 (2): EXT_STMT -L1 (2): ASSIGN CV0($result) string("") -L2 (8): EXT_STMT -L3 (8): T3 = FETCH_R (global) string("_GET") -L4 (8): T4 = FETCH_DIM_R T3 string("p1") -L5 (8): ASSIGN CV1($words) T4 -L6 (9): EXT_STMT -L7 (9): INIT_FCALL 1 128 string("f") -L8 (9): SEND_VAR CV1($words) 1 -L9 (9): DO_FCALL -L10 (11): EXT_STMT -L11 (11): ECHO CV0($result) -L12 (11): RETURN int(1) - -F: ; (lines=8, args=1, vars=2, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/3_global_variables/3_global_variables.php:3-7 -L0 (3): EXT_NOP -L1 (3): CV0($word) = RECV 1 -L2 (4): EXT_STMT -L3 (4): BIND_GLOBAL CV1($result) string("result") -L4 (6): EXT_STMT -L5 (6): ASSIGN CV1($result) CV0($word) -L6 (7): EXT_STMT -L7 (7): RETURN null -``` +
+ -- DISCOVERY: +### Compile + ```bash -cpg.call(".*BIND_GLOBAL.*").location.l +$_main: + ; (lines=9, args=0, vars=2, tmps=5) + ; (before optimizer) + ; /.../PHP/2_global_variables/1_instance_2_global_variables/1_instance_2_global_variables.php:1-11 + ; return [] RANGE[0..0] +0000 ASSIGN CV0($result) string("") +0001 T3 = FETCH_R (global) string("_GET") +0002 T4 = FETCH_DIM_R T3 string("p1") +0003 ASSIGN CV1($words) T4 +0004 INIT_FCALL 1 128 string("f") +0005 SEND_VAR CV1($words) 1 +0006 DO_UCALL +0007 ECHO CV0($result) +0008 RETURN int(1) + +F: + ; (lines=4, args=1, vars=2, tmps=1) + ; (before optimizer) + ; /.../PHP/2_global_variables/1_instance_2_global_variables/1_instance_2_global_variables.php:3-7 + ; return [] RANGE[0..0] +0000 CV0($word) = RECV 1 +0001 BIND_GLOBAL CV1($result) string("result") +0002 ASSIGN CV1($result) CV0($word) +0003 RETURN null ``` -- PRECONDITIONS: - 1. +
-- TRANSFORMATION: +
+ -``` +### Discovery + + +ideal rule should looking for `global` variables used in a function +```scala +val x2 = (name, "2_global_variables_iall", cpg.call(".*BIND_GLOBAL.*").location.toJson); ``` +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | yes | yes | no | no | no | yes | +| 17 May 2023 | yes | yes | | | | | yes | + +
+ + diff --git a/PHP/30_anonymous_classes/1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.bash b/PHP/30_anonymous_classes/1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.bash index 1c4d043..91837f9 100644 --- a/PHP/30_anonymous_classes/1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.bash +++ b/PHP/30_anonymous_classes/1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.bash @@ -1,30 +1,30 @@ -$_main: ; (lines=14, args=0, vars=2, tmps=8) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/68_anonymous_classes/68_anonymous_classes.php:1-10 -L0 (2): EXT_STMT -L1 (2): T2 = FETCH_R (global) string("_GET") -L2 (2): T3 = FETCH_DIM_R T2 string("p1") -L3 (2): ASSIGN CV0($b) T3 -L4 (3): EXT_STMT -L5 (3): V5 = DECLARE_ANON_CLASS string("class@anonymous") -L6 (3): V6 = NEW 0 V5 -L7 (3): DO_FCALL -L8 (3): ASSIGN CV1($util) V6 -L9 (10): EXT_STMT -L10 (10): INIT_METHOD_CALL 1 CV1($util) string("log") -L11 (10): SEND_VAR_EX CV0($b) 1 -L12 (10): DO_FCALL -L13 (10): RETURN int(1) +$_main: + ; (lines=13, args=0, vars=3, tmps=9) + ; (before optimizer) + ; /.../PHP/30_anonymous_classes/1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.php:1-10 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($b) T4 +0003 V6 = DECLARE_ANON_CLASS string("class@anonymous") +0004 V7 = NEW 0 V6 +0005 DO_FCALL +0006 ASSIGN CV1($util) V7 +0007 INIT_METHOD_CALL 1 CV1($util) string("log") +0008 SEND_VAR_EX CV0($b) 1 +0009 V10 = DO_FCALL +0010 ASSIGN CV2($a) V10 +0011 ECHO CV2($a) +0012 RETURN int(1) LIVE RANGES: - 6: L7 - L8 (new) + 7: 0005 - 0006 (new) -class@anonymous::log: ; (lines=6, args=1, vars=1, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/68_anonymous_classes/68_anonymous_classes.php:4-7 -L0 (4): EXT_NOP -L1 (4): CV0($msg) = RECV 1 -L2 (6): EXT_STMT -L3 (6): ECHO CV0($msg) -L4 (7): EXT_STMT -L5 (7): RETURN null +class@anonymous::log: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/30_anonymous_classes/1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($msg) = RECV 1 +0001 RETURN CV0($msg) +0002 RETURN null diff --git a/PHP/30_anonymous_classes/1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.json b/PHP/30_anonymous_classes/1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.json index c3772f1..489a166 100644 --- a/PHP/30_anonymous_classes/1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.json +++ b/PHP/30_anonymous_classes/1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.json @@ -1,4 +1,5 @@ { + "description": "This instance demonstrates the use of anonymous classes.", "code": { "path": "./1_instance_30_anonymous_classes.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_30_anonymous_classes.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "Perfect", + "notes": "The opecode searches for `DECLARE_ANON_CLASS` in the opcode." }, "compile": { "binary": "./1_instance_30_anonymous_classes.bash", @@ -17,7 +18,7 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_30_anonymous_classes.php", - "sink_line": 6, + "sink_line": 10, "source_file": "./1_instance_30_anonymous_classes.php", "source_line": 2, "expectation": true @@ -30,7 +31,7 @@ "negative_test_case": false }, "remediation": { - "notes": "", + "notes": "If named classes are easier for SAST tools, it should be possible to transform an anonymous class into a named class.", "transformation": null, "modeling_rule": null } diff --git a/PHP/30_anonymous_classes/1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.php b/PHP/30_anonymous_classes/1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.php index 33b8cf4..aed7328 100644 --- a/PHP/30_anonymous_classes/1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.php +++ b/PHP/30_anonymous_classes/1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.php @@ -1,10 +1,10 @@ log($b); \ No newline at end of file +$a = $util->log($b); +echo $a; // sink \ No newline at end of file diff --git a/PHP/30_anonymous_classes/30_anonymous_classes.json b/PHP/30_anonymous_classes/30_anonymous_classes.json index acd0ef6..5296b5f 100644 --- a/PHP/30_anonymous_classes/30_anonymous_classes.json +++ b/PHP/30_anonymous_classes/30_anonymous_classes.json @@ -1,6 +1,6 @@ { "name": "Anonymous Classes", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/30_anonymous_classes/README.md b/PHP/30_anonymous_classes/README.md new file mode 100644 index 0000000..22f017e --- /dev/null +++ b/PHP/30_anonymous_classes/README.md @@ -0,0 +1,129 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Anonymous Classes + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +Anonymous classes are classes without a specific name. They can be useful for one-off objects. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +This instance demonstrates the use of anonymous classes. + +### Code + +```PHP +log($b); +echo $a; // sink +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=13, args=0, vars=3, tmps=9) + ; (before optimizer) + ; /.../PHP/30_anonymous_classes/1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.php:1-10 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($b) T4 +0003 V6 = DECLARE_ANON_CLASS string("class@anonymous") +0004 V7 = NEW 0 V6 +0005 DO_FCALL +0006 ASSIGN CV1($util) V7 +0007 INIT_METHOD_CALL 1 CV1($util) string("log") +0008 SEND_VAR_EX CV0($b) 1 +0009 V10 = DO_FCALL +0010 ASSIGN CV2($a) V10 +0011 ECHO CV2($a) +0012 RETURN int(1) +LIVE RANGES: + 7: 0005 - 0006 (new) + +class@anonymous::log: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/30_anonymous_classes/1_instance_30_anonymous_classes/1_instance_30_anonymous_classes.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($msg) = RECV 1 +0001 RETURN CV0($msg) +0002 RETURN null +``` + +
+ +
+ + +### Discovery + + +The opecode searches for `DECLARE_ANON_CLASS` in the opcode. + +```scala +val x30 = (name, "30_anonymous_classes_iall", cpg.call(".*DECLARE_ANON_CLASS.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | yes | no | no | no | no | yes | +| 17 May 2023 | yes | yes | | | | | yes | + +
+ +
+ + +### Remediation + + +If named classes are easier for SAST tools, it should be possible to transform an anonymous class into a named class. + +
+ +
diff --git a/PHP/30_anonymous_classes/docs/description.md b/PHP/30_anonymous_classes/docs/description.md new file mode 100644 index 0000000..0d5f24d --- /dev/null +++ b/PHP/30_anonymous_classes/docs/description.md @@ -0,0 +1 @@ +Anonymous classes are classes without a specific name. They can be useful for one-off objects. \ No newline at end of file diff --git a/PHP/31_static_method_variable/1_instance_31_static_method_variable/1_instance_31_static_method_variable.bash b/PHP/31_static_method_variable/1_instance_31_static_method_variable/1_instance_31_static_method_variable.bash new file mode 100644 index 0000000..5eff9b3 --- /dev/null +++ b/PHP/31_static_method_variable/1_instance_31_static_method_variable/1_instance_31_static_method_variable.bash @@ -0,0 +1,25 @@ + +$_main: + ; (lines=10, args=0, vars=3, tmps=6) + ; (before optimizer) + ; /.../PHP/31_static_method_variable/1_instance_31_static_method_variable/1_instance_31_static_method_variable.php:1-12 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($a) T4 +0003 ASSIGN CV1($func) string("F") +0004 INIT_STATIC_METHOD_CALL 1 string("myclass") CV1($func) +0005 SEND_VAR_EX CV0($a) 1 +0006 V7 = DO_FCALL +0007 ASSIGN CV2($b) V7 +0008 ECHO CV2($b) +0009 RETURN int(1) + +myclass::F: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/31_static_method_variable/1_instance_31_static_method_variable/1_instance_31_static_method_variable.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN CV0($b) +0002 RETURN null diff --git a/PHP/31_static_method_variable/1_instance_31_static_method_variable/1_instance_31_static_method_variable.json b/PHP/31_static_method_variable/1_instance_31_static_method_variable/1_instance_31_static_method_variable.json index af7b917..7e6bc5d 100644 --- a/PHP/31_static_method_variable/1_instance_31_static_method_variable/1_instance_31_static_method_variable.json +++ b/PHP/31_static_method_variable/1_instance_31_static_method_variable/1_instance_31_static_method_variable.json @@ -1,4 +1,5 @@ { + "description": "This instance shows the use of a static function.", "code": { "path": "./1_instance_31_static_method_variable.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_31_static_method_variable.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "FP", + "notes": "The rule searches for `INIT_STATIC_METHOD_CALL` in opcode, where one argument is a variable." }, "compile": { "binary": "./1_instance_31_static_method_variable.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_31_static_method_variable.php", - "sink_line": 6, + "sink_line": 11, "source_file": "./1_instance_31_static_method_variable.php", - "source_line": 10, + "source_line": 8, "expectation": true }, "properties": { diff --git a/PHP/31_static_method_variable/1_instance_31_static_method_variable/1_instance_31_static_method_variable.php b/PHP/31_static_method_variable/1_instance_31_static_method_variable/1_instance_31_static_method_variable.php index 5398b28..38a47de 100644 --- a/PHP/31_static_method_variable/1_instance_31_static_method_variable/1_instance_31_static_method_variable.php +++ b/PHP/31_static_method_variable/1_instance_31_static_method_variable/1_instance_31_static_method_variable.php @@ -1,13 +1,11 @@ + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=10, args=0, vars=3, tmps=6) + ; (before optimizer) + ; /.../PHP/31_static_method_variable/1_instance_31_static_method_variable/1_instance_31_static_method_variable.php:1-12 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($a) T4 +0003 ASSIGN CV1($func) string("F") +0004 INIT_STATIC_METHOD_CALL 1 string("myclass") CV1($func) +0005 SEND_VAR_EX CV0($a) 1 +0006 V7 = DO_FCALL +0007 ASSIGN CV2($b) V7 +0008 ECHO CV2($b) +0009 RETURN int(1) + +myclass::F: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/31_static_method_variable/1_instance_31_static_method_variable/1_instance_31_static_method_variable.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN CV0($b) +0002 RETURN null +``` + +
+ +
+ + +### Discovery + + +The rule searches for `INIT_STATIC_METHOD_CALL` in opcode, where one argument is a variable. + +```scala +val x31 = (name, "31_static_method_variable_iall", cpg.call(".*INIT_STATIC_METHOD_CALL.*").argument.order(2).code("CV.*|T.*|V.*").astParent.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | no | no | no | yes | +| 17 May 2023 | no | yes | | | | | yes | + +
+ + diff --git a/PHP/31_static_method_variable/docs/description.md b/PHP/31_static_method_variable/docs/description.md new file mode 100644 index 0000000..39ab77f --- /dev/null +++ b/PHP/31_static_method_variable/docs/description.md @@ -0,0 +1 @@ +In PHP a static method can be stored in a variable and than be called from that variable. \ No newline at end of file diff --git a/PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.bash b/PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.bash index 9b6d183..f20e857 100644 --- a/PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.bash +++ b/PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.bash @@ -1,30 +1,27 @@ -$_main: ; (lines=13, args=0, vars=2, tmps=7) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/29_set_overloading/29_set_overloading.php:1-12 -L0 (3): NOP -L1 (10): EXT_STMT -L2 (10): T2 = FETCH_R (global) string("_GET") -L3 (10): T3 = FETCH_DIM_R T2 string("p1") -L4 (10): ASSIGN CV0($b) T3 -L5 (11): EXT_STMT -L6 (11): V5 = NEW 0 string("PropertyTest") -L7 (11): DO_FCALL -L8 (11): ASSIGN CV1($obj) V5 -L9 (12): EXT_STMT -L10 (12): ASSIGN_OBJ CV1($obj) string("var") -L11 (12): OP_DATA CV0($b) -L12 (12): RETURN int(1) +$_main: + ; (lines=9, args=0, vars=2, tmps=7) + ; (before optimizer) + ; /.../PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.php:1-12 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 ASSIGN_OBJ CV1($obj) string("var") +0007 OP_DATA CV0($b) +0008 RETURN int(1) LIVE RANGES: - 5: L7 - L8 (new) + 5: 0004 - 0005 (new) -PropertyTest::__set: ; (lines=7, args=2, vars=2, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/29_set_overloading/29_set_overloading.php:5-7 -L0 (5): EXT_NOP -L1 (5): CV0($name) = RECV 1 -L2 (5): CV1($value) = RECV 2 -L3 (6): EXT_STMT -L4 (6): ECHO CV1($value) -L5 (7): EXT_STMT -L6 (7): RETURN null +PropertyTest::__set: + ; (lines=4, args=2, vars=2, tmps=0) + ; (before optimizer) + ; /.../PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 CV1($value) = RECV 2 +0002 ECHO CV1($value) +0003 RETURN null diff --git a/PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.json b/PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.json index a0af71b..f6a12d7 100644 --- a/PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.json +++ b/PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.json @@ -1,13 +1,14 @@ { + "description": "The instance shows, that writing data to the existing but private variable `var` of `obj` triggers `__set` to be called, which is vulnerable.", "code": { "path": "./1_instance_32_set_overloading.php", - "injection_skeleton_broken": false + "injection_skeleton_broken": true }, "discovery": { - "rule": "./1_instance_32_set_overloading.sc", + "rule": "../32_set_overloading.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "FP", + "notes": "../docs/discovery_notes.md" }, "compile": { "binary": "./1_instance_32_set_overloading.bash", diff --git a/PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.php b/PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.php index d1b68c9..cf8f59f 100644 --- a/PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.php +++ b/PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.php @@ -1,12 +1,12 @@ var = $b; \ No newline at end of file diff --git a/PHP/32_set_overloading/2_instance_32_set_overloading/2_instance_32_set_overloading.bash b/PHP/32_set_overloading/2_instance_32_set_overloading/2_instance_32_set_overloading.bash new file mode 100644 index 0000000..07729d6 --- /dev/null +++ b/PHP/32_set_overloading/2_instance_32_set_overloading/2_instance_32_set_overloading.bash @@ -0,0 +1,27 @@ + +$_main: + ; (lines=9, args=0, vars=2, tmps=7) + ; (before optimizer) + ; /.../PHP/32_set_overloading/2_instance_32_set_overloading/2_instance_32_set_overloading.php:1-12 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 ASSIGN_OBJ CV1($obj) string("x") +0007 OP_DATA CV0($b) +0008 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::__set: + ; (lines=4, args=2, vars=2, tmps=0) + ; (before optimizer) + ; /.../PHP/32_set_overloading/2_instance_32_set_overloading/2_instance_32_set_overloading.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 CV1($value) = RECV 2 +0002 ECHO CV1($value) +0003 RETURN null diff --git a/PHP/32_set_overloading/2_instance_32_set_overloading/2_instance_32_set_overloading.json b/PHP/32_set_overloading/2_instance_32_set_overloading/2_instance_32_set_overloading.json new file mode 100644 index 0000000..591b37b --- /dev/null +++ b/PHP/32_set_overloading/2_instance_32_set_overloading/2_instance_32_set_overloading.json @@ -0,0 +1,38 @@ +{ + "description": "This instance shows, that writing data to the non-existing variable `x` of the object `obj` will invoke the `__set` function.", + "code": { + "path": "./2_instance_32_set_overloading.php", + "injection_skeleton_broken": true + }, + "expectation": { + "type": "xss", + "sink_file": "./2_instance_32_set_overloading.php", + "sink_line": 6, + "source_file": "./2_instance_32_set_overloading.php", + "source_line": 10, + "expectation": true + }, + "compile": { + "binary": "./2_instance_32_set_overloading.bash", + "instruction": null, + "dependencies": null + }, + "discovery": { + "rule": "../32_set_overloading.sc", + "method": "joern", + "rule_accuracy": "FP", + "notes": "../docs/discovery_notes.md" + }, + "properties": { + "category": "S0", + "feature_vs_internal_api": "FEATURE", + "input_sanitizer": false, + "source_and_sink": false, + "negative_test_case": false + }, + "remediation": { + "notes": "", + "transformation": null, + "modeling_rule": null + } +} \ No newline at end of file diff --git a/PHP/32_set_overloading/2_instance_32_set_overloading/2_instance_32_set_overloading.php b/PHP/32_set_overloading/2_instance_32_set_overloading/2_instance_32_set_overloading.php new file mode 100644 index 0000000..fb85718 --- /dev/null +++ b/PHP/32_set_overloading/2_instance_32_set_overloading/2_instance_32_set_overloading.php @@ -0,0 +1,12 @@ +x = $b; \ No newline at end of file diff --git a/PHP/32_set_overloading/32_set_overloading.json b/PHP/32_set_overloading/32_set_overloading.json index f81ee57..9c68f72 100644 --- a/PHP/32_set_overloading/32_set_overloading.json +++ b/PHP/32_set_overloading/32_set_overloading.json @@ -1,6 +1,6 @@ { "name": "Set Overloading", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -8,7 +8,8 @@ "php_v7.4.9" ], "instances": [ - "./1_instance_32_set_overloading/1_instance_32_set_overloading.json" + "./1_instance_32_set_overloading/1_instance_32_set_overloading.json", + "./2_instance_32_set_overloading/2_instance_32_set_overloading.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.sc b/PHP/32_set_overloading/32_set_overloading.sc similarity index 50% rename from PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.sc rename to PHP/32_set_overloading/32_set_overloading.sc index b0c7a1c..3649828 100644 --- a/PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.sc +++ b/PHP/32_set_overloading/32_set_overloading.sc @@ -1,7 +1,7 @@ @main def main(name : String): Unit = { importCpg(name) - def methods1 = cpg.method.name("__set").name.l - val x32 = (name, "32_set_overloading_iall", cpg.call("NEW").argument.filter{x => methods1.contains(x.code.toLowerCase)}.location.toJson); + def methodClasses = cpg.method.name("__set").astParentFullName.l + val x32 = (name, "32_set_overloading_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); println(x32) delete; } \ No newline at end of file diff --git a/PHP/32_set_overloading/README.md b/PHP/32_set_overloading/README.md new file mode 100644 index 0000000..9e3ef55 --- /dev/null +++ b/PHP/32_set_overloading/README.md @@ -0,0 +1,237 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Set Overloading + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +In many object-oriented programming languages overloading provides the ability of having multiple methods with the same name but different quantities and types of arguments. In PHP however [Overloading](https://www.php.net/manual/en/language.oop5.overloading.php) describes the concept of dynamically creating properties and methods. This pattern targets the usage of property overloading for `__set()`. This method is run when data is written to inaccessible (protected or private) or non-existing properties. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | +| [2 Instance](#2-instance) | yes | joern | yes | + +
+ + +## 1 Instance + + +The instance shows, that writing data to the existing but private variable `var` of `obj` triggers `__set` to be called, which is vulnerable. + +### Code + +```PHP +var = $b; +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=9, args=0, vars=2, tmps=7) + ; (before optimizer) + ; /.../PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.php:1-12 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 ASSIGN_OBJ CV1($obj) string("var") +0007 OP_DATA CV0($b) +0008 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::__set: + ; (lines=4, args=2, vars=2, tmps=0) + ; (before optimizer) + ; /.../PHP/32_set_overloading/1_instance_32_set_overloading/1_instance_32_set_overloading.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 CV1($value) = RECV 2 +0002 ECHO CV1($value) +0003 RETURN null +``` + +
+ +
+ + +### Discovery + + +The discovery rule first gets all class names, where the method `__set` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__set` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__set` method within its lifetime. + +```scala +def methodClasses = cpg.method.name("__set").astParentFullName.l +val x32 = (name, "32_set_overloading_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | no | no | no | yes | +| 17 May 2023 | yes | no | | | | | yes | + +
+ +
+ +
+ +
+ + +## 2 Instance + + +This instance shows, that writing data to the non-existing variable `x` of the object `obj` will invoke the `__set` function. + +### Code + +```PHP +x = $b; +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=9, args=0, vars=2, tmps=7) + ; (before optimizer) + ; /.../PHP/32_set_overloading/2_instance_32_set_overloading/2_instance_32_set_overloading.php:1-12 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 ASSIGN_OBJ CV1($obj) string("x") +0007 OP_DATA CV0($b) +0008 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::__set: + ; (lines=4, args=2, vars=2, tmps=0) + ; (before optimizer) + ; /.../PHP/32_set_overloading/2_instance_32_set_overloading/2_instance_32_set_overloading.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 CV1($value) = RECV 2 +0002 ECHO CV1($value) +0003 RETURN null +``` + +
+ +
+ + +### Discovery + + +The discovery rule first gets all class names, where the method `__set` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__set` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__set` method within its lifetime. + +```scala +def methodClasses = cpg.method.name("__set").astParentFullName.l +val x32 = (name, "32_set_overloading_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | Ground Truth | +|-------------|----------|----------|----------------| +| 17 May 2023 | yes | no | yes | + +
+ +
+ +
diff --git a/PHP/32_set_overloading/docs/description.md b/PHP/32_set_overloading/docs/description.md new file mode 100644 index 0000000..d5203e0 --- /dev/null +++ b/PHP/32_set_overloading/docs/description.md @@ -0,0 +1 @@ +In many object-oriented programming languages overloading provides the ability of having multiple methods with the same name but different quantities and types of arguments. In PHP however [Overloading](https://www.php.net/manual/en/language.oop5.overloading.php) describes the concept of dynamically creating properties and methods. This pattern targets the usage of property overloading for `__set()`. This method is run when data is written to inaccessible (protected or private) or non-existing properties. \ No newline at end of file diff --git a/PHP/32_set_overloading/docs/discovery_notes.md b/PHP/32_set_overloading/docs/discovery_notes.md new file mode 100644 index 0000000..5316b0d --- /dev/null +++ b/PHP/32_set_overloading/docs/discovery_notes.md @@ -0,0 +1,3 @@ +The discovery rule first gets all class names, where the method `__set` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__set` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__set` method within its lifetime. \ No newline at end of file diff --git a/PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.bash b/PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.bash new file mode 100644 index 0000000..54a32e9 --- /dev/null +++ b/PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.bash @@ -0,0 +1,42 @@ + +$_main: + ; (lines=11, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.php:1-18 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 ASSIGN_OBJ CV1($obj) string("x") +0007 OP_DATA CV0($b) +0008 T9 = FETCH_OBJ_R CV1($obj) string("x") +0009 FREE T9 +0010 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::__set: + ; (lines=5, args=2, vars=2, tmps=1) + ; (before optimizer) + ; /.../PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 CV1($value) = RECV 2 +0002 ASSIGN_OBJ THIS CV0($name) +0003 OP_DATA CV1($value) +0004 RETURN null + +PropertyTest::__get: + ; (lines=6, args=1, vars=1, tmps=2) + ; (before optimizer) + ; /.../PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.php:9-12 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 T1 = FETCH_OBJ_R THIS CV0($name) +0002 ECHO T1 +0003 T2 = FETCH_OBJ_R THIS CV0($name) +0004 RETURN T2 +0005 RETURN null diff --git a/PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.json b/PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.json index f291fb3..88030b5 100644 --- a/PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.json +++ b/PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.json @@ -1,13 +1,14 @@ { + "description": "The instance shows overloading of the `__get` function.", "code": { "path": "./1_instance_33_get_overloading.php", - "injection_skeleton_broken": false + "injection_skeleton_broken": true }, "discovery": { "rule": "./1_instance_33_get_overloading.sc", "method": "joern", "rule_accuracy": "FP", - "notes": null + "notes": "The discovery rule first gets all class names, where the method `__get` is defined.\nAfterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__get` defined.\nThe rule would be perfect, if we could additionally check, if one of the created objects invokes the `__get` method within its lifetime." }, "compile": { "binary": "./1_instance_33_get_overloading.bash", diff --git a/PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.php b/PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.php index c432a39..d18dad5 100644 --- a/PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.php +++ b/PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.php @@ -1,18 +1,18 @@ $name = $value; } - public function __get($name){ - echo $this->$name; + public function __get($name) { + echo $this->$name; // sink return $this->$name; } } -$b = $_GET["p1"]; +$b = $_GET["p1"]; // source $obj = new PropertyTest; -$obj->var = $b; -$res = $obj->var; \ No newline at end of file +$obj->x = $b; +$obj->x; \ No newline at end of file diff --git a/PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.sc b/PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.sc index de06ad3..ee37970 100644 --- a/PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.sc +++ b/PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.sc @@ -1,7 +1,7 @@ @main def main(name : String): Unit = { importCpg(name) - def methods2 = cpg.method.name("__get").name.l - val x33 = (name, "33_get_overloading_iall", cpg.call("NEW").argument.filter{x => methods2.contains(x.code.toLowerCase)}.location.toJson); + def methodClasses = cpg.method.name("__get").astParentFullName.l + val x33 = (name, "33_get_overloading_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); println(x33) delete; } \ No newline at end of file diff --git a/PHP/33_get_overloading/33_get_overloading.json b/PHP/33_get_overloading/33_get_overloading.json index fc5ee58..3df23d3 100644 --- a/PHP/33_get_overloading/33_get_overloading.json +++ b/PHP/33_get_overloading/33_get_overloading.json @@ -1,6 +1,6 @@ { "name": "Get Overloading", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", diff --git a/PHP/33_get_overloading/README.md b/PHP/33_get_overloading/README.md new file mode 100644 index 0000000..c649590 --- /dev/null +++ b/PHP/33_get_overloading/README.md @@ -0,0 +1,142 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Get Overloading + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +In many object-oriented programming languages overloading provides the ability of having multiple methods with the same name but different quantities and types of arguments. In PHP however [Overloading](https://www.php.net/manual/en/language.oop5.overloading.php) describes the concept of dynamically creating properties and methods. This pattern targets the usage of property overloading for `__get()`. This method is run when data from inaccessible (protected or private) or non-existing properties is read. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +The instance shows overloading of the `__get` function. + +### Code + +```PHP +$name = $value; + } + + public function __get($name) { + echo $this->$name; // sink + return $this->$name; + } +} + +$b = $_GET["p1"]; // source +$obj = new PropertyTest; +$obj->x = $b; +$obj->x; +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=11, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.php:1-18 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 ASSIGN_OBJ CV1($obj) string("x") +0007 OP_DATA CV0($b) +0008 T9 = FETCH_OBJ_R CV1($obj) string("x") +0009 FREE T9 +0010 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::__set: + ; (lines=5, args=2, vars=2, tmps=1) + ; (before optimizer) + ; /.../PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 CV1($value) = RECV 2 +0002 ASSIGN_OBJ THIS CV0($name) +0003 OP_DATA CV1($value) +0004 RETURN null + +PropertyTest::__get: + ; (lines=6, args=1, vars=1, tmps=2) + ; (before optimizer) + ; /.../PHP/33_get_overloading/1_instance_33_get_overloading/1_instance_33_get_overloading.php:9-12 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 T1 = FETCH_OBJ_R THIS CV0($name) +0002 ECHO T1 +0003 T2 = FETCH_OBJ_R THIS CV0($name) +0004 RETURN T2 +0005 RETURN null +``` + +
+ +
+ + +### Discovery + + +The discovery rule first gets all class names, where the method `__get` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__get` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__get` method within its lifetime. + +```scala +def methodClasses = cpg.method.name("__get").astParentFullName.l +val x33 = (name, "33_get_overloading_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | no | no | no | yes | +| 17 May 2023 | no | no | | | | | yes | + +
+ +
diff --git a/PHP/33_get_overloading/docs/description.md b/PHP/33_get_overloading/docs/description.md new file mode 100644 index 0000000..8a5a729 --- /dev/null +++ b/PHP/33_get_overloading/docs/description.md @@ -0,0 +1 @@ +In many object-oriented programming languages overloading provides the ability of having multiple methods with the same name but different quantities and types of arguments. In PHP however [Overloading](https://www.php.net/manual/en/language.oop5.overloading.php) describes the concept of dynamically creating properties and methods. This pattern targets the usage of property overloading for `__get()`. This method is run when data from inaccessible (protected or private) or non-existing properties is read. \ No newline at end of file diff --git a/PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.bash b/PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.bash new file mode 100644 index 0000000..6355130 --- /dev/null +++ b/PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.bash @@ -0,0 +1,41 @@ + +$_main: + ; (lines=12, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.php:1-21 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 INIT_METHOD_CALL 1 CV1($obj) string("setx") +0007 SEND_VAR_EX CV0($b) 1 +0008 DO_FCALL +0009 T9 = ISSET_ISEMPTY_PROP_OBJ (isset) CV1($obj) string("x") +0010 FREE T9 +0011 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::__isset: + ; (lines=5, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.php:5-8 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 T1 = FETCH_OBJ_R THIS string("x") +0002 ECHO T1 +0003 RETURN bool(true) +0004 RETURN null + +PropertyTest::setx: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.php:10-12 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("x") +0002 OP_DATA CV0($b) +0003 RETURN null diff --git a/PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.json b/PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.json index e6c8bee..c5b90cb 100644 --- a/PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.json +++ b/PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.json @@ -1,13 +1,14 @@ { + "description": "This instance shows, that `__isset` is called, when the function `isset()` is called.", "code": { "path": "./1_instance_34_isset_overloading.php", - "injection_skeleton_broken": false + "injection_skeleton_broken": true }, "discovery": { - "rule": "./1_instance_34_isset_overloading.sc", + "rule": "../34_isset_overloading.sc", "method": "joern", "rule_accuracy": "FP", - "notes": null + "notes": "../docs/discovery_notes.md" }, "compile": { "binary": "./1_instance_34_isset_overloading.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_34_isset_overloading.php", - "sink_line": 9, + "sink_line": 6, "source_file": "./1_instance_34_isset_overloading.php", - "source_line": 19, + "source_line": 15, "expectation": true }, "properties": { diff --git a/PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.php b/PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.php index 7919218..bd4a952 100644 --- a/PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.php +++ b/PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.php @@ -1,26 +1,20 @@ x' set?\n"; + public function __isset($name) { + echo $this->x; // sink return true; } - public function setx($b) - { + public function setx($b) { $this->x = $b; } } -$b = $_GET["p1"]; +$b = $_GET["p1"]; // source $obj = new PropertyTest; $obj->setx($b); // XSS vulnerability in the function __isset() -if (isset($obj->x)) { - echo "isset called"; -} \ No newline at end of file +isset($obj->x); diff --git a/PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.sc b/PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.sc deleted file mode 100644 index 65d9552..0000000 --- a/PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.sc +++ /dev/null @@ -1,7 +0,0 @@ -@main def main(name : String): Unit = { - importCpg(name) - def methods3 = cpg.method.name("__isset").name.l - val x34 = (name, "34_isset_overloading_iall", cpg.call("NEW").argument.filter{x => methods3.contains(x.code.toLowerCase)}.location.toJson); - println(x34) - delete; -} \ No newline at end of file diff --git a/PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.bash b/PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.bash new file mode 100644 index 0000000..f0c05d1 --- /dev/null +++ b/PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.bash @@ -0,0 +1,41 @@ + +$_main: + ; (lines=12, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.php:1-20 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 INIT_METHOD_CALL 1 CV1($obj) string("setx") +0007 SEND_VAR_EX CV0($b) 1 +0008 DO_FCALL +0009 T9 = ISSET_ISEMPTY_PROP_OBJ (empty) CV1($obj) string("x") +0010 FREE T9 +0011 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::__isset: + ; (lines=5, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.php:5-8 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 T1 = FETCH_OBJ_R THIS string("x") +0002 ECHO T1 +0003 RETURN bool(true) +0004 RETURN null + +PropertyTest::setx: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.php:10-12 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("x") +0002 OP_DATA CV0($b) +0003 RETURN null diff --git a/PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.json b/PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.json index 3d767fb..a58ecdf 100644 --- a/PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.json +++ b/PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.json @@ -1,13 +1,14 @@ { + "description": "This instance shows, that `__isset` is also invoked when `empty()` is called.", "code": { "path": "./2_instance_34_isset_overloading.php", - "injection_skeleton_broken": false + "injection_skeleton_broken": true }, "discovery": { - "rule": "./2_instance_34_isset_overloading.sc", + "rule": "../34_isset_overloading.sc", "method": "joern", "rule_accuracy": "FP", - "notes": null + "notes": "../docs/discovery_notes.md" }, "compile": { "binary": "./2_instance_34_isset_overloading.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./2_instance_34_isset_overloading.php", - "sink_line": 9, + "sink_line": 6, "source_file": "./2_instance_34_isset_overloading.php", - "source_line": 19, + "source_line": 15, "expectation": true }, "properties": { diff --git a/PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.php b/PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.php index 4cca721..56b6adf 100644 --- a/PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.php +++ b/PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.php @@ -1,26 +1,20 @@ x' set?\n"; + public function __isset($name) { + echo $this->x; // sink return true; } - public function setx($b) - { + public function setx($b) { $this->x = $b; } } -$b = $_GET["p1"]; +$b = $_GET["p1"]; // source $obj = new PropertyTest; $obj->setx($b); // XSS vulnerability in the function __isset() -if (empty($obj->x)) { - echo "isset called"; -} \ No newline at end of file +empty($obj->x); \ No newline at end of file diff --git a/PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.sc b/PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.sc deleted file mode 100644 index ffe150c..0000000 --- a/PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.sc +++ /dev/null @@ -1,7 +0,0 @@ -@main def main(name : String): Unit = { - importCpg(name) - def methods3 = cpg.method.name("__set").name.l - val x34 = (name, "34_isset_overloading_iall", cpg.call("NEW").argument.filter{x => methods3.contains(x.code.toLowerCase)}.location.toJson); - println(x34) - delete; -} \ No newline at end of file diff --git a/PHP/34_isset_overloading/34_isset_overloading.json b/PHP/34_isset_overloading/34_isset_overloading.json index cc62f88..1438477 100644 --- a/PHP/34_isset_overloading/34_isset_overloading.json +++ b/PHP/34_isset_overloading/34_isset_overloading.json @@ -1,6 +1,6 @@ { "name": "Isset Overloading", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -8,7 +8,10 @@ "php_v7.4.9" ], "instances": [ - "./1_instance_34_isset_overloading/1_instance_34_isset_overloading.json" + "./1_instance_34_isset_overloading/1_instance_34_isset_overloading.json", + "./2_instance_34_isset_overloading/2_instance_34_isset_overloading.json", + "./3_instance_34_isset_overloading/3_instance_34_isset_overloading.json", + "./4_instance_34_isset_overloading/4_instance_34_isset_overloading.json" ], "version": "v1.0" } \ No newline at end of file diff --git a/PHP/34_isset_overloading/34_isset_overloading.sc b/PHP/34_isset_overloading/34_isset_overloading.sc new file mode 100644 index 0000000..f32f752 --- /dev/null +++ b/PHP/34_isset_overloading/34_isset_overloading.sc @@ -0,0 +1,8 @@ +@main def main(name : String): Unit = { + importCpg(name) + // Get all classes (lowercase) where `__isset` is defined + def methodClasses = cpg.method.name("__isset").astParentFullName.l + val x34 = (name, "34_isset_overloading_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); + println(x34) + delete; +} \ No newline at end of file diff --git a/PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.bash b/PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.bash new file mode 100644 index 0000000..f8e126b --- /dev/null +++ b/PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.bash @@ -0,0 +1,41 @@ + +$_main: + ; (lines=12, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.php:1-22 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 INIT_METHOD_CALL 1 CV1($obj) string("setx") +0007 SEND_VAR_EX CV0($b) 1 +0008 DO_FCALL +0009 T9 = ISSET_ISEMPTY_PROP_OBJ (isset) CV1($obj) string("var") +0010 FREE T9 +0011 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::__isset: + ; (lines=5, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.php:5-8 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 T1 = FETCH_OBJ_R THIS string("x") +0002 ECHO T1 +0003 RETURN bool(true) +0004 RETURN null + +PropertyTest::setx: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.php:10-12 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("x") +0002 OP_DATA CV0($b) +0003 RETURN null diff --git a/PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.json b/PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.json new file mode 100644 index 0000000..fa396e7 --- /dev/null +++ b/PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.json @@ -0,0 +1,38 @@ +{ + "description": "This instance shows, that `__isset` is invoked when trying to access non existant variables.", + "code": { + "path": "./3_instance_34_isset_overloading.php", + "injection_skeleton_broken": true + }, + "expectation": { + "type": "xss", + "sink_file": "./3_instance_34_isset_overloading.php", + "sink_line": 6, + "source_file": "./3_instance_34_isset_overloading.php", + "source_line": 15, + "expectation": true + }, + "compile": { + "binary": "./3_instance_34_isset_overloading.bash", + "instruction": null, + "dependencies": null + }, + "discovery": { + "rule": "../34_isset_overloading.sc", + "method": "joern", + "rule_accuracy": "FP", + "notes": "../docs/discovery_notes.md" + }, + "properties": { + "category": "S0", + "feature_vs_internal_api": "FEATURE", + "input_sanitizer": false, + "source_and_sink": false, + "negative_test_case": false + }, + "remediation": { + "notes": "", + "transformation": null, + "modeling_rule": null + } +} \ No newline at end of file diff --git a/PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.php b/PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.php new file mode 100644 index 0000000..74368e3 --- /dev/null +++ b/PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.php @@ -0,0 +1,21 @@ +x; // sink + return true; + } + + public function setx($b) { + $this->x = $b; + } +} + +$b = $_GET["p1"]; // source +$obj = new PropertyTest; +$obj->setx($b); + +// XSS vulnerability in the function __isset() +// __isset() is called, because $obj->var does not exist +isset($obj->var); diff --git a/PHP/34_isset_overloading/4_instance_34_isset_overloading/4_instance_34_isset_overloading.bash b/PHP/34_isset_overloading/4_instance_34_isset_overloading/4_instance_34_isset_overloading.bash new file mode 100644 index 0000000..f148fa6 --- /dev/null +++ b/PHP/34_isset_overloading/4_instance_34_isset_overloading/4_instance_34_isset_overloading.bash @@ -0,0 +1,30 @@ + +$_main: + ; (lines=11, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/4_instance_34_isset_overloading/4_instance_34_isset_overloading.php:1-17 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 ASSIGN_OBJ CV1($obj) string("x") +0007 OP_DATA CV0($b) +0008 T9 = ISSET_ISEMPTY_PROP_OBJ (isset) CV1($obj) string("x") +0009 FREE T9 +0010 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::__isset: + ; (lines=5, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/4_instance_34_isset_overloading/4_instance_34_isset_overloading.php:6-9 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 T1 = FETCH_OBJ_R THIS string("x") +0002 ECHO T1 +0003 RETURN bool(true) +0004 RETURN null diff --git a/PHP/34_isset_overloading/4_instance_34_isset_overloading/4_instance_34_isset_overloading.json b/PHP/34_isset_overloading/4_instance_34_isset_overloading/4_instance_34_isset_overloading.json new file mode 100644 index 0000000..f8503c3 --- /dev/null +++ b/PHP/34_isset_overloading/4_instance_34_isset_overloading/4_instance_34_isset_overloading.json @@ -0,0 +1,38 @@ +{ + "description": "This instance is not vulnerable. As the object has the property `x`, `__isset` will not be called.", + "code": { + "path": "./4_instance_34_isset_overloading.php", + "injection_skeleton_broken": true + }, + "expectation": { + "type": "xss", + "sink_file": "./4_instance_34_isset_overloading.php", + "sink_line": 7, + "source_file": "./4_instance_34_isset_overloading.php", + "source_line": 12, + "expectation": false + }, + "compile": { + "binary": "./4_instance_34_isset_overloading.bash", + "instruction": null, + "dependencies": null + }, + "discovery": { + "rule": "../34_isset_overloading.sc", + "method": "joern", + "rule_accuracy": "FP", + "notes": "../docs/discovery_notes.md" + }, + "properties": { + "category": "S0", + "feature_vs_internal_api": "FEATURE", + "input_sanitizer": false, + "source_and_sink": false, + "negative_test_case": false + }, + "remediation": { + "notes": "", + "transformation": null, + "modeling_rule": null + } +} \ No newline at end of file diff --git a/PHP/34_isset_overloading/4_instance_34_isset_overloading/4_instance_34_isset_overloading.php b/PHP/34_isset_overloading/4_instance_34_isset_overloading/4_instance_34_isset_overloading.php new file mode 100644 index 0000000..c2d48be --- /dev/null +++ b/PHP/34_isset_overloading/4_instance_34_isset_overloading/4_instance_34_isset_overloading.php @@ -0,0 +1,17 @@ +x; // sink + return true; + } +} + +$b = $_GET["p1"]; // source +$obj = new PropertyTest; +$obj->x = $b; + +// __isset() is not called, because $x is public +isset($obj->x); \ No newline at end of file diff --git a/PHP/34_isset_overloading/README.md b/PHP/34_isset_overloading/README.md new file mode 100644 index 0000000..9c78040 --- /dev/null +++ b/PHP/34_isset_overloading/README.md @@ -0,0 +1,539 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Isset Overloading + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +In many object-oriented programming languages overloading provides the ability of having multiple methods with the same name but different quantities and types of arguments. In PHP however [Overloading](https://www.php.net/manual/en/language.oop5.overloading.php) describes the concept of dynamically creating properties and methods. This pattern targets the usage of property overloading for `__isset()`. This method is triggered by calling isset() or empty() on inaccessible (protected or private) or non-existing properties. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | +| [2 Instance](#2-instance) | yes | joern | yes | +| [3 Instance](#3-instance) | yes | joern | yes | +| [4 Instance](#4-instance) | yes | joern | yes | + +
+ + +## 1 Instance + + +This instance shows, that `__isset` is called, when the function `isset()` is called. + +### Code + +```PHP +x; // sink + return true; + } + + public function setx($b) { + $this->x = $b; + } +} + +$b = $_GET["p1"]; // source +$obj = new PropertyTest; +$obj->setx($b); + +// XSS vulnerability in the function __isset() +isset($obj->x); +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=12, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.php:1-21 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 INIT_METHOD_CALL 1 CV1($obj) string("setx") +0007 SEND_VAR_EX CV0($b) 1 +0008 DO_FCALL +0009 T9 = ISSET_ISEMPTY_PROP_OBJ (isset) CV1($obj) string("x") +0010 FREE T9 +0011 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::__isset: + ; (lines=5, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.php:5-8 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 T1 = FETCH_OBJ_R THIS string("x") +0002 ECHO T1 +0003 RETURN bool(true) +0004 RETURN null + +PropertyTest::setx: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/1_instance_34_isset_overloading/1_instance_34_isset_overloading.php:10-12 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("x") +0002 OP_DATA CV0($b) +0003 RETURN null +``` + +
+ +
+ + +### Discovery + + +The discovery rule first gets all class names, where the method `__isset` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__isset` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__isset` method within its lifetime. + +```scala +// Get all classes (lowercase) where `__isset` is defined +def methodClasses = cpg.method.name("__isset").astParentFullName.l +val x34 = (name, "34_isset_overloading_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | no | no | no | yes | +| 17 May 2023 | no | no | | | | | yes | + +
+ +
+ +
+ +
+ + +## 2 Instance + + +This instance shows, that `__isset` is also invoked when `empty()` is called. + +### Code + +```PHP +x; // sink + return true; + } + + public function setx($b) { + $this->x = $b; + } +} + +$b = $_GET["p1"]; // source +$obj = new PropertyTest; +$obj->setx($b); + +// XSS vulnerability in the function __isset() +empty($obj->x); +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=12, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.php:1-20 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 INIT_METHOD_CALL 1 CV1($obj) string("setx") +0007 SEND_VAR_EX CV0($b) 1 +0008 DO_FCALL +0009 T9 = ISSET_ISEMPTY_PROP_OBJ (empty) CV1($obj) string("x") +0010 FREE T9 +0011 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::__isset: + ; (lines=5, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.php:5-8 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 T1 = FETCH_OBJ_R THIS string("x") +0002 ECHO T1 +0003 RETURN bool(true) +0004 RETURN null + +PropertyTest::setx: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/2_instance_34_isset_overloading/2_instance_34_isset_overloading.php:10-12 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("x") +0002 OP_DATA CV0($b) +0003 RETURN null +``` + +
+ +
+ + +### Discovery + + +The discovery rule first gets all class names, where the method `__isset` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__isset` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__isset` method within its lifetime. + +```scala +// Get all classes (lowercase) where `__isset` is defined +def methodClasses = cpg.method.name("__isset").astParentFullName.l +val x34 = (name, "34_isset_overloading_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | no | no | no | yes | +| 17 May 2023 | no | no | | | | | yes | + +
+ +
+ +
+ +
+ + +## 3 Instance + + +This instance shows, that `__isset` is invoked when trying to access non existant variables. + +### Code + +```PHP +x; // sink + return true; + } + + public function setx($b) { + $this->x = $b; + } +} + +$b = $_GET["p1"]; // source +$obj = new PropertyTest; +$obj->setx($b); + +// XSS vulnerability in the function __isset() +// __isset() is called, because $obj->var does not exist +isset($obj->var); +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=12, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.php:1-22 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 INIT_METHOD_CALL 1 CV1($obj) string("setx") +0007 SEND_VAR_EX CV0($b) 1 +0008 DO_FCALL +0009 T9 = ISSET_ISEMPTY_PROP_OBJ (isset) CV1($obj) string("var") +0010 FREE T9 +0011 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::__isset: + ; (lines=5, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.php:5-8 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 T1 = FETCH_OBJ_R THIS string("x") +0002 ECHO T1 +0003 RETURN bool(true) +0004 RETURN null + +PropertyTest::setx: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/3_instance_34_isset_overloading/3_instance_34_isset_overloading.php:10-12 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("x") +0002 OP_DATA CV0($b) +0003 RETURN null +``` + +
+ +
+ + +### Discovery + + +The discovery rule first gets all class names, where the method `__isset` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__isset` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__isset` method within its lifetime. + +```scala +// Get all classes (lowercase) where `__isset` is defined +def methodClasses = cpg.method.name("__isset").astParentFullName.l +val x34 = (name, "34_isset_overloading_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | no | no | no | yes | +| 17 May 2023 | no | no | | | | | yes | + +
+ +
+ +
+ +
+ + +## 4 Instance + + +This instance is not vulnerable. As the object has the property `x`, `__isset` will not be called. + +### Code + +```PHP +x; // sink + return true; + } +} + +$b = $_GET["p1"]; // source +$obj = new PropertyTest; +$obj->x = $b; + +// __isset() is not called, because $x is public +isset($obj->x); +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=11, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/4_instance_34_isset_overloading/4_instance_34_isset_overloading.php:1-17 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 ASSIGN_OBJ CV1($obj) string("x") +0007 OP_DATA CV0($b) +0008 T9 = ISSET_ISEMPTY_PROP_OBJ (isset) CV1($obj) string("x") +0009 FREE T9 +0010 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::__isset: + ; (lines=5, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/34_isset_overloading/4_instance_34_isset_overloading/4_instance_34_isset_overloading.php:6-9 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 T1 = FETCH_OBJ_R THIS string("x") +0002 ECHO T1 +0003 RETURN bool(true) +0004 RETURN null +``` + +
+ +
+ + +### Discovery + + +The discovery rule first gets all class names, where the method `__isset` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__isset` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__isset` method within its lifetime. + +```scala +// Get all classes (lowercase) where `__isset` is defined +def methodClasses = cpg.method.name("__isset").astParentFullName.l +val x34 = (name, "34_isset_overloading_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | yes | yes | yes | yes | yes | no | +| 17 May 2023 | no | no | | | | | no | + +
+ +
+ +
diff --git a/PHP/34_isset_overloading/docs/description.md b/PHP/34_isset_overloading/docs/description.md new file mode 100644 index 0000000..87babe4 --- /dev/null +++ b/PHP/34_isset_overloading/docs/description.md @@ -0,0 +1 @@ +In many object-oriented programming languages overloading provides the ability of having multiple methods with the same name but different quantities and types of arguments. In PHP however [Overloading](https://www.php.net/manual/en/language.oop5.overloading.php) describes the concept of dynamically creating properties and methods. This pattern targets the usage of property overloading for `__isset()`. This method is triggered by calling isset() or empty() on inaccessible (protected or private) or non-existing properties. \ No newline at end of file diff --git a/PHP/34_isset_overloading/docs/discovery_notes.md b/PHP/34_isset_overloading/docs/discovery_notes.md new file mode 100644 index 0000000..5551537 --- /dev/null +++ b/PHP/34_isset_overloading/docs/discovery_notes.md @@ -0,0 +1,3 @@ +The discovery rule first gets all class names, where the method `__isset` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__isset` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__isset` method within its lifetime. \ No newline at end of file diff --git a/PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.bash b/PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.bash new file mode 100644 index 0000000..bfb2000 --- /dev/null +++ b/PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.bash @@ -0,0 +1,39 @@ + +$_main: + ; (lines=11, args=0, vars=2, tmps=7) + ; (before optimizer) + ; /.../PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.php:1-18 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 INIT_METHOD_CALL 1 CV1($obj) string("setx") +0007 SEND_VAR_EX CV0($b) 1 +0008 DO_FCALL +0009 UNSET_OBJ CV1($obj) string("x") +0010 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::setx: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("x") +0002 OP_DATA CV0($b) +0003 RETURN null + +PropertyTest::__unset: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.php:9-11 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 T1 = FETCH_OBJ_R THIS string("x") +0002 ECHO T1 +0003 RETURN null diff --git a/PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.json b/PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.json index 585cfe7..0952def 100644 --- a/PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.json +++ b/PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.json @@ -1,13 +1,14 @@ { + "description": "This instance shows, that `__unset` is invoked, when `unset` is called on an instance of the class.", "code": { "path": "./1_instance_35_unset_overloading.php", - "injection_skeleton_broken": false + "injection_skeleton_broken": true }, "discovery": { - "rule": "./1_instance_35_unset_overloading.sc", + "rule": "../35_unset_overloading.sc", "method": "joern", "rule_accuracy": "FP", - "notes": null + "notes": "../docs/discovery_notes.md" }, "compile": { "binary": "./1_instance_35_unset_overloading.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_35_unset_overloading.php", - "sink_line": 19, + "sink_line": 10, "source_file": "./1_instance_35_unset_overloading.php", - "source_line": 23, + "source_line": 14, "expectation": true }, "properties": { diff --git a/PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.php b/PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.php index c93fe8c..a371c68 100644 --- a/PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.php +++ b/PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.php @@ -1,28 +1,18 @@ var; - } - - public function setx($b) - { + public function setx($b) { $this->x = $b; } - public function __unset($name) - { - echo "Unsetting " . $this->x; + public function __unset($name) { + echo $this->x; // sink } } -$b = $_GET["p1"]; +$b = $_GET["p1"]; // source $obj = new PropertyTest; -$obj->var = $b; $obj->setx($b); // will call __unset() function, XSS vulnerability unset($obj->x); \ No newline at end of file diff --git a/PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.sc b/PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.sc deleted file mode 100644 index 99dd18a..0000000 --- a/PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.sc +++ /dev/null @@ -1,7 +0,0 @@ -@main def main(name : String): Unit = { - importCpg(name) - def methods4 = cpg.method.name("__unset").name.l - val x35 = (name, "35_unset_overloading_iall", cpg.call("NEW").argument.filter{x => methods4.contains(x.code.toLowerCase)}.location.toJson); - println(x35) - delete; -} \ No newline at end of file diff --git a/PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.bash b/PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.bash new file mode 100644 index 0000000..25cc769 --- /dev/null +++ b/PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.bash @@ -0,0 +1,39 @@ + +$_main: + ; (lines=11, args=0, vars=2, tmps=7) + ; (before optimizer) + ; /.../PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.php:1-18 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 INIT_METHOD_CALL 1 CV1($obj) string("setx") +0007 SEND_VAR_EX CV0($b) 1 +0008 DO_FCALL +0009 UNSET_OBJ CV1($obj) string("var") +0010 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::setx: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("x") +0002 OP_DATA CV0($b) +0003 RETURN null + +PropertyTest::__unset: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.php:9-11 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 T1 = FETCH_OBJ_R THIS string("x") +0002 ECHO T1 +0003 RETURN null diff --git a/PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.json b/PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.json new file mode 100644 index 0000000..cc4c866 --- /dev/null +++ b/PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.json @@ -0,0 +1,38 @@ +{ + "description": "This instance shows, that wenn calling unset on a property of an object that does not exist it invokes calling `__unset`.", + "code": { + "path": "./2_instance_35_unset_overloading.php", + "injection_skeleton_broken": true + }, + "expectation": { + "type": "xss", + "sink_file": "./2_instance_35_unset_overloading.php", + "sink_line": 10, + "source_file": "./2_instance_35_unset_overloading.php", + "source_line": 14, + "expectation": true + }, + "compile": { + "binary": "./2_instance_35_unset_overloading.bash", + "instruction": null, + "dependencies": null + }, + "discovery": { + "rule": "../35_unset_overloading.sc", + "method": "joern", + "rule_accuracy": "FP", + "notes": "../docs/discovery_notes.md" + }, + "properties": { + "category": "S0", + "feature_vs_internal_api": "FEATURE", + "input_sanitizer": false, + "source_and_sink": false, + "negative_test_case": false + }, + "remediation": { + "notes": "", + "transformation": null, + "modeling_rule": null + } +} \ No newline at end of file diff --git a/PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.php b/PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.php new file mode 100644 index 0000000..f74534c --- /dev/null +++ b/PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.php @@ -0,0 +1,18 @@ +x = $b; + } + + public function __unset($name) { + echo $this->x; // sink + } +} + +$b = $_GET["p1"]; // source +$obj = new PropertyTest; +$obj->setx($b); +// will call __unset() function because $obj->var does not exist, XSS vulnerability +unset($obj->var); \ No newline at end of file diff --git a/PHP/35_unset_overloading/35_unset_overloading.json b/PHP/35_unset_overloading/35_unset_overloading.json index a88eb87..f6b9326 100644 --- a/PHP/35_unset_overloading/35_unset_overloading.json +++ b/PHP/35_unset_overloading/35_unset_overloading.json @@ -1,6 +1,6 @@ { "name": "Unset Overloading", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -8,7 +8,9 @@ "php_v7.4.9" ], "instances": [ - "./1_instance_35_unset_overloading/1_instance_35_unset_overloading.json" + "./1_instance_35_unset_overloading/1_instance_35_unset_overloading.json", + "./2_instance_35_unset_overloading/2_instance_35_unset_overloading.json", + "./3_instance_35_unset_overloading/3_instance_35_unset_overloading.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/35_unset_overloading/35_unset_overloading.sc b/PHP/35_unset_overloading/35_unset_overloading.sc new file mode 100644 index 0000000..6dbfba6 --- /dev/null +++ b/PHP/35_unset_overloading/35_unset_overloading.sc @@ -0,0 +1,7 @@ +@main def main(name : String): Unit = { + importCpg(name) + def methodClasses = cpg.method.name("__unset").astParentFullName.l + val x35 = (name, "35_unset_overloading_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); + println(x35) + delete; +} \ No newline at end of file diff --git a/PHP/35_unset_overloading/3_instance_35_unset_overloading/3_instance_35_unset_overloading.bash b/PHP/35_unset_overloading/3_instance_35_unset_overloading/3_instance_35_unset_overloading.bash new file mode 100644 index 0000000..768265a --- /dev/null +++ b/PHP/35_unset_overloading/3_instance_35_unset_overloading/3_instance_35_unset_overloading.bash @@ -0,0 +1,28 @@ + +$_main: + ; (lines=10, args=0, vars=2, tmps=7) + ; (before optimizer) + ; /.../PHP/35_unset_overloading/3_instance_35_unset_overloading/3_instance_35_unset_overloading.php:1-14 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 ASSIGN_OBJ CV1($obj) string("x") +0007 OP_DATA CV0($b) +0008 UNSET_OBJ CV1($obj) string("x") +0009 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::__unset: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/35_unset_overloading/3_instance_35_unset_overloading/3_instance_35_unset_overloading.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 T1 = FETCH_OBJ_R THIS string("x") +0002 ECHO T1 +0003 RETURN null diff --git a/PHP/35_unset_overloading/3_instance_35_unset_overloading/3_instance_35_unset_overloading.json b/PHP/35_unset_overloading/3_instance_35_unset_overloading/3_instance_35_unset_overloading.json new file mode 100644 index 0000000..bfba0e8 --- /dev/null +++ b/PHP/35_unset_overloading/3_instance_35_unset_overloading/3_instance_35_unset_overloading.json @@ -0,0 +1,38 @@ +{ + "description": "This instance is not vulnerable, because it calls `unset` on a public member of the object. This does not invoke `__unset`.", + "code": { + "path": "./3_instance_35_unset_overloading.php", + "injection_skeleton_broken": true + }, + "expectation": { + "type": "xss", + "sink_file": "./3_instance_35_unset_overloading.php", + "sink_line": 6, + "source_file": "./3_instance_35_unset_overloading.php", + "source_line": 10, + "expectation": false + }, + "compile": { + "binary": "./3_instance_35_unset_overloading.bash", + "instruction": null, + "dependencies": null + }, + "discovery": { + "rule": "../35_unset_overloading.sc", + "method": "joern", + "rule_accuracy": "FP", + "notes": "../docs/discovery_notes.md" + }, + "properties": { + "category": "S0", + "feature_vs_internal_api": "FEATURE", + "input_sanitizer": false, + "source_and_sink": false, + "negative_test_case": false + }, + "remediation": { + "notes": "", + "transformation": null, + "modeling_rule": null + } +} \ No newline at end of file diff --git a/PHP/35_unset_overloading/3_instance_35_unset_overloading/3_instance_35_unset_overloading.php b/PHP/35_unset_overloading/3_instance_35_unset_overloading/3_instance_35_unset_overloading.php new file mode 100644 index 0000000..03f6dc6 --- /dev/null +++ b/PHP/35_unset_overloading/3_instance_35_unset_overloading/3_instance_35_unset_overloading.php @@ -0,0 +1,14 @@ +x; // sink + } +} + +$b = $_GET["p1"]; // source +$obj = new PropertyTest; +$obj->x = $b; +// will not call __unset() function, because x is public +unset($obj->x); \ No newline at end of file diff --git a/PHP/35_unset_overloading/README.md b/PHP/35_unset_overloading/README.md new file mode 100644 index 0000000..d4e171a --- /dev/null +++ b/PHP/35_unset_overloading/README.md @@ -0,0 +1,386 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Unset Overloading + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +In many object-oriented programming languages overloading provides the ability of having multiple methods with the same name but different quantities and types of arguments. In PHP however [Overloading](https://www.php.net/manual/en/language.oop5.overloading.php) describes the concept of dynamically creating properties and methods. This pattern targets the usage of property overloading for `__unset()`. This method is invoked when unset() is used on inaccessible (protected or private) or non-existing properties. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | +| [2 Instance](#2-instance) | yes | joern | yes | +| [3 Instance](#3-instance) | yes | joern | yes | + +
+ + +## 1 Instance + + +This instance shows, that `__unset` is invoked, when `unset` is called on an instance of the class. + +### Code + +```PHP +x = $b; + } + + public function __unset($name) { + echo $this->x; // sink + } +} + +$b = $_GET["p1"]; // source +$obj = new PropertyTest; +$obj->setx($b); +// will call __unset() function, XSS vulnerability +unset($obj->x); +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=11, args=0, vars=2, tmps=7) + ; (before optimizer) + ; /.../PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.php:1-18 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 INIT_METHOD_CALL 1 CV1($obj) string("setx") +0007 SEND_VAR_EX CV0($b) 1 +0008 DO_FCALL +0009 UNSET_OBJ CV1($obj) string("x") +0010 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::setx: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("x") +0002 OP_DATA CV0($b) +0003 RETURN null + +PropertyTest::__unset: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/35_unset_overloading/1_instance_35_unset_overloading/1_instance_35_unset_overloading.php:9-11 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 T1 = FETCH_OBJ_R THIS string("x") +0002 ECHO T1 +0003 RETURN null +``` + +
+ +
+ + +### Discovery + + +The discovery rule first gets all class names, where the method `__unset` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__unset` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__unset` method within its lifetime. + +```scala +def methodClasses = cpg.method.name("__unset").astParentFullName.l +val x35 = (name, "35_unset_overloading_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | no | no | no | yes | +| 17 May 2023 | yes | no | | | | | yes | + +
+ +
+ +
+ +
+ + +## 2 Instance + + +This instance shows, that wenn calling unset on a property of an object that does not exist it invokes calling `__unset`. + +### Code + +```PHP +x = $b; + } + + public function __unset($name) { + echo $this->x; // sink + } +} + +$b = $_GET["p1"]; // source +$obj = new PropertyTest; +$obj->setx($b); +// will call __unset() function because $obj->var does not exist, XSS vulnerability +unset($obj->var); +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=11, args=0, vars=2, tmps=7) + ; (before optimizer) + ; /.../PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.php:1-18 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 INIT_METHOD_CALL 1 CV1($obj) string("setx") +0007 SEND_VAR_EX CV0($b) 1 +0008 DO_FCALL +0009 UNSET_OBJ CV1($obj) string("var") +0010 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::setx: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("x") +0002 OP_DATA CV0($b) +0003 RETURN null + +PropertyTest::__unset: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/35_unset_overloading/2_instance_35_unset_overloading/2_instance_35_unset_overloading.php:9-11 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 T1 = FETCH_OBJ_R THIS string("x") +0002 ECHO T1 +0003 RETURN null +``` + +
+ +
+ + +### Discovery + + +The discovery rule first gets all class names, where the method `__unset` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__unset` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__unset` method within its lifetime. + +```scala +def methodClasses = cpg.method.name("__unset").astParentFullName.l +val x35 = (name, "35_unset_overloading_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | Ground Truth | +|-------------|----------|----------|----------------| +| 17 May 2023 | yes | no | yes | + +
+ +
+ +
+ +
+ + +## 3 Instance + + +This instance is not vulnerable, because it calls `unset` on a public member of the object. This does not invoke `__unset`. + +### Code + +```PHP +x; // sink + } +} + +$b = $_GET["p1"]; // source +$obj = new PropertyTest; +$obj->x = $b; +// will not call __unset() function, because x is public +unset($obj->x); +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=10, args=0, vars=2, tmps=7) + ; (before optimizer) + ; /.../PHP/35_unset_overloading/3_instance_35_unset_overloading/3_instance_35_unset_overloading.php:1-14 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("PropertyTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 ASSIGN_OBJ CV1($obj) string("x") +0007 OP_DATA CV0($b) +0008 UNSET_OBJ CV1($obj) string("x") +0009 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +PropertyTest::__unset: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/35_unset_overloading/3_instance_35_unset_overloading/3_instance_35_unset_overloading.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 T1 = FETCH_OBJ_R THIS string("x") +0002 ECHO T1 +0003 RETURN null +``` + +
+ +
+ + +### Discovery + + +The discovery rule first gets all class names, where the method `__unset` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__unset` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__unset` method within its lifetime. + +```scala +def methodClasses = cpg.method.name("__unset").astParentFullName.l +val x35 = (name, "35_unset_overloading_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | Ground Truth | +|-------------|----------|----------|----------------| +| 17 May 2023 | no | no | no | + +
+ +
+ +
diff --git a/PHP/35_unset_overloading/docs/description.md b/PHP/35_unset_overloading/docs/description.md new file mode 100644 index 0000000..5951af5 --- /dev/null +++ b/PHP/35_unset_overloading/docs/description.md @@ -0,0 +1 @@ +In many object-oriented programming languages overloading provides the ability of having multiple methods with the same name but different quantities and types of arguments. In PHP however [Overloading](https://www.php.net/manual/en/language.oop5.overloading.php) describes the concept of dynamically creating properties and methods. This pattern targets the usage of property overloading for `__unset()`. This method is invoked when unset() is used on inaccessible (protected or private) or non-existing properties. \ No newline at end of file diff --git a/PHP/35_unset_overloading/docs/discovery_notes.md b/PHP/35_unset_overloading/docs/discovery_notes.md new file mode 100644 index 0000000..c12a6e9 --- /dev/null +++ b/PHP/35_unset_overloading/docs/discovery_notes.md @@ -0,0 +1,3 @@ +The discovery rule first gets all class names, where the method `__unset` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__unset` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__unset` method within its lifetime. \ No newline at end of file diff --git a/PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.bash b/PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.bash index dcd9bd0..6fcbbbc 100644 --- a/PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.bash +++ b/PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.bash @@ -1,45 +1,36 @@ -$_main: ; (lines=17, args=0, vars=2, tmps=8) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/33_call_overloading/33_call_overloading.php:1-19 -L0 (12): EXT_STMT -L1 (12): T2 = FETCH_R (global) string("_GET") -L2 (12): T3 = FETCH_DIM_R T2 string("p1") -L3 (12): ASSIGN CV0($b) T3 -L4 (13): EXT_STMT -L5 (13): V5 = NEW 0 string("MethodTest") -L6 (13): DO_FCALL -L7 (13): ASSIGN CV1($obj) V5 -L8 (14): EXT_STMT -L9 (14): ASSIGN_OBJ CV1($obj) string("x") -L10 (14): OP_DATA CV0($b) -L11 (18): EXT_STMT -L12 (18): INIT_METHOD_CALL 2 CV1($obj) string("runTest") -L13 (18): SEND_VAL_EX string("arg1") 1 -L14 (18): SEND_VAR_EX CV0($b) 2 -L15 (18): DO_FCALL -L16 (19): RETURN int(1) +$_main: + ; (lines=12, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.php:1-16 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("MethodTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 ASSIGN_OBJ CV1($obj) string("x") +0007 OP_DATA CV0($b) +0008 INIT_METHOD_CALL 1 CV1($obj) string("runTest") +0009 SEND_VAR_EX CV0($b) 1 +0010 DO_FCALL +0011 RETURN int(1) LIVE RANGES: - 5: L6 - L7 (new) + 5: 0004 - 0005 (new) -MethodTest::__call: ; (lines=13, args=2, vars=3, tmps=2) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/33_call_overloading/33_call_overloading.php:4-9 -L0 (4): EXT_NOP -L1 (4): CV0($name) = RECV 1 -L2 (4): CV1($arguments) = RECV 2 -L3 (6): EXT_STMT -L4 (6): V3 = FE_RESET_R CV1($arguments) L10 -L5 (6): FE_FETCH_R V3 CV2($arg) L10 -L6 (7): EXT_STMT -L7 (7): T4 = CONCAT CV2($arg) string(" -") -L8 (7): ECHO T4 -L9 (6): JMP L5 -L10 (6): FE_FREE V3 -L11 (9): EXT_STMT -L12 (9): RETURN null +MethodTest::__call: + ; (lines=8, args=2, vars=3, tmps=1) + ; (before optimizer) + ; /.../PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.php:3-7 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 CV1($arguments) = RECV 2 +0002 V3 = FE_RESET_R CV1($arguments) 0006 +0003 FE_FETCH_R V3 CV2($arg) 0006 +0004 ECHO CV2($arg) +0005 JMP 0003 +0006 FE_FREE V3 +0007 RETURN null LIVE RANGES: - 3: L5 - L10 (loop) - - + 3: 0003 - 0006 (loop) diff --git a/PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.json b/PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.json index 8b8c972..0d10766 100644 --- a/PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.json +++ b/PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.json @@ -1,13 +1,14 @@ { + "description": "This instance shows how the `__call` method is invoked.", "code": { "path": "./1_instance_36_call_overloading.php", - "injection_skeleton_broken": false + "injection_skeleton_broken": true }, "discovery": { "rule": "./1_instance_36_call_overloading.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "FP", + "notes": "The discovery rule first gets all class names, where the method `__call` is defined.\nAfterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__call` defined.\nThe rule would be perfect, if we could additionally check, if one of the created objects invokes the `__call` method within its lifetime." }, "compile": { "binary": "./1_instance_36_call_overloading.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_36_call_overloading.php", - "sink_line": 7, + "sink_line": 5, "source_file": "./1_instance_36_call_overloading.php", - "source_line": 12, + "source_line": 10, "expectation": true }, "properties": { diff --git a/PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.php b/PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.php index c87bc18..5e8b5f7 100644 --- a/PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.php +++ b/PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.php @@ -1,18 +1,15 @@ x = $b; -// Will call the __call() function -// and print the argument $b +// Will call the __call() function and print the argument $b // XSS vulnerability -$obj->runTest('arg1',$b); +$obj->runTest($b); diff --git a/PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.sc b/PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.sc index 5f52962..23c4790 100644 --- a/PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.sc +++ b/PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.sc @@ -1,7 +1,8 @@ @main def main(name : String): Unit = { importCpg(name) - def methods5 = cpg.method.name("__call").name.l - val x36 = (name, "36_call_overloading_iall", cpg.call("NEW").argument.filter{x => methods5.contains(x.code.toLowerCase)}.location.toJson); + // Get all classes (lowercase) where `__call` is defined + def methodClasses = cpg.method.name("__call").astParentFullName.l + val x36 = (name, "36_call_overloading_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); println(x36) delete; } \ No newline at end of file diff --git a/PHP/36_call_overloading/36_call_overloading.json b/PHP/36_call_overloading/36_call_overloading.json index f98128c..01b2a08 100644 --- a/PHP/36_call_overloading/36_call_overloading.json +++ b/PHP/36_call_overloading/36_call_overloading.json @@ -1,6 +1,6 @@ { "name": "Call Overloading", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", diff --git a/PHP/36_call_overloading/README.md b/PHP/36_call_overloading/README.md new file mode 100644 index 0000000..6dcc9fd --- /dev/null +++ b/PHP/36_call_overloading/README.md @@ -0,0 +1,134 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Call Overloading + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +In many object-oriented programming languages overloading provides the ability of having multiple methods with the same name but different quantities and types of arguments. In PHP however [Overloading](https://www.php.net/manual/en/language.oop5.overloading.php) describes the concept of dynamically creating properties and methods. This pattern targets the usage of method overloading for `__call()`. This method is triggered when invoking inaccessible methods in an object context. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +This instance shows how the `__call` method is invoked. + +### Code + +```PHP +x = $b; +// Will call the __call() function and print the argument $b +// XSS vulnerability +$obj->runTest($b); +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=12, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.php:1-16 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("MethodTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 ASSIGN_OBJ CV1($obj) string("x") +0007 OP_DATA CV0($b) +0008 INIT_METHOD_CALL 1 CV1($obj) string("runTest") +0009 SEND_VAR_EX CV0($b) 1 +0010 DO_FCALL +0011 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +MethodTest::__call: + ; (lines=8, args=2, vars=3, tmps=1) + ; (before optimizer) + ; /.../PHP/36_call_overloading/1_instance_36_call_overloading/1_instance_36_call_overloading.php:3-7 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 CV1($arguments) = RECV 2 +0002 V3 = FE_RESET_R CV1($arguments) 0006 +0003 FE_FETCH_R V3 CV2($arg) 0006 +0004 ECHO CV2($arg) +0005 JMP 0003 +0006 FE_FREE V3 +0007 RETURN null +LIVE RANGES: + 3: 0003 - 0006 (loop) +``` + +
+ +
+ + +### Discovery + + +The discovery rule first gets all class names, where the method `__call` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__call` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__call` method within its lifetime. + +```scala +// Get all classes (lowercase) where `__call` is defined +def methodClasses = cpg.method.name("__call").astParentFullName.l +val x36 = (name, "36_call_overloading_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | no | no | no | yes | +| 17 May 2023 | yes | no | | | | | yes | + +
+ +
diff --git a/PHP/36_call_overloading/docs/description.md b/PHP/36_call_overloading/docs/description.md new file mode 100644 index 0000000..432598a --- /dev/null +++ b/PHP/36_call_overloading/docs/description.md @@ -0,0 +1 @@ +In many object-oriented programming languages overloading provides the ability of having multiple methods with the same name but different quantities and types of arguments. In PHP however [Overloading](https://www.php.net/manual/en/language.oop5.overloading.php) describes the concept of dynamically creating properties and methods. This pattern targets the usage of method overloading for `__call()`. This method is triggered when invoking inaccessible methods in an object context. \ No newline at end of file diff --git a/PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.bash b/PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.bash index 7c07cf4..bda5219 100644 --- a/PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.bash +++ b/PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.bash @@ -1,43 +1,36 @@ -$_main: ; (lines=17, args=0, vars=2, tmps=8) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/124_callstatic_overloading/124_callstatic_overloading.php:1-19 -L0 (12): EXT_STMT -L1 (12): T2 = FETCH_R (global) string("_GET") -L2 (12): T3 = FETCH_DIM_R T2 string("p1") -L3 (12): ASSIGN CV0($b) T3 -L4 (13): EXT_STMT -L5 (13): V5 = NEW 0 string("MethodTest") -L6 (13): DO_FCALL -L7 (13): ASSIGN CV1($obj) V5 -L8 (14): EXT_STMT -L9 (14): ASSIGN_OBJ CV1($obj) string("x") -L10 (14): OP_DATA CV0($b) -L11 (18): EXT_STMT -L12 (18): INIT_STATIC_METHOD_CALL 2 string("MethodTest") string("runTest") -L13 (18): SEND_VAL_EX string("arg1") 1 -L14 (18): SEND_VAR_EX CV0($b) 2 -L15 (18): DO_FCALL -L16 (19): RETURN int(1) +$_main: + ; (lines=12, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.php:1-17 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("MethodTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 ASSIGN_OBJ CV1($obj) string("x") +0007 OP_DATA CV0($b) +0008 INIT_STATIC_METHOD_CALL 1 string("MethodTest") string("runTest") +0009 SEND_VAR_EX CV0($b) 1 +0010 DO_FCALL +0011 RETURN int(1) LIVE RANGES: - 5: L6 - L7 (new) + 5: 0004 - 0005 (new) -MethodTest::__callStatic: ; (lines=13, args=2, vars=3, tmps=2) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/124_callstatic_overloading/124_callstatic_overloading.php:4-9 -L0 (4): EXT_NOP -L1 (4): CV0($name) = RECV 1 -L2 (4): CV1($arguments) = RECV 2 -L3 (6): EXT_STMT -L4 (6): V3 = FE_RESET_R CV1($arguments) L10 -L5 (6): FE_FETCH_R V3 CV2($arg) L10 -L6 (7): EXT_STMT -L7 (7): T4 = CONCAT CV2($arg) string(" -") -L8 (7): ECHO T4 -L9 (6): JMP L5 -L10 (6): FE_FREE V3 -L11 (9): EXT_STMT -L12 (9): RETURN null +MethodTest::__callStatic: + ; (lines=8, args=2, vars=3, tmps=1) + ; (before optimizer) + ; /.../PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.php:3-7 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 CV1($arguments) = RECV 2 +0002 V3 = FE_RESET_R CV1($arguments) 0006 +0003 FE_FETCH_R V3 CV2($arg) 0006 +0004 ECHO CV2($arg) +0005 JMP 0003 +0006 FE_FREE V3 +0007 RETURN null LIVE RANGES: - 3: L5 - L10 (loop) + 3: 0003 - 0006 (loop) diff --git a/PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.json b/PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.json index 5d9ee58..305e4d9 100644 --- a/PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.json +++ b/PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.json @@ -1,4 +1,5 @@ { + "description": "This instance shows, how `__callstatic` is used, when calling a static function on a class.", "code": { "path": "./1_instance_37_callstatic_overloading.php", "injection_skeleton_broken": false @@ -7,7 +8,7 @@ "rule": "./1_instance_37_callstatic_overloading.sc", "method": "joern", "rule_accuracy": "FP", - "notes": null + "notes": "The discovery rule first gets all class names, where the method `__callstatic` is defined.\nAfterwards it filters all `INIT_STATIC_METHOD_CALL` if an argument contains any of the classes where `__callstatic` was defined." }, "compile": { "binary": "./1_instance_37_callstatic_overloading.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_37_callstatic_overloading.php", - "sink_line": 7, + "sink_line": 5, "source_file": "./1_instance_37_callstatic_overloading.php", - "source_line": 12, + "source_line": 10, "expectation": true }, "properties": { diff --git a/PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.php b/PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.php index 642a027..45d916e 100644 --- a/PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.php +++ b/PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.php @@ -1,18 +1,16 @@ x = $b; // Will call the __call() function // and print the argument $b // XSS vulnerability -MethodTest::runTest('arg1',$b); +MethodTest::runTest($b); diff --git a/PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.sc b/PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.sc index 06127bc..ad59ee5 100644 --- a/PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.sc +++ b/PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.sc @@ -1,7 +1,7 @@ @main def main(name : String): Unit = { importCpg(name) - def methods6 = cpg.method.name("__callstatic").name.l - val x37 = (name, "37_callstatic_overloading_iall", cpg.call("INIT_STATIC_METHOD_CALL").argument.filter{x => methods6.contains(x.code.toLowerCase)}.location.toJson); + def methodClasses = cpg.method.name("__callstatic").astParentFullName.l + val x37 = (name, "37_callstatic_overloading_iall", cpg.call("INIT_STATIC_METHOD_CALL").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); println(x37) delete; } \ No newline at end of file diff --git a/PHP/37_callstatic_overloading/37_callstatic_overloading.json b/PHP/37_callstatic_overloading/37_callstatic_overloading.json index 3e8f7d4..27679cc 100644 --- a/PHP/37_callstatic_overloading/37_callstatic_overloading.json +++ b/PHP/37_callstatic_overloading/37_callstatic_overloading.json @@ -1,6 +1,6 @@ { "name": "Callstatic Overloading", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", diff --git a/PHP/37_callstatic_overloading/README.md b/PHP/37_callstatic_overloading/README.md new file mode 100644 index 0000000..ede80e0 --- /dev/null +++ b/PHP/37_callstatic_overloading/README.md @@ -0,0 +1,133 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Callstatic Overloading + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +In many object-oriented programming languages overloading provides the ability of having multiple methods with the same name but different quantities and types of arguments. In PHP however [Overloading](https://www.php.net/manual/en/language.oop5.overloading.php) describes the concept of dynamically creating properties and methods. This pattern targets the usage of method overloading for `__callStatic()`. This method is triggered when invoking inaccessible methods in a static context. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +This instance shows, how `__callstatic` is used, when calling a static function on a class. + +### Code + +```PHP +x = $b; +// Will call the __call() function +// and print the argument $b +// XSS vulnerability +MethodTest::runTest($b); +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=12, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.php:1-17 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 0 string("MethodTest") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V5 +0006 ASSIGN_OBJ CV1($obj) string("x") +0007 OP_DATA CV0($b) +0008 INIT_STATIC_METHOD_CALL 1 string("MethodTest") string("runTest") +0009 SEND_VAR_EX CV0($b) 1 +0010 DO_FCALL +0011 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0005 (new) + +MethodTest::__callStatic: + ; (lines=8, args=2, vars=3, tmps=1) + ; (before optimizer) + ; /.../PHP/37_callstatic_overloading/1_instance_37_callstatic_overloading/1_instance_37_callstatic_overloading.php:3-7 + ; return [] RANGE[0..0] +0000 CV0($name) = RECV 1 +0001 CV1($arguments) = RECV 2 +0002 V3 = FE_RESET_R CV1($arguments) 0006 +0003 FE_FETCH_R V3 CV2($arg) 0006 +0004 ECHO CV2($arg) +0005 JMP 0003 +0006 FE_FREE V3 +0007 RETURN null +LIVE RANGES: + 3: 0003 - 0006 (loop) +``` + +
+ +
+ + +### Discovery + + +The discovery rule first gets all class names, where the method `__callstatic` is defined. +Afterwards it filters all `INIT_STATIC_METHOD_CALL` if an argument contains any of the classes where `__callstatic` was defined. + +```scala +def methodClasses = cpg.method.name("__callstatic").astParentFullName.l +val x37 = (name, "37_callstatic_overloading_iall", cpg.call("INIT_STATIC_METHOD_CALL").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | no | no | no | yes | +| 17 May 2023 | no | no | | | | | yes | + +
+ +
diff --git a/PHP/37_callstatic_overloading/docs/description.md b/PHP/37_callstatic_overloading/docs/description.md new file mode 100644 index 0000000..2980dfc --- /dev/null +++ b/PHP/37_callstatic_overloading/docs/description.md @@ -0,0 +1 @@ +In many object-oriented programming languages overloading provides the ability of having multiple methods with the same name but different quantities and types of arguments. In PHP however [Overloading](https://www.php.net/manual/en/language.oop5.overloading.php) describes the concept of dynamically creating properties and methods. This pattern targets the usage of method overloading for `__callStatic()`. This method is triggered when invoking inaccessible methods in a static context. \ No newline at end of file diff --git a/PHP/38_invoke/1_instance_38_invoke/1_instance_38_invoke.bash b/PHP/38_invoke/1_instance_38_invoke/1_instance_38_invoke.bash index 0dc9280..f1d9918 100644 --- a/PHP/38_invoke/1_instance_38_invoke/1_instance_38_invoke.bash +++ b/PHP/38_invoke/1_instance_38_invoke/1_instance_38_invoke.bash @@ -1,35 +1,29 @@ -$_main: ; (lines=19, args=0, vars=3, tmps=9) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/35_invoke/35_invoke.php:1-13 -L0 (9): EXT_STMT -L1 (9): V3 = NEW 0 string("CallableClass") -L2 (9): DO_FCALL -L3 (9): ASSIGN CV0($obj) V3 -L4 (10): EXT_STMT -L5 (10): INIT_FCALL 2 112 string("fopen") -L6 (10): SEND_VAL string("php://stdin") 1 -L7 (10): SEND_VAL string("r") 2 -L8 (10): V6 = DO_FCALL -L9 (10): ASSIGN CV1($_fp) V6 -L10 (11): EXT_STMT -L11 (11): T8 = FETCH_R (global) string("_GET") -L12 (11): T9 = FETCH_DIM_R T8 string("p1") -L13 (11): ASSIGN CV2($b) T9 -L14 (13): EXT_STMT -L15 (13): INIT_DYNAMIC_CALL 1 CV0($obj) -L16 (13): SEND_VAR_EX CV2($b) 1 -L17 (13): DO_FCALL -L18 (13): RETURN int(1) +$_main: + ; (lines=12, args=0, vars=3, tmps=8) + ; (before optimizer) + ; /.../PHP/38_invoke/1_instance_38_invoke/1_instance_38_invoke.php:1-10 + ; return [] RANGE[0..0] +0000 V3 = NEW 0 string("CallableClass") +0001 DO_FCALL +0002 ASSIGN CV0($obj) V3 +0003 T6 = FETCH_R (global) string("_GET") +0004 T7 = FETCH_DIM_R T6 string("p1") +0005 ASSIGN CV1($b) T7 +0006 INIT_DYNAMIC_CALL 1 CV0($obj) +0007 SEND_VAR_EX CV1($b) 1 +0008 V9 = DO_FCALL +0009 ASSIGN CV2($a) V9 +0010 ECHO CV2($a) +0011 RETURN int(1) LIVE RANGES: - 3: L2 - L3 (new) + 3: 0001 - 0002 (new) -CallableClass::__invoke: ; (lines=6, args=1, vars=1, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/35_invoke/35_invoke.php:4-7 -L0 (4): EXT_NOP -L1 (4): CV0($x) = RECV 1 -L2 (6): EXT_STMT -L3 (6): ECHO CV0($x) -L4 (7): EXT_STMT -L5 (7): RETURN null +CallableClass::__invoke: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/38_invoke/1_instance_38_invoke/1_instance_38_invoke.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($x) = RECV 1 +0001 RETURN CV0($x) +0002 RETURN null diff --git a/PHP/38_invoke/1_instance_38_invoke/1_instance_38_invoke.json b/PHP/38_invoke/1_instance_38_invoke/1_instance_38_invoke.json index ed7fde9..116153f 100644 --- a/PHP/38_invoke/1_instance_38_invoke/1_instance_38_invoke.json +++ b/PHP/38_invoke/1_instance_38_invoke/1_instance_38_invoke.json @@ -1,4 +1,5 @@ { + "description": "This instance shows, that when you have a callable object and you call the object, `__invoke` will be called.", "code": { "path": "./1_instance_38_invoke.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_38_invoke.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "FP", + "notes": "The discovery rule first gets all class names, where the method `__invoke` is defined.\nAfterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__invoke` defined.\nThe rule would be perfect, if we could additionally check, if one of the created objects invokes the `__invoke` method within its lifetime." }, "compile": { "binary": "./1_instance_38_invoke.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_38_invoke.php", - "sink_line": 6, + "sink_line": 10, "source_file": "./1_instance_38_invoke.php", - "source_line": 11, + "source_line": 8, "expectation": true }, "properties": { diff --git a/PHP/38_invoke/1_instance_38_invoke/1_instance_38_invoke.php b/PHP/38_invoke/1_instance_38_invoke/1_instance_38_invoke.php index 3f709e1..9d5845a 100644 --- a/PHP/38_invoke/1_instance_38_invoke/1_instance_38_invoke.php +++ b/PHP/38_invoke/1_instance_38_invoke/1_instance_38_invoke.php @@ -1,13 +1,10 @@ methods7.contains(x.code.toLowerCase)}.location.toJson); + def methodClasses = cpg.method.name("__invoke").astParentFullName.l + val x38 = (name, "38_invoke_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); println(x38) delete; } \ No newline at end of file diff --git a/PHP/38_invoke/38_invoke.json b/PHP/38_invoke/38_invoke.json index d3487dc..994be4c 100644 --- a/PHP/38_invoke/38_invoke.json +++ b/PHP/38_invoke/38_invoke.json @@ -1,6 +1,6 @@ { "name": "Invoke", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_38_invoke/1_instance_38_invoke.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/38_invoke/README.md b/PHP/38_invoke/README.md new file mode 100644 index 0000000..4efdcfa --- /dev/null +++ b/PHP/38_invoke/README.md @@ -0,0 +1,121 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Invoke + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +`__invoke` is one of PHP [Magic Methods](https://www.php.net/manual/en/language.oop5.magic.php), that override PHP default actions. It is called when a script tries to call an object as a function. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +This instance shows, that when you have a callable object and you call the object, `__invoke` will be called. + +### Code + +```PHP + + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=12, args=0, vars=3, tmps=8) + ; (before optimizer) + ; /.../PHP/38_invoke/1_instance_38_invoke/1_instance_38_invoke.php:1-10 + ; return [] RANGE[0..0] +0000 V3 = NEW 0 string("CallableClass") +0001 DO_FCALL +0002 ASSIGN CV0($obj) V3 +0003 T6 = FETCH_R (global) string("_GET") +0004 T7 = FETCH_DIM_R T6 string("p1") +0005 ASSIGN CV1($b) T7 +0006 INIT_DYNAMIC_CALL 1 CV0($obj) +0007 SEND_VAR_EX CV1($b) 1 +0008 V9 = DO_FCALL +0009 ASSIGN CV2($a) V9 +0010 ECHO CV2($a) +0011 RETURN int(1) +LIVE RANGES: + 3: 0001 - 0002 (new) + +CallableClass::__invoke: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/38_invoke/1_instance_38_invoke/1_instance_38_invoke.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($x) = RECV 1 +0001 RETURN CV0($x) +0002 RETURN null +``` + +
+ +
+ + +### Discovery + + +The discovery rule first gets all class names, where the method `__invoke` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__invoke` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__invoke` method within its lifetime. + +```scala +def methodClasses = cpg.method.name("__invoke").astParentFullName.l +val x38 = (name, "38_invoke_iall", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | no | no | no | yes | +| 17 May 2023 | yes | | | | | | yes | + +
+ + diff --git a/PHP/38_invoke/docs/description.md b/PHP/38_invoke/docs/description.md new file mode 100644 index 0000000..139267f --- /dev/null +++ b/PHP/38_invoke/docs/description.md @@ -0,0 +1 @@ +`__invoke` is one of PHP [Magic Methods](https://www.php.net/manual/en/language.oop5.magic.php), that override PHP default actions. It is called when a script tries to call an object as a function. \ No newline at end of file diff --git a/PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.bash b/PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.bash index 1bfb547..9891638 100644 --- a/PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.bash +++ b/PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.bash @@ -1,51 +1,47 @@ -$_main: ; (lines=24, args=0, vars=4, tmps=11) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/38_serialize_unserialize/38_serialize_unserialize.php:1-19 -L0 (3): NOP -L1 (14): EXT_STMT -L2 (14): T4 = FETCH_R (global) string("_GET") -L3 (14): T5 = FETCH_DIM_R T4 string("p1") -L4 (14): ASSIGN CV0($b) T5 -L5 (15): EXT_STMT -L6 (15): V7 = NEW 1 string("A") -L7 (15): SEND_VAR_EX CV0($b) 1 -L8 (15): DO_FCALL -L9 (15): ASSIGN CV1($a) V7 -L10 (16): EXT_STMT -L11 (16): INIT_FCALL 1 96 string("serialize") -L12 (16): SEND_VAR CV1($a) 1 -L13 (16): V10 = DO_FCALL -L14 (16): ASSIGN CV2($s) V10 -L15 (17): EXT_STMT -L16 (17): INIT_FCALL 1 96 string("unserialize") -L17 (17): SEND_VAR CV2($s) 1 -L18 (17): V12 = DO_FCALL -L19 (17): ASSIGN CV3($h) V12 -L20 (19): EXT_STMT -L21 (19): INIT_METHOD_CALL 0 CV3($h) string("show_one") -L22 (19): DO_FCALL -L23 (19): RETURN int(1) +$_main: + ; (lines=20, args=0, vars=5, tmps=12) + ; (before optimizer) + ; /.../PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.php:1-20 + ; return [] RANGE[0..0] +0000 T5 = FETCH_R (global) string("_GET") +0001 T6 = FETCH_DIM_R T5 string("p1") +0002 ASSIGN CV0($b) T6 +0003 V8 = NEW 1 string("A") +0004 SEND_VAR_EX CV0($b) 1 +0005 DO_FCALL +0006 ASSIGN CV1($a) V8 +0007 INIT_FCALL 1 96 string("serialize") +0008 SEND_VAR CV1($a) 1 +0009 V11 = DO_ICALL +0010 ASSIGN CV2($s) V11 +0011 INIT_FCALL 1 96 string("unserialize") +0012 SEND_VAR CV2($s) 1 +0013 V13 = DO_ICALL +0014 ASSIGN CV3($h) V13 +0015 INIT_METHOD_CALL 0 CV3($h) string("show_one") +0016 V15 = DO_FCALL +0017 ASSIGN CV4($c) V15 +0018 ECHO CV4($c) +0019 RETURN int(1) LIVE RANGES: - 7: L7 - L9 (new) + 8: 0004 - 0006 (new) -A::__construct: ; (lines=7, args=1, vars=1, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/38_serialize_unserialize/38_serialize_unserialize.php:5-7 -L0 (5): EXT_NOP -L1 (5): CV0($b) = RECV 1 -L2 (6): EXT_STMT -L3 (6): ASSIGN_OBJ THIS string("one") -L4 (6): OP_DATA CV0($b) -L5 (7): EXT_STMT -L6 (7): RETURN null +A::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("one") +0002 OP_DATA CV0($b) +0003 RETURN null -A::show_one: ; (lines=6, args=0, vars=0, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/38_serialize_unserialize/38_serialize_unserialize.php:9-11 -L0 (9): EXT_NOP -L1 (10): EXT_STMT -L2 (10): T0 = FETCH_OBJ_R THIS string("one") -L3 (10): ECHO T0 -L4 (11): EXT_STMT -L5 (11): RETURN null +A::show_one: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.php:9-11 + ; return [] RANGE[0..0] +0000 T0 = FETCH_OBJ_R THIS string("one") +0001 RETURN T0 +0002 RETURN null diff --git a/PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.json b/PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.json index 382c7be..52a2fb6 100644 --- a/PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.json +++ b/PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.json @@ -1,4 +1,5 @@ { + "description": "The instance shows `serialize` and `unserialize` called on an object as tarpits. After the object is unserialized, it has the same properties as before.", "code": { "path": "./1_instance_39_serialize_unserialize.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_39_serialize_unserialize.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "Perfect", + "notes": "The rule searches for a function call to serialize or unserialize in opcode." }, "compile": { "binary": "./1_instance_39_serialize_unserialize.bash", @@ -17,7 +18,7 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_39_serialize_unserialize.php", - "sink_line": 10, + "sink_line": 20, "source_file": "./1_instance_39_serialize_unserialize.php", "source_line": 14, "expectation": true diff --git a/PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.php b/PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.php index b120a99..067c6c0 100644 --- a/PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.php +++ b/PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.php @@ -1,19 +1,20 @@ one = $b; - } - - public function show_one() { - echo $this->one; - } - } + function __construct($b) { + $this->one = $b; + } -$b = $_GET["p1"]; + public function show_one() { + return $this->one; + } +} + +$b = $_GET["p1"]; // source $a = new A($b); $s = serialize($a); $h = unserialize($s); // will print $b, XSS vulnerability -$h->show_one(); \ No newline at end of file +$c = $h->show_one(); +echo $c; // sink \ No newline at end of file diff --git a/PHP/39_serialize_unserialize/39_serialize_unserialize.json b/PHP/39_serialize_unserialize/39_serialize_unserialize.json index e3eaa33..b0f42c3 100644 --- a/PHP/39_serialize_unserialize/39_serialize_unserialize.json +++ b/PHP/39_serialize_unserialize/39_serialize_unserialize.json @@ -1,6 +1,6 @@ { "name": "Serialize Unserialize", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/39_serialize_unserialize/README.md b/PHP/39_serialize_unserialize/README.md new file mode 100644 index 0000000..23b2fe0 --- /dev/null +++ b/PHP/39_serialize_unserialize/README.md @@ -0,0 +1,146 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Serialize Unserialize + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +In PHP `serialize()` can be used to bring an object in a storable format. `unserialize()` does the opposite and creates a PHP value from a stored representation. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +The instance shows `serialize` and `unserialize` called on an object as tarpits. After the object is unserialized, it has the same properties as before. + +### Code + +```PHP +one = $b; + } + + public function show_one() { + return $this->one; + } +} + +$b = $_GET["p1"]; // source +$a = new A($b); +$s = serialize($a); +$h = unserialize($s); +// will print $b, XSS vulnerability +$c = $h->show_one(); +echo $c; // sink +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=20, args=0, vars=5, tmps=12) + ; (before optimizer) + ; /.../PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.php:1-20 + ; return [] RANGE[0..0] +0000 T5 = FETCH_R (global) string("_GET") +0001 T6 = FETCH_DIM_R T5 string("p1") +0002 ASSIGN CV0($b) T6 +0003 V8 = NEW 1 string("A") +0004 SEND_VAR_EX CV0($b) 1 +0005 DO_FCALL +0006 ASSIGN CV1($a) V8 +0007 INIT_FCALL 1 96 string("serialize") +0008 SEND_VAR CV1($a) 1 +0009 V11 = DO_ICALL +0010 ASSIGN CV2($s) V11 +0011 INIT_FCALL 1 96 string("unserialize") +0012 SEND_VAR CV2($s) 1 +0013 V13 = DO_ICALL +0014 ASSIGN CV3($h) V13 +0015 INIT_METHOD_CALL 0 CV3($h) string("show_one") +0016 V15 = DO_FCALL +0017 ASSIGN CV4($c) V15 +0018 ECHO CV4($c) +0019 RETURN int(1) +LIVE RANGES: + 8: 0004 - 0006 (new) + +A::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("one") +0002 OP_DATA CV0($b) +0003 RETURN null + +A::show_one: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/39_serialize_unserialize/1_instance_39_serialize_unserialize/1_instance_39_serialize_unserialize.php:9-11 + ; return [] RANGE[0..0] +0000 T0 = FETCH_OBJ_R THIS string("one") +0001 RETURN T0 +0002 RETURN null +``` + +
+ +
+ + +### Discovery + + +The rule searches for a function call to serialize or unserialize in opcode. + +```scala +val x39 = (name, "39_serialize_unserialize_iall", cpg.call("INIT_FCALL").argument.order(2).code("serialize|unserialize").astParent.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | yes | no | no | yes | +| 17 May 2023 | no | yes | | | | | yes | + +
+ +
diff --git a/PHP/39_serialize_unserialize/docs/description.md b/PHP/39_serialize_unserialize/docs/description.md new file mode 100644 index 0000000..3f3df99 --- /dev/null +++ b/PHP/39_serialize_unserialize/docs/description.md @@ -0,0 +1 @@ +In PHP `serialize()` can be used to bring an object in a storable format. `unserialize()` does the opposite and creates a PHP value from a stored representation. \ No newline at end of file diff --git a/PHP/3_global_array/1_instance_3_global_array/1_instance_3_global_array.bash b/PHP/3_global_array/1_instance_3_global_array/1_instance_3_global_array.bash new file mode 100644 index 0000000..764537f --- /dev/null +++ b/PHP/3_global_array/1_instance_3_global_array/1_instance_3_global_array.bash @@ -0,0 +1,23 @@ + +$_main: + ; (lines=8, args=0, vars=2, tmps=5) + ; (before optimizer) + ; /.../PHP/3_global_array/1_instance_3_global_array/1_instance_3_global_array.php:1-9 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($a) T3 +0003 INIT_FCALL 0 96 string("f") +0004 V5 = DO_UCALL +0005 ASSIGN CV1($b) V5 +0006 ECHO CV1($b) +0007 RETURN int(1) + +F: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/3_global_array/1_instance_3_global_array/1_instance_3_global_array.php:2-4 + ; return [] RANGE[0..0] +0000 T0 = FETCH_R (global) string("a") +0001 RETURN T0 +0002 RETURN null diff --git a/PHP/3_global_array/1_instance_3_global_array/1_instance_3_global_array.json b/PHP/3_global_array/1_instance_3_global_array/1_instance_3_global_array.json index 436f7af..ace0a7c 100644 --- a/PHP/3_global_array/1_instance_3_global_array/1_instance_3_global_array.json +++ b/PHP/3_global_array/1_instance_3_global_array/1_instance_3_global_array.json @@ -1,4 +1,5 @@ { + "description": "This instance targets using the `GLOBALS` array within a function.", "code": { "path": "./1_instance_3_global_array.php", "injection_skeleton_broken": false @@ -10,21 +11,21 @@ "notes": "The discovery rule would be more accurate if we could check if the GLOBALS fetch is done outside the main block" }, "remediation": { - "notes": null, + "notes": "Most likely, this needs manual transformation, by passing the value as an argument to the function or using a class and an instance variable instead.", "transformation": null, "modeling_rule": null }, "compile": { - "binary": "", + "binary": "./1_instance_3_global_array.bash", "dependencies": null, "instruction": null }, "expectation": { "type": "xss", "sink_file": "./1_instance_3_global_array.php", - "sink_line": 9, + "sink_line": 8, "source_file": "./1_instance_3_global_array.php", - "source_line": 7, + "source_line": 6, "expectation": true }, "properties": { diff --git a/PHP/3_global_array/1_instance_3_global_array/1_instance_3_global_array.php b/PHP/3_global_array/1_instance_3_global_array/1_instance_3_global_array.php index 0695f6f..8c3f056 100644 --- a/PHP/3_global_array/1_instance_3_global_array/1_instance_3_global_array.php +++ b/PHP/3_global_array/1_instance_3_global_array/1_instance_3_global_array.php @@ -1,6 +1,5 @@ + + +## 1 Instance + + +This instance targets using the `GLOBALS` array within a function. -function F(){ +### Code + +```PHP + + +More -- OPCODE: +
+ + +### Compile + ```bash -$_main: ; (lines=8, args=0, vars=1, tmps=4) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/4_global_array/first_ex/first_ex.php:1-9 -L0 (7): EXT_STMT -L1 (7): T1 = FETCH_R (global) string("_GET") -L2 (7): T2 = FETCH_DIM_R T1 string("p1") -L3 (7): ASSIGN CV0($a) T2 -L4 (8): EXT_STMT -L5 (8): INIT_FCALL 0 112 string("f") -L6 (8): DO_FCALL -L7 (9): RETURN int(1) - -F: ; (lines=7, args=0, vars=0, tmps=2) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/4_global_array/first_ex/first_ex.php:3-5 -L0 (3): EXT_NOP -L1 (4): EXT_STMT -L2 (4): T0 = FETCH_R (global) string("GLOBALS") -L3 (4): T1 = FETCH_DIM_R T0 string("a") -L4 (4): ECHO T1 -L5 (5): EXT_STMT -L6 (5): RETURN null +$_main: + ; (lines=8, args=0, vars=2, tmps=5) + ; (before optimizer) + ; /.../PHP/3_global_array/1_instance_3_global_array/1_instance_3_global_array.php:1-9 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($a) T3 +0003 INIT_FCALL 0 96 string("f") +0004 V5 = DO_UCALL +0005 ASSIGN CV1($b) V5 +0006 ECHO CV1($b) +0007 RETURN int(1) + +F: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/3_global_array/1_instance_3_global_array/1_instance_3_global_array.php:2-4 + ; return [] RANGE[0..0] +0000 T0 = FETCH_R (global) string("a") +0001 RETURN T0 +0002 RETURN null +``` + +
+ +
+ + +### Discovery + + +The discovery rule would be more accurate if we could check if the GLOBALS fetch is done outside the main block + +```scala +val x3 = (name, "3_global_array_i1", cpg.call(".*FETCH_W.*|.*FETCH_R.*|.*FETCH_RW.*").argument.code("GLOBALS").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | yes | no | yes | no | yes | yes | +| 17 May 2023 | yes | no | | | | | yes | + +
+ +
+ + +### Remediation + + +Most likely, this needs manual transformation, by passing the value as an argument to the function or using a class and an instance variable instead. + +
+ + + + + +
+ + +## 2 Instance + + +This instance targets using the `GLOBALS` array outside of functions inside the main block. + +### Code + +```PHP + + +More + +
+ + +### Compile + ```bash -cpg.call(".*FETCH_W.*|.*FETCH_R.*|.*FETCH_RW.*").argument.code("GLOBALS").location.l +$_main: + ; (lines=7, args=0, vars=2, tmps=5) + ; (before optimizer) + ; /.../PHP/3_global_array/2_instance_3_global_array/2_instance_3_global_array.php:1-4 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($a) T3 +0003 T5 = FETCH_R (global) string("a") +0004 ASSIGN CV1($b) T5 +0005 ECHO CV1($b) +0006 RETURN int(1) ``` -- PRECONDITIONS: - 1. +
-- TRANSFORMATION: +
+ +### Discovery + + +Using discovery rule of another instance. A specific discovery rule for this instance would be more accurate if we could check if the GLOBALS fetch is done INSIDE the main block + +```scala +val x3 = (name, "3_global_array_i2", cpg.call(".*FETCH_W.*|.*FETCH_R.*|.*FETCH_RW.*").argument.code("GLOBALS").location.toJson); ``` -``` \ No newline at end of file +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | Ground Truth | +|-------------|----------|----------|----------------| +| 17 May 2023 | yes | yes | yes | +| 26 May 2023 | yes | yes | yes | + +
+ +
+ + +### Remediation + + +Instead of using the `GLOBALS` array, one could transform the code to use the 'normal' name of the variable instead + +
+ +
+ + diff --git a/PHP/3_global_array/docs/description.md b/PHP/3_global_array/docs/description.md new file mode 100644 index 0000000..e798afe --- /dev/null +++ b/PHP/3_global_array/docs/description.md @@ -0,0 +1 @@ +This pattern targets [`GLOBALS`](https://www.php.net/manual/en/reserved.variables.globals.php) array. This array contains references to all variables which are defined in the global scope. \ No newline at end of file diff --git a/PHP/40_trait/1_instance_40_trait/1_instance_40_trait.bash b/PHP/40_trait/1_instance_40_trait/1_instance_40_trait.bash index 1fdd146..2ac49e4 100644 --- a/PHP/40_trait/1_instance_40_trait/1_instance_40_trait.bash +++ b/PHP/40_trait/1_instance_40_trait/1_instance_40_trait.bash @@ -1,30 +1,30 @@ -$_main: ; (lines=14, args=0, vars=2, tmps=7) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/67_trait/67_trait.php:1-16 -L0 (2): EXT_STMT -L1 (2): T2 = FETCH_R (global) string("_GET") -L2 (2): T3 = FETCH_DIM_R T2 string("p1") -L3 (2): ASSIGN CV0($b) T3 -L4 (10): DECLARE_CLASS string("myhelloworld") -L5 (14): EXT_STMT -L6 (14): V5 = NEW 0 string("MyHelloWorld") -L7 (14): DO_FCALL -L8 (14): ASSIGN CV1($o) V5 -L9 (16): EXT_STMT -L10 (16): INIT_METHOD_CALL 1 CV1($o) string("sayHello") -L11 (16): SEND_VAR_EX CV0($b) 1 -L12 (16): DO_FCALL -L13 (16): RETURN int(1) +$_main: + ; (lines=13, args=0, vars=3, tmps=8) + ; (before optimizer) + ; /.../PHP/40_trait/1_instance_40_trait/1_instance_40_trait.php:1-16 + ; return [] RANGE[0..0] +0000 DECLARE_CLASS string("myhelloworld") +0001 T3 = FETCH_R (global) string("_GET") +0002 T4 = FETCH_DIM_R T3 string("p1") +0003 ASSIGN CV0($b) T4 +0004 V6 = NEW 0 string("MyHelloWorld") +0005 DO_FCALL +0006 ASSIGN CV1($o) V6 +0007 INIT_METHOD_CALL 1 CV1($o) string("sayHello") +0008 SEND_VAR_EX CV0($b) 1 +0009 V9 = DO_FCALL +0010 ASSIGN CV2($a) V9 +0011 ECHO CV2($a) +0012 RETURN int(1) LIVE RANGES: - 5: L7 - L8 (new) + 6: 0005 - 0006 (new) -SayWorld::sayHello: ; (lines=6, args=1, vars=1, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/67_trait/67_trait.php:5-7 -L0 (5): EXT_NOP -L1 (5): CV0($b) = RECV 1 -L2 (6): EXT_STMT -L3 (6): ECHO CV0($b) -L4 (7): EXT_STMT -L5 (7): RETURN null +SayWorld::sayHello: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/40_trait/1_instance_40_trait/1_instance_40_trait.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN CV0($b) +0002 RETURN null diff --git a/PHP/40_trait/1_instance_40_trait/1_instance_40_trait.json b/PHP/40_trait/1_instance_40_trait/1_instance_40_trait.json index dc3a75e..b1bf749 100644 --- a/PHP/40_trait/1_instance_40_trait/1_instance_40_trait.json +++ b/PHP/40_trait/1_instance_40_trait/1_instance_40_trait.json @@ -1,4 +1,5 @@ { + "description": "The instance shows, that the trait `SayWorld` is used by `MyHelloWorld`.", "code": { "path": "./1_instance_40_trait.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_40_trait.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "FP", + "notes": "The rule searches for class declarations (`DECLARE_CLASS`) in opcode. It would be more accurate, if a trait was involved. This pattern might profit from source code detection as well." }, "compile": { "binary": "./1_instance_40_trait.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_40_trait.php", - "sink_line": 6, + "sink_line": 16, "source_file": "./1_instance_40_trait.php", - "source_line": 2, + "source_line": 12, "expectation": true }, "properties": { diff --git a/PHP/40_trait/1_instance_40_trait/1_instance_40_trait.php b/PHP/40_trait/1_instance_40_trait/1_instance_40_trait.php index e8cd522..5051b4a 100644 --- a/PHP/40_trait/1_instance_40_trait/1_instance_40_trait.php +++ b/PHP/40_trait/1_instance_40_trait/1_instance_40_trait.php @@ -1,16 +1,16 @@ sayHello($b); \ No newline at end of file +// will call the function sayHello() +$a = $o->sayHello($b); +echo $a; // sink \ No newline at end of file diff --git a/PHP/40_trait/40_trait.json b/PHP/40_trait/40_trait.json index a5725fb..6b8f40d 100644 --- a/PHP/40_trait/40_trait.json +++ b/PHP/40_trait/40_trait.json @@ -1,6 +1,6 @@ { "name": "Trait", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_40_trait/1_instance_40_trait.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/40_trait/README.md b/PHP/40_trait/README.md new file mode 100644 index 0000000..ce13746 --- /dev/null +++ b/PHP/40_trait/README.md @@ -0,0 +1,125 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Trait + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +PHP only supports single inheritance. A trait can define methods to be used in multiple classes. This makes it possible for a class in PHP to inherit multiple behaviours. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +The instance shows, that the trait `SayWorld` is used by `MyHelloWorld`. + +### Code + +```PHP +sayHello($b); +echo $a; // sink +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=13, args=0, vars=3, tmps=8) + ; (before optimizer) + ; /.../PHP/40_trait/1_instance_40_trait/1_instance_40_trait.php:1-16 + ; return [] RANGE[0..0] +0000 DECLARE_CLASS string("myhelloworld") +0001 T3 = FETCH_R (global) string("_GET") +0002 T4 = FETCH_DIM_R T3 string("p1") +0003 ASSIGN CV0($b) T4 +0004 V6 = NEW 0 string("MyHelloWorld") +0005 DO_FCALL +0006 ASSIGN CV1($o) V6 +0007 INIT_METHOD_CALL 1 CV1($o) string("sayHello") +0008 SEND_VAR_EX CV0($b) 1 +0009 V9 = DO_FCALL +0010 ASSIGN CV2($a) V9 +0011 ECHO CV2($a) +0012 RETURN int(1) +LIVE RANGES: + 6: 0005 - 0006 (new) + +SayWorld::sayHello: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/40_trait/1_instance_40_trait/1_instance_40_trait.php:3-5 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN CV0($b) +0002 RETURN null +``` + +
+ +
+ + +### Discovery + + +The rule searches for class declarations (`DECLARE_CLASS`) in opcode. It would be more accurate, if a trait was involved. This pattern might profit from source code detection as well. + +```scala +val x40 = (name, "40_trait_iall", cpg.call(".*DECLARE_CLASS.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | yes | no | no | no | no | yes | +| 17 May 2023 | yes | yes | | | | | yes | + +
+ +
diff --git a/PHP/40_trait/docs/description.md b/PHP/40_trait/docs/description.md new file mode 100644 index 0000000..4b7723f --- /dev/null +++ b/PHP/40_trait/docs/description.md @@ -0,0 +1 @@ +PHP only supports single inheritance. A trait can define methods to be used in multiple classes. This makes it possible for a class in PHP to inherit multiple behaviours. \ No newline at end of file diff --git a/PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.bash b/PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.bash index a7051c4..904da6b 100644 --- a/PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.bash +++ b/PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.bash @@ -1,40 +1,41 @@ -$_main: ; (lines=12, args=0, vars=1, tmps=6) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/90_self_methods/90_self_methods.php:1-17 -L0 (15): EXT_STMT -L1 (15): V1 = NEW 0 string("myclass") -L2 (15): DO_FCALL -L3 (15): ASSIGN CV0($obj) V1 -L4 (17): EXT_STMT -L5 (17): INIT_METHOD_CALL 1 CV0($obj) string("F") -L6 (17): CHECK_FUNC_ARG 1 -L7 (17): V4 = FETCH_FUNC_ARG (global) string("_GET") -L8 (17): V5 = FETCH_DIM_FUNC_ARG V4 string("p1") -L9 (17): SEND_FUNC_ARG V5 1 -L10 (17): DO_FCALL -L11 (17): RETURN int(1) +$_main: + ; (lines=12, args=0, vars=3, tmps=8) + ; (before optimizer) + ; /.../PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.php:1-16 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($b) T4 +0003 V6 = NEW 0 string("myclass") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V6 +0006 INIT_METHOD_CALL 1 CV1($obj) string("F") +0007 SEND_VAR_EX CV0($b) 1 +0008 V9 = DO_FCALL +0009 ASSIGN CV2($a) V9 +0010 ECHO CV2($a) +0011 RETURN int(1) LIVE RANGES: - 1: L2 - L3 (new) + 6: 0004 - 0005 (new) -myclass::F: ; (lines=8, args=1, vars=1, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/90_self_methods/90_self_methods.php:5-7 -L0 (5): EXT_NOP -L1 (5): CV0($b) = RECV 1 -L2 (6): EXT_STMT -L3 (6): INIT_STATIC_METHOD_CALL 1 (self) (exception) string("T") -L4 (6): SEND_VAR_EX CV0($b) 1 -L5 (6): DO_FCALL -L6 (7): EXT_STMT -L7 (7): RETURN null +myclass::F: + ; (lines=6, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 INIT_STATIC_METHOD_CALL 1 (self) (exception) string("T") +0002 SEND_VAR_EX CV0($b) 1 +0003 V1 = DO_FCALL +0004 RETURN V1 +0005 RETURN null -myclass::T: ; (lines=6, args=1, vars=1, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/90_self_methods/90_self_methods.php:9-11 -L0 (9): EXT_NOP -L1 (9): CV0($b) = RECV 1 -L2 (10): EXT_STMT -L3 (10): ECHO CV0($b) -L4 (11): EXT_STMT -L5 (11): RETURN null +myclass::T: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.php:8-10 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN CV0($b) +0002 RETURN null diff --git a/PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.json b/PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.json index bc52a8e..c943d61 100644 --- a/PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.json +++ b/PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.json @@ -1,4 +1,5 @@ { + "description": "The instance shows, how to call a static function of a class from a non static function of that class.", "code": { "path": "./1_instance_41_self_methods.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_41_self_methods.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "FP", + "notes": "The rule looks for static method calls (`INIT_STATIC_METHOD_CALL`) in the opcode and checks if the argument of that function is `self`." }, "compile": { "binary": "./1_instance_41_self_methods.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_41_self_methods.php", - "sink_line": 10, + "sink_line": 16, "source_file": "./1_instance_41_self_methods.php", - "source_line": 17, + "source_line": 13, "expectation": true }, "properties": { diff --git a/PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.php b/PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.php index a7efa35..2b483f9 100644 --- a/PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.php +++ b/PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.php @@ -1,17 +1,16 @@ F($_GET['p1']); \ No newline at end of file +$a = $obj->F($b); +echo $a; // sink \ No newline at end of file diff --git a/PHP/41_self_methods/1_instance_41_self_methods/_1_instance_41_self_methods.bash b/PHP/41_self_methods/1_instance_41_self_methods/_1_instance_41_self_methods.bash new file mode 100644 index 0000000..1c332a1 --- /dev/null +++ b/PHP/41_self_methods/1_instance_41_self_methods/_1_instance_41_self_methods.bash @@ -0,0 +1,41 @@ + +$_main: + ; (lines=12, args=0, vars=3, tmps=8) + ; (before optimizer) + ; /.../PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.php:1-17 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($b) T4 +0003 V6 = NEW 0 string("myclass") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V6 +0006 INIT_METHOD_CALL 1 CV1($obj) string("F") +0007 SEND_VAR_EX CV0($b) 1 +0008 V9 = DO_FCALL +0009 ASSIGN CV2($a) V9 +0010 ECHO CV2($a) +0011 RETURN int(1) +LIVE RANGES: + 6: 0004 - 0005 (new) + +myclass::F: + ; (lines=6, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 INIT_STATIC_METHOD_CALL 1 (self) (exception) string("T") +0002 SEND_VAR_EX CV0($b) 1 +0003 V1 = DO_FCALL +0004 RETURN V1 +0005 RETURN null + +myclass::T: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.php:9-11 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN CV0($b) +0002 RETURN null diff --git a/PHP/41_self_methods/41_self_methods.json b/PHP/41_self_methods/41_self_methods.json index dd3598b..d92259f 100644 --- a/PHP/41_self_methods/41_self_methods.json +++ b/PHP/41_self_methods/41_self_methods.json @@ -1,6 +1,6 @@ { "name": "Self Methods", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_41_self_methods/1_instance_41_self_methods.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/41_self_methods/README.md b/PHP/41_self_methods/README.md new file mode 100644 index 0000000..6f816c1 --- /dev/null +++ b/PHP/41_self_methods/README.md @@ -0,0 +1,136 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Self Methods + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +In PHP `self` is used to refer to the current class. So `self::method` refers to a static method defined in the current class. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +The instance shows, how to call a static function of a class from a non static function of that class. + +### Code + +```PHP +F($b); +echo $a; // sink +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=12, args=0, vars=3, tmps=8) + ; (before optimizer) + ; /.../PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.php:1-16 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($b) T4 +0003 V6 = NEW 0 string("myclass") +0004 DO_FCALL +0005 ASSIGN CV1($obj) V6 +0006 INIT_METHOD_CALL 1 CV1($obj) string("F") +0007 SEND_VAR_EX CV0($b) 1 +0008 V9 = DO_FCALL +0009 ASSIGN CV2($a) V9 +0010 ECHO CV2($a) +0011 RETURN int(1) +LIVE RANGES: + 6: 0004 - 0005 (new) + +myclass::F: + ; (lines=6, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 INIT_STATIC_METHOD_CALL 1 (self) (exception) string("T") +0002 SEND_VAR_EX CV0($b) 1 +0003 V1 = DO_FCALL +0004 RETURN V1 +0005 RETURN null + +myclass::T: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/41_self_methods/1_instance_41_self_methods/1_instance_41_self_methods.php:8-10 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN CV0($b) +0002 RETURN null +``` + +
+ +
+ + +### Discovery + + +The rule looks for static method calls (`INIT_STATIC_METHOD_CALL`) in the opcode and checks if the argument of that function is `self`. + +```scala +val x41 = (name, "41_self_methods_iall", cpg.call(".*INIT_STATIC_METHOD_CALL.*").argument.order(1).code("self").astParent.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | yes | no | no | yes | +| 22 May 2023 | yes | yes | | | | | yes | + +
+ +
diff --git a/PHP/41_self_methods/docs/description.md b/PHP/41_self_methods/docs/description.md new file mode 100644 index 0000000..ad13542 --- /dev/null +++ b/PHP/41_self_methods/docs/description.md @@ -0,0 +1 @@ +In PHP `self` is used to refer to the current class. So `self::method` refers to a static method defined in the current class. \ No newline at end of file diff --git a/PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.bash b/PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.bash index 03dc587..d359421 100644 --- a/PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.bash +++ b/PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.bash @@ -1,45 +1,35 @@ -$_main: ; (lines=11, args=0, vars=2, tmps=6) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/28_destructor/28_destructor.php:1-19 -L0 (4): NOP -L1 (16): EXT_STMT -L2 (16): T2 = FETCH_R (global) string("_GET") -L3 (16): T3 = FETCH_DIM_R T2 string("p1") -L4 (16): ASSIGN CV0($b) T3 -L5 (19): EXT_STMT -L6 (19): V5 = NEW 1 string("BaseClass") -L7 (19): SEND_VAR_EX CV0($b) 1 -L8 (19): DO_FCALL -L9 (19): ASSIGN CV1($obj) V5 -L10 (19): RETURN int(1) +$_main: + ; (lines=8, args=0, vars=2, tmps=6) + ; (before optimizer) + ; /.../PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.php:1-16 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 1 string("BaseClass") +0004 SEND_VAR_EX CV0($b) 1 +0005 DO_FCALL +0006 ASSIGN CV1($obj) V5 +0007 RETURN int(1) LIVE RANGES: - 5: L7 - L9 (new) + 5: 0004 - 0006 (new) -BaseClass::__construct: ; (lines=9, args=1, vars=1, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/28_destructor/28_destructor.php:6-9 -L0 (6): EXT_NOP -L1 (6): CV0($b) = RECV 1 -L2 (7): EXT_STMT -L3 (7): ECHO string("In BaseClass constructor -") -L4 (8): EXT_STMT -L5 (8): ASSIGN_OBJ THIS string("var") -L6 (8): OP_DATA CV0($b) -L7 (9): EXT_STMT -L8 (9): RETURN null - -BaseClass::__destruct: ; (lines=8, args=0, vars=0, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/28_destructor/28_destructor.php:10-13 -L0 (10): EXT_NOP -L1 (11): EXT_STMT -L2 (11): ECHO string("Destroying BaseClass -") -L3 (12): EXT_STMT -L4 (12): T0 = FETCH_OBJ_R THIS string("var") -L5 (12): ECHO T0 -L6 (13): EXT_STMT -L7 (13): RETURN null +BaseClass::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("var") +0002 OP_DATA CV0($b) +0003 RETURN null +BaseClass::__destruct: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.php:8-10 + ; return [] RANGE[0..0] +0000 T0 = FETCH_OBJ_R THIS string("var") +0001 ECHO T0 +0002 RETURN null diff --git a/PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.json b/PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.json index 614eeb7..1981c62 100644 --- a/PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.json +++ b/PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.json @@ -1,13 +1,14 @@ { + "description": "This instance shows a simple use of `__destruct` and that method contains a sink.", "code": { "path": "./1_instance_42_destructor.php", - "injection_skeleton_broken": false + "injection_skeleton_broken": true }, "discovery": { "rule": "./1_instance_42_destructor.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "FP", + "notes": "The discovery rule first gets all class names, where the method `__destruct` is defined.\nAfterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__destruct` defined.\nThe rule would be perfect, if we could additionally check, if one of the created objects invokes the `__destruct` method within its lifetime." }, "compile": { "binary": "./1_instance_42_destructor.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_42_destructor.php", - "sink_line": 12, + "sink_line": 9, "source_file": "./1_instance_42_destructor.php", - "source_line": 16, + "source_line": 13, "expectation": true }, "properties": { diff --git a/PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.php b/PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.php index 3f87d4b..cf84e80 100644 --- a/PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.php +++ b/PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.php @@ -1,19 +1,16 @@ var = $b; } function __destruct() { - print "Destroying " . __CLASS__ . "\n"; - echo $this->var; + echo $this->var; // sink } } -$b = $_GET["p1"]; +$b = $_GET["p1"]; // source // In BaseClass constructor // There is XSS when the object will be destroyed $obj = new BaseClass($b); \ No newline at end of file diff --git a/PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.sc b/PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.sc index a30c204..89c3f1a 100644 --- a/PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.sc +++ b/PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.sc @@ -1,7 +1,7 @@ @main def main(name : String): Unit = { importCpg(name) - def methods8 = cpg.method.name("__destruct").name.l - val x42 = (name, "42_destructor_iall", cpg.call("NEW").argument.filter{x => methods8.contains(x.code.toLowerCase)}.location.toJson); + def classMethods = cpg.method.name("__destruct").astParentFullName.l + val x42 = (name, "42_destructor_iall", cpg.call("NEW").argument.filter{x => classMethods.contains(x.code.toLowerCase)}.location.toJson); println(x42) delete; } \ No newline at end of file diff --git a/PHP/42_destructor/42_destructor.json b/PHP/42_destructor/42_destructor.json index 0325831..a96bfcc 100644 --- a/PHP/42_destructor/42_destructor.json +++ b/PHP/42_destructor/42_destructor.json @@ -1,6 +1,6 @@ { "name": "Destructor", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_42_destructor/1_instance_42_destructor.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/42_destructor/README.md b/PHP/42_destructor/README.md new file mode 100644 index 0000000..ee4f6f9 --- /dev/null +++ b/PHP/42_destructor/README.md @@ -0,0 +1,133 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Destructor + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +In PHP `__destruct()` will be called as soon as there are no more references pointing to the object or in a shutdown operation. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +This instance shows a simple use of `__destruct` and that method contains a sink. + +### Code + +```PHP +var = $b; + } + function __destruct() { + echo $this->var; // sink + } +} + +$b = $_GET["p1"]; // source +// In BaseClass constructor +// There is XSS when the object will be destroyed +$obj = new BaseClass($b); +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=8, args=0, vars=2, tmps=6) + ; (before optimizer) + ; /.../PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.php:1-16 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 1 string("BaseClass") +0004 SEND_VAR_EX CV0($b) 1 +0005 DO_FCALL +0006 ASSIGN CV1($obj) V5 +0007 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0006 (new) + +BaseClass::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.php:5-7 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("var") +0002 OP_DATA CV0($b) +0003 RETURN null + +BaseClass::__destruct: + ; (lines=3, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/42_destructor/1_instance_42_destructor/1_instance_42_destructor.php:8-10 + ; return [] RANGE[0..0] +0000 T0 = FETCH_OBJ_R THIS string("var") +0001 ECHO T0 +0002 RETURN null +``` + +
+ +
+ + +### Discovery + + +The discovery rule first gets all class names, where the method `__destruct` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__destruct` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__destruct` method within its lifetime. + +```scala +def classMethods = cpg.method.name("__destruct").astParentFullName.l +val x42 = (name, "42_destructor_iall", cpg.call("NEW").argument.filter{x => classMethods.contains(x.code.toLowerCase)}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | yes | no | no | yes | +| 22 May 2023 | no | no | | | | | yes | + +
+ +
diff --git a/PHP/42_destructor/docs/description.md b/PHP/42_destructor/docs/description.md new file mode 100644 index 0000000..80769db --- /dev/null +++ b/PHP/42_destructor/docs/description.md @@ -0,0 +1 @@ +In PHP `__destruct()` will be called as soon as there are no more references pointing to the object or in a shutdown operation. \ No newline at end of file diff --git a/PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.bash b/PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.bash index d8d01d3..01d22dd 100644 --- a/PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.bash +++ b/PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.bash @@ -1,40 +1,41 @@ -$_main: ; (lines=13, args=0, vars=2, tmps=6) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/34_tostring_echo_object/34_tostring_echo_object.php:1-17 -L0 (4): NOP -L1 (14): EXT_STMT -L2 (14): T2 = FETCH_R (global) string("_GET") -L3 (14): T3 = FETCH_DIM_R T2 string("p1") -L4 (14): ASSIGN CV0($b) T3 -L5 (15): EXT_STMT -L6 (15): V5 = NEW 1 string("TestClass") -L7 (15): SEND_VAR_EX CV0($b) 1 -L8 (15): DO_FCALL -L9 (15): ASSIGN CV1($class) V5 -L10 (17): EXT_STMT -L11 (17): ECHO CV1($class) -L12 (17): RETURN int(1) +$_main: + ; (lines=10, args=0, vars=2, tmps=6) + ; (before optimizer) + ; /.../PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.php:1-16 + ; return [] RANGE[0..0] +0000 DECLARE_CLASS string("testclass") +0001 T2 = FETCH_R (global) string("_GET") +0002 T3 = FETCH_DIM_R T2 string("p1") +0003 ASSIGN CV0($b) T3 +0004 V5 = NEW 1 string("TestClass") +0005 SEND_VAR_EX CV0($b) 1 +0006 DO_FCALL +0007 ASSIGN CV1($class) V5 +0008 ECHO CV1($class) +0009 RETURN int(1) LIVE RANGES: - 5: L7 - L9 (new) + 5: 0005 - 0007 (new) -TestClass::__construct: ; (lines=7, args=1, vars=1, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/34_tostring_echo_object/34_tostring_echo_object.php:5-7 -L0 (5): EXT_NOP -L1 (5): CV0($foo) = RECV 1 -L2 (6): EXT_STMT -L3 (6): ASSIGN_OBJ THIS string("foo") -L4 (6): OP_DATA CV0($foo) -L5 (7): EXT_STMT -L6 (7): RETURN null +TestClass::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($foo) = RECV 1 +0001 ASSIGN_OBJ THIS string("foo") +0002 OP_DATA CV0($foo) +0003 RETURN null -TestClass::__toString: ; (lines=6, args=0, vars=0, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/34_tostring_echo_object/34_tostring_echo_object.php:9-11 -L0 (9): EXT_NOP -L1 (10): EXT_STMT -L2 (10): T0 = FETCH_OBJ_R THIS string("foo") -L3 (10): RETURN T0 -L4 (11): EXT_STMT -L5 (11): RETURN null +TestClass::__toString: + ; (lines=5, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.php:8-10 + ; return [] RANGE[0..0] +0000 T0 = FETCH_OBJ_R THIS string("foo") +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +0003 VERIFY_RETURN_TYPE +0004 RETURN null +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) diff --git a/PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.json b/PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.json index e24c382..6c12f4d 100644 --- a/PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.json +++ b/PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.json @@ -1,4 +1,5 @@ { + "description": "The instance shows, that when you call `echo` on an object, the `to_string` method of that object will be called.", "code": { "path": "./1_instance_43_tostring_echo_object.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_43_tostring_echo_object.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "FP", + "notes": "The discovery rule first gets all class names, where the method `__toString` is defined.\nAfterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__toString` defined.\nThe rule would be perfect, if we could additionally check, if one of the created objects invokes the `__toString` method within its lifetime." }, "compile": { "binary": "./1_instance_43_tostring_echo_object.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_43_tostring_echo_object.php", - "sink_line": 17, + "sink_line": 16, "source_file": "./1_instance_43_tostring_echo_object.php", - "source_line": 14, + "source_line": 13, "expectation": true }, "properties": { @@ -30,7 +31,7 @@ "negative_test_case": false }, "remediation": { - "notes": "", + "notes": "If that is a problem, is it easier for a SAST tool, to call `__toString` manually before passing it to `echo`?", "transformation": null, "modeling_rule": null } diff --git a/PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.php b/PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.php index 2bb1d21..dd0d00f 100644 --- a/PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.php +++ b/PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.php @@ -1,17 +1,16 @@ foo = $foo; } - public function __toString(){ + public function __toString() { return $this->foo; } } -$b = $_GET["p1"]; +$b = $_GET["p1"]; // source $class = new TestClass($b); // XSS vulnerability, will print the input $b -echo $class; \ No newline at end of file +echo $class; // sink \ No newline at end of file diff --git a/PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.sc b/PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.sc index a0e6241..e0a1ff7 100644 --- a/PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.sc +++ b/PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.sc @@ -1,7 +1,7 @@ @main def main(name : String): Unit = { importCpg(name) - def methods9 = cpg.method.name("__tostring").name.l - val x43 = (name, "43_tostring_echo_object_iall", cpg.call("NEW").argument.filter{x => methods9.contains(x.code.toLowerCase)}.location.toJson); + def classMethods = cpg.method.name("__tostring").astParentFullName.l + val x43 = (name, "43_tostring_echo_object_iall", cpg.call("NEW").argument.filter{x => classMethods.contains(x.code.toLowerCase)}.location.toJson); println(x43) delete; } \ No newline at end of file diff --git a/PHP/43_tostring_echo_object/43_tostring_echo_object.json b/PHP/43_tostring_echo_object/43_tostring_echo_object.json index 04a4c9a..39c056c 100644 --- a/PHP/43_tostring_echo_object/43_tostring_echo_object.json +++ b/PHP/43_tostring_echo_object/43_tostring_echo_object.json @@ -1,6 +1,6 @@ { "name": "Tostring Echo Object", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/43_tostring_echo_object/README.md b/PHP/43_tostring_echo_object/README.md new file mode 100644 index 0000000..f9c7218 --- /dev/null +++ b/PHP/43_tostring_echo_object/README.md @@ -0,0 +1,149 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Tostring Echo Object + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +`__toString()` is one of PHP magic functions, that override PHP's default behaviour. When implementing this function you can decide what happens when the object is treated as a string. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +The instance shows, that when you call `echo` on an object, the `to_string` method of that object will be called. + +### Code + +```PHP +foo = $foo; + } + + public function __toString() { + return $this->foo; + } +} + +$b = $_GET["p1"]; // source +$class = new TestClass($b); +// XSS vulnerability, will print the input $b +echo $class; // sink +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=10, args=0, vars=2, tmps=6) + ; (before optimizer) + ; /.../PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.php:1-16 + ; return [] RANGE[0..0] +0000 DECLARE_CLASS string("testclass") +0001 T2 = FETCH_R (global) string("_GET") +0002 T3 = FETCH_DIM_R T2 string("p1") +0003 ASSIGN CV0($b) T3 +0004 V5 = NEW 1 string("TestClass") +0005 SEND_VAR_EX CV0($b) 1 +0006 DO_FCALL +0007 ASSIGN CV1($class) V5 +0008 ECHO CV1($class) +0009 RETURN int(1) +LIVE RANGES: + 5: 0005 - 0007 (new) + +TestClass::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($foo) = RECV 1 +0001 ASSIGN_OBJ THIS string("foo") +0002 OP_DATA CV0($foo) +0003 RETURN null + +TestClass::__toString: + ; (lines=5, args=0, vars=0, tmps=1) + ; (before optimizer) + ; /.../PHP/43_tostring_echo_object/1_instance_43_tostring_echo_object/1_instance_43_tostring_echo_object.php:8-10 + ; return [] RANGE[0..0] +0000 T0 = FETCH_OBJ_R THIS string("foo") +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +0003 VERIFY_RETURN_TYPE +0004 RETURN null +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) +``` + +
+ +
+ + +### Discovery + + +The discovery rule first gets all class names, where the method `__toString` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__toString` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__toString` method within its lifetime. + +```scala +def classMethods = cpg.method.name("__tostring").astParentFullName.l +val x43 = (name, "43_tostring_echo_object_iall", cpg.call("NEW").argument.filter{x => classMethods.contains(x.code.toLowerCase)}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | yes | no | no | no | no | yes | +| 22 May 2023 | yes | yes | | | | | yes | + +
+ +
+ + +### Remediation + + +If that is a problem, is it easier for a SAST tool, to call `__toString` manually before passing it to `echo`? + +
+ +
diff --git a/PHP/43_tostring_echo_object/docs/description.md b/PHP/43_tostring_echo_object/docs/description.md new file mode 100644 index 0000000..914ab61 --- /dev/null +++ b/PHP/43_tostring_echo_object/docs/description.md @@ -0,0 +1 @@ +`__toString()` is one of PHP magic functions, that override PHP's default behaviour. When implementing this function you can decide what happens when the object is treated as a string. \ No newline at end of file diff --git a/PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.bash b/PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.bash index 4d4ef2a..e98adb9 100644 --- a/PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.bash +++ b/PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.bash @@ -1,57 +1,54 @@ -$_main: ; (lines=16, args=0, vars=2, tmps=7) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/85_verify_return_type/first_ex/first_ex.php:1-23 -L0 (4): NOP -L1 (5): NOP -L2 (21): EXT_STMT -L3 (21): T2 = FETCH_R (global) string("_GET") -L4 (21): T3 = FETCH_DIM_R T2 string("p1") -L5 (21): ASSIGN CV0($b) T3 -L6 (22): EXT_STMT -L7 (22): V5 = NEW 1 string("TestClass") -L8 (22): SEND_VAR_EX CV0($b) 1 -L9 (22): DO_FCALL -L10 (22): ASSIGN CV1($c) V5 -L11 (23): EXT_STMT -L12 (23): INIT_FCALL 1 96 string("f") -L13 (23): SEND_VAR CV1($c) 1 -L14 (23): DO_FCALL -L15 (23): RETURN int(1) +$_main: + ; (lines=12, args=0, vars=2, tmps=7) + ; (before optimizer) + ; /.../PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.php:1-21 + ; return [] RANGE[0..0] +0000 DECLARE_CLASS string("testclass") +0001 T2 = FETCH_R (global) string("_GET") +0002 T3 = FETCH_DIM_R T2 string("p1") +0003 ASSIGN CV0($b) T3 +0004 V5 = NEW 1 string("TestClass") +0005 SEND_VAR_EX CV0($b) 1 +0006 DO_FCALL +0007 ASSIGN CV1($c) V5 +0008 INIT_FCALL 1 96 string("f") +0009 SEND_VAR CV1($c) 1 +0010 DO_UCALL +0011 RETURN int(1) LIVE RANGES: - 5: L8 - L10 (new) + 5: 0005 - 0007 (new) -F: ; (lines=6, args=1, vars=1, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/85_verify_return_type/first_ex/first_ex.php:17-19 -L0 (17): EXT_NOP -L1 (17): CV0($c) = RECV 1 -L2 (18): EXT_STMT -L3 (18): ECHO string("message") -L4 (19): EXT_STMT -L5 (19): RETURN null +F: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.php:15-17 + ; return [] RANGE[0..0] +0000 CV0($c) = RECV 1 +0001 ECHO string("message") +0002 RETURN null -TestClass::__construct: ; (lines=7, args=1, vars=1, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/85_verify_return_type/first_ex/first_ex.php:6-8 -L0 (6): EXT_NOP -L1 (6): CV0($foo) = RECV 1 -L2 (7): EXT_STMT -L3 (7): ASSIGN_OBJ THIS string("foo") -L4 (7): OP_DATA CV0($foo) -L5 (8): EXT_STMT -L6 (8): RETURN null +TestClass::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($val) = RECV 1 +0001 ASSIGN_OBJ THIS string("x") +0002 OP_DATA CV0($val) +0003 RETURN null -TestClass::__toString: ; (lines=10, args=0, vars=0, tmps=3) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/85_verify_return_type/first_ex/first_ex.php:10-13 -L0 (10): EXT_NOP -L1 (11): EXT_STMT -L2 (11): T0 = FETCH_OBJ_R THIS string("foo") -L3 (11): T1 = CONCAT string("XSS: ") T0 -L4 (11): ECHO T1 -L5 (12): EXT_STMT -L6 (12): T2 = FETCH_OBJ_R THIS string("foo") -L7 (12): RETURN T2 -L8 (13): EXT_STMT -L9 (13): RETURN null +TestClass::__toString: + ; (lines=7, args=0, vars=0, tmps=2) + ; (before optimizer) + ; /.../PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.php:8-11 + ; return [] RANGE[0..0] +0000 T0 = FETCH_OBJ_R THIS string("x") +0001 ECHO T0 +0002 T1 = FETCH_OBJ_R THIS string("x") +0003 VERIFY_RETURN_TYPE T1 +0004 RETURN T1 +0005 VERIFY_RETURN_TYPE +0006 RETURN null +LIVE RANGES: + 1: 0003 - 0004 (tmp/var) diff --git a/PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.json b/PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.json index 4d1e591..ce00849 100644 --- a/PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.json +++ b/PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.json @@ -1,13 +1,14 @@ { + "description": "The instance defines a function, that takes a string as an argument. So if the argument is an object, `__toString` will be called on that object.", "code": { "path": "./1_instance_44_verify_return_type.php", - "injection_skeleton_broken": false + "injection_skeleton_broken": true }, "discovery": { - "rule": "../44_verify_return_type.sc", + "rule": "./1_instance_44_verify_return_type.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "FP", + "notes": "The discovery rule first gets all class names, where the method `__toString` is defined.\nAfterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__toString` defined.\nThe rule would be perfect, if we could additionally check, if one of the created objects invokes the `__toString` method within its lifetime." }, "compile": { "binary": "./1_instance_44_verify_return_type.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_44_verify_return_type.php", - "sink_line": 11, + "sink_line": 9, "source_file": "./1_instance_44_verify_return_type.php", - "source_line": 21, + "source_line": 19, "expectation": true }, "properties": { @@ -30,7 +31,7 @@ "negative_test_case": false }, "remediation": { - "notes": "", + "notes": "Call `__toString` manually on the object, when it is passed to a function, that takes strings as arguments.", "transformation": null, "modeling_rule": null } diff --git a/PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.php b/PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.php index acacd09..f0c4d0a 100644 --- a/PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.php +++ b/PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.php @@ -1,15 +1,13 @@ foo = $foo; +class TestClass { + public $x; + public function __construct($val) { + $this->x = $val; } - public function __toString(){ - echo 'XSS: ' . $this->foo; - return $this->foo; + public function __toString() { + echo $this->x; // sink + return $this->x; } } @@ -18,6 +16,6 @@ function F(string $c){ echo 'message'; } -$b = $_GET["p1"]; +$b = $_GET["p1"]; // source $c = new TestClass($b); F($c); \ No newline at end of file diff --git a/PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.sc b/PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.sc index 408c774..1d4cbd1 100644 --- a/PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.sc +++ b/PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.sc @@ -1,6 +1,7 @@ @main def main(name : String): Unit = { importCpg(name) - val x44 = (name, "44_verify_return_type_iall", cpg.call(".*VERIFY_RETURN_TYPE.*").location.toJson); + def methodClasses = cpg.method.name("__tostring").astParentFullName.l + val x44 = (name, "44_verify_return_type_i1", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); println(x44) delete; -} \ No newline at end of file +} \ No newline at end of file diff --git a/PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.bash b/PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.bash index 090da09..d7adf15 100644 --- a/PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.bash +++ b/PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.bash @@ -1,58 +1,56 @@ -$_main: ; (lines=10, args=0, vars=1, tmps=4) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/85_verify_return_type/second_ex/second_ex.php:1-22 -L0 (4): NOP -L1 (20): EXT_STMT -L2 (20): T1 = FETCH_R (global) string("_GET") -L3 (20): T2 = FETCH_DIM_R T1 string("p1") -L4 (20): ASSIGN CV0($b) T2 -L5 (22): EXT_STMT -L6 (22): INIT_FCALL 1 160 string("f") -L7 (22): SEND_VAR CV0($b) 1 -L8 (22): DO_FCALL -L9 (22): RETURN int(1) +$_main: + ; (lines=8, args=0, vars=1, tmps=4) + ; (before optimizer) + ; /.../PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.php:1-20 + ; return [] RANGE[0..0] +0000 DECLARE_CLASS string("testclass") +0001 T1 = FETCH_R (global) string("_GET") +0002 T2 = FETCH_DIM_R T1 string("p1") +0003 ASSIGN CV0($b) T2 +0004 INIT_FCALL 1 160 string("f") +0005 SEND_VAR CV0($b) 1 +0006 DO_UCALL +0007 RETURN int(1) -F: ; (lines=13, args=1, vars=2, tmps=3) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/85_verify_return_type/second_ex/second_ex.php:16-19 -L0 (16): EXT_NOP -L1 (16): CV0($b) = RECV 1 -L2 (17): EXT_STMT -L3 (17): V2 = NEW 1 string("TestClass") -L4 (17): SEND_VAR_EX CV0($b) 1 -L5 (17): DO_FCALL -L6 (17): ASSIGN CV1($class) V2 -L7 (18): EXT_STMT -L8 (18): VERIFY_RETURN_TYPE CV1($class) -L9 (18): RETURN CV1($class) -L10 (19): EXT_STMT -L11 (19): VERIFY_RETURN_TYPE -L12 (19): RETURN null +F: + ; (lines=9, args=1, vars=2, tmps=3) + ; (before optimizer) + ; /.../PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.php:15-18 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 V2 = NEW 1 string("TestClass") +0002 SEND_VAR_EX CV0($b) 1 +0003 DO_FCALL +0004 ASSIGN CV1($class) V2 +0005 VERIFY_RETURN_TYPE CV1($class) +0006 RETURN CV1($class) +0007 VERIFY_RETURN_TYPE +0008 RETURN null LIVE RANGES: - 2: L4 - L6 (new) + 2: 0002 - 0004 (new) -TestClass::__construct: ; (lines=7, args=1, vars=1, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/85_verify_return_type/second_ex/second_ex.php:5-7 -L0 (5): EXT_NOP -L1 (5): CV0($foo) = RECV 1 -L2 (6): EXT_STMT -L3 (6): ASSIGN_OBJ THIS string("foo") -L4 (6): OP_DATA CV0($foo) -L5 (7): EXT_STMT -L6 (7): RETURN null +TestClass::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($val) = RECV 1 +0001 ASSIGN_OBJ THIS string("x") +0002 OP_DATA CV0($val) +0003 RETURN null -TestClass::__toString: ; (lines=10, args=0, vars=0, tmps=3) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/85_verify_return_type/second_ex/second_ex.php:9-12 -L0 (9): EXT_NOP -L1 (10): EXT_STMT -L2 (10): T0 = FETCH_OBJ_R THIS string("foo") -L3 (10): T1 = CONCAT string("XSS: ") T0 -L4 (10): ECHO T1 -L5 (11): EXT_STMT -L6 (11): T2 = FETCH_OBJ_R THIS string("foo") -L7 (11): RETURN T2 -L8 (12): EXT_STMT -L9 (12): RETURN null +TestClass::__toString: + ; (lines=7, args=0, vars=0, tmps=2) + ; (before optimizer) + ; /.../PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.php:8-11 + ; return [] RANGE[0..0] +0000 T0 = FETCH_OBJ_R THIS string("x") +0001 ECHO T0 +0002 T1 = FETCH_OBJ_R THIS string("x") +0003 VERIFY_RETURN_TYPE T1 +0004 RETURN T1 +0005 VERIFY_RETURN_TYPE +0006 RETURN null +LIVE RANGES: + 1: 0003 - 0004 (tmp/var) diff --git a/PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.json b/PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.json index fcbc51c..ff687e6 100644 --- a/PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.json +++ b/PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.json @@ -1,13 +1,14 @@ { + "description": "This instance shows, a function, that returns a string. When returning an object from that function, the `__toString` method of that object is invoked.", "code": { "path": "./2_instance_44_verify_return_type.php", "injection_skeleton_broken": false }, "discovery": { - "rule": "../44_verify_return_type.sc", + "rule": "./2_instance_44_verify_return_type.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "Perfect", + "notes": "That rule searches for `VERIFY_RETURN_TYPE` in opcode and will find all occurences, where any function has an explicit return type." }, "compile": { "binary": "./2_instance_44_verify_return_type.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./2_instance_44_verify_return_type.php", - "sink_line": 10, + "sink_line": 9, "source_file": "./2_instance_44_verify_return_type.php", - "source_line": 20, + "source_line": 19, "expectation": true }, "properties": { @@ -30,7 +31,7 @@ "negative_test_case": false }, "remediation": { - "notes": "", + "notes": "The function returning a specific type could call the conversion to that type explicitly. That might not only include calling `__toString`, but also other type conversions.", "transformation": null, "modeling_rule": null } diff --git a/PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.php b/PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.php index fd79425..9eed584 100644 --- a/PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.php +++ b/PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.php @@ -1,22 +1,20 @@ foo = $foo; +class TestClass { + public $x; + public function __construct($val) { + $this->x = $val; } - public function __toString(){ - echo 'XSS: ' . $this->foo; - return $this->foo; + public function __toString() { + echo $this->x; // sink + return $this->x; } } // will call the function __toString(), XSS vulnerability -function F($b):string{ +function F($b):string { $class = new TestClass($b); return $class; } -$b = $_GET["p1"]; -// will print string +$b = $_GET["p1"]; // source F($b); \ No newline at end of file diff --git a/PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.sc b/PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.sc index 408c774..2b0f268 100644 --- a/PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.sc +++ b/PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.sc @@ -1,6 +1,6 @@ @main def main(name : String): Unit = { importCpg(name) - val x44 = (name, "44_verify_return_type_iall", cpg.call(".*VERIFY_RETURN_TYPE.*").location.toJson); + val x44 = (name, "44_verify_return_type_i2", cpg.call(".*VERIFY_RETURN_TYPE.*").location.toJson); println(x44) delete; } \ No newline at end of file diff --git a/PHP/44_verify_return_type/44_verify_return_type.json b/PHP/44_verify_return_type/44_verify_return_type.json index 9ce63e0..0f44b09 100644 --- a/PHP/44_verify_return_type/44_verify_return_type.json +++ b/PHP/44_verify_return_type/44_verify_return_type.json @@ -1,6 +1,6 @@ { "name": "Verify Return Type", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -11,5 +11,5 @@ "./1_instance_44_verify_return_type/1_instance_44_verify_return_type.json", "./2_instance_44_verify_return_type/2_instance_44_verify_return_type.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/44_verify_return_type/44_verify_return_type.sc b/PHP/44_verify_return_type/44_verify_return_type.sc deleted file mode 100644 index 408c774..0000000 --- a/PHP/44_verify_return_type/44_verify_return_type.sc +++ /dev/null @@ -1,6 +0,0 @@ -@main def main(name : String): Unit = { - importCpg(name) - val x44 = (name, "44_verify_return_type_iall", cpg.call(".*VERIFY_RETURN_TYPE.*").location.toJson); - println(x44) - delete; -} \ No newline at end of file diff --git a/PHP/44_verify_return_type/README.md b/PHP/44_verify_return_type/README.md new file mode 100644 index 0000000..5d6cbbd --- /dev/null +++ b/PHP/44_verify_return_type/README.md @@ -0,0 +1,328 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Verify Return Type + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +Type declarations can be added in PHP to ensure, the arguments or the return value has the right type. If not, a `TypeError` will be thrown. If an argument or a return value does not have the right type, it will implicitly converted to that type, if possible. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | +| [2 Instance](#2-instance) | yes | joern | yes | + +
+ + +## 1 Instance + + +The instance defines a function, that takes a string as an argument. So if the argument is an object, `__toString` will be called on that object. + +### Code + +```PHP +x = $val; + } + + public function __toString() { + echo $this->x; // sink + return $this->x; + } +} + +// will call the function __toString(), XSS vulnerability +function F(string $c){ + echo 'message'; +} + +$b = $_GET["p1"]; // source +$c = new TestClass($b); +F($c); +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=12, args=0, vars=2, tmps=7) + ; (before optimizer) + ; /.../PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.php:1-21 + ; return [] RANGE[0..0] +0000 DECLARE_CLASS string("testclass") +0001 T2 = FETCH_R (global) string("_GET") +0002 T3 = FETCH_DIM_R T2 string("p1") +0003 ASSIGN CV0($b) T3 +0004 V5 = NEW 1 string("TestClass") +0005 SEND_VAR_EX CV0($b) 1 +0006 DO_FCALL +0007 ASSIGN CV1($c) V5 +0008 INIT_FCALL 1 96 string("f") +0009 SEND_VAR CV1($c) 1 +0010 DO_UCALL +0011 RETURN int(1) +LIVE RANGES: + 5: 0005 - 0007 (new) + +F: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.php:15-17 + ; return [] RANGE[0..0] +0000 CV0($c) = RECV 1 +0001 ECHO string("message") +0002 RETURN null + +TestClass::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($val) = RECV 1 +0001 ASSIGN_OBJ THIS string("x") +0002 OP_DATA CV0($val) +0003 RETURN null + +TestClass::__toString: + ; (lines=7, args=0, vars=0, tmps=2) + ; (before optimizer) + ; /.../PHP/44_verify_return_type/1_instance_44_verify_return_type/1_instance_44_verify_return_type.php:8-11 + ; return [] RANGE[0..0] +0000 T0 = FETCH_OBJ_R THIS string("x") +0001 ECHO T0 +0002 T1 = FETCH_OBJ_R THIS string("x") +0003 VERIFY_RETURN_TYPE T1 +0004 RETURN T1 +0005 VERIFY_RETURN_TYPE +0006 RETURN null +LIVE RANGES: + 1: 0003 - 0004 (tmp/var) +``` + +
+ +
+ + +### Discovery + + +The discovery rule first gets all class names, where the method `__toString` is defined. +Afterwards it collects all `NEW` calles and filters them to see which of the instanciated objects has the method `__toString` defined. +The rule would be perfect, if we could additionally check, if one of the created objects invokes the `__toString` method within its lifetime. + +```scala +def methodClasses = cpg.method.name("__tostring").astParentFullName.l +val x44 = (name, "44_verify_return_type_i1", cpg.call("NEW").argument.filter{x => methodClasses.contains(x.code.toLowerCase)}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | yes | no | no | yes | +| 22 May 2023 | yes | no | | | | | yes | + +
+ +
+ + +### Remediation + + +Call `__toString` manually on the object, when it is passed to a function, that takes strings as arguments. + +
+ +
+ +
+ +
+ + +## 2 Instance + + +This instance shows, a function, that returns a string. When returning an object from that function, the `__toString` method of that object is invoked. + +### Code + +```PHP +x = $val; + } + + public function __toString() { + echo $this->x; // sink + return $this->x; + } +} + +// will call the function __toString(), XSS vulnerability +function F($b):string { + $class = new TestClass($b); + return $class; +} +$b = $_GET["p1"]; // source +F($b); +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=8, args=0, vars=1, tmps=4) + ; (before optimizer) + ; /.../PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.php:1-20 + ; return [] RANGE[0..0] +0000 DECLARE_CLASS string("testclass") +0001 T1 = FETCH_R (global) string("_GET") +0002 T2 = FETCH_DIM_R T1 string("p1") +0003 ASSIGN CV0($b) T2 +0004 INIT_FCALL 1 160 string("f") +0005 SEND_VAR CV0($b) 1 +0006 DO_UCALL +0007 RETURN int(1) + +F: + ; (lines=9, args=1, vars=2, tmps=3) + ; (before optimizer) + ; /.../PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.php:15-18 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 V2 = NEW 1 string("TestClass") +0002 SEND_VAR_EX CV0($b) 1 +0003 DO_FCALL +0004 ASSIGN CV1($class) V2 +0005 VERIFY_RETURN_TYPE CV1($class) +0006 RETURN CV1($class) +0007 VERIFY_RETURN_TYPE +0008 RETURN null +LIVE RANGES: + 2: 0002 - 0004 (new) + +TestClass::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($val) = RECV 1 +0001 ASSIGN_OBJ THIS string("x") +0002 OP_DATA CV0($val) +0003 RETURN null + +TestClass::__toString: + ; (lines=7, args=0, vars=0, tmps=2) + ; (before optimizer) + ; /.../PHP/44_verify_return_type/2_instance_44_verify_return_type/2_instance_44_verify_return_type.php:8-11 + ; return [] RANGE[0..0] +0000 T0 = FETCH_OBJ_R THIS string("x") +0001 ECHO T0 +0002 T1 = FETCH_OBJ_R THIS string("x") +0003 VERIFY_RETURN_TYPE T1 +0004 RETURN T1 +0005 VERIFY_RETURN_TYPE +0006 RETURN null +LIVE RANGES: + 1: 0003 - 0004 (tmp/var) +``` + +
+ +
+ + +### Discovery + + +That rule searches for `VERIFY_RETURN_TYPE` in opcode and will find all occurences, where any function has an explicit return type. + +```scala +val x44 = (name, "44_verify_return_type_i2", cpg.call(".*VERIFY_RETURN_TYPE.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | yes | no | no | yes | +| 22 May 2023 | yes | no | | | | | yes | + +
+ +
+ + +### Remediation + + +The function returning a specific type could call the conversion to that type explicitly. That might not only include calling `__toString`, but also other type conversions. + +
+ +
+ +
diff --git a/PHP/44_verify_return_type/docs/description.md b/PHP/44_verify_return_type/docs/description.md new file mode 100644 index 0000000..83145c3 --- /dev/null +++ b/PHP/44_verify_return_type/docs/description.md @@ -0,0 +1 @@ +Type declarations can be added in PHP to ensure, the arguments or the return value has the right type. If not, a `TypeError` will be thrown. If an argument or a return value does not have the right type, it will implicitly converted to that type, if possible. \ No newline at end of file diff --git a/PHP/46_object_to_array/1_instance_46_object_to_array/1_instance_46_object_to_array.bash b/PHP/46_object_to_array/1_instance_46_object_to_array/1_instance_46_object_to_array.bash index eeb2548..c3e9af2 100644 --- a/PHP/46_object_to_array/1_instance_46_object_to_array/1_instance_46_object_to_array.bash +++ b/PHP/46_object_to_array/1_instance_46_object_to_array/1_instance_46_object_to_array.bash @@ -1,35 +1,30 @@ -$_main: ; (lines=18, args=0, vars=3, tmps=9) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/80_object_to_array/first_ex/first_ex.php:1-16 -L0 (2): EXT_STMT -L1 (2): T3 = FETCH_R (global) string("_GET") -L2 (2): T4 = FETCH_DIM_R T3 string("p1") -L3 (2): ASSIGN CV0($b) T4 -L4 (4): NOP -L5 (5): NOP -L6 (11): EXT_STMT -L7 (11): V6 = NEW 1 string("A") -L8 (11): SEND_VAR_EX CV0($b) 1 -L9 (11): DO_FCALL -L10 (11): ASSIGN CV1($a) V6 -L11 (13): EXT_STMT -L12 (13): T9 = CAST (array) CV1($a) -L13 (13): ASSIGN CV2($arr) T9 -L14 (16): EXT_STMT -L15 (16): T11 = FETCH_DIM_R CV2($arr) string("b") -L16 (16): ECHO T11 -L17 (16): RETURN int(1) +$_main: + ; (lines=12, args=0, vars=3, tmps=9) + ; (before optimizer) + ; /.../PHP/46_object_to_array/1_instance_46_object_to_array/1_instance_46_object_to_array.php:1-16 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($b) T4 +0003 V6 = NEW 1 string("A") +0004 SEND_VAR_EX CV0($b) 1 +0005 DO_FCALL +0006 ASSIGN CV1($a) V6 +0007 T9 = CAST (array) CV1($a) +0008 ASSIGN CV2($arr) T9 +0009 T11 = FETCH_DIM_R CV2($arr) string("y") +0010 ECHO T11 +0011 RETURN int(1) LIVE RANGES: - 6: L8 - L10 (new) + 6: 0004 - 0006 (new) -A::__construct: ; (lines=7, args=1, vars=1, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/80_object_to_array/first_ex/first_ex.php:7-9 -L0 (7): EXT_NOP -L1 (7): CV0($b) = RECV 1 -L2 (8): EXT_STMT -L3 (8): ASSIGN_OBJ THIS string("b") -L4 (8): OP_DATA CV0($b) -L5 (9): EXT_STMT -L6 (9): RETURN null +A::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/46_object_to_array/1_instance_46_object_to_array/1_instance_46_object_to_array.php:6-8 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("y") +0002 OP_DATA CV0($b) +0003 RETURN null diff --git a/PHP/46_object_to_array/1_instance_46_object_to_array/1_instance_46_object_to_array.json b/PHP/46_object_to_array/1_instance_46_object_to_array/1_instance_46_object_to_array.json index 6267afd..bbbb6d1 100644 --- a/PHP/46_object_to_array/1_instance_46_object_to_array/1_instance_46_object_to_array.json +++ b/PHP/46_object_to_array/1_instance_46_object_to_array/1_instance_46_object_to_array.json @@ -1,4 +1,5 @@ { + "description": "This instance creates an object and casts that object to an array.", "code": { "path": "./1_instance_46_object_to_array.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_46_object_to_array.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "Perfect", + "notes": "The rule looks for all casts and checks for which of them the argument is an array." }, "compile": { "binary": "./1_instance_46_object_to_array.bash", @@ -19,7 +20,7 @@ "sink_file": "./1_instance_46_object_to_array.php", "sink_line": 16, "source_file": "./1_instance_46_object_to_array.php", - "source_line": 2, + "source_line": 10, "expectation": true }, "properties": { diff --git a/PHP/46_object_to_array/1_instance_46_object_to_array/1_instance_46_object_to_array.php b/PHP/46_object_to_array/1_instance_46_object_to_array/1_instance_46_object_to_array.php index f24c497..b9dc54a 100644 --- a/PHP/46_object_to_array/1_instance_46_object_to_array/1_instance_46_object_to_array.php +++ b/PHP/46_object_to_array/1_instance_46_object_to_array/1_instance_46_object_to_array.php @@ -1,16 +1,16 @@ b = $b; +class A { + public $x = 'safe'; + public $y = 'safe'; + + function __construct($b) { + $this->y = $b; } } +$b = $_GET["p1"]; // source $a = new A($b); // object to array $arr = (array) $a; // print the property $b in the object // XSS vulnerability -echo $arr['b']; \ No newline at end of file +echo $arr['y']; // sink \ No newline at end of file diff --git a/PHP/46_object_to_array/46_object_to_array.json b/PHP/46_object_to_array/46_object_to_array.json index 2d30c6b..8bc025a 100644 --- a/PHP/46_object_to_array/46_object_to_array.json +++ b/PHP/46_object_to_array/46_object_to_array.json @@ -1,6 +1,6 @@ { - "name": "Object to Array", - "description": "", + "name": "Object To Array", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_46_object_to_array/1_instance_46_object_to_array.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/46_object_to_array/README.md b/PHP/46_object_to_array/README.md new file mode 100644 index 0000000..f7e089c --- /dev/null +++ b/PHP/46_object_to_array/README.md @@ -0,0 +1,125 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Object To Array + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +In PHP you can cast any object to a simple 1D array using `(array)`. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +This instance creates an object and casts that object to an array. + +### Code + +```PHP +y = $b; + } +} +$b = $_GET["p1"]; // source +$a = new A($b); +// object to array +$arr = (array) $a; +// print the property $b in the object +// XSS vulnerability +echo $arr['y']; // sink +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| D2 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=12, args=0, vars=3, tmps=9) + ; (before optimizer) + ; /.../PHP/46_object_to_array/1_instance_46_object_to_array/1_instance_46_object_to_array.php:1-16 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($b) T4 +0003 V6 = NEW 1 string("A") +0004 SEND_VAR_EX CV0($b) 1 +0005 DO_FCALL +0006 ASSIGN CV1($a) V6 +0007 T9 = CAST (array) CV1($a) +0008 ASSIGN CV2($arr) T9 +0009 T11 = FETCH_DIM_R CV2($arr) string("y") +0010 ECHO T11 +0011 RETURN int(1) +LIVE RANGES: + 6: 0004 - 0006 (new) + +A::__construct: + ; (lines=4, args=1, vars=1, tmps=1) + ; (before optimizer) + ; /.../PHP/46_object_to_array/1_instance_46_object_to_array/1_instance_46_object_to_array.php:6-8 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN_OBJ THIS string("y") +0002 OP_DATA CV0($b) +0003 RETURN null +``` + +
+ +
+ + +### Discovery + + +The rule looks for all casts and checks for which of them the argument is an array. + +```scala +val x46 = (name, "46_object_to_array_iall", cpg.call(".*CAST.*").argument.order(0).code("array").astParent.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | no | no | no | yes | +| 22 May 2023 | no | yes | | | | | yes | + +
+ +
diff --git a/PHP/46_object_to_array/docs/description.md b/PHP/46_object_to_array/docs/description.md new file mode 100644 index 0000000..6305db3 --- /dev/null +++ b/PHP/46_object_to_array/docs/description.md @@ -0,0 +1 @@ +In PHP you can cast any object to a simple 1D array using `(array)`. \ No newline at end of file diff --git a/PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.bash b/PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.bash index 132aa3a..4b8b264 100644 --- a/PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.bash +++ b/PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.bash @@ -1,35 +1,26 @@ -$_main: ; (lines=9, args=0, vars=1, tmps=5) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/27_construct_with_inheritance/first_ex/first_ex.php:1-18 -L0 (18): EXT_STMT -L1 (18): V1 = NEW 1 string("child_class") -L2 (18): CHECK_FUNC_ARG 1 -L3 (18): V2 = FETCH_FUNC_ARG (global) string("_GET") -L4 (18): V3 = FETCH_DIM_FUNC_ARG V2 string("p1") -L5 (18): SEND_FUNC_ARG V3 1 -L6 (18): DO_FCALL -L7 (18): ASSIGN CV0($b) V1 -L8 (18): RETURN int(1) +$_main: + ; (lines=9, args=0, vars=2, tmps=6) + ; (before optimizer) + ; /.../PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.php:1-16 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 1 string("child_class") +0004 SEND_VAR_EX CV0($b) 1 +0005 DO_FCALL +0006 ASSIGN CV1($a) V5 +0007 ECHO CV1($a) +0008 RETURN int(1) LIVE RANGES: - 1: L2 - L7 (new) + 5: 0004 - 0006 (new) -parent_class::__construct: ; (lines=6, args=1, vars=1, tmps=0) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/27_construct_with_inheritance/first_ex/first_ex.php:5-7 -L0 (5): EXT_NOP -L1 (5): CV0($b) = RECV 1 -L2 (6): EXT_STMT -L3 (6): ECHO CV0($b) -L4 (7): EXT_STMT -L5 (7): RETURN null - -parent_class::F: ; (lines=6, args=1, vars=2, tmps=1) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/27_construct_with_inheritance/first_ex/first_ex.php:9-11 -L0 (9): EXT_NOP -L1 (9): CV0($b) = RECV 1 -L2 (10): EXT_STMT -L3 (10): ASSIGN CV1($a) CV0($b) -L4 (11): EXT_STMT -L5 (11): RETURN null +parent_class::__construct: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN CV0($b) +0002 RETURN null diff --git a/PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.json b/PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.json index bff9e1d..9d74ecf 100644 --- a/PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.json +++ b/PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.json @@ -1,4 +1,5 @@ { + "description": "This instance shows a construct with inheritance, where the child class is instantiated and the constructor from the parent class is called.", "code": { "path": "./1_instance_48_construct_with_inheritance.php", "injection_skeleton_broken": false @@ -7,7 +8,7 @@ "rule": "./1_instance_48_construct_with_inheritance.sc", "method": "joern", "rule_accuracy": null, - "notes": null + "notes": "This pattern would profit from source code discovery. As inheritance cannot be detected on opcode level." }, "compile": { "binary": "./1_instance_48_construct_with_inheritance.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_48_construct_with_inheritance.php", - "sink_line": 6, + "sink_line": 15, "source_file": "./1_instance_48_construct_with_inheritance.php", - "source_line": 18, + "source_line": 13, "expectation": true }, "properties": { diff --git a/PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.php b/PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.php index d389f52..e1a4b77 100644 --- a/PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.php +++ b/PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.php @@ -1,18 +1,15 @@ (x.name,x.astParentFullName)}.l; - println(x) - println("*********************************************") + // DOES NOT WORK + val x48 = cpg.method.astParentType("TYPE_DECL").map{x => (x.name,x.astParentFullName)}.l; + println(x48) delete; } \ No newline at end of file diff --git a/PHP/48_construct_with_inheritance/48_construct_with_inheritance.json b/PHP/48_construct_with_inheritance/48_construct_with_inheritance.json index 2a0a22a..8069303 100644 --- a/PHP/48_construct_with_inheritance/48_construct_with_inheritance.json +++ b/PHP/48_construct_with_inheritance/48_construct_with_inheritance.json @@ -1,6 +1,6 @@ { "name": "Construct With Inheritance", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/48_construct_with_inheritance/README.md b/PHP/48_construct_with_inheritance/README.md new file mode 100644 index 0000000..5f48947 --- /dev/null +++ b/PHP/48_construct_with_inheritance/README.md @@ -0,0 +1,121 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Construct With Inheritance + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +When a child class inherits from a parent class and the child class does not implement a certain method, the method defined in parent class will be used. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | no | + +## 1 Instance + +This instance shows a construct with inheritance, where the child class is instantiated and the constructor from the parent class is called. + +### Code + +```PHP + + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=9, args=0, vars=2, tmps=6) + ; (before optimizer) + ; /.../PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.php:1-16 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 V5 = NEW 1 string("child_class") +0004 SEND_VAR_EX CV0($b) 1 +0005 DO_FCALL +0006 ASSIGN CV1($a) V5 +0007 ECHO CV1($a) +0008 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0006 (new) + +parent_class::__construct: + ; (lines=3, args=1, vars=1, tmps=0) + ; (before optimizer) + ; /.../PHP/48_construct_with_inheritance/1_instance_48_construct_with_inheritance/1_instance_48_construct_with_inheritance.php:4-6 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 RETURN CV0($b) +0002 RETURN null +``` + +
+ +
+ + +### Discovery + + +This pattern would profit from source code discovery. As inheritance cannot be detected on opcode level. + +```scala +// DOES NOT WORK +val x48 = cpg.method.astParentType("TYPE_DECL").map{x => (x.name,x.astParentFullName)}.l; +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | yes | no | no | yes | +| 22 May 2023 | no | yes | | | | | yes | + +
+ + diff --git a/PHP/48_construct_with_inheritance/docs/description.md b/PHP/48_construct_with_inheritance/docs/description.md new file mode 100644 index 0000000..2720822 --- /dev/null +++ b/PHP/48_construct_with_inheritance/docs/description.md @@ -0,0 +1 @@ +When a child class inherits from a parent class and the child class does not implement a certain method, the method defined in parent class will be used. \ No newline at end of file diff --git a/PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.bash b/PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.bash index b872f34..c0d59b5 100644 --- a/PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.bash +++ b/PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.bash @@ -1,44 +1,39 @@ -$_main: ; (lines=16, args=0, vars=0, tmps=6) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/126_static_instance/126_static_instance.php:1-17 -L0 (4): NOP -L1 (5): NOP -L2 (16): EXT_STMT -L3 (16): INIT_STATIC_METHOD_CALL 0 string("Myclass") string("oneInstance") -L4 (16): V0 = DO_FCALL -L5 (16): V0 = SEPARATE V0 -L6 (16): T2 = FETCH_R (global) string("_GET") -L7 (16): T3 = FETCH_DIM_R T2 string("p1") -L8 (16): ASSIGN_OBJ V0 string("x") -L9 (16): OP_DATA T3 -L10 (17): EXT_STMT -L11 (17): INIT_STATIC_METHOD_CALL 0 string("Myclass") string("oneInstance") -L12 (17): V4 = DO_FCALL -L13 (17): T5 = FETCH_OBJ_R V4 string("x") -L14 (17): ECHO T5 -L15 (17): RETURN int(1) -LIVE RANGES: - 0: L6 - L8 (tmp/var) +$_main: + ; (lines=14, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.php:1-17 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 INIT_STATIC_METHOD_CALL 0 string("Myclass") string("oneInstance") +0004 V5 = DO_UCALL +0005 V5 = SEPARATE V5 +0006 ASSIGN_OBJ V5 string("x") +0007 OP_DATA CV0($b) +0008 INIT_STATIC_METHOD_CALL 0 string("Myclass") string("oneInstance") +0009 V7 = DO_UCALL +0010 T8 = FETCH_OBJ_R V7 string("x") +0011 ASSIGN CV1($a) T8 +0012 ECHO CV1($a) +0013 RETURN int(1) -Myclass::oneInstance: ; (lines=16, args=0, vars=0, tmps=7) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/126_static_instance/126_static_instance.php:7-13 -L0 (7): EXT_NOP -L1 (9): EXT_STMT -L2 (9): T0 = FETCH_STATIC_PROP_R string("instance") (self) (exception) -L3 (9): T1 = INSTANCEOF T0 (self) (no-autolod) (exception) -L4 (9): T2 = BOOL_NOT T1 -L5 (9): JMPZ T2 L11 -L6 (10): EXT_STMT -L7 (10): V4 = NEW 0 (self) (exception) -L8 (10): DO_FCALL -L9 (10): ASSIGN_STATIC_PROP string("instance") -L10 (10): OP_DATA V4 -L11 (12): EXT_STMT -L12 (12): T6 = FETCH_STATIC_PROP_R string("instance") (self) (exception) -L13 (12): RETURN T6 -L14 (13): EXT_STMT -L15 (13): RETURN null +Myclass::oneInstance: + ; (lines=11, args=0, vars=0, tmps=7) + ; (before optimizer) + ; /.../PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.php:6-11 + ; return [] RANGE[0..0] +0000 T0 = FETCH_STATIC_PROP_R string("instance") (self) (exception) +0001 T1 = INSTANCEOF T0 (self) (no-autoload) (silent) (exception) +0002 T2 = BOOL_NOT T1 +0003 JMPZ T2 0008 +0004 V4 = NEW 0 (self) (exception) +0005 DO_FCALL +0006 ASSIGN_STATIC_PROP string("instance") +0007 OP_DATA V4 +0008 T6 = FETCH_STATIC_PROP_R string("instance") (self) (exception) +0009 RETURN T6 +0010 RETURN null LIVE RANGES: - 4: L8 - L9 (new) + 4: 0005 - 0006 (new) diff --git a/PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.json b/PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.json index d9c5ec8..78230de 100644 --- a/PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.json +++ b/PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.json @@ -1,4 +1,5 @@ { + "description": "This instance shows a class, that has only one static instance.", "code": { "path": "./1_instance_49_static_instance.php", "injection_skeleton_broken": false @@ -6,7 +7,7 @@ "discovery": { "rule": "./1_instance_49_static_instance.sc", "method": "joern", - "rule_accuracy": null, + "rule_accuracy": "FP", "notes": null }, "compile": { @@ -19,7 +20,7 @@ "sink_file": "./1_instance_49_static_instance.php", "sink_line": 17, "source_file": "./1_instance_49_static_instance.php", - "source_line": 16, + "source_line": 14, "expectation": true }, "properties": { diff --git a/PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.php b/PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.php index c82edfd..8dc44c1 100644 --- a/PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.php +++ b/PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.php @@ -1,17 +1,17 @@ x = $_GET["p1"]; -echo Myclass::oneInstance()->x; \ No newline at end of file +$b = $_GET["p1"]; // source +Myclass::oneInstance()->x = $b; +$a = Myclass::oneInstance()->x; +echo $a; // sink \ No newline at end of file diff --git a/PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.sc b/PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.sc index 0875791..da24fbd 100644 --- a/PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.sc +++ b/PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.sc @@ -1,17 +1,14 @@ @main def main(name : String): Unit = { importCpg(name) - val x47 = (name, "49_static_instance", cpg.method.filter{ m => - -val fieldsHoldingConstruct = m.call.name(".*__construct.*").cfgNext.isLiteral.where(_.inCall.name("ASSIGN_STATIC_PROP_1")).code.l - -val returnedVars = m.call.name("FETCH_STATIC_PROP_R").inCall.name("=").filter{ assign => + val x49 = (name, "49_static_instance", cpg.method.filter{ m => + val fieldsHoldingConstruct = m.call.name(".*__construct.*").cfgNext.isLiteral.where(_.inCall.name("ASSIGN_STATIC_PROP_1")).code.l + val returnedVars = m.call.name("FETCH_STATIC_PROP_R").inCall.name("=").filter{ assign => val target = assign.argument.order(0).code.headOption target.isDefined && assign.cfgNext.cfgNext.isCall.codeExact(s"RETURN ${target.get}").size > 0 }.flatMap{ assign => assign.argument.order(1).isCall.argument.order(0).isLiteral.code.headOption }.l - (returnedVars intersect fieldsHoldingConstruct).size > 0 }.location.toJson); - println(x47) + println(x49) delete; -} \ No newline at end of file +} \ No newline at end of file diff --git a/PHP/49_static_instance/49_static_instance.json b/PHP/49_static_instance/49_static_instance.json index 5b0a5da..c29dcab 100644 --- a/PHP/49_static_instance/49_static_instance.json +++ b/PHP/49_static_instance/49_static_instance.json @@ -1,6 +1,6 @@ { "name": "Static Instance", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_49_static_instance/1_instance_49_static_instance.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/49_static_instance/README.md b/PHP/49_static_instance/README.md new file mode 100644 index 0000000..7135563 --- /dev/null +++ b/PHP/49_static_instance/README.md @@ -0,0 +1,141 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Static Instance + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +In PHP a static variable can contain an instance of that class. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | no | + +## 1 Instance + +This instance shows a class, that has only one static instance. + +### Code + +```PHP +x = $b; +$a = Myclass::oneInstance()->x; +echo $a; // sink +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=14, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.php:1-17 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 INIT_STATIC_METHOD_CALL 0 string("Myclass") string("oneInstance") +0004 V5 = DO_UCALL +0005 V5 = SEPARATE V5 +0006 ASSIGN_OBJ V5 string("x") +0007 OP_DATA CV0($b) +0008 INIT_STATIC_METHOD_CALL 0 string("Myclass") string("oneInstance") +0009 V7 = DO_UCALL +0010 T8 = FETCH_OBJ_R V7 string("x") +0011 ASSIGN CV1($a) T8 +0012 ECHO CV1($a) +0013 RETURN int(1) + +Myclass::oneInstance: + ; (lines=11, args=0, vars=0, tmps=7) + ; (before optimizer) + ; /.../PHP/49_static_instance/1_instance_49_static_instance/1_instance_49_static_instance.php:6-11 + ; return [] RANGE[0..0] +0000 T0 = FETCH_STATIC_PROP_R string("instance") (self) (exception) +0001 T1 = INSTANCEOF T0 (self) (no-autoload) (silent) (exception) +0002 T2 = BOOL_NOT T1 +0003 JMPZ T2 0008 +0004 V4 = NEW 0 (self) (exception) +0005 DO_FCALL +0006 ASSIGN_STATIC_PROP string("instance") +0007 OP_DATA V4 +0008 T6 = FETCH_STATIC_PROP_R string("instance") (self) (exception) +0009 RETURN T6 +0010 RETURN null +LIVE RANGES: + 4: 0005 - 0006 (new) +``` + +
+ +
+ + +### Discovery + + +```scala +val x49 = (name, "49_static_instance", cpg.method.filter{ m => +val fieldsHoldingConstruct = m.call.name(".*__construct.*").cfgNext.isLiteral.where(_.inCall.name("ASSIGN_STATIC_PROP_1")).code.l +val returnedVars = m.call.name("FETCH_STATIC_PROP_R").inCall.name("=").filter{ assign => +val target = assign.argument.order(0).code.headOption +target.isDefined && assign.cfgNext.cfgNext.isCall.codeExact(s"RETURN ${target.get}").size > 0 +}.flatMap{ assign => assign.argument.order(1).isCall.argument.order(0).isLiteral.code.headOption }.l +(returnedVars intersect fieldsHoldingConstruct).size > 0 + +}.location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | FP | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | no | no | no | yes | +| 22 May 2023 | no | no | | | | | yes | + +
+ +
diff --git a/PHP/49_static_instance/docs/description.md b/PHP/49_static_instance/docs/description.md new file mode 100644 index 0000000..f8b2be0 --- /dev/null +++ b/PHP/49_static_instance/docs/description.md @@ -0,0 +1 @@ +In PHP a static variable can contain an instance of that class. \ No newline at end of file diff --git a/PHP/4_conditional_assignment/1_instance_4_conditional_assignment/1_instance_4_conditional_assignment.bash b/PHP/4_conditional_assignment/1_instance_4_conditional_assignment/1_instance_4_conditional_assignment.bash index e4435e3..5ef1438 100644 --- a/PHP/4_conditional_assignment/1_instance_4_conditional_assignment/1_instance_4_conditional_assignment.bash +++ b/PHP/4_conditional_assignment/1_instance_4_conditional_assignment/1_instance_4_conditional_assignment.bash @@ -1,22 +1,20 @@ -$_main: ; (lines=18, args=0, vars=3, tmps=8) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/52_conditional_assignment/52_conditional_assignment.php:1-5 -L0 (2): EXT_STMT -L1 (2): ASSIGN CV0($x) int(5) -L2 (3): EXT_STMT -L3 (3): T4 = FETCH_R (global) string("_GET") -L4 (3): T5 = FETCH_DIM_R T4 string("p1") -L5 (3): ASSIGN CV1($d) T5 -L6 (4): EXT_STMT -L7 (4): T7 = IS_SMALLER int(9) CV0($x) -L8 (4): JMPZ T7 L12 -L9 (4): V8 = ASSIGN CV2($b) string("safe") -L10 (4): T9 = QM_ASSIGN V8 -L11 (4): JMP L14 -L12 (4): V10 = ASSIGN CV2($b) CV1($d) -L13 (4): T9 = QM_ASSIGN V10 -L14 (4): FREE T9 -L15 (5): EXT_STMT -L16 (5): ECHO CV2($b) -L17 (5): RETURN int(1) +$_main: + ; (lines=14, args=0, vars=3, tmps=8) + ; (before optimizer) + ; /.../PHP/4_conditional_assignment/1_instance_4_conditional_assignment/1_instance_4_conditional_assignment.php:1-5 + ; return [] RANGE[0..0] +0000 ASSIGN CV0($c) int(5) +0001 T4 = FETCH_R (global) string("_GET") +0002 T5 = FETCH_DIM_R T4 string("p1") +0003 ASSIGN CV1($a) T5 +0004 T7 = IS_SMALLER int(9) CV0($c) +0005 JMPZ T7 0009 +0006 T8 = ASSIGN CV2($b) string("safe") +0007 T9 = QM_ASSIGN T8 +0008 JMP 0011 +0009 T10 = ASSIGN CV2($b) CV1($a) +0010 T9 = QM_ASSIGN T10 +0011 FREE T9 +0012 ECHO CV2($b) +0013 RETURN int(1) diff --git a/PHP/4_conditional_assignment/1_instance_4_conditional_assignment/1_instance_4_conditional_assignment.json b/PHP/4_conditional_assignment/1_instance_4_conditional_assignment/1_instance_4_conditional_assignment.json index 1e9f779..c2d5ab9 100644 --- a/PHP/4_conditional_assignment/1_instance_4_conditional_assignment/1_instance_4_conditional_assignment.json +++ b/PHP/4_conditional_assignment/1_instance_4_conditional_assignment/1_instance_4_conditional_assignment.json @@ -1,4 +1,5 @@ { + "description": "This instance captures the conditional assignment of a variable using the Question Mark Operator.", "code": { "path": "./1_instance_4_conditional_assignment.php", "injection_skeleton_broken": false @@ -7,7 +8,7 @@ "rule": "./1_instance_4_conditional_assignment.sc", "method": "joern", "rule_accuracy": "Perfect", - "notes": "This rule should discover all conditional assignment" + "notes": "The rule searches for `QM_ASSIGN`, which stands for Question Mark Assign. This rule should discover all conditional assignments." }, "remediation": { "notes": "./docs/remediation_notes.md", @@ -24,7 +25,7 @@ "sink_file": "./1_instance_4_conditional_assignment.php", "sink_line": 5, "source_file": "./1_instance_4_conditional_assignment.php", - "source_line": 2, + "source_line": 3, "expectation": true }, "properties": { diff --git a/PHP/4_conditional_assignment/4_conditional_assignment.json b/PHP/4_conditional_assignment/4_conditional_assignment.json index 2b6dba7..59d6073 100644 --- a/PHP/4_conditional_assignment/4_conditional_assignment.json +++ b/PHP/4_conditional_assignment/4_conditional_assignment.json @@ -1,6 +1,6 @@ { "name": "Conditional Assignment", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_4_conditional_assignment/1_instance_4_conditional_assignment.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/4_conditional_assignment/README.md b/PHP/4_conditional_assignment/README.md index d40f7fc..dc7bd81 100644 --- a/PHP/4_conditional_assignment/README.md +++ b/PHP/4_conditional_assignment/README.md @@ -1,74 +1,116 @@ -# Pattern: Conditional Assignment +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) -## Category +# Conditional Assignment -Variables +Tags: sast, php, php_v7.4.9 -## Definition +Version: v1.0 -## Instances +## Description -### Instance 1 +The ternary operator in PHP is a shorthand way of writing an `if-else` statement that returns one of two values based on a given condition. -- CATEGORY: S0 -- FEATURE vs INTERNAL API: FEATURE -- INPUT SANITIZERS: NO -- SOURCES AND SINKS: NO -- NEGATIVE TEST CASES: NO -- CODE: +## Overview -```php +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +This instance captures the conditional assignment of a variable using the Question Mark Operator. + +### Code + +```PHP 9? $b = "safe" : $b = $d; -echo $b; +$c = 5; +$a = $_GET["p1"]; // source +$c > 9? $b = "safe" : $b = $a; // tarpit +echo $b; // sink ``` -- MEASUREMENT: +### Instance Properties -| Tool | RIPS | phpSAFE | WAP | Progpilot | Comm_1 | Comm_2 | Correct | -| ------------- | ---- | ------- | ---- | --------- | ------- | --------- | ------- | -| Vulnerability | YES | NO | YES | YES | YES | YES | YES | -Measurements Date: 8 June 2021 +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | -- OPCODE: +
+ +More -```bash -$_main: ; (lines=18, args=0, vars=3, tmps=8) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/52_conditional_assignment/52_conditional_assignment.php:1-5 -L0 (2): EXT_STMT -L1 (2): ASSIGN CV0($x) int(5) -L2 (3): EXT_STMT -L3 (3): T4 = FETCH_R (global) string("_GET") -L4 (3): T5 = FETCH_DIM_R T4 string("p1") -L5 (3): ASSIGN CV1($d) T5 -L6 (4): EXT_STMT -L7 (4): T7 = IS_SMALLER int(9) CV0($x) -L8 (4): JMPZ T7 L12 -L9 (4): V8 = ASSIGN CV2($b) string("safe") -L10 (4): T9 = QM_ASSIGN V8 -L11 (4): JMP L14 -L12 (4): V10 = ASSIGN CV2($b) CV1($d) -L13 (4): T9 = QM_ASSIGN V10 -L14 (4): FREE T9 -L15 (5): EXT_STMT -L16 (5): ECHO CV2($b) -L17 (5): RETURN int(1) -``` +
+ -- DISCOVERY: +### Compile + ```bash -cpg.call(".*QM_ASSIGN.*").location.l +$_main: + ; (lines=14, args=0, vars=3, tmps=8) + ; (before optimizer) + ; /.../PHP/4_conditional_assignment/1_instance_4_conditional_assignment/1_instance_4_conditional_assignment.php:1-5 + ; return [] RANGE[0..0] +0000 ASSIGN CV0($c) int(5) +0001 T4 = FETCH_R (global) string("_GET") +0002 T5 = FETCH_DIM_R T4 string("p1") +0003 ASSIGN CV1($a) T5 +0004 T7 = IS_SMALLER int(9) CV0($c) +0005 JMPZ T7 0009 +0006 T8 = ASSIGN CV2($b) string("safe") +0007 T9 = QM_ASSIGN T8 +0008 JMP 0011 +0009 T10 = ASSIGN CV2($b) CV1($a) +0010 T9 = QM_ASSIGN T10 +0011 FREE T9 +0012 ECHO CV2($b) +0013 RETURN int(1) ``` -- PRECONDITIONS: - 1. -- TRANSFORMATION: +
-``` +
+ + +### Discovery + +The rule searches for `QM_ASSIGN`, which stands for Question Mark Assign. This rule should discover all conditional assignments. + +```scala +val x4 = (name, "4_conditional_assignment_iall", cpg.call(".*QM_ASSIGN.*").location.toJson); ``` +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | yes | no | yes | yes | yes | yes | +| 17 May 2023 | yes | yes | | | | | yes | + +
+ +
+ + +### Remediation + + +- Can we transform this tarpit in a standard if-then-else that may be easier to be treated by SAST tools? + +- Can we create a modeling rule for such a syntactic construct? + +
+ +
diff --git a/PHP/4_conditional_assignment/docs/description.md b/PHP/4_conditional_assignment/docs/description.md new file mode 100644 index 0000000..d56d262 --- /dev/null +++ b/PHP/4_conditional_assignment/docs/description.md @@ -0,0 +1 @@ +The ternary operator in PHP is a shorthand way of writing an `if-else` statement that returns one of two values based on a given condition. \ No newline at end of file diff --git a/PHP/50_throw_exception/1_instance_50_throw_exception/1_instance_50_throw_exception.bash b/PHP/50_throw_exception/1_instance_50_throw_exception/1_instance_50_throw_exception.bash index ea68cb7..1db07fb 100644 --- a/PHP/50_throw_exception/1_instance_50_throw_exception/1_instance_50_throw_exception.bash +++ b/PHP/50_throw_exception/1_instance_50_throw_exception/1_instance_50_throw_exception.bash @@ -1,56 +1,47 @@ -$_main: ; (lines=26, args=0, vars=2, tmps=6) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/40_throw_exception/40_throw_exception.php:1-16 -L0 (9): EXT_STMT -L1 (9): T2 = FETCH_R (global) string("_GET") -L2 (9): T3 = FETCH_DIM_R T2 string("p1") -L3 (9): ASSIGN CV0($b) T3 -L4 (10): NOP -L5 (11): EXT_STMT -L6 (11): INIT_FCALL 2 176 string("inverse") -L7 (11): SEND_VAL int(5) 1 -L8 (11): SEND_VAR CV0($b) 2 -L9 (11): DO_FCALL -L10 (12): EXT_STMT -L11 (12): INIT_FCALL 2 176 string("inverse") -L12 (12): SEND_VAL int(0) 1 -L13 (12): SEND_VAR CV0($b) 2 -L14 (12): DO_FCALL -L15 (12): JMP L25 -L16 (13): CV1($e) = CATCH string("Exception") -L17 (15): EXT_STMT -L18 (15): ECHO string("Caught exception: ") -L19 (15): EXT_STMT -L20 (15): INIT_METHOD_CALL 0 CV1($e) string("getMessage") -L21 (15): V7 = DO_FCALL -L22 (15): ECHO V7 -L23 (15): EXT_STMT -L24 (15): ECHO string(" +$_main: + ; (lines=19, args=0, vars=2, tmps=6) + ; (before optimizer) + ; /.../PHP/50_throw_exception/1_instance_50_throw_exception/1_instance_50_throw_exception.php:1-16 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 INIT_FCALL 2 176 string("inverse") +0004 SEND_VAL int(5) 1 +0005 SEND_VAR CV0($b) 2 +0006 DO_UCALL +0007 INIT_FCALL 2 176 string("inverse") +0008 SEND_VAL int(0) 1 +0009 SEND_VAR CV0($b) 2 +0010 DO_UCALL +0011 JMP 0018 +0012 CV1($e) = CATCH string("Exception") +0013 ECHO string("Caught exception: ") +0014 INIT_METHOD_CALL 0 CV1($e) string("getMessage") +0015 V7 = DO_FCALL +0016 ECHO V7 +0017 ECHO string(" ") -L25 (16): RETURN int(1) +0018 RETURN int(1) EXCEPTION TABLE: - L5, L16, -, - + 0003, 0012, -, - -inverse: ; (lines=16, args=2, vars=2, tmps=4) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/40_throw_exception/40_throw_exception.php:2-7 -L0 (2): EXT_NOP -L1 (2): CV0($x) = RECV 1 -L2 (2): CV1($b) = RECV 2 -L3 (3): EXT_STMT -L4 (3): T2 = BOOL_NOT CV0($x) -L5 (3): JMPZ T2 L11 -L6 (4): EXT_STMT -L7 (4): V3 = NEW 1 string("Exception") -L8 (4): SEND_VAR_EX CV1($b) 1 -L9 (4): DO_FCALL -L10 (4): THROW V3 -L11 (6): EXT_STMT -L12 (6): T5 = DIV int(1) CV0($x) -L13 (6): RETURN T5 -L14 (7): EXT_STMT -L15 (7): RETURN null +inverse: + ; (lines=11, args=2, vars=2, tmps=4) + ; (before optimizer) + ; /.../PHP/50_throw_exception/1_instance_50_throw_exception/1_instance_50_throw_exception.php:2-7 + ; return [] RANGE[0..0] +0000 CV0($x) = RECV 1 +0001 CV1($b) = RECV 2 +0002 T2 = BOOL_NOT CV0($x) +0003 JMPZ T2 0008 +0004 V3 = NEW 1 string("Exception") +0005 SEND_VAR_EX CV1($b) 1 +0006 DO_FCALL +0007 THROW V3 +0008 T5 = DIV int(1) CV0($x) +0009 RETURN T5 +0010 RETURN null LIVE RANGES: - 3: L8 - L10 (new) - + 3: 0005 - 0007 (new) diff --git a/PHP/50_throw_exception/1_instance_50_throw_exception/1_instance_50_throw_exception.json b/PHP/50_throw_exception/1_instance_50_throw_exception/1_instance_50_throw_exception.json index abf9d37..296c8b3 100644 --- a/PHP/50_throw_exception/1_instance_50_throw_exception/1_instance_50_throw_exception.json +++ b/PHP/50_throw_exception/1_instance_50_throw_exception/1_instance_50_throw_exception.json @@ -1,4 +1,5 @@ { + "description": "This instance shows a simple example for throwing and catching an exception.", "code": { "path": "./1_instance_50_throw_exception.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_50_throw_exception.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "Perfect", + "notes": "The rule searches for a call for `THROW` on opcode level." }, "compile": { "binary": "./1_instance_50_throw_exception.bash", diff --git a/PHP/50_throw_exception/1_instance_50_throw_exception/1_instance_50_throw_exception.php b/PHP/50_throw_exception/1_instance_50_throw_exception/1_instance_50_throw_exception.php index 6cfd945..9610484 100644 --- a/PHP/50_throw_exception/1_instance_50_throw_exception/1_instance_50_throw_exception.php +++ b/PHP/50_throw_exception/1_instance_50_throw_exception/1_instance_50_throw_exception.php @@ -6,11 +6,11 @@ function inverse($x,$b) { return 1/$x; } -$b = $_GET["p1"]; +$b = $_GET["p1"]; // source try { inverse(5,$b); inverse(0,$b); } catch (Exception $e) { // Message has the input $b, XSS Vulnerability - echo 'Caught exception: ', $e->getMessage(), "\n"; + echo 'Caught exception: ', $e->getMessage(), "\n"; // sink } \ No newline at end of file diff --git a/PHP/50_throw_exception/50_throw_exception.json b/PHP/50_throw_exception/50_throw_exception.json index bd293be..3ef9758 100644 --- a/PHP/50_throw_exception/50_throw_exception.json +++ b/PHP/50_throw_exception/50_throw_exception.json @@ -1,6 +1,6 @@ { "name": "Throw Exception", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_50_throw_exception/1_instance_50_throw_exception.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/50_throw_exception/README.md b/PHP/50_throw_exception/README.md new file mode 100644 index 0000000..c6791c0 --- /dev/null +++ b/PHP/50_throw_exception/README.md @@ -0,0 +1,142 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Throw Exception + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +In PHP [Exceptions](https://www.php.net/manual/en/language.exceptions.php) are similar to other languages. An exception can be thrown and caught, try blocks indicate positions in code, where exceptions can occur. This pattern should target throwing an exception + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +This instance shows a simple example for throwing and catching an exception. + +### Code + +```PHP +getMessage(), "\n"; // sink +} +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| D2 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=19, args=0, vars=2, tmps=6) + ; (before optimizer) + ; /.../PHP/50_throw_exception/1_instance_50_throw_exception/1_instance_50_throw_exception.php:1-16 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 INIT_FCALL 2 176 string("inverse") +0004 SEND_VAL int(5) 1 +0005 SEND_VAR CV0($b) 2 +0006 DO_UCALL +0007 INIT_FCALL 2 176 string("inverse") +0008 SEND_VAL int(0) 1 +0009 SEND_VAR CV0($b) 2 +0010 DO_UCALL +0011 JMP 0018 +0012 CV1($e) = CATCH string("Exception") +0013 ECHO string("Caught exception: ") +0014 INIT_METHOD_CALL 0 CV1($e) string("getMessage") +0015 V7 = DO_FCALL +0016 ECHO V7 +0017 ECHO string(" +") +0018 RETURN int(1) +EXCEPTION TABLE: + 0003, 0012, -, - + +inverse: + ; (lines=11, args=2, vars=2, tmps=4) + ; (before optimizer) + ; /.../PHP/50_throw_exception/1_instance_50_throw_exception/1_instance_50_throw_exception.php:2-7 + ; return [] RANGE[0..0] +0000 CV0($x) = RECV 1 +0001 CV1($b) = RECV 2 +0002 T2 = BOOL_NOT CV0($x) +0003 JMPZ T2 0008 +0004 V3 = NEW 1 string("Exception") +0005 SEND_VAR_EX CV1($b) 1 +0006 DO_FCALL +0007 THROW V3 +0008 T5 = DIV int(1) CV0($x) +0009 RETURN T5 +0010 RETURN null +LIVE RANGES: + 3: 0005 - 0007 (new) +``` + +
+ +
+ + +### Discovery + + +The rule searches for a call for `THROW` on opcode level. + +```scala +val x50 = (name, "50_throw_exception_iall", cpg.call(".*THROW.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | no | no | no | yes | +| 22 May 2023 | no | no | | | | | yes | + +
+ +
diff --git a/PHP/50_throw_exception/docs/description.md b/PHP/50_throw_exception/docs/description.md new file mode 100644 index 0000000..9bfbf79 --- /dev/null +++ b/PHP/50_throw_exception/docs/description.md @@ -0,0 +1 @@ +In PHP [Exceptions](https://www.php.net/manual/en/language.exceptions.php) are similar to other languages. An exception can be thrown and caught, try blocks indicate positions in code, where exceptions can occur. This pattern should target throwing an exception \ No newline at end of file diff --git a/PHP/51_catch_exceptions/1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.bash b/PHP/51_catch_exceptions/1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.bash new file mode 100644 index 0000000..3a5f3dc --- /dev/null +++ b/PHP/51_catch_exceptions/1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.bash @@ -0,0 +1,48 @@ + +$_main: + ; (lines=20, args=0, vars=2, tmps=6) + ; (before optimizer) + ; /.../PHP/51_catch_exceptions/1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.php:1-18 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 INIT_FCALL 2 176 string("inverse") +0004 SEND_VAL int(5) 1 +0005 SEND_VAR CV0($b) 2 +0006 DO_UCALL +0007 INIT_FCALL 2 176 string("inverse") +0008 SEND_VAL int(0) 1 +0009 SEND_VAR CV0($b) 2 +0010 DO_UCALL +0011 JMP 0019 +0012 CV1($e) = CATCH string("Exception") +0013 ECHO CV0($b) +0014 ECHO string("Caught exception: ") +0015 INIT_METHOD_CALL 0 CV1($e) string("getMessage") +0016 V7 = DO_FCALL +0017 ECHO V7 +0018 ECHO string(" +") +0019 RETURN int(1) +EXCEPTION TABLE: + 0003, 0012, -, - + +inverse: + ; (lines=11, args=2, vars=2, tmps=4) + ; (before optimizer) + ; /.../PHP/51_catch_exceptions/1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.php:2-7 + ; return [] RANGE[0..0] +0000 CV0($x) = RECV 1 +0001 CV1($b) = RECV 2 +0002 T2 = BOOL_NOT CV0($x) +0003 JMPZ T2 0008 +0004 V3 = NEW 1 string("Exception") +0005 SEND_VAR_EX CV1($b) 1 +0006 DO_FCALL +0007 THROW V3 +0008 T5 = DIV int(1) CV0($x) +0009 RETURN T5 +0010 RETURN null +LIVE RANGES: + 3: 0005 - 0007 (new) diff --git a/PHP/51_catch_exceptions/1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.json b/PHP/51_catch_exceptions/1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.json index a73faad..6494560 100644 --- a/PHP/51_catch_exceptions/1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.json +++ b/PHP/51_catch_exceptions/1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.json @@ -1,13 +1,14 @@ { + "description": "This instance focuses on the catch part of the exception.", "code": { "path": "./1_instance_51_catch_exceptions.php", - "injection_skeleton_broken": false + "injection_skeleton_broken": true }, "discovery": { "rule": "./1_instance_51_catch_exceptions.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "Perfect", + "notes": "The rule searches for all calls to `CATCH` on opcode level." }, "compile": { "binary": "./1_instance_51_catch_exceptions.bash", @@ -17,7 +18,7 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_51_catch_exceptions.php", - "sink_line": 16, + "sink_line": 15, "source_file": "./1_instance_51_catch_exceptions.php", "source_line": 9, "expectation": true diff --git a/PHP/51_catch_exceptions/1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.php b/PHP/51_catch_exceptions/1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.php new file mode 100644 index 0000000..1a6396e --- /dev/null +++ b/PHP/51_catch_exceptions/1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.php @@ -0,0 +1,17 @@ +getMessage(), "\n"; +} diff --git a/PHP/51_catch_exceptions/51_catch_exceptions.json b/PHP/51_catch_exceptions/51_catch_exceptions.json index 7d335ef..d2d0406 100644 --- a/PHP/51_catch_exceptions/51_catch_exceptions.json +++ b/PHP/51_catch_exceptions/51_catch_exceptions.json @@ -1,6 +1,6 @@ { "name": "Catch Exceptions", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/51_catch_exceptions/README.md b/PHP/51_catch_exceptions/README.md new file mode 100644 index 0000000..ce19f18 --- /dev/null +++ b/PHP/51_catch_exceptions/README.md @@ -0,0 +1,144 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Catch Exceptions + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +In PHP [Exceptions](https://www.php.net/manual/en/language.exceptions.php) are similar to other languages. An exception can be thrown and caught, try blocks indicate positions in code, where exceptions can occur. This pattern should target catching an exception. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +This instance focuses on the catch part of the exception. + +### Code + +```PHP +getMessage(), "\n"; +} +``` + +### Instance Properties + +| category | feature_vs_internal_api | input_sanitizer | negative_test_case | source_and_sink | +|------------|---------------------------|-------------------|----------------------|-------------------| +| S0 | FEATURE | no | no | no | + +
+ +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=20, args=0, vars=2, tmps=6) + ; (before optimizer) + ; /.../PHP/51_catch_exceptions/1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.php:1-18 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 INIT_FCALL 2 176 string("inverse") +0004 SEND_VAL int(5) 1 +0005 SEND_VAR CV0($b) 2 +0006 DO_UCALL +0007 INIT_FCALL 2 176 string("inverse") +0008 SEND_VAL int(0) 1 +0009 SEND_VAR CV0($b) 2 +0010 DO_UCALL +0011 JMP 0019 +0012 CV1($e) = CATCH string("Exception") +0013 ECHO CV0($b) +0014 ECHO string("Caught exception: ") +0015 INIT_METHOD_CALL 0 CV1($e) string("getMessage") +0016 V7 = DO_FCALL +0017 ECHO V7 +0018 ECHO string(" +") +0019 RETURN int(1) +EXCEPTION TABLE: + 0003, 0012, -, - + +inverse: + ; (lines=11, args=2, vars=2, tmps=4) + ; (before optimizer) + ; /.../PHP/51_catch_exceptions/1_instance_51_catch_exceptions/1_instance_51_catch_exceptions.php:2-7 + ; return [] RANGE[0..0] +0000 CV0($x) = RECV 1 +0001 CV1($b) = RECV 2 +0002 T2 = BOOL_NOT CV0($x) +0003 JMPZ T2 0008 +0004 V3 = NEW 1 string("Exception") +0005 SEND_VAR_EX CV1($b) 1 +0006 DO_FCALL +0007 THROW V3 +0008 T5 = DIV int(1) CV0($x) +0009 RETURN T5 +0010 RETURN null +LIVE RANGES: + 3: 0005 - 0007 (new) +``` + +
+ +
+ + +### Discovery + + +The rule searches for all calls to `CATCH` on opcode level. + +```scala +val x51 = (name, "51_catch_exception_iall", cpg.call(".*CATCH.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | yes | yes | no | yes | no | yes | +| 22 May 2023 | no | no | | | | | yes | + +
+ +
diff --git a/PHP/51_catch_exceptions/docs/description.md b/PHP/51_catch_exceptions/docs/description.md new file mode 100644 index 0000000..778c904 --- /dev/null +++ b/PHP/51_catch_exceptions/docs/description.md @@ -0,0 +1 @@ +In PHP [Exceptions](https://www.php.net/manual/en/language.exceptions.php) are similar to other languages. An exception can be thrown and caught, try blocks indicate positions in code, where exceptions can occur. This pattern should target catching an exception. \ No newline at end of file diff --git a/PHP/52_try_catch_finally/1_instance_52_try_catch_finally/1_instance_52_try_catch_finally.bash b/PHP/52_try_catch_finally/1_instance_52_try_catch_finally/1_instance_52_try_catch_finally.bash index d327481..e761bb8 100644 --- a/PHP/52_try_catch_finally/1_instance_52_try_catch_finally/1_instance_52_try_catch_finally.bash +++ b/PHP/52_try_catch_finally/1_instance_52_try_catch_finally/1_instance_52_try_catch_finally.bash @@ -1,59 +1,51 @@ -$_main: ; (lines=11, args=0, vars=1, tmps=5) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/42_try_catch_finally/first_ex/first_ex.php:1-22 -L0 (17): EXT_STMT -L1 (17): T1 = FETCH_R (global) string("_GET") -L2 (17): T2 = FETCH_DIM_R T1 string("p1") -L3 (17): ASSIGN CV0($b) T2 -L4 (18): EXT_STMT -L5 (18): INIT_FCALL 1 240 string("foo") -L6 (18): T4 = CONCAT CV0($b) string(" +$_main: + ; (lines=10, args=0, vars=2, tmps=6) + ; (before optimizer) + ; /.../PHP/52_try_catch_finally/1_instance_52_try_catch_finally/1_instance_52_try_catch_finally.php:1-22 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 INIT_FCALL 1 240 string("foo") +0004 T5 = CONCAT CV0($b) string(" ") -L7 (18): SEND_VAL T4 1 -L8 (18): V5 = DO_FCALL -L9 (18): ECHO V5 -L10 (22): RETURN int(1) +0005 SEND_VAL T5 1 +0006 V6 = DO_UCALL +0007 ASSIGN CV1($a) V6 +0008 ECHO CV1($a) +0009 RETURN int(1) -foo: ; (lines=30, args=1, vars=3, tmps=7) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/42_try_catch_finally/first_ex/first_ex.php:2-16 -L0 (2): EXT_NOP -L1 (2): CV0($b) = RECV 1 -L2 (4): EXT_STMT -L3 (4): ASSIGN CV1($bar) CV0($b) -L4 (5): NOP -L5 (6): EXT_STMT -L6 (6): V5 = NEW 1 string("Exception") -L7 (6): SEND_VAL_EX string("Exception") 1 -L8 (6): DO_FCALL -L9 (6): THROW V5 -L10 (6): JMP L18 -L11 (7): CV2($e) = CATCH string("Exception") -L12 (8): EXT_STMT -L13 (8): ECHO string("catch +foo: + ; (lines=21, args=1, vars=3, tmps=7) + ; (before optimizer) + ; /.../PHP/52_try_catch_finally/1_instance_52_try_catch_finally/1_instance_52_try_catch_finally.php:2-15 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN CV1($bar) CV0($b) +0002 V5 = NEW 1 string("Exception") +0003 SEND_VAL_EX string("Exception") 1 +0004 DO_FCALL +0005 THROW V5 +0006 JMP 0012 +0007 CV2($e) = CATCH string("Exception") +0008 ECHO string("catch ") -L14 (10): EXT_STMT -L15 (10): T7 = QM_ASSIGN CV1($bar) -L16 (10): T4 = FAST_CALL L20 T7 -L17 (10): RETURN T7 -L18 (11): T4 = FAST_CALL L20 -L19 (11): JMP L28 -L20 (12): EXT_STMT -L21 (12): ECHO string("finally +0009 T7 = QM_ASSIGN CV1($bar) +0010 T4 = FAST_CALL 0014 T7 +0011 RETURN T7 +0012 T4 = FAST_CALL 0014 +0013 JMP 0020 +0014 ECHO string("finally ") -L22 (14): EXT_STMT -L23 (14): INIT_FCALL 1 96 string("htmlspecialchars") -L24 (14): SEND_VAR CV1($bar) 1 -L25 (14): V8 = DO_FCALL -L26 (14): ASSIGN CV1($bar) V8 -L27 (14): FAST_RET T4 -L28 (16): EXT_STMT -L29 (16): RETURN null +0015 INIT_FCALL 1 96 string("htmlspecialchars") +0016 SEND_VAR CV1($bar) 1 +0017 V8 = DO_ICALL +0018 ASSIGN CV1($bar) V8 +0019 FAST_RET T4 +0020 RETURN null LIVE RANGES: - 5: L7 - L9 (new) - 7: L16 - L17 (tmp/var) + 5: 0003 - 0005 (new) + 7: 0010 - 0011 (tmp/var) EXCEPTION TABLE: - L5, L11, L20, L27 - - + 0002, 0007, 0014, 0019 \ No newline at end of file diff --git a/PHP/52_try_catch_finally/1_instance_52_try_catch_finally/1_instance_52_try_catch_finally.json b/PHP/52_try_catch_finally/1_instance_52_try_catch_finally/1_instance_52_try_catch_finally.json index 38408cf..2cf370e 100644 --- a/PHP/52_try_catch_finally/1_instance_52_try_catch_finally/1_instance_52_try_catch_finally.json +++ b/PHP/52_try_catch_finally/1_instance_52_try_catch_finally/1_instance_52_try_catch_finally.json @@ -1,13 +1,14 @@ { + "description": "This instance shows a 'try, catch, finally' construct. The unsanitized `$bar` from the `catch` will be returned.", "code": { "path": "./1_instance_52_try_catch_finally.php", "injection_skeleton_broken": false }, "discovery": { - "rule": "./1_instance_52_try_catch_finally.sc", + "rule": "../52_try_catch_finally.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "Perfect", + "notes": "The rule searches for `FAST_RET` on opcode level." }, "compile": { "binary": "./1_instance_52_try_catch_finally.bash", @@ -19,7 +20,7 @@ "sink_file": "./1_instance_52_try_catch_finally.php", "sink_line": 18, "source_file": "./1_instance_52_try_catch_finally.php", - "source_line": 17, + "source_line": 16, "expectation": true }, "properties": { diff --git a/PHP/52_try_catch_finally/1_instance_52_try_catch_finally/1_instance_52_try_catch_finally.php b/PHP/52_try_catch_finally/1_instance_52_try_catch_finally/1_instance_52_try_catch_finally.php index 31741d4..a0487b8 100644 --- a/PHP/52_try_catch_finally/1_instance_52_try_catch_finally/1_instance_52_try_catch_finally.php +++ b/PHP/52_try_catch_finally/1_instance_52_try_catch_finally/1_instance_52_try_catch_finally.php @@ -1,6 +1,5 @@ + + +## 1 Instance + + +This instance shows a 'try, catch, finally' construct. The unsanitized `$bar` from the `catch` will be returned. + +### Code + +```PHP + + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=10, args=0, vars=2, tmps=6) + ; (before optimizer) + ; /.../PHP/52_try_catch_finally/1_instance_52_try_catch_finally/1_instance_52_try_catch_finally.php:1-22 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 INIT_FCALL 1 240 string("foo") +0004 T5 = CONCAT CV0($b) string(" +") +0005 SEND_VAL T5 1 +0006 V6 = DO_UCALL +0007 ASSIGN CV1($a) V6 +0008 ECHO CV1($a) +0009 RETURN int(1) + +foo: + ; (lines=21, args=1, vars=3, tmps=7) + ; (before optimizer) + ; /.../PHP/52_try_catch_finally/1_instance_52_try_catch_finally/1_instance_52_try_catch_finally.php:2-15 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN CV1($bar) CV0($b) +0002 V5 = NEW 1 string("Exception") +0003 SEND_VAL_EX string("Exception") 1 +0004 DO_FCALL +0005 THROW V5 +0006 JMP 0012 +0007 CV2($e) = CATCH string("Exception") +0008 ECHO string("catch +") +0009 T7 = QM_ASSIGN CV1($bar) +0010 T4 = FAST_CALL 0014 T7 +0011 RETURN T7 +0012 T4 = FAST_CALL 0014 +0013 JMP 0020 +0014 ECHO string("finally +") +0015 INIT_FCALL 1 96 string("htmlspecialchars") +0016 SEND_VAR CV1($bar) 1 +0017 V8 = DO_ICALL +0018 ASSIGN CV1($bar) V8 +0019 FAST_RET T4 +0020 RETURN null +LIVE RANGES: + 5: 0003 - 0005 (new) + 7: 0010 - 0011 (tmp/var) +EXCEPTION TABLE: + 0002, 0007, 0014, 0019 +``` + +
+ +
+ + +### Discovery + + +The rule searches for `FAST_RET` on opcode level. + +```scala +val x52 = (name, "52_try_catch_finally_iall", cpg.call(".*FAST_RET.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | yes | no | no | yes | no | yes | +| 22 May 2023 | yes | yes | | | | | yes | + +
+ + + + + +
+ + +## 2 Instance + + +This instance shows the same construct as the previous instance. But this time, the sanitized value from the finally statement is returned. + +### Code + +```PHP + + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=10, args=0, vars=2, tmps=6) + ; (before optimizer) + ; /.../PHP/52_try_catch_finally/2_instance_52_try_catch_finally/2_instance_52_try_catch_finally.php:1-24 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($b) T3 +0003 INIT_FCALL 1 240 string("foo") +0004 T5 = CONCAT CV0($b) string(" +") +0005 SEND_VAL T5 1 +0006 V6 = DO_UCALL +0007 ASSIGN CV1($a) V6 +0008 ECHO CV1($a) +0009 RETURN int(1) + +foo: + ; (lines=23, args=1, vars=3, tmps=7) + ; (before optimizer) + ; /.../PHP/52_try_catch_finally/2_instance_52_try_catch_finally/2_instance_52_try_catch_finally.php:2-17 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 ASSIGN CV1($bar) CV0($b) +0002 V5 = NEW 1 string("Exception") +0003 SEND_VAL_EX string("Exception") 1 +0004 DO_FCALL +0005 THROW V5 +0006 JMP 0012 +0007 CV2($e) = CATCH string("Exception") +0008 ECHO string("catch +") +0009 T7 = QM_ASSIGN CV1($bar) +0010 T4 = FAST_CALL 0014 T7 +0011 RETURN T7 +0012 T4 = FAST_CALL 0014 +0013 JMP 0022 +0014 ECHO string("finally +") +0015 INIT_FCALL 1 96 string("htmlspecialchars") +0016 SEND_VAR CV1($bar) 1 +0017 V8 = DO_ICALL +0018 ASSIGN CV1($bar) V8 +0019 DISCARD_EXCEPTION T4 +0020 RETURN CV1($bar) +0021 FAST_RET T4 +0022 RETURN null +LIVE RANGES: + 5: 0003 - 0005 (new) + 7: 0010 - 0011 (tmp/var) +EXCEPTION TABLE: + 0002, 0007, 0014, 0021 +``` + +
+ +
+ + +### Discovery + + +The rule searches for `FAST_RET` on opcode level. + +```scala +val x52 = (name, "52_try_catch_finally_iall", cpg.call(".*FAST_RET.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | RIPS | Ground Truth | +|-------------|----------|----------|--------|----------------| +| 08 Jun 2021 | yes | yes | no | no | +| 22 May 2023 | yes | yes | | no | + +
+ +
+ + diff --git a/PHP/52_try_catch_finally/docs/description.md b/PHP/52_try_catch_finally/docs/description.md new file mode 100644 index 0000000..28bb233 --- /dev/null +++ b/PHP/52_try_catch_finally/docs/description.md @@ -0,0 +1 @@ +In PHP [Exceptions](https://www.php.net/manual/en/language.exceptions.php) are similar to other languages. An exception can be thrown and caught, try blocks indicate positions in code, where exceptions can occur. This pattern should target the try-catch-finally block. The `finally` block will always be executed, regardless of whether an exception has been thrown, and before normal execution resumes. \ No newline at end of file diff --git a/PHP/53_track_error/1_instance_53_track_error/1_instance_53_track_error.bash b/PHP/53_track_error/1_instance_53_track_error/1_instance_53_track_error.bash index 48041d3..ca673f5 100644 --- a/PHP/53_track_error/1_instance_53_track_error/1_instance_53_track_error.bash +++ b/PHP/53_track_error/1_instance_53_track_error/1_instance_53_track_error.bash @@ -1,24 +1,22 @@ -$_main: ; (lines=18, args=0, vars=2, tmps=8) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/106_track_error/106_track_error.php:1-5 -L0 (2): EXT_STMT -L1 (2): T2 = FETCH_R (global) string("_GET") -L2 (2): T3 = FETCH_DIM_R T2 string("p1") -L3 (2): ASSIGN CV0($a) T3 -L4 (3): EXT_STMT -L5 (3): T5 = BEGIN_SILENCE -L6 (3): INIT_FCALL 1 96 string("trigger_error") -L7 (3): SEND_VAR CV0($a) 1 -L8 (3): DO_FCALL -L9 (3): END_SILENCE T5 -L10 (4): EXT_STMT -L11 (4): INIT_FCALL 0 80 string("error_get_last") -L12 (4): V7 = DO_FCALL -L13 (4): ASSIGN CV1($e) V7 -L14 (5): EXT_STMT -L15 (5): T9 = FETCH_DIM_R CV1($e) string("message") -L16 (5): ECHO T9 -L17 (5): RETURN int(1) +$_main: + ; (lines=14, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/53_track_error/1_instance_53_track_error/1_instance_53_track_error.php:1-5 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($a) T3 +0003 T5 = BEGIN_SILENCE +0004 INIT_FCALL 1 96 string("trigger_error") +0005 SEND_VAR CV0($a) 1 +0006 DO_ICALL +0007 END_SILENCE T5 +0008 INIT_FCALL 0 80 string("error_get_last") +0009 V7 = DO_ICALL +0010 ASSIGN CV1($e) V7 +0011 T9 = FETCH_DIM_R CV1($e) string("message") +0012 ECHO T9 +0013 RETURN int(1) LIVE RANGES: - 5: L6 - L9 (silence) \ No newline at end of file + 5: 0004 - 0007 (silence) diff --git a/PHP/53_track_error/1_instance_53_track_error/1_instance_53_track_error.json b/PHP/53_track_error/1_instance_53_track_error/1_instance_53_track_error.json index ccab388..51522e2 100644 --- a/PHP/53_track_error/1_instance_53_track_error/1_instance_53_track_error.json +++ b/PHP/53_track_error/1_instance_53_track_error/1_instance_53_track_error.json @@ -1,4 +1,5 @@ { + "description": "The instance triggers an error, which will is suppressed using the @ operator. Afterwards the error will be retrieved and the user controlled value outputted.", "code": { "path": "./1_instance_53_track_error.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_53_track_error.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "Perfect", + "notes": "The discovery rule searches for `BEGIN_SILENCE` on opcode level." }, "compile": { "binary": "./1_instance_53_track_error.bash", diff --git a/PHP/53_track_error/1_instance_53_track_error/1_instance_53_track_error.php b/PHP/53_track_error/1_instance_53_track_error/1_instance_53_track_error.php index 4fec4f1..e2cdea7 100644 --- a/PHP/53_track_error/1_instance_53_track_error/1_instance_53_track_error.php +++ b/PHP/53_track_error/1_instance_53_track_error/1_instance_53_track_error.php @@ -1,5 +1,5 @@ + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=14, args=0, vars=2, tmps=8) + ; (before optimizer) + ; /.../PHP/53_track_error/1_instance_53_track_error/1_instance_53_track_error.php:1-5 + ; return [] RANGE[0..0] +0000 T2 = FETCH_R (global) string("_GET") +0001 T3 = FETCH_DIM_R T2 string("p1") +0002 ASSIGN CV0($a) T3 +0003 T5 = BEGIN_SILENCE +0004 INIT_FCALL 1 96 string("trigger_error") +0005 SEND_VAR CV0($a) 1 +0006 DO_ICALL +0007 END_SILENCE T5 +0008 INIT_FCALL 0 80 string("error_get_last") +0009 V7 = DO_ICALL +0010 ASSIGN CV1($e) V7 +0011 T9 = FETCH_DIM_R CV1($e) string("message") +0012 ECHO T9 +0013 RETURN int(1) +LIVE RANGES: + 5: 0004 - 0007 (silence) +``` + +
+ +
+ + +### Discovery + + +The discovery rule searches for `BEGIN_SILENCE` on opcode level. + +```scala +val x53 = (name, "53_track_error_iall", cpg.call(".*BEGIN_SILENCE.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | no | yes | no | no | yes | +| 22 May 2023 | no | no | | | | | yes | + +
+ + diff --git a/PHP/53_track_error/docs/description.md b/PHP/53_track_error/docs/description.md new file mode 100644 index 0000000..f688b1a --- /dev/null +++ b/PHP/53_track_error/docs/description.md @@ -0,0 +1 @@ +PHP suppports one [error control operator](https://www.php.net/manual/en/language.operators.errorcontrol.php). When the @ symbol is prepended to an expression in PHP, any error that might occur when evaluating this expression will be suppressed. \ No newline at end of file diff --git a/PHP/54_generators/1_instance_54_generators/1_instance_54_generators.bash b/PHP/54_generators/1_instance_54_generators/1_instance_54_generators.bash index 4ca6869..7817441 100644 --- a/PHP/54_generators/1_instance_54_generators/1_instance_54_generators.bash +++ b/PHP/54_generators/1_instance_54_generators/1_instance_54_generators.bash @@ -1,47 +1,36 @@ -$_main: ; (lines=19, args=0, vars=3, tmps=7) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/50_generators/first_ex/first_ex.php:1-12 -L0 (7): EXT_STMT -L1 (7): T3 = FETCH_R (global) string("_GET") -L2 (7): T4 = FETCH_DIM_R T3 string("p1") -L3 (7): ASSIGN CV0($b) T4 -L4 (8): EXT_STMT -L5 (8): INIT_FCALL 1 176 string("gen_one_to_three") -L6 (8): SEND_VAR CV0($b) 1 -L7 (8): V6 = DO_FCALL -L8 (8): ASSIGN CV1($generator) V6 -L9 (9): EXT_STMT -L10 (9): V8 = FE_RESET_R CV1($generator) L17 -L11 (9): FE_FETCH_R V8 CV2($value) L17 -L12 (11): EXT_STMT -L13 (11): NOP -L14 (11): T9 = FAST_CONCAT CV2($value) string(" -") -L15 (11): ECHO T9 -L16 (9): JMP L11 -L17 (9): FE_FREE V8 -L18 (12): RETURN int(1) +$_main: + ; (lines=13, args=0, vars=3, tmps=6) + ; (before optimizer) + ; /.../PHP/54_generators/1_instance_54_generators/1_instance_54_generators.php:1-13 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($b) T4 +0003 INIT_FCALL 1 176 string("gen_one_to_three") +0004 SEND_VAR CV0($b) 1 +0005 V6 = DO_UCALL +0006 ASSIGN CV1($generator) V6 +0007 V8 = FE_RESET_R CV1($generator) 0011 +0008 FE_FETCH_R V8 CV2($value) 0011 +0009 ECHO CV2($value) +0010 JMP 0008 +0011 FE_FREE V8 +0012 RETURN int(1) LIVE RANGES: - 8: L11 - L17 (loop) + 8: 0008 - 0011 (loop) -gen_one_to_three: ; (lines=15, args=1, vars=2, tmps=4) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/50_generators/first_ex/first_ex.php:2-6 -L0 (2): EXT_NOP -L1 (2): CV0($b) = RECV 1 -L2 (2): GENERATOR_CREATE -L3 (3): EXT_STMT -L4 (3): ASSIGN CV1($i) int(1) -L5 (3): JMP L10 -L6 (4): EXT_STMT -L7 (4): YIELD CV0($b) -L8 (3): T4 = POST_INC CV1($i) -L9 (3): FREE T4 -L10 (3): T5 = IS_SMALLER_OR_EQUAL CV1($i) int(3) -L11 (3): EXT_STMT -L12 (3): JMPNZ T5 L6 -L13 (6): EXT_STMT -L14 (6): GENERATOR_RETURN null -LIVE RANGES: - 5: L11 - L12 (tmp/var) +gen_one_to_three: + ; (lines=9, args=1, vars=2, tmps=4) + ; (before optimizer) + ; /.../PHP/54_generators/1_instance_54_generators/1_instance_54_generators.php:2-6 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 GENERATOR_CREATE +0002 ASSIGN CV1($i) int(1) +0003 JMP 0006 +0004 YIELD CV0($b) +0005 PRE_INC CV1($i) +0006 T5 = IS_SMALLER_OR_EQUAL CV1($i) int(3) +0007 JMPNZ T5 0004 +0008 GENERATOR_RETURN null diff --git a/PHP/54_generators/1_instance_54_generators/1_instance_54_generators.json b/PHP/54_generators/1_instance_54_generators/1_instance_54_generators.json index 65886f7..8a74eb9 100644 --- a/PHP/54_generators/1_instance_54_generators/1_instance_54_generators.json +++ b/PHP/54_generators/1_instance_54_generators/1_instance_54_generators.json @@ -1,4 +1,5 @@ { + "description": "The instance shows a simple generator, that generates the input value three times.", "code": { "path": "./1_instance_54_generators.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_54_generators.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "Perfect", + "notes": "The discovery rule searches for `GENERATOR_CREATE` on opcode level." }, "compile": { "binary": "./1_instance_54_generators.bash", @@ -17,9 +18,9 @@ "expectation": { "type": "xss", "sink_file": "./1_instance_54_generators.php", - "sink_line": 11, + "sink_line": 12, "source_file": "./1_instance_54_generators.php", - "source_line": 7, + "source_line": 8, "expectation": true }, "properties": { diff --git a/PHP/54_generators/1_instance_54_generators/1_instance_54_generators.php b/PHP/54_generators/1_instance_54_generators/1_instance_54_generators.php index 3b59e51..2b73915 100644 --- a/PHP/54_generators/1_instance_54_generators/1_instance_54_generators.php +++ b/PHP/54_generators/1_instance_54_generators/1_instance_54_generators.php @@ -4,9 +4,10 @@ function gen_one_to_three($b) { yield $b; } } -$b = $_GET["p1"]; + +$b = $_GET["p1"]; // source $generator = gen_one_to_three($b); foreach ($generator as $value) { // XSS, it will print the input $b. - echo "$value\n"; + echo $value; // sink } \ No newline at end of file diff --git a/PHP/54_generators/1_instance_54_generators/1_instance_54_generators.sc b/PHP/54_generators/1_instance_54_generators/1_instance_54_generators.sc index 5c0f361..eff72ac 100644 --- a/PHP/54_generators/1_instance_54_generators/1_instance_54_generators.sc +++ b/PHP/54_generators/1_instance_54_generators/1_instance_54_generators.sc @@ -1,6 +1,6 @@ @main def main(name : String): Unit = { importCpg(name) - val x52 = (name, "54_generators_iall", cpg.call(".*GENERATOR_CREATE.*").location.toJson); - println(x52) + val x54 = (name, "54_generators_iall", cpg.call(".*GENERATOR_CREATE.*").location.toJson); + println(x54) delete; } \ No newline at end of file diff --git a/PHP/54_generators/54_generators.json b/PHP/54_generators/54_generators.json index bce0b04..05de28a 100644 --- a/PHP/54_generators/54_generators.json +++ b/PHP/54_generators/54_generators.json @@ -1,6 +1,6 @@ { "name": "Generators", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_54_generators/1_instance_54_generators.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/54_generators/README.md b/PHP/54_generators/README.md new file mode 100644 index 0000000..8a3d727 --- /dev/null +++ b/PHP/54_generators/README.md @@ -0,0 +1,128 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Generators + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +A [generator](https://www.php.net/manual/en/language.generators.overview.php) in PHP provides an easy way to implement simple iterators without implementing a class that implements the Iterator interface. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +The instance shows a simple generator, that generates the input value three times. + +### Code + +```PHP + + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=13, args=0, vars=3, tmps=6) + ; (before optimizer) + ; /.../PHP/54_generators/1_instance_54_generators/1_instance_54_generators.php:1-13 + ; return [] RANGE[0..0] +0000 T3 = FETCH_R (global) string("_GET") +0001 T4 = FETCH_DIM_R T3 string("p1") +0002 ASSIGN CV0($b) T4 +0003 INIT_FCALL 1 176 string("gen_one_to_three") +0004 SEND_VAR CV0($b) 1 +0005 V6 = DO_UCALL +0006 ASSIGN CV1($generator) V6 +0007 V8 = FE_RESET_R CV1($generator) 0011 +0008 FE_FETCH_R V8 CV2($value) 0011 +0009 ECHO CV2($value) +0010 JMP 0008 +0011 FE_FREE V8 +0012 RETURN int(1) +LIVE RANGES: + 8: 0008 - 0011 (loop) + +gen_one_to_three: + ; (lines=9, args=1, vars=2, tmps=4) + ; (before optimizer) + ; /.../PHP/54_generators/1_instance_54_generators/1_instance_54_generators.php:2-6 + ; return [] RANGE[0..0] +0000 CV0($b) = RECV 1 +0001 GENERATOR_CREATE +0002 ASSIGN CV1($i) int(1) +0003 JMP 0006 +0004 YIELD CV0($b) +0005 PRE_INC CV1($i) +0006 T5 = IS_SMALLER_OR_EQUAL CV1($i) int(3) +0007 JMPNZ T5 0004 +0008 GENERATOR_RETURN null +``` + +
+ +
+ + +### Discovery + + +The discovery rule searches for `GENERATOR_CREATE` on opcode level. + +```scala +val x54 = (name, "54_generators_iall", cpg.call(".*GENERATOR_CREATE.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | no | yes | no | yes | +| 22 May 2023 | yes | no | | | | | yes | + +
+ + diff --git a/PHP/54_generators/docs/description.md b/PHP/54_generators/docs/description.md new file mode 100644 index 0000000..6bda900 --- /dev/null +++ b/PHP/54_generators/docs/description.md @@ -0,0 +1 @@ +A [generator](https://www.php.net/manual/en/language.generators.overview.php) in PHP provides an easy way to implement simple iterators without implementing a class that implements the Iterator interface. \ No newline at end of file diff --git a/PHP/55_goto/1_instance_55_goto/1_instance_55_goto.bash b/PHP/55_goto/1_instance_55_goto/1_instance_55_goto.bash index 67354ff..e113adf 100644 --- a/PHP/55_goto/1_instance_55_goto/1_instance_55_goto.bash +++ b/PHP/55_goto/1_instance_55_goto/1_instance_55_goto.bash @@ -1,22 +1,17 @@ -$_main: ; (lines=18, args=0, vars=2, tmps=7) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/69_goto/69_goto.php:1-12 -L0 (2): EXT_STMT -L1 (2): ASSIGN CV0($b) string("abcde") -L2 (3): EXT_STMT -L3 (3): ASSIGN CV1($cond) int(1) -L4 (5): EXT_STMT -L5 (5): ECHO CV0($b) -L6 (6): EXT_STMT -L7 (6): T4 = FETCH_R (global) string("_GET") -L8 (6): T5 = FETCH_DIM_R T4 string("p1") -L9 (6): ASSIGN CV0($b) T5 -L10 (9): EXT_STMT -L11 (9): T7 = IS_EQUAL CV1($cond) int(1) -L12 (9): JMPZ T7 L17 -L13 (10): EXT_STMT -L14 (10): ASSIGN CV1($cond) int(0) -L15 (11): EXT_STMT -L16 (11): JMP L4 -L17 (12): RETURN int(1) +$_main: + ; (lines=11, args=0, vars=2, tmps=7) + ; (before optimizer) + ; /.../PHP/55_goto/1_instance_55_goto/1_instance_55_goto.php:1-12 + ; return [] RANGE[0..0] +0000 ASSIGN CV0($b) string("abcde") +0001 ASSIGN CV1($cond) int(1) +0002 ECHO CV0($b) +0003 T4 = FETCH_R (global) string("_GET") +0004 T5 = FETCH_DIM_R T4 string("p1") +0005 ASSIGN CV0($b) T5 +0006 T7 = IS_EQUAL CV1($cond) int(1) +0007 JMPZ T7 0010 +0008 ASSIGN CV1($cond) int(0) +0009 JMP 0002 +0010 RETURN int(1) diff --git a/PHP/55_goto/1_instance_55_goto/1_instance_55_goto.json b/PHP/55_goto/1_instance_55_goto/1_instance_55_goto.json index d73c36f..a4f723b 100644 --- a/PHP/55_goto/1_instance_55_goto/1_instance_55_goto.json +++ b/PHP/55_goto/1_instance_55_goto/1_instance_55_goto.json @@ -1,4 +1,5 @@ { + "description": "This instance shows a simple `goto` programm.", "code": { "path": "./1_instance_55_goto.php", "injection_skeleton_broken": false @@ -7,7 +8,7 @@ "rule": "./1_instance_55_goto.py", "method": "python", "rule_accuracy": null, - "notes": null + "notes": "This instance could profit from source code discovery, as `goto` cannot be found on opcode level. The current rule is written in python and uses `grep` to find the keyword `goto`" }, "compile": { "binary": "./1_instance_55_goto.bash", diff --git a/PHP/55_goto/1_instance_55_goto/1_instance_55_goto.php b/PHP/55_goto/1_instance_55_goto/1_instance_55_goto.php index 1650cc3..6a0f0a8 100644 --- a/PHP/55_goto/1_instance_55_goto/1_instance_55_goto.php +++ b/PHP/55_goto/1_instance_55_goto/1_instance_55_goto.php @@ -2,11 +2,11 @@ $b = 'abcde'; $cond = 1; point: -echo $b; -$b = $_GET["p1"]; +echo $b; // sink +$b = $_GET["p1"]; // source // will return back to print $b // XSS vulnerability -if ($cond == 1){ +if ($cond == 1) { $cond = 0; goto point; } \ No newline at end of file diff --git a/PHP/55_goto/55_goto.json b/PHP/55_goto/55_goto.json index b711e28..e5d9f7d 100644 --- a/PHP/55_goto/55_goto.json +++ b/PHP/55_goto/55_goto.json @@ -1,6 +1,6 @@ { "name": "Goto", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_55_goto/1_instance_55_goto.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/55_goto/README.md b/PHP/55_goto/README.md new file mode 100644 index 0000000..cd2cca6 --- /dev/null +++ b/PHP/55_goto/README.md @@ -0,0 +1,129 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Goto + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +The [goto](https://www.php.net/manual/en/control-structures.goto.php) statement can be used, to jump to another section in the programm indicated by a label. This is considered bad coding style. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | python | no | + +## 1 Instance + +This instance shows a simple `goto` programm. + +### Code + +```PHP + + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=11, args=0, vars=2, tmps=7) + ; (before optimizer) + ; /.../PHP/55_goto/1_instance_55_goto/1_instance_55_goto.php:1-12 + ; return [] RANGE[0..0] +0000 ASSIGN CV0($b) string("abcde") +0001 ASSIGN CV1($cond) int(1) +0002 ECHO CV0($b) +0003 T4 = FETCH_R (global) string("_GET") +0004 T5 = FETCH_DIM_R T4 string("p1") +0005 ASSIGN CV0($b) T5 +0006 T7 = IS_EQUAL CV1($cond) int(1) +0007 JMPZ T7 0010 +0008 ASSIGN CV1($cond) int(0) +0009 JMP 0002 +0010 RETURN int(1) +``` + +
+ +
+ + +### Discovery + + +This instance could profit from source code discovery, as `goto` cannot be found on opcode level. The current rule is written in python and uses `grep` to find the keyword `goto` + +```python +#!/usr/bin/env python3 + +import subprocess +import sys +from pathlib import Path + +if __name__ == "__main__": +project_folder = Path(sys.argv[1]) +cmd = "grep -Hn -r 'goto' " + str(project_folder) +try: +result = subprocess.check_output(cmd, shell=True) +results = result.decode('utf-8-sig') +results = results.split('\n') +for r in results[:-1]: +values = r.split(':') +line = values[1] +file = values[0] +if '.php' in file: +print(file + '%' + line) +except: +#no line found +print('') +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| python | | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | yes | no | no | no | no | no | yes | +| 22 May 2023 | yes | no | | | | | yes | + +
+ + diff --git a/PHP/55_goto/docs/description.md b/PHP/55_goto/docs/description.md new file mode 100644 index 0000000..bdae90c --- /dev/null +++ b/PHP/55_goto/docs/description.md @@ -0,0 +1 @@ +The [goto](https://www.php.net/manual/en/control-structures.goto.php) statement can be used, to jump to another section in the programm indicated by a label. This is considered bad coding style. \ No newline at end of file diff --git a/PHP/56_exit/1_instance_56_exit/1_instance_56_exit.bash b/PHP/56_exit/1_instance_56_exit/1_instance_56_exit.bash index 191c384..4e48367 100644 --- a/PHP/56_exit/1_instance_56_exit/1_instance_56_exit.bash +++ b/PHP/56_exit/1_instance_56_exit/1_instance_56_exit.bash @@ -1,11 +1,11 @@ -$_main: ; (lines=7, args=0, vars=1, tmps=3) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/108_exit/108_exit.php:1-5 -L0 (2): EXT_STMT -L1 (2): T1 = FETCH_R (global) string("_GET") -L2 (2): T2 = FETCH_DIM_R T1 string("p1") -L3 (2): ASSIGN CV0($a) T2 -L4 (3): EXT_STMT -L5 (3): EXIT CV0($a) -L6 (5): RETURN int(1) +$_main: + ; (lines=5, args=0, vars=1, tmps=3) + ; (before optimizer) + ; /.../PHP/56_exit/1_instance_56_exit/1_instance_56_exit.php:1-3 + ; return [] RANGE[0..0] +0000 T1 = FETCH_R (global) string("_GET") +0001 T2 = FETCH_DIM_R T1 string("p1") +0002 ASSIGN CV0($a) T2 +0003 EXIT CV0($a) +0004 RETURN int(1) diff --git a/PHP/56_exit/1_instance_56_exit/1_instance_56_exit.json b/PHP/56_exit/1_instance_56_exit/1_instance_56_exit.json index c18f8b8..e8bd19c 100644 --- a/PHP/56_exit/1_instance_56_exit/1_instance_56_exit.json +++ b/PHP/56_exit/1_instance_56_exit/1_instance_56_exit.json @@ -1,4 +1,5 @@ { + "description": "The instance demonstrates `exit`, where the argument for that function is a user controlled value.", "code": { "path": "./1_instance_56_exit.php", "injection_skeleton_broken": false @@ -6,8 +7,8 @@ "discovery": { "rule": "./1_instance_56_exit.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "Perfect", + "notes": "The rule searches for `EXIT` on opcode level and filters out those, where the argument is a variable." }, "compile": { "binary": "./1_instance_56_exit.bash", diff --git a/PHP/56_exit/1_instance_56_exit/1_instance_56_exit.php b/PHP/56_exit/1_instance_56_exit/1_instance_56_exit.php index 46d9628..38c0501 100644 --- a/PHP/56_exit/1_instance_56_exit/1_instance_56_exit.php +++ b/PHP/56_exit/1_instance_56_exit/1_instance_56_exit.php @@ -1,4 +1,3 @@ +$a = $_GET["p1"]; // source +exit($a); // sink \ No newline at end of file diff --git a/PHP/56_exit/1_instance_56_exit/1_instance_56_exit.sc b/PHP/56_exit/1_instance_56_exit/1_instance_56_exit.sc index f3ccab1..21680a5 100644 --- a/PHP/56_exit/1_instance_56_exit/1_instance_56_exit.sc +++ b/PHP/56_exit/1_instance_56_exit/1_instance_56_exit.sc @@ -1,6 +1,6 @@ @main def main(name : String): Unit = { importCpg(name) - val x52 = (name, "55_Exit_iall", cpg.call(".*EXIT.*").argument.code("CV.*|T.*|V.*").location.toJson); - println(x52) + val x56 = (name, "55_Exit_iall", cpg.call(".*EXIT.*").argument.code("CV.*|T.*|V.*").location.toJson); + println(x56) delete; } \ No newline at end of file diff --git a/PHP/56_exit/56_exit.json b/PHP/56_exit/56_exit.json index 0f71077..c5ca415 100644 --- a/PHP/56_exit/56_exit.json +++ b/PHP/56_exit/56_exit.json @@ -1,6 +1,6 @@ { "name": "Exit", - "description": "", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -10,5 +10,5 @@ "instances": [ "./1_instance_56_exit/1_instance_56_exit.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/56_exit/README.md b/PHP/56_exit/README.md new file mode 100644 index 0000000..6f53566 --- /dev/null +++ b/PHP/56_exit/README.md @@ -0,0 +1,93 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Exit + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +In PHP [`exit`](https://www.php.net/manual/en/function.exit.php) outputs a message and terminates the script. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +The instance demonstrates `exit`, where the argument for that function is a user controlled value. + +### Code + +```PHP + + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=5, args=0, vars=1, tmps=3) + ; (before optimizer) + ; /.../PHP/56_exit/1_instance_56_exit/1_instance_56_exit.php:1-3 + ; return [] RANGE[0..0] +0000 T1 = FETCH_R (global) string("_GET") +0001 T2 = FETCH_DIM_R T1 string("p1") +0002 ASSIGN CV0($a) T2 +0003 EXIT CV0($a) +0004 RETURN int(1) +``` + +
+ +
+ + +### Discovery + + +The rule searches for `EXIT` on opcode level and filters out those, where the argument is a variable. + +```scala +val x56 = (name, "55_Exit_iall", cpg.call(".*EXIT.*").argument.code("CV.*|T.*|V.*").location.toJson); +``` + +| discovery method | expected accuracy | +|--------------------|---------------------| +| joern | Perfect | + +
+ +
+ + +### Measurement + + +| Tool | Comm_1 | Comm_2 | phpSAFE | Progpilot | RIPS | WAP | Ground Truth | +|-------------|----------|----------|-----------|-------------|--------|-------|----------------| +| 08 Jun 2021 | no | no | yes | yes | yes | yes | yes | +| 22 May 2023 | no | no | | | | | yes | + +
+ + diff --git a/PHP/56_exit/docs/description.md b/PHP/56_exit/docs/description.md new file mode 100644 index 0000000..d69aab1 --- /dev/null +++ b/PHP/56_exit/docs/description.md @@ -0,0 +1,2 @@ +In PHP [`exit`](https://www.php.net/manual/en/function.exit.php) outputs a message and terminates the script. + diff --git a/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.json b/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.json index bda6932..4efdbaa 100644 --- a/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.json +++ b/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.json @@ -1,25 +1,26 @@ { + "description": "The instance consists of two PHP files, the first file redirects to the second file, that contains the sink.", "code": { - "path": "./1_instance_57_js_redirect.php", + "path": "./1_instance_57_js_redirect_1.php", "injection_skeleton_broken": false }, "discovery": { "rule": "./1_instance_57_js_redirect.sc", "method": "joern", - "rule_accuracy": null, - "notes": null + "rule_accuracy": "FP", + "notes": "The rule searches for a redirect written in JS in the code." }, "compile": { - "binary": "./1_instance_57_js_redirect.bash", + "binary": "./1_instance_57_js_redirect_1.bash", "instruction": null, "dependencies": null }, "expectation": { "type": "xss", - "sink_file": "./1_instance_57_js_redirect.php", - "sink_line": 5, - "source_file": "./1_instance_57_js_redirect.php", - "source_line": 5, + "sink_file": "./1_instance_57_js_redirect_0.php", + "sink_line": 4, + "source_file": "./1_instance_57_js_redirect_1.php", + "source_line": 4, "expectation": true }, "properties": { diff --git a/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.sc b/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.sc new file mode 100644 index 0000000..345c871 --- /dev/null +++ b/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.sc @@ -0,0 +1,7 @@ +@main def main(name : String): Unit = { + importCpg(name) + // TODO: replace line below with your detection query + val x57 = (name, "57_js_redirect_iall", cpg.call.code(".*") +0008 RETURN int(1) +LIVE RANGES: + 4: 0004 - 0005 (tmp/var) diff --git a/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect_1.php b/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect_1.php new file mode 100644 index 0000000..02ad45a --- /dev/null +++ b/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect_1.php @@ -0,0 +1,6 @@ + window.location='1_instance_57_js_redirect_0.php' "; diff --git a/PHP/57_js_redirect/57_js_redirect.json b/PHP/57_js_redirect/57_js_redirect.json index 5b20c0d..1865682 100644 --- a/PHP/57_js_redirect/57_js_redirect.json +++ b/PHP/57_js_redirect/57_js_redirect.json @@ -1,6 +1,6 @@ { - "name": "JS Redirect", - "description": "", + "name": "Js Redirect", + "description": "./docs/description.md", "family": "code_pattern_php", "tags": [ "sast", @@ -8,7 +8,7 @@ "php_v7.4.9" ], "instances": [ - "./1_instance_57_JS_redirect/1_instance_57_JS_redirect.json" + "./1_instance_57_js_redirect/1_instance_57_js_redirect.json" ], - "version": "v0.draft" + "version": "v1.0" } \ No newline at end of file diff --git a/PHP/57_js_redirect/README.md b/PHP/57_js_redirect/README.md new file mode 100644 index 0000000..94c53fd --- /dev/null +++ b/PHP/57_js_redirect/README.md @@ -0,0 +1,114 @@ +[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) + +# Js Redirect + +Tags: sast, php, php_v7.4.9 + +Version: v1.0 + +## Description + +Redirects in Javascript can be done using `window.location`. This patterns tries to find redirects like this. + +## Overview + +| Instances | has discovery rule | discovery method | rule successfull | +|---------------------------|----------------------|--------------------|--------------------| +| [1 Instance](#1-instance) | yes | joern | yes | + +## 1 Instance + +The instance consists of two PHP files, the first file redirects to the second file, that contains the sink. + +### Code + +#### Source File + +```PHP + window.location='1_instance_57_js_redirect_0.php' "; +``` + +#### Sink File + +```PHP + + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=9, args=0, vars=0, tmps=5) + ; (before optimizer) + ; /.../PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect_1.php:1-7 + ; return [] RANGE[0..0] +0000 INIT_FCALL 0 80 string("session_start") +0001 DO_ICALL +0002 T3 = FETCH_R (global) string("_GET") +0003 T4 = FETCH_DIM_R T3 string("p1") +0004 V1 = FETCH_W (global) string("_SESSION") +0005 ASSIGN_DIM V1 string("abc") +0006 OP_DATA T4 +0007 ECHO string("") +0008 RETURN int(1) +LIVE RANGES: + 4: 0004 - 0005 (tmp/var) +``` + +
+ +
+ + +### Discovery + + +The rule searches for a redirect written in JS in the code. + +```scala +// TODO: replace line below with your detection query +val x57 = (name, "57_js_redirect_iall", cpg.call.code(".*") -L11 (8): RETURN int(1) -LIVE RANGES: - 4: L6 - L7 (tmp/var) \ No newline at end of file diff --git a/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.json b/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.json old mode 100644 new mode 100755 index 4efdbaa..eedde4f --- a/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.json +++ b/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.json @@ -1,38 +1,38 @@ -{ - "description": "The instance consists of two PHP files, the first file redirects to the second file, that contains the sink.", - "code": { - "path": "./1_instance_57_js_redirect_1.php", - "injection_skeleton_broken": false - }, - "discovery": { - "rule": "./1_instance_57_js_redirect.sc", - "method": "joern", - "rule_accuracy": "FP", - "notes": "The rule searches for a redirect written in JS in the code." - }, - "compile": { - "binary": "./1_instance_57_js_redirect_1.bash", - "instruction": null, - "dependencies": null - }, - "expectation": { - "type": "xss", - "sink_file": "./1_instance_57_js_redirect_0.php", - "sink_line": 4, - "source_file": "./1_instance_57_js_redirect_1.php", - "source_line": 4, - "expectation": true - }, - "properties": { - "category": "S0", - "feature_vs_internal_api": "FEATURE", - "input_sanitizer": false, - "source_and_sink": false, - "negative_test_case": false - }, - "remediation": { - "notes": "", - "transformation": null, - "modeling_rule": null - } +{ + "description": "The instance consists of two PHP files, the first file redirects to the second file, that contains the sink.", + "code": { + "path": "./1_instance_57_js_redirect_1.php", + "injection_skeleton_broken": false + }, + "discovery": { + "rule": "./1_instance_57_js_redirect.sc", + "method": "joern", + "rule_accuracy": "FP", + "notes": "The rule searches for a redirect written in JS in the code." + }, + "compile": { + "binary": "./1_instance_57_js_redirect_1.bash", + "instruction": null, + "dependencies": null + }, + "expectation": { + "type": "xss", + "sink_file": "./1_instance_57_js_redirect_0.php", + "sink_line": 4, + "source_file": "./1_instance_57_js_redirect_1.php", + "source_line": 4, + "expectation": true + }, + "properties": { + "category": "S0", + "feature_vs_internal_api": "FEATURE", + "input_sanitizer": false, + "source_and_sink": false, + "negative_test_case": false + }, + "remediation": { + "notes": "", + "transformation": null, + "modeling_rule": null + } } \ No newline at end of file diff --git a/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.php b/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.php deleted file mode 100644 index 15b8172..0000000 --- a/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.php +++ /dev/null @@ -1,7 +0,0 @@ - window.location='a.php' "; diff --git a/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.py b/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.py deleted file mode 100644 index 9be0061..0000000 --- a/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python3 - -import subprocess -import sys -from pathlib import Path - -if __name__ == "__main__": - project_folder = Path(sys.argv[1]) - cmd = "grep -Hn -r 'window.location' " + str(project_folder) - try: - result = subprocess.check_output(cmd, shell=True) - results = result.decode('utf-8-sig') - results = results.split('\n') - for r in results[:-1]: - values = r.split(':') - line = values[1] - file = values[0] - if '.php' in file: - print(file + '%' + line) - except: - #no line found - print('') diff --git a/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.sc b/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.sc old mode 100644 new mode 100755 index 345c871..27d5261 --- a/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.sc +++ b/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect.sc @@ -1,7 +1,7 @@ -@main def main(name : String): Unit = { - importCpg(name) - // TODO: replace line below with your detection query - val x57 = (name, "57_js_redirect_iall", cpg.call.code(".*") -0008 RETURN int(1) -LIVE RANGES: - 4: 0004 - 0005 (tmp/var) + +$_main: + ; (lines=9, args=0, vars=0, tmps=5) + ; (before optimizer) + ; /.../PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect_1.php:1-7 + ; return [] RANGE[0..0] +0000 INIT_FCALL 0 80 string("session_start") +0001 DO_ICALL +0002 T3 = FETCH_R (global) string("_GET") +0003 T4 = FETCH_DIM_R T3 string("p1") +0004 V1 = FETCH_W (global) string("_SESSION") +0005 ASSIGN_DIM V1 string("abc") +0006 OP_DATA T4 +0007 ECHO string("") +0008 RETURN int(1) +LIVE RANGES: + 4: 0004 - 0005 (tmp/var) diff --git a/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect_1.php b/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect_1.php old mode 100644 new mode 100755 index 02ad45a..12ad97c --- a/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect_1.php +++ b/PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect_1.php @@ -1,6 +1,6 @@ - window.location='1_instance_57_js_redirect_0.php' "; + window.location='1_instance_57_js_redirect_0.php' "; diff --git a/PHP/57_js_redirect/1_instance_57_js_redirect/a.bash b/PHP/57_js_redirect/1_instance_57_js_redirect/a.bash deleted file mode 100644 index 72e3fa4..0000000 --- a/PHP/57_js_redirect/1_instance_57_js_redirect/a.bash +++ /dev/null @@ -1,12 +0,0 @@ - -$_main: ; (lines=8, args=0, vars=0, tmps=3) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/125_JS_redirect/a.php:1-5 -L0 (3): EXT_STMT -L1 (3): INIT_FCALL 0 80 string("session_start") -L2 (3): DO_FCALL -L3 (5): EXT_STMT -L4 (5): T1 = FETCH_R (global) string("_SESSION") -L5 (5): T2 = FETCH_DIM_R T1 string("abc") -L6 (5): ECHO T2 -L7 (5): RETURN int(1) diff --git a/PHP/57_js_redirect/1_instance_57_js_redirect/a.php b/PHP/57_js_redirect/1_instance_57_js_redirect/a.php deleted file mode 100644 index 9f6d8b2..0000000 --- a/PHP/57_js_redirect/1_instance_57_js_redirect/a.php +++ /dev/null @@ -1,5 +0,0 @@ - window.location='a.php' "; - -// a.php - -session_start(); - -echo $_SESSION["abc"]; -``` - -- MEASUREMENT: - -| Tool | RIPS | phpSAFE | WAP | Progpilot | Comm_1 | Comm_2 | Correct | -| ------------- | ---- | ------- | ---- | --------- | ------- | --------- | ------- | -| Vulnerability | NO | NO | NO | NO | NO | NO | YES | -Measurements Date: 8 June 2021 - -- OPCODE: - -```bash - -$_main: ; (lines=12, args=0, vars=0, tmps=5) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/125_window_location/125_window_location.php:1-8 -L0 (3): EXT_STMT -L1 (3): INIT_FCALL 0 80 string("session_start") -L2 (3): DO_FCALL -L3 (5): EXT_STMT -L4 (5): T3 = FETCH_R (global) string("_GET") -L5 (5): T4 = FETCH_DIM_R T3 string("p1") -L6 (5): V1 = FETCH_W (global) string("_SESSION") -L7 (5): ASSIGN_DIM V1 string("abc") -L8 (5): OP_DATA T4 -L9 (7): EXT_STMT -L10 (7): ECHO string("") -L11 (8): RETURN int(1) -LIVE RANGES: - 4: L6 - L7 (tmp/var) - -$_main: ; (lines=8, args=0, vars=0, tmps=3) - ; (before optimizer) - ; /home/user/gitlab/static-tools---latex/paper_code/PHP/Testability_Patterns/125_JS_redirect/a.php:1-5 -L0 (3): EXT_STMT -L1 (3): INIT_FCALL 0 80 string("session_start") -L2 (3): DO_FCALL -L3 (5): EXT_STMT -L4 (5): T1 = FETCH_R (global) string("_SESSION") -L5 (5): T2 = FETCH_DIM_R T1 string("abc") -L6 (5): ECHO T2 -L7 (5): RETURN int(1) -``` - -- DISCOVERY: - -```bash -SCRIPTING -``` - -- PRECONDITIONS: - 1. - -- TRANSFORMATION: - -``` - -``` - diff --git a/PHP/57_js_redirect/README.md b/PHP/57_js_redirect/README.md old mode 100644 new mode 100755 index 94c53fd..ebcad82 --- a/PHP/57_js_redirect/README.md +++ b/PHP/57_js_redirect/README.md @@ -1,114 +1,114 @@ -[//]: # (This file is automatically generated. If you wish to make any changes, please use the JSON files and regenerate this file using the tpframework.) - -# Js Redirect - -Tags: sast, php, php_v7.4.9 - -Version: v1.0 - -## Description - -Redirects in Javascript can be done using `window.location`. This patterns tries to find redirects like this. - -## Overview - -| Instances | has discovery rule | discovery method | rule successfull | -|---------------------------|----------------------|--------------------|--------------------| -| [1 Instance](#1-instance) | yes | joern | yes | - -## 1 Instance - -The instance consists of two PHP files, the first file redirects to the second file, that contains the sink. - -### Code - -#### Source File - -```PHP - window.location='1_instance_57_js_redirect_0.php' "; -``` - -#### Sink File - -```PHP - - -More - -
- - -### Compile - - -```bash -$_main: - ; (lines=9, args=0, vars=0, tmps=5) - ; (before optimizer) - ; /.../PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect_1.php:1-7 - ; return [] RANGE[0..0] -0000 INIT_FCALL 0 80 string("session_start") -0001 DO_ICALL -0002 T3 = FETCH_R (global) string("_GET") -0003 T4 = FETCH_DIM_R T3 string("p1") -0004 V1 = FETCH_W (global) string("_SESSION") -0005 ASSIGN_DIM V1 string("abc") -0006 OP_DATA T4 -0007 ECHO string("") -0008 RETURN int(1) -LIVE RANGES: - 4: 0004 - 0005 (tmp/var) -``` - -
- -
- - -### Discovery - - -The rule searches for a redirect written in JS in the code. - -```scala -// TODO: replace line below with your detection query -val x57 = (name, "57_js_redirect_iall", cpg.call.code(".*"; +``` + +#### Sink File + +```PHP + + +More + +
+ + +### Compile + + +```bash +$_main: + ; (lines=9, args=0, vars=0, tmps=5) + ; (before optimizer) + ; /.../PHP/57_js_redirect/1_instance_57_js_redirect/1_instance_57_js_redirect_1.php:1-7 + ; return [] RANGE[0..0] +0000 INIT_FCALL 0 80 string("session_start") +0001 DO_ICALL +0002 T3 = FETCH_R (global) string("_GET") +0003 T4 = FETCH_DIM_R T3 string("p1") +0004 V1 = FETCH_W (global) string("_SESSION") +0005 ASSIGN_DIM V1 string("abc") +0006 OP_DATA T4 +0007 ECHO string("") +0008 RETURN int(1) +LIVE RANGES: + 4: 0004 - 0005 (tmp/var) +``` + +
+ +
+ + +### Discovery + + +The rule searches for a redirect written in JS in the code. + +```scala +// TODO: replace line below with your detection query +val x57 = (name, "57_js_redirect_iall", cpg.call.code(".*