目錄php
經過diff 8.8.1的補丁,很容易發現修復點,位於core\modules\file\file.module
前端
補丁在文件名兩側進行了trim(..., '.'),結合漏洞通告能夠知道應該是文件名過濾不嚴致使.開頭的文件上傳。node
漏洞點位於_file_save_upload_single
函數sql
function _file_save_upload_single(\SplFileInfo $file_info, $form_field_name, $validators = [], $destination = FALSE, $replace = FileSystemInterface::EXISTS_REPLACE) { ... // Begin building file entity. $values = [ 'uid' => $user->id(), 'status' => 0, 'filename' => $file_info->getClientOriginalName(),// 'uri' => $file_info->getRealPath(), 'filesize' => $file_info->getSize(), ]; $values['filemime'] = \Drupal::service('file.mime_type.guesser')->guess($values['filename']); $file = File::create($values); ... // If we made it this far it's safe to record this file in the database. $file->save(); ... return $file; }
全局搜索調用本函數的地方,發現只在core/modules/file/file.module:file_save_upload()
中被調用。函數
因爲此處不是控制器,沒法直接調用,所以繼續反向追蹤調用此函數的位置。在多處找到調用,好比位於core/modules/update/src/Form/UpdateManagerInstall.php:submitForm()
,這是update模塊的updatemanagerinstall表單。ui
public function submitForm(array &$form, FormStateInterface $form_state) { $local_cache = NULL; $all_files = $this->getRequest()->files->get('files', []); if ($form_state->getValue('project_url')) { ... } elseif (!empty($all_files['project_upload'])) { $validators = ['file_validate_extensions' => [$this->archiverManager->getExtensions()]]; if (!($finfo = file_save_upload('project_upload', $validators, NULL, 0, FileSystemInterface::EXISTS_REPLACE))) { // Failed to upload the file. file_save_upload() calls // \Drupal\Core\Messenger\MessengerInterface::addError() on failure. return; } $local_cache = $finfo->getFileUri(); }
這裏的$validators經過$this->archiverManager->getExtensions()
調用archiver管理器進行取值,因爲這裏設計不少內部成員變量,所以經過調試的方式來分析會快一些。下面就開始嘗試構造路由到這個update模塊。this
經過在update模塊根目錄下的update.routing.yml
路由文件能夠發現相應的路由:url
嘗試上傳.htaccess設計
果真受到了限制,下面調試跟進這個$validators是如何取值的。最終跟進core/lib/Drupal/Component/Annotation/Plugin/Discovery/AnnotatedClassDiscovery.php:getDefinitions()
方法,這裏經過遍歷全部module目錄下的src/plugin/archiver/
下的全部php文件,而後解析這個php文件的annotation。調試後發現只有system模塊下存在這個目錄:3d
能夠看到這裏的annotation中限定了後綴名爲{"tar", "tgz", "tar.gz", "tar.bz2"}
到這裏就能夠中止調試了,這個update模塊因爲限制了後綴名,沒法知足咱們的條件。下面再找一些$validators的值不是$this->archiverManager->getExtensions()
的模塊。
發現core/modules/image/src/Controller/QuickEditImageController.php:upload()
public function upload(EntityInterface $entity, $field_name, $langcode, $view_mode_id) { $field = $this->getField($entity, $field_name, $langcode); $field_validators = $field->getUploadValidators(); $field_settings = $field->getFieldDefinition()->getSettings(); $destination = $field->getUploadLocation(); // Add upload resolution validation. if ($field_settings['max_resolution'] || $field_settings['min_resolution']) { $field_validators['file_validate_image_resolution'] = [$field_settings['max_resolution'], $field_settings['min_resolution']]; } // Create the destination directory if it does not already exist. if (isset($destination) && !$this->fileSystem->prepareDirectory($destination, FileSystemInterface::CREATE_DIRECTORY)) { return new JsonResponse(['main_error' => $this->t('The destination directory could not be created.'), 'errors' => '']); } // Attempt to save the image given the field's constraints. $result = file_save_upload('image', $field_validators, $destination); ...
這裏的$validators是經過$field->getUploadValidators()
來取值的,跟以前的module一樣的思路,先構造路由而後進行調試跟進。
訪問quickedit/image/upload/node/1/field_image/en/full
映射到本控制器,而後跟進getUploadValidators()。通過一系列跟進以後發現配置在config表中,sql語句大概是SELECT name, data FROM config WHERE collection = '' AND name ='field.field.node.article.field_image';
剩下的調用file_save_upload
的地方也都作了驗證,沒有能夠利用的地方,都限制了文件後綴名。
看完全部調用點以後有點懷疑人生,會不會是相似於CVE-2018-7600那樣,durpal6中雖然有漏洞,可是沒找到錯誤的寫法從而沒法利用?經過再次閱讀官方通告以後發現也許真是這樣,可是幸運的是...
意思大概是經過第三方contributed模塊可能致使.htaccess文件上傳?
而後我嘗試在第三方模塊中尋找與文件上傳相關的模塊,找到了一個名爲imce的文件/圖片管理模塊
IMCE is an image/file uploader and browser that supports personal directories and quota.
安裝完畢以後直接訪問路徑/imce/public
便可得到一個管理界面(後臺)。
上傳.php文件會自動在後面加上.txt後綴。嘗試上傳.htaccess
然而這只是個前端過濾而已,經過抓包修改文件名便可成功上傳。
經過閱讀源碼發現opUpload()
方法調用了file_save_upload()
進行文件上傳。
public function opUpload(ImceFM $fm) { ... $validators = []; // Extension validator $exts = $fm->getConf('extensions', ''); $validators['file_validate_extensions'] = [$exts === '*' ? NULL : $exts]; ... // Save files if ($files = file_save_upload('imce', $validators, $destination, NULL, $replace)) {
其中後綴名$validators從$fm->getConf('extensions','')
獲取。跟蹤源碼後發現,也是從config表中找到imce 模塊的一些配置
因爲$validators是*,即爲不限制後綴名,從而形成.htaccess文件上傳。
經過diff 8.8.1的補丁,很容易發現修復點,位於core\modules\file\file.module
補丁在文件名兩側進行了trim(..., '.')。
上傳以後變成