PHP任意文件上传漏洞(cve-2006-7243):
-
在PHP版本小于5.3.4的move_uploaded_file()函数中,存在CVE-2006-7243这个漏洞。
-形成原因:move_uploaded_file()底层源码用c编写,判断上传文件路径的时候使用了char指针,C语言中char指针以\0作为字符串结束的标志,所以会文件名被\0截断。\0后面的内容会被忽略。 -
这里的问题是,可以在文件名中插入空字符,利用插入空字符的方式,攻击者可以上传任意文件,引起远程代码执行漏洞等。
-
在上传文件的文件名中,可以使用\0进行截断,例如1.php\0.jpg。
下面是move_uploadea_file()的源代码:
/* {{{ proto bool move_uploaded_file(string path, string new_path)
Move a file if and only if it was created by an upload */
PHP_FUNCTION(move_uploaded_file)
{
char *path, *new_path;
size_t path_len, new_path_len;
zend_bool successful = 0;
#ifndef PHP_WIN32
int oldmask; int ret;
#endif
if (!SG(rfc1867_uploaded_files)) {
RETURN_FALSE;
}
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_STRING(path, path_len)
Z_PARAM_PATH(new_path, new_path_len)
ZEND_PARSE_PARAMETERS_END();
if (!zend_hash_str_exists(SG(rfc1867_uploaded_files), path, path_len)) {
RETURN_FALSE;
}
if (php_check_open_basedir(new_path)) {
RETURN_FALSE;
}
if (VCWD_RENAME(path, new_path) == 0) {
successful = 1;
#ifndef PHP_WIN32
oldmask = umask(077);
umask(oldmask);
ret = VCWD_CHMOD(new_path, 0666 & ~oldmask);
if (ret == -1) {
php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
}
#endif
} else if (php_copy_file_ex(path, new_path, STREAM_DISABLE_OPEN_BASEDIR) == SUCCESS) {
VCWD_UNLINK(path);
successful = 1;
}
if (successful) {
zend_hash_str_del(SG(rfc1867_uploaded_files), path, path_len);
} else {
php_error_docref(NULL, E_WARNING, "Unable to move '%s' to '%s'", path, new_path);
}
RETURN_BOOL(successful);
}
对于这个漏洞进行测试:
我们准备了一个PHP脚本
<?php echo "<script>alert('xixixiixix')</script>";?>
- 在DVWA中找到 file upoload板块,(DVWA security设置安全等级)
low级:
这个级别没有进行任何检测,可以直接上传PHP代码
使用后缀为.php文件,直接上传成功
访问地址验证:
脚本成功在服务区运行
Medium级:
1.写一个PHP的弹窗,将文件后缀改成.jpg格式:
2.使用burp抓包,在hex中使用00将.jpg截断:
将其上传成PHP文件 保证能在服务器执行
提示上传成功
3.验证是否能在服务端执行:
用url访问文件 可以成功执行
在看源代码:
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
// Is it an image?
if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
( $uploaded_size < 100000 ) ) {
// Can we move the file to the upload folder?
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>
增加了三个变量分别用于表示上传文件的名字、类型和大小