├── .gitmodules ├── CREDITS ├── EXPERIMENTAL ├── README.md ├── config.m4 ├── config.w32 ├── injection.c ├── php_injection.h └── tests └── basic.phpt /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libinjection"] 2 | path = libinjection 3 | url = https://github.com/libinjection/libinjection.git 4 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | injection 2 | -------------------------------------------------------------------------------- /EXPERIMENTAL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adsr/injection-php/1a1c99d4da634e6a3de2d2fc3927f5cd56dfc2bb/EXPERIMENTAL -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # injection-php 2 | 3 | This is a hand-written libinjection wrapper for PHP 7+ (and 5). libinjection 4 | includes a SWIG-generated PHP extension. This one is simpler. It wraps two 5 | simple functions in the API, `libinjection_is_sqli` and `libinjection_xss`. 6 | 7 | See https://github.com/libinjection/libinjection for the underlying library. 8 | 9 | ### Building 10 | 11 | $ # Clone repo and submodule 12 | $ git clone --recursive https://github.com/adsr/injection-php.git 13 | $ cd injection-php 14 | $ 15 | $ # Install php-dev 16 | $ sudo apt-get install php-dev # ...or equivalent for your system 17 | $ 18 | $ # Build library 19 | $ pushd libinjection 20 | $ ./autogen.sh && ./configure && make 21 | $ popd 22 | $ 23 | $ # Build PHP extension 24 | $ phpize && ./configure && make 25 | $ 26 | $ # Run tests 27 | $ NO_INTERACTION=1 make test 28 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | PHP_ARG_WITH(injection, for libinjection support, 2 | [ --with-injection Include libinjection support]) 3 | 4 | if test "$PHP_INJECTION" != "no"; then 5 | INJECTION_DIR="./libinjection/src" 6 | PHP_ADD_INCLUDE($INJECTION_DIR) 7 | LIBNAME=injection 8 | LIBSYMBOL=libinjection_version 9 | PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, 10 | [ 11 | LDFLAGS="$LDFLAGS $INJECTION_DIR/.libs/libinjection.a" 12 | AC_DEFINE(HAVE_INJECTIONLIB,1,[ ]) 13 | ],[ 14 | AC_MSG_ERROR([wrong libinjection version or lib not found]) 15 | ],[ 16 | -L$INJECTION_DIR/.libs 17 | ]) 18 | 19 | PHP_NEW_EXTENSION(injection, injection.c, $ext_shared) 20 | fi 21 | -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | // $Id$ 2 | // vim:ft=javascript 3 | 4 | // If your extension references something external, use ARG_WITH 5 | // ARG_WITH("injection", "for injection support", "no"); 6 | 7 | // Otherwise, use ARG_ENABLE 8 | // ARG_ENABLE("injection", "enable injection support", "no"); 9 | 10 | if (PHP_INJECTION != "no") { 11 | EXTENSION("injection", "injection.c"); 12 | } 13 | -------------------------------------------------------------------------------- /injection.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | injection | 4 | +----------------------------------------------------------------------+ 5 | | Licensed under the Apache License, Version 2.0 (the "License"); you | 6 | | may not use this file except in compliance with the License. You may | 7 | | obtain a copy of the License at | 8 | | http://www.apache.org/licenses/LICENSE-2.0 | 9 | | | 10 | | Unless required by applicable law or agreed to in writing, software | 11 | | distributed under the License is distributed on an "AS IS" BASIS, | 12 | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | 13 | | implied. See the License for the specific language governing | 14 | | permissions and limitations under the License. | 15 | +----------------------------------------------------------------------+ 16 | | Author: Adam Saponara | 17 | +----------------------------------------------------------------------+ 18 | */ 19 | 20 | /* $Id$ */ 21 | 22 | #ifdef HAVE_CONFIG_H 23 | #include "config.h" 24 | #endif 25 | 26 | #include "php.h" 27 | #include "php_ini.h" 28 | #include "ext/standard/info.h" 29 | #include "php_injection.h" 30 | 31 | #include 32 | #include 33 | 34 | #if PHP_MAJOR_VERSION >= 7 35 | #define COMPAT_RETURN_STRINGL(str, len, dup) RETURN_STRINGL(str, len) 36 | #define COMPAT_STRLEN_DELTA 1 37 | #define compat_strlen_t size_t 38 | #else 39 | #define COMPAT_RETURN_STRINGL(str, len, dup) RETURN_STRINGL(str, len, dup) 40 | #define COMPAT_STRLEN_DELTA 0 41 | #define compat_strlen_t int 42 | #endif 43 | 44 | ZEND_DECLARE_MODULE_GLOBALS(injection) 45 | 46 | ZEND_BEGIN_ARG_INFO_EX(arginfo_injection_is_x, 0, 0, 1) 47 | ZEND_ARG_INFO(0, str) 48 | ZEND_END_ARG_INFO() 49 | 50 | /* {{{ injection_functions[] 51 | * 52 | * Every user visible function must have an entry in injection_functions[]. 53 | */ 54 | const zend_function_entry injection_functions[] = { 55 | PHP_FE(injection_is_sqli, arginfo_injection_is_x) 56 | PHP_FE(injection_is_xss, arginfo_injection_is_x) 57 | #ifdef PHP_FE_END 58 | PHP_FE_END /* Must be the last line in injection_functions[] */ 59 | #else 60 | {NULL, NULL, NULL} 61 | #endif 62 | }; 63 | /* }}} */ 64 | 65 | /* {{{ injection_module_entry 66 | */ 67 | zend_module_entry injection_module_entry = { 68 | #if ZEND_MODULE_API_NO >= 20010901 69 | STANDARD_MODULE_HEADER, 70 | #endif 71 | "injection", 72 | injection_functions, 73 | NULL, 74 | NULL, 75 | NULL, 76 | NULL, 77 | PHP_MINFO(injection), 78 | #if ZEND_MODULE_API_NO >= 20010901 79 | PHP_INJECTION_VERSION, 80 | #endif 81 | STANDARD_MODULE_PROPERTIES 82 | }; 83 | /* }}} */ 84 | 85 | #ifdef COMPILE_DL_INJECTION 86 | ZEND_GET_MODULE(injection) 87 | #endif 88 | 89 | /* {{{ 90 | * Initialize module globals */ 91 | static void _injection_init_globals(zend_injection_globals *g) 92 | { 93 | memset(g, 0, sizeof(zend_injection_globals)); 94 | } 95 | /* }}} */ 96 | 97 | /* {{{ PHP_MINFO_FUNCTION 98 | */ 99 | PHP_MINFO_FUNCTION(injection) 100 | { 101 | php_info_print_table_start(); 102 | php_info_print_table_header(2, "injection support", "enabled"); 103 | php_info_print_table_header(2, "extension version", PHP_INJECTION_VERSION); 104 | php_info_print_table_header(2, "libinjection version", libinjection_version()); 105 | php_info_print_table_end(); 106 | } 107 | /* }}} */ 108 | 109 | /* {{{ proto mixed injection_is_sqli(string sql) 110 | Return fingerprint if sqli is detected in string. Return FALSE otherwise. */ 111 | PHP_FUNCTION(injection_is_sqli) 112 | { 113 | char *str; 114 | compat_strlen_t str_len; 115 | struct libinjection_sqli_state state; 116 | 117 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { 118 | return; 119 | } 120 | 121 | libinjection_sqli_init(&state, str, str_len, FLAG_NONE); 122 | if (libinjection_is_sqli(&state)) { 123 | COMPAT_RETURN_STRINGL(state.fingerprint, strlen(state.fingerprint), 1); 124 | } 125 | 126 | RETURN_FALSE; 127 | } 128 | /* }}} */ 129 | 130 | /* {{{ proto mixed injection_is_xss(string str) 131 | Return TRUE xss is detected in string. Return FALSE otherwise. */ 132 | PHP_FUNCTION(injection_is_xss) 133 | { 134 | char *str; 135 | compat_strlen_t str_len; 136 | 137 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { 138 | return; 139 | } 140 | 141 | if (libinjection_xss(str, str_len)) { 142 | RETURN_TRUE; 143 | } 144 | 145 | RETURN_FALSE; 146 | } 147 | /* }}} */ 148 | 149 | /* 150 | * Local variables: 151 | * tab-width: 4 152 | * c-basic-offset: 4 153 | * End: 154 | * vim600: noet sw=4 ts=4 fdm=marker 155 | * vim<600: noet sw=4 ts=4 156 | */ 157 | -------------------------------------------------------------------------------- /php_injection.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | injection | 4 | +----------------------------------------------------------------------+ 5 | | Licensed under the Apache License, Version 2.0 (the "License"); you | 6 | | may not use this file except in compliance with the License. You may | 7 | | obtain a copy of the License at | 8 | | http://www.apache.org/licenses/LICENSE-2.0 | 9 | | | 10 | | Unless required by applicable law or agreed to in writing, software | 11 | | distributed under the License is distributed on an "AS IS" BASIS, | 12 | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | 13 | | implied. See the License for the specific language governing | 14 | | permissions and limitations under the License. | 15 | +----------------------------------------------------------------------+ 16 | | Author: Adam Saponara | 17 | +----------------------------------------------------------------------+ 18 | */ 19 | 20 | /* $Id$ */ 21 | 22 | #ifndef PHP_INJECTION_H 23 | #define PHP_INJECTION_H 24 | 25 | extern zend_module_entry injection_module_entry; 26 | #define phpext_injection_ptr &injection_module_entry 27 | 28 | #ifdef PHP_WIN32 29 | # define PHP_INJECTION_API __declspec(dllexport) 30 | #elif defined(__GNUC__) && __GNUC__ >= 4 31 | # define PHP_INJECTION_API __attribute__ ((visibility("default"))) 32 | #else 33 | # define PHP_INJECTION_API 34 | #endif 35 | 36 | /* backward compat macros */ 37 | 38 | #if !defined(uint32) 39 | typedef unsigned int uint32; 40 | #endif 41 | 42 | #if !defined(uint64) 43 | typedef unsigned long long uint64; 44 | #endif 45 | 46 | #ifndef TSRMLS_CC 47 | #define TSRMLS_FETCH() 48 | #define TSRMLS_CC 49 | #define TSRMLS_DC 50 | #define TSRMLS_D 51 | #define TSRMLS_C 52 | #endif 53 | 54 | #ifndef ZVAL_EMPTY_ARRAY 55 | #define ZVAL_EMPTY_ARRAY(value) array_init(value) 56 | #endif 57 | 58 | #ifndef RETVAL_EMPTY_ARRAY 59 | #define RETVAL_EMPTY_ARRAY() ZVAL_EMPTY_ARRAY(return_value) 60 | #endif 61 | 62 | #ifndef RETURN_EMPTY_ARRAY 63 | #define RETURN_EMPTY_ARRAY() do { RETVAL_EMPTY_ARRAY(); return; } while (0) 64 | #endif 65 | 66 | #ifndef IS_MIXED 67 | # define IS_MIXED 0 68 | #endif 69 | 70 | #ifndef ZEND_ARG_INFO_WITH_DEFAULT_VALUE 71 | #define ZEND_ARG_INFO_WITH_DEFAULT_VALUE(pass_by_ref, name, default_value) \ 72 | ZEND_ARG_INFO(pass_by_ref, name) 73 | #endif 74 | 75 | #if PHP_VERSION_ID < 70200 76 | #undef ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX 77 | #define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, class_name, allow_null) \ 78 | static const zend_internal_arg_info name[] = { \ 79 | { (const char*)(zend_uintptr_t)(required_num_args), ( #class_name ), 0, return_reference, allow_null, 0 }, 80 | #endif 81 | 82 | #ifndef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX 83 | # define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(name, return_reference, required_num_args, class_name, allow_null) \ 84 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, class_name, allow_null) 85 | #endif 86 | 87 | #ifndef ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX 88 | # define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(name, return_reference, num_args, type) \ 89 | ZEND_BEGIN_ARG_INFO_EX(name, 0, return_reference, num_args) 90 | #endif 91 | 92 | #ifndef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX 93 | # define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(name, return_reference, required_num_args, class_name, type) \ 94 | ZEND_BEGIN_ARG_INFO_EX(name, 0, return_reference, required_num_args) 95 | #endif 96 | 97 | #ifndef ZEND_ARG_TYPE_MASK 98 | # define ZEND_ARG_TYPE_MASK(pass_by_ref, name, type_mask, default_value) \ 99 | ZEND_ARG_TYPE_INFO(pass_by_ref, name, 0, 0) 100 | #endif 101 | 102 | #ifndef ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE 103 | # define ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(pass_by_ref, name, type_hint, allow_null, default_value) \ 104 | ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) 105 | #endif 106 | #ifdef ZTS 107 | #include "TSRM.h" 108 | #endif 109 | 110 | #define PHP_INJECTION_VERSION "0.1.0" 111 | 112 | ZEND_BEGIN_MODULE_GLOBALS(injection) 113 | ZEND_END_MODULE_GLOBALS(injection) 114 | 115 | PHP_MINFO_FUNCTION(injection); 116 | 117 | PHP_FUNCTION(injection_is_sqli); 118 | PHP_FUNCTION(injection_is_xss); 119 | 120 | #ifdef ZTS 121 | #define INJECTION_G(v) TSRMG(injection_globals_id, zend_injection_globals *, v) 122 | #else 123 | #define INJECTION_G(v) (injection_globals.v) 124 | #endif 125 | 126 | #endif /* PHP_INJECTION_H */ 127 | 128 | /* 129 | * Local variables: 130 | * tab-width: 4 131 | * c-basic-offset: 4 132 | * End: 133 | * vim600: noet sw=4 ts=4 fdm=marker 134 | * vim<600: noet sw=4 ts=4 135 | */ 136 | -------------------------------------------------------------------------------- /tests/basic.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | basic 3 | --FILE-- 4 | bb 49 | aa 50 | bb 51 | 52 | 53 | 54 | 55 | 60 | 63 | 64 | 67 | 68 | 69 | 70 | 71 | 75 | 76 | 77 | 79 | 80 | 81 | <1234 foo 82 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 95 | 96 | 97 | <% foo>