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 902aedb2..6127a1c5 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 96cc2666..1a77258c 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 04dddd0f..0c7e24b2 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 4295fcc3..50a8330e 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 7fd4a558..c9c4551c 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 00000000..4f17c492 --- /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 0b559ff1..5cc38db6 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 00000000..8071df89 --- /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 00000000..c66dff12 --- /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 b1f69b02..f8ec0a71 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 443b7948..839d7d93 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 c650e591..4db61c8c 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 99811aed..6b613b0e 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 00000000..157a6dfb --- /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 7bd9b3d6..1acb7a82 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 7ef0e652..b9e07634 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 0189b0cb..72529718 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 cd3e3dd0..ca899a42 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 00000000..07f64119 --- /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 27fcff04..b18bfc22 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 ef20f68b..cd711193 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 00000000..57a3c44f --- /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 fb345d28..815aef06 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 d14a60a6..911b0a71 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 818cb2bc..8db1a8c6 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 00000000..12e46a30 --- /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 00000000..2ce12368 --- /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 6ca130c5..423ed4d7 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 00000000..190f1a7d --- /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 733559eb..99a0de63 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 af8f3dd9..1549cb75 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 65be58c5..9ac91ff9 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 00000000..017e6993 --- /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 4f6d9bef..e30e1667 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 62cea8c6..08ff9245 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 4c66fbad..32eaa773 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 5460d672..128c7fd9 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 00000000..b89e7576 --- /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 90428329..163c84bc 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 00000000..34662c28 --- /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 00000000..5d9f307e --- /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 00000000..73908b14 --- /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 a248e640..d3fc0b84 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 00000000..e23a5d43 --- /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 c88386a1..07a05cac 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 ad68ba89..b9f8509c 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 55899f85..00000000 --- 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 240811eb..ce18b99e 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 00000000..1a216a48 --- /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 00000000..fcc1af7c --- /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 d5d90d56..d5ebc109 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 71ac2049..347ad4e6 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 e8f9a9f8..33d7a99b 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 0c088865..1d90fa21 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 36197a25..7e62162c 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 66092c20..d8745c9f 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 00000000..674f4128 --- /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 0c13c409..0e56c527 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 345b3a4a..fb447438 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 98f017ef..9a55f09c 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 5c5f1f19..65f5489b 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 99a4d816..56e98457 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 00000000..e768102e --- /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 a970ae3c..495e7962 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 67e7db99..9a76e250 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 ea287fc9..fb22dc62 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 af9a4a37..839f7c58 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 f31dcf8a..2759c7dc 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 b0cf89b5..a7e3c236 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 00000000..ed4e3ca3 --- /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 00000000..b236eb61 --- /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 a5acf70b..930356a5 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 9168bbd4..bde8f724 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 03103ede..5b0a5e2c 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 48549130..22d958d4 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 f0c6fffd..fca48ef7 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 00000000..7d87a6af --- /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 57738d99..72355cd3 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 59e2ac15..eb7ab25c 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 4da97681..fdc3410f 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 c18f87c5..d966df50 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 2e7dcf0e..4e42e27b 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 00000000..3b89cf8e --- /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 98b5c0f4..e1c24958 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 bb05015b..f9dfa70e 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 6697cbb1..83dbbae3 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 427bb714..b30fe87a 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 00000000..74fd84eb --- /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 00000000..9a29a245 --- /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 3d77ba54..8287b5c8 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 88c3b0ff..3a369dc6 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 40574a36..a5a75131 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 00000000..08b8bc28 --- /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 89a475b9..b34e8693 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 f3576dfc..984687fd 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 fea0bb42..ae7e5862 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 00000000..3a9c7e81 --- /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 f463ea59..ec80e1bc 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 f5ece33b..240baace 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 6e1ae201..8a129481 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 00000000..3b428ac5 --- /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 aaf47d87..e59d2146 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 fdcad25d..93b36757 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 d4015eaf..120df5eb 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 11631160..b68cda0f 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 00000000..1c4cb3cb --- /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 00000000..d7417b97 --- /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 873be5f3..d3902683 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 374f154e..9d41c6ab 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 59fe5867..b26474ed 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 1c4d043b..91837f9d 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 c3772f1f..489a166c 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 33b8cf49..aed73286 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 acd0ef64..5296b5f1 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 00000000..22f017e2 --- /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 00000000..0d5f24dd --- /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 00000000..5eff9b36 --- /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 af7b9170..7e6bc5d8 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 5398b280..38a47de3 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 00000000..39ab77f8 --- /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 9b6d1830..f20e857d 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 a0af71b9..f6a12d77 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 d1b68c98..cf8f59fa 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 00000000..07729d65 --- /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 00000000..591b37b3 --- /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 00000000..fb85718a --- /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 f81ee570..9c68f728 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 b0c7a1ce..3649828c 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 00000000..9e3ef559 --- /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 00000000..d5203e00 --- /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 00000000..5316b0df --- /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 00000000..54a32e98 --- /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 f291fb3e..88030b53 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 c432a399..d18dad5b 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 de06ad30..ee37970a 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 fc5ee58a..3df23d34 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 00000000..c649590a --- /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 00000000..8a5a729f --- /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 00000000..63551305 --- /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 e6c8bee1..c5b90cbd 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 7919218b..bd4a9523 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 65d95525..00000000 --- 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 00000000..f0c05d1d --- /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 3d767fb1..a58ecdf8 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 4cca7211..56b6adfd 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 ffe150ce..00000000 --- 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 cc62f888..1438477b 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 00000000..f32f752b --- /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 00000000..f8e126bf --- /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 00000000..fa396e7b --- /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 00000000..74368e3a --- /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 00000000..f148fa6f --- /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 00000000..f8503c32 --- /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 00000000..c2d48bea --- /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 00000000..9c78040a --- /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 00000000..87babe42 --- /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 00000000..5551537d --- /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 00000000..bfb20002 --- /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 585cfe71..0952defb 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 c93fe8c9..a371c68d 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 99dd18a4..00000000 --- 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 00000000..25cc7691 --- /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 00000000..cc4c866c --- /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 00000000..f74534c9 --- /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 a88eb87e..f6b93266 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 00000000..6dbfba65 --- /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 00000000..768265ac --- /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 00000000..bfba0e81 --- /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 00000000..03f6dc61 --- /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 00000000..d4e171ac --- /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 00000000..5951af56 --- /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 00000000..c12a6e97 --- /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 dcd9bd0a..6fcbbbcc 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 8b8c972a..0d10766a 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 c87bc185..5e8b5f73 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 5f529629..23c47907 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 f98128c9..01b2a08e 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 00000000..6dcc9fd8 --- /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 00000000..432598a0 --- /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 7c07cf41..bda5219b 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 5d9ee589..305e4d9e 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 642a0277..45d916ea 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 06127bca..ad59ee5b 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 3e8f7d4f..27679cc4 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 00000000..ede80e0b --- /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 00000000..2980dfc9 --- /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 0dc9280e..f1d9918d 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 ed7fde95..116153f7 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 3f709e16..9d5845a5 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 d3487dca..994be4c7 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 00000000..4efdcfac --- /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 00000000..139267fc --- /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 1bfb5475..98916386 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 382c7be2..52a2fb64 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 b120a99f..067c6c01 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 e3eaa338..b0f42c38 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 00000000..23b2fe0f --- /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 00000000..3f3df99b --- /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 00000000..764537f8 --- /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 436f7af8..ace0a7ca 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 0695f6fd..8c3f0561 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 00000000..e798afe6 --- /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 1fdd146e..2ac49e4c 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 dc3a75e5..b1bf7492 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 e8cd5221..5051b4a7 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 a5725fba..6b8f40d9 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 00000000..ce137463 --- /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 00000000..4b7723f6 --- /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 a7051c4a..904da6b3 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 bc52a8ee..c943d618 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 a7efa35b..2b483f95 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 00000000..1c332a11 --- /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 dd3598b0..d92259f3 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 00000000..6f816c1d --- /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 00000000..ad13542c --- /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 03dc5871..d3594211 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 614eeb72..1981c622 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 3f87d4b6..cf84e80c 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 a30c2041..89c3f1a5 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 03258316..a96bfcc1 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 00000000..ee4f6f9a --- /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 00000000..80769db7 --- /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 d8d01d3f..01d22ddd 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 e24c382a..6c12f4d2 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 2bb1d214..dd0d00f8 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 a0e62418..e0a1ff72 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 04a4c9ad..39c056c8 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 00000000..f9c7218e --- /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 00000000..914ab61e --- /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 4d4ef2ac..e98adb9a 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 4d1e591a..ce00849f 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 acacd09e..f0c4d0a5 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 408c774c..1d4cbd19 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 090da097..d7adf152 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 fcbc51cb..ff687e6a 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 fd794256..9eed584d 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 408c774c..2b0f2683 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 9ce63e03..0f44b09b 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 408c774c..00000000 --- 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 00000000..5d6cbbdc --- /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 00000000..83145c31 --- /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 eeb25482..c3e9af20 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 6267afda..bbbb6d10 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 f24c4976..b9dc54a9 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 2d30c6b7..8bc025a1 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 00000000..f7e089c5 --- /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 00000000..6305db36 --- /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 132aa3a9..4b8b264a 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 bff9e1d6..9d74ecfa 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 d389f527..e1a4b774 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 2a0a22a9..80693039 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 00000000..5f48947f --- /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 00000000..2720822d --- /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 b872f34e..c0d59b5f 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 d9c5ec80..78230dee 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 c82edfd8..8dc44c1c 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 0875791e..da24fbd4 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 5b0a5daf..c29dcabe 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 00000000..7135563b --- /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 00000000..f8b2be03 --- /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 e4435e3c..5ef1438c 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 1e9f7794..c2d5ab96 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 2b6dba71..59d6073a 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 d40f7fc6..dc7bd816 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 00000000..d56d262f --- /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 ea68cb7b..1db07fb9 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 abf9d372..296c8b3c 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 6cfd9451..96104840 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 bd293be8..3ef9758a 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 00000000..c6791c06 --- /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 00000000..9bfbf79d --- /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 00000000..3a5f3dc2 --- /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 a73faad1..6494560c 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 00000000..1a6396e0 --- /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 7d335ef9..d2d0406c 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 00000000..ce19f18c --- /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 00000000..778c9047 --- /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 d3274814..e761bb80 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 38408cf7..2cf370ee 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 31741d48..a0487b8f 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 00000000..28bb233d --- /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 48041d38..ca673f59 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 ccab388e..51522e2d 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 4fec4f1d..e2cdea7a 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 00000000..f688b1aa --- /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 4ca68699..78174419 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 65886f7a..8a74eb93 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 3b59e51b..2b739155 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 5c0f361b..eff72ac5 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 bce0b043..05de28a0 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 00000000..8a3d727d --- /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 00000000..6bda9009 --- /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 67354ffe..e113adff 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 d73c36f4..a4f723be 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 1650cc3a..6a0f0a83 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 b711e281..e5d9f7d8 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 00000000..cd2cca6d --- /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 00000000..bdae90c2 --- /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 191c384d..4e48367b 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 c18f8b8f..e8bd19c4 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 46d9628c..38c0501e 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 f3ccab1a..21680a5a 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 0f71077b..c5ca415b 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 00000000..6f53566c --- /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 00000000..d69aab1f --- /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 bda69323..4efdbaa6 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 00000000..345c8716 --- /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 00000000..02ad45a4 --- /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 5b20c0de..1865682f 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 00000000..94c53fd9 --- /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 4efdbaa6..eedde4fc --- 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 15b81724..00000000 --- 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 9be0061a..00000000 --- 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 345c8716..27d52616 --- 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 02ad45a4..12ad97c1 --- 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 72e3fa4e..00000000 --- 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 9f6d8b2c..00000000 --- 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 94c53fd9..ebcad829 --- 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(".*