-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#2305 위장한 파일 업로드를 이용한 XSS, SSRF 취약점 고침
- 취약점 제보자 - Provensec (https://www.provensec.com) - Author: Subodh Kumar - 취약점 패치 제공 : @kijin - 이 패치는 Rhymix에서 문제를 고친 코드를 기반으로하여 XE1에 맞게 일부 변경되어 적용되었습니다
- Loading branch information
bnu
committed
Sep 20, 2018
1 parent
92c79f9
commit 8d7d0e9
Showing
6 changed files
with
163 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,148 @@ | ||
<?php | ||
/* Copyright (C) NAVER <http://www.navercorp.com> */ | ||
|
||
class UploadFileFilter | ||
{ | ||
private static $_block_list = array ('exec', 'system', 'passthru', 'show_source', 'phpinfo', 'fopen', 'file_get_contents', 'file_put_contents', 'fwrite', 'proc_open', 'popen'); | ||
/** | ||
* Generic checker | ||
* | ||
* @param string $file | ||
* @param string $filename | ||
* @return bool | ||
*/ | ||
public static function check($file, $filename = null) | ||
{ | ||
// Return error if the file is not uploaded. | ||
if (!$file || !file_exists($file) || !is_uploaded_file($file)) | ||
{ | ||
return false; | ||
} | ||
|
||
// Return error if the file size is zero. | ||
if (($filesize = filesize($file)) == 0) | ||
{ | ||
return false; | ||
} | ||
|
||
// Get the extension. | ||
$ext = $filename ? strtolower(substr(strrchr($filename, '.'), 1)) : ''; | ||
|
||
public function check($file) | ||
// Check the first 4KB of the file for possible XML content. | ||
$fp = fopen($file, 'rb'); | ||
$first4kb = fread($fp, 4096); | ||
$is_xml = preg_match('/<(?:\?xml|!DOCTYPE|html|head|body|meta|script|svg)\b/i', $first4kb); | ||
|
||
// Check SVG files. | ||
if (($ext === 'svg' || $is_xml) && !self::_checkSVG($fp, 0, $filesize)) | ||
{ | ||
fclose($fp); | ||
return false; | ||
} | ||
|
||
// Check XML files. | ||
if (($ext === 'xml' || $is_xml) && !self::_checkXML($fp, 0, $filesize)) | ||
{ | ||
fclose($fp); | ||
return false; | ||
} | ||
|
||
// Check HTML files. | ||
if (($ext === 'html' || $ext === 'shtml' || $ext === 'xhtml' || $ext === 'phtml' || $is_xml) && !self::_checkHTML($fp, 0, $filesize)) | ||
{ | ||
fclose($fp); | ||
return false; | ||
} | ||
|
||
// Return true if everything is OK. | ||
fclose($fp); | ||
return true; | ||
} | ||
|
||
/** | ||
* Check SVG file for XSS or SSRF vulnerabilities (#1088, #1089) | ||
* | ||
* @param resource $fp | ||
* @param int $from | ||
* @param int $to | ||
* @return bool | ||
*/ | ||
protected static function _checkSVG($fp, $from, $to) | ||
{ | ||
if (self::_matchStream('/<script|<handler\b|xlink:href\s*=\s*"(?!data:)/i', $fp, $from, $to)) | ||
{ | ||
return false; | ||
} | ||
if (self::_matchStream('/\b(?:ev:(?:event|listener|observer)|on[a-z]+)\s*=/i', $fp, $from, $to)) | ||
{ | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Check XML file for external entity inclusion. | ||
* | ||
* @param resource $fp | ||
* @param int $from | ||
* @param int $to | ||
* @return bool | ||
*/ | ||
protected static function _checkXML($fp, $from, $to) | ||
{ | ||
// TODO: 기능개선후 enable | ||
if (self::_matchStream('/<!ENTITY/i', $fp, $from, $to)) | ||
{ | ||
return false; | ||
} | ||
|
||
return TRUE; // disable | ||
if (! $file || ! FileHandler::exists($file)) return TRUE; | ||
return self::_check ( $file ); | ||
return true; | ||
} | ||
|
||
private function _check($file) | ||
/** | ||
* Check HTML file for PHP code, server-side includes, and other nastiness. | ||
* | ||
* @param resource $fp | ||
* @param int $from | ||
* @param int $to | ||
* @return bool | ||
*/ | ||
protected static function _checkHTML($fp, $from, $to) | ||
{ | ||
if (! ($fp = fopen ( $file, 'r' ))) return FALSE; | ||
if (self::_matchStream('/<\?(?!xml\b)|<!--#(?:include|exec|echo|config|fsize|flastmod|printenv)\b/i', $fp, $from, $to)) | ||
{ | ||
return false; | ||
} | ||
|
||
$has_php_tag = FALSE; | ||
return true; | ||
} | ||
|
||
while ( ! feof ( $fp ) ) | ||
/** | ||
* Match a stream against a regular expression. | ||
* | ||
* This method is useful when dealing with large files, | ||
* because we don't need to load the entire file into memory. | ||
* We allow a generous overlap in case the matching string | ||
* occurs across a block boundary. | ||
* | ||
* @param string $regexp | ||
* @param resource $fp | ||
* @param int $from | ||
* @param int $to | ||
* @param int $block_size (optional) | ||
* @param int $overlap_size (optional) | ||
* @return bool | ||
*/ | ||
protected static function _matchStream($regexp, $fp, $from, $to, $block_size = 16384, $overlap_size = 1024) | ||
{ | ||
fseek($fp, $position = $from); | ||
while (strlen($content = fread($fp, $block_size + $overlap_size)) > 0) | ||
{ | ||
$content = fread ( $fp, 8192 ); | ||
if (FALSE === $has_php_tag) $has_php_tag = strpos ( $content, '<?' ); | ||
foreach ( self::$_block_list as $v ) | ||
if (preg_match($regexp, $content)) | ||
{ | ||
if (FALSE !== $has_php_tag && FALSE !== strpos ( $content, $v )) | ||
{ | ||
fclose ( $fp ); | ||
return FALSE; | ||
} | ||
return true; | ||
} | ||
fseek($fp, min($to, $position += $block_size)); | ||
} | ||
|
||
fclose ( $fp ); | ||
|
||
return TRUE; | ||
return false; | ||
} | ||
} | ||
|
||
/* End of file : UploadFileFilter.class.php */ | ||
/* Location: ./classes/security/UploadFileFilter.class.php */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8d7d0e9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UploadFileFilter는 클래스 이름만 똑같고 제가 라이믹스에서 완전히 새로 작성한 것이므로, func.inc.php에 새로 추가된 함수들처럼 Copyright를 붙여주시면 감사하겠습니다^^