PbootCMS-XSS(stored)漏洞分析

  • 2019 年 10 月 7 日
  • 筆記

本文作者:WHITE(Ms08067實驗室核心成員)

一、漏洞摘要

bootCMS是全新內核且永久開源免費的cms,在其V2.0.2版本中存在存儲型XSS 漏洞名稱:PbootCMS存儲型XSS 產品首頁:https://www.pbootcms.com 軟體鏈接:

https://github.com/hnaoyun/PbootCMS 版本:V2.0.2-20190915

二、漏洞概述

漏洞路徑為

/PbootCMS/apps/home/controller/ParserController.php

public function parserSiteLabel($content)      {          $pattern = '/{pboot:site([w]+)(s+[^}]+)?}/';          if (preg_match_all($pattern, $content, $matches)) {              $data = $this->model->getSite();              $count = count($matches[0]);              for ($i = 0; $i < $count; $i ++) {                  $params = $this->parserParam($matches[2][$i]);                  switch ($matches[1][$i]) {                      case 'index':                          $content = str_replace($matches[0][$i], Url::home('home/Index/'), $content);                          break;                      case 'path':                          $content = str_replace($matches[0][$i], SITE_DIR, $content);                          break;                      case 'logo':                          if (isset($data->logo) && $data->logo) {                              if (! preg_match('/^http/', $data->logo)) {                                  $content = str_replace($matches[0][$i], $this->adjustLabelData($params, SITE_DIR . $data->logo), $content);                              } else {                                  $content = str_replace($matches[0][$i], $this->adjustLabelData($params, $data->logo), $content);                              }                          } else {                              $content = str_replace($matches[0][$i], STATIC_DIR . '/images/logo.png', $content);                          }                          break;                      case 'tplpath':                          $content = str_replace($matches[0][$i], APP_THEME_DIR, $content);                          break;                      case 'language':                          $content = str_replace($matches[0][$i], get_lg(), $content);                          break;                      case 'statistical':                          if (isset($data->statistical)) {                              $content = str_replace($matches[0][$i], decode_string($data->statistical), $content);                          } else {                              $content = str_replace($matches[0][$i], '', $content);                          }                      case 'copyright':                          if (isset($data->copyright)) {                              $content = str_replace($matches[0][$i], decode_string($data->copyright), $content);                          } else {                              $content = str_replace($matches[0][$i], '', $content);                          }                      default:                          if (isset($data->{$matches[1][$i]})) {                              $content = str_replace($matches[0][$i], $this->adjustLabelData($params, $data->{$matches[1][$i]}), $content);                          } else {                              $content = str_replace($matches[0][$i], '', $content);                          }                  }              }          }          return $content;      }  

內容傳入此函數後進行了decode_string()方法

位於PbootCMS/core/function/handle.php

function decode_string($string)  {      if (! $string)          return $string;      if (is_array($string)) { // 數組處理          foreach ($string as $key => $value) {              $string[$key] = decode_string($value);          }      } elseif (is_object($string)) { // 對象處理          foreach ($string as $key => $value) {              $string->$key = decode_string($value);          }      } else { // 字元串處理          $string = stripcslashes($string);          $string = htmlspecialchars_decode($string, ENT_QUOTES);      }      return $string;  }

此方法是html實體編碼轉義普通字元,而不是將普通字元轉義成html實體編碼,應當使用escape_string()處理數據,該方法同樣位於PbootCMS/core/function/handle.php。

function escape_string($string)  {      if (! $string)          return $string;      if (is_array($string)) { // 數組處理          foreach ($string as $key => $value) {              $string[$key] = escape_string($value);          }      } elseif (is_object($string)) { // 對象處理          foreach ($string as $key => $value) {              $string->$key = escape_string($value);          }      } else { // 字元串處理          $string = htmlspecialchars(trim($string), ENT_QUOTES, 'UTF-8');          $string = addslashes($string);      }      return $string;  }

三、利用程式碼

登陸後台在後台的-基礎內容-站點資訊-統計程式碼和尾部資訊等處插入xss payload payload:<img src=x onerror=alert(1)>

進入主頁觸發xss

四、參考資訊

五、修補程式

case 'statistical':                          if (isset($data->statistical)) {                              $content = str_replace($matches[0][$i], decode_string($data->statistical), $content);                          } else {                              $content = str_replace($matches[0][$i], '', $content);                          }                      case 'copyright':                          if (isset($data->copyright)) {                              $content = str_replace($matches[0][$i], decode_string($data->copyright), $content);                          } else {                              $content = str_replace($matches[0][$i], '', $content);                          }

將其中的decode_string修改為escape_string即可修復!