author: 80vul-B
team:http://www.80vul.com
date:2009-04-27
一 描叙
php手册里:
—————————————————————————————–
int preg_match ( string pattern, string subject [, array matches [, int flags]] )
在 subject 字符串中搜索与 pattern 给出的正则表达式相匹配的内容。
如果提供了 matches,则其会被搜索的结果所填充。$matches[0] 将包含与整个模式匹配的文本,$matches[1] 将包含与第一个捕获的括号中的子模式所匹配的文本,以此类推。
—————————————————————————————–
这个是一个应用比较多的函数,很多应用程序忘记对preg_match(_all)的变量进行初始化,导致安全漏洞.
二 分析
patch_match的部分源码:
PHP_FUNCTION(preg_match) { php_do_pcre_match(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } ... // php_pcre.c static void php_do_pcre_match(INTERNAL_FUNCTION_PARAMETERS, int global) /* {{{ */ { ... if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, ((global) ? "ssz|ll" : "ss|zll"), ®ex, ®ex_len, &subject, &subject_len, &subpats, &flags, &start_offset) == FAILURE) { RETURN_FALSE; } // 调用zend_parse_parameters检查传入的参数,参数类型及格式限定为了ss|zll // zend_API.c ZEND_API int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, ...) { ... retval = zend_parse_va_args(num_args, type_spec, &va, 0 TSRMLS_CC); ... static int zend_parse_va_args(int num_args, char *type_spec, va_list *va, int flags TSRMLS_DC) { ... while (num_args-- > 0) { arg = (zval **) p - (arg_count-i); if (*type_spec == '|') { type_spec++; } if (zend_parse_arg(i+1, arg, va, &type_spec, quiet TSRMLS_CC) == FAILURE) { // 调用zend_parse_arg检查每个参数的类型 return FAILURE; } ... static int zend_parse_arg(int arg_num, zval **arg, va_list *va, char **spec, int quiet TSRMLS_DC) { ... expected_type = zend_parse_arg_impl(arg_num, arg, va, spec TSRMLS_CC); if (expected_type) { if (!quiet && *expected_type) { char *space; char *class_name = get_active_class_name(&space TSRMLS_CC); zend_error(E_WARNING, "%s%s%s() expects parameter %d to be %s, %s given", class_name, space, get_active_function_name(TSRMLS_C), arg_num, expected_type, zend_zval_type_name(*arg)); // 如果参数的类型非法,报错并导致zend_parse_parameters返回FAILURE } ... static char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, char **spec TSRMLS_DC) { char *spec_walk = *spec; char c = *spec_walk++; ... switch (c) { ... case 's': { char **p = va_arg(*va, char **); int *pl = va_arg(*va, int *); switch (Z_TYPE_PP(arg)) { case IS_NULL: if (return_null) { *p = NULL; *pl = 0; break; } /* break omitted intentionally */ case IS_STRING: case IS_LONG: case IS_DOUBLE: case IS_BOOL: convert_to_string_ex(arg); *p = Z_STRVAL_PP(arg); *pl = Z_STRLEN_PP(arg); break; case IS_OBJECT: if (parse_arg_object_to_string(arg, p, pl, IS_STRING TSRMLS_CC) == SUCCESS) { break; } case IS_ARRAY: case IS_RESOURCE: default: return "string"; } } break; ...
// 由上面的代码可以看到如果传入preg_match的第一个或者第二个参数是一个数组或者资源类型的话,将会报错并返回false,这将导致如果使用第三个参数的话,该变量将不会被赋值
三 测试代码
<?php //preg_match.php?ipmatches[]=1111 $ip[]='1'; preg_match("/[/d/.]{7,15}/", $ip, $ipmatches); var_dump($ipmatches); ?>
四 实际应用
[SODB-2009-01]:Discuz!<5.50 preg_match()的变量$onlineipmatches未初始化漏洞
[http://www.80vul.com/dzvul/]
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论