当前位置:WooYun(白帽子技术社区) >> 代码审计 >> 代码审计案例一枚fanwe o2o 笔记

代码审计案例一枚fanwe o2o 笔记

phith0n (我也不会难过 你不要小看我) | 2015-08-11 11:06

FROM: https://www.leavesongs.com/PENETRATION/fanwe-o2o-demo-website-getshell.html

    早前一个被我捂烂的漏洞,其实不是要捂的,当注入交到乌云,审核比较忙测试的时候没复现,就给打回来了。我一直想写个详细的再交,结果没时间就没写,这两天上去一看鸡毛都没了,全补完了,shell也掉光了,后台也进不去……
    想想算了不挖了。还好我有记笔记的习惯,拿出来分享一下。
    以下是笔记。
    今天挖了一阵子方维O2O的本地生活系统。这个系统是不开源的,偶然拿到了一个版本的源码,于是有了这次挖洞之旅。
    首先翻到了一个注入,拿下了管理员密码。实际上,demo站已经给了一个低权限的管理员账号demo/demo。
    登录后台:


    0x01 鸡肋文件包含漏洞
    大概看了一下功能不多,很多敏感功能(如sql操作)demo管理员没权限。
    后台一般安全做的比较差,最容易出现的是文件包含漏洞。我很快在源码里找到一处鸡肋文件包含。/admin/Lib/Action/ApiLoginAction.class.php
public function install()
{
    $class_name = $_REQUEST['class_name'];
    $directory = APP_ROOT_PATH."system/api_login/";
    $read_modules = true;
    
    $file = $directory.$class_name."_api.php";
    if(file_exists($file))
    {
        $module = require_once($file);
        $rs = M("ApiLogin")->where("class_name = '".$class_name."'")->count();
        if($rs > 0)
        {
            $this->error(l("API_INSTALLED"));
        }
    }
    else
    {
        $this->error(l("INVALID_OPERATION"));
    }

    之所以叫鸡肋,因为需要截断:$directory.$class_name."_api.php";
    但我看demo站的php是5.3.3,记得5.3.4以后才解决截断问题。而且fanwe全局并没有addslashes,不影响截断。
    所以简单尝试了一下……结果还真截断不了:

    可能是其他什么原因,反正不能截断。这个鸡肋漏洞是用不了了。再继续翻源码。


    0x02 解压缩造成的鸡肋文件上传漏洞
    /admin/Lib/Action/FileAction.class.php,一个文件管理的controller。(审计的时候嗅觉也比较重要,看到这个文件名FileAction我就感觉这里会出问题,因为是文件操作)
    实际上也没我想的那么糟糕,这里是上传的控制器,上传的地方过滤的比较严,不能直接上传php文件。
    但有个上传压缩包并解压的函数:
/**
* 图标上传
*/
public function do_upload_icon()
{
  require_once APP_ROOT_PATH."system/utils/zip.php";
  $archive  = new PHPZip();
  $font_dir = APP_ROOT_PATH."public/iconfont";
  
  $result = $archive->unZip($_FILES['file']['tmp_name'], $font_dir);
  if(empty($result)||$result==-1)
  {
    ajax_return(array("status"=>false,"info"=>"图标库更新失败,请手动解压后上传文件到".$font_dir));
  }
  
  if ( $dir = opendir( $font_dir."/" ) )
  {
    while ( $file = readdir( $dir ) )
    {
      $check = is_dir( $font_dir."/". $file );
      if ( !$check )
      {
        @unlink( $font_dir ."/". $file );
      }
    }
  }

  
  

  $result = $archive->unZip($_FILES['file']['tmp_name'], $font_dir);    
  //清空原文件
  

  foreach($result as $k=>$v)
  {
    $file = APP_ROOT_PATH."public/iconfont/".$k;
    $file_arr = explode("/", $file);
    
    foreach($file_arr as $f)
    {
      if($f=="iconfont.css"||$f=="iconfont.eot"||$f=="iconfont.svg"||$f=="iconfont.ttf"||$f=="iconfont.woff")
      {
        //echo APP_ROOT_PATH."public/iconfont/".$f;
        @rename($file,APP_ROOT_PATH."public/iconfont/".$f);
      }
    }
    
  }
  
  foreach($result as $k=>$v)
  {
    $file = APP_ROOT_PATH."public/iconfont/".$k;
    @unlink($file);
  }
  foreach($result as $k=>$v)
  {
    $file = APP_ROOT_PATH."public/iconfont/".$k;
    @rmdir($file);
  }
  ajax_return(array("status"=>true,"info"=>""));
}

    看过我去年写的一篇文章:https://www.leavesongs.com/PENETRATION/after-phpcms-upload-vul.html 的同学应该记忆犹新,解压这种操作有很多方法可以传shell。
    这里也一样,虽然解压完成后删除了所有原有文件。但其解压了zip文件后,它判断了是否成功,不成功则直接退出了:
if(empty($result)||$result==-1)
{
    ajax_return(array("status"=>false,"info"=>"图标库更新失败,请手动解压后上传文件到".$font_dir));
}

    那么我可以构造一个“能够解压一半”的压缩包,解压出部分php文件,然后出错。这样就执行不到“删除”的代码了。
    另外一个方法是,我解压的时候修改文件名为“../xxxx.php”,就能把php文件解压到上层目录中,也能避免被删除的命运。
    相对的,第二种方法更简单。
    于是我构造压缩包,先写好一个webshell,名字就叫aaaaaaaaaaaaaaaaaaaaaa.php。压缩后用editplus编辑:

    将前4个a替换成“/../”,这样保证了整个文件的长度不变。
    再构造本地上传单页:
<form action="http://o2odemo.fanwe.net/m.php?m=File&a=do_upload_icon" method="post" enctype ="multipart/form-data">
<input name="file" type="file" />
<input type="submit" value="upload" />
</form>

    选择后传上去。结果访问发现403:

    又重新换文件名试了一下,也403。试了一下不存在的.php文件,也403。基本上就是这个规则:public目录下,所有.php文件都是403。
    试了txt文件,是可以上传的,说明public目录有写权限:

    另外尝试了传到其他目录,比如根目录、admin目录,结果404,应该是没写权限。
    所以,现在这个洞也是很悲剧很鸡肋的:只有public目录有写权限,但public目录下不能执行php。

    0x03 组合漏洞出奇迹
    这是突然想到:之前挖的那个鸡肋文件包含,不就正好排上用场了吗?
    之前的文件包含漏洞,鸡肋就鸡肋在只能包含php文件,一般情况下如果我们能写入php文件其实就已经getshell了。
    但这里不一样,我解压出来一个xxxx_api.php,虽然在public目录下不能执行,但通过文件包含的方法包含之,即可执行我的webshell了。
    于是将文件名改成aaaaaaaaaaaa_api.php

    上传后直接包含,成功:

    菜刀连接:

    

    0x04 法2:apache解析漏洞的逆袭
    平时用apache用的不多,一直觉得apache的那个解析漏洞是很老的版本才会有的。但这次还真被我碰上了。
    通过上一个漏洞getshell后,再回来思考还有没有别的方法。
    这个时候应该换位思考,如果我是运维,我一般会怎样禁用一个目录中的php文件?
    很可能是一个正则:^/public/.*\.php$,只要HTTP请求符合这个正则,就返回403。
    我曾经写过一篇文章:https://www.leavesongs.com/PENETRATION/nginx-deny-exec-php-file.html,讲的是nginx如何正确禁用执行。
    文中被绕过的方法实际上就是这个正则:

    这样通过后缀去禁止执行的方式是很不可靠的,文中我通过pathinfo的方式(xxx.php/xxx)来绕过了这个正则。
    这里我也试了用pathinfo,可惜还是返回403 。那么针对这个正则:“^/public/.*\.php$”,真的没有办法了吗?
    思路就是:有没有其他后缀可以被解析,如果有就能绕过这个正则了。
    试了一下phtml、php3/4/5,都不能解析。这个时候我想到apache的解析漏洞了:当apache不识别最后一个后缀时,会向前寻找直到找到一个能够识别的后缀。
    于是将名字改成xxx.php.phi:

    上传发现已经可以解析了:

    一个解析漏洞的逆袭。

    0x05 拿到shell以后的反思
    限制执行这个问题,看了看配置文件。果然和我想的一样,是限制了public目录下几个后缀,不允许执行:
<Directory "/fanwe/www/o2odemo/public">
    <FilesMatch ".(php|asp|jsp)$">
     Deny from all
    </FilesMatch>
</Directory>

    并且查看了整个web目录的权限,web目录所有者是root,只有public是777,其他文件全部是755和644,好家伙和我想的一样。看来我自己的直觉现在也是越来越准拉,哈哈~(完)

分享到:
  1. 1#
    回复此人 感谢
    刘海哥 (‮moc.ghuil.www) | 2015-08-11 11:11

    mark

  2. 2#
    回复此人 感谢
    mramydnei | 2015-08-11 11:14

    p牛好棒

  3. 3#
    回复此人 感谢
    retanoj | 2015-08-11 11:19

    膜拜。。。

  4. 4#
    回复此人 感谢
    sin (寻找最优雅的解决方案) | 2015-08-11 11:31

    666

  5. 5#
    回复此人 感谢
    Mark (渗透你的心) | 2015-08-11 11:51

    p牛

  6. 6#
    回复此人 感谢
    wefgod (求大牛指点) | 2015-08-11 11:52

    给力!

  7. 7#
    回复此人 感谢
    浮萍 | 2015-08-11 12:01

    啪啪

  8. 8#
    回复此人 感谢
    不能忍 (听说只有帅的人才会送我wb!) | 2015-08-11 12:04

    组合漏洞出奇迹。。。这个比较精华

  9. 9#
    回复此人 感谢
    scanf (www.scanfsec.com 网络尖刀) | 2015-08-11 12:04

    淡淡的

  10. 10#
    回复此人 感谢
    玉林嘎 | 2015-08-11 12:14

    强到不行

  11. 11#
    回复此人 感谢
    jeary ((:‮?办么怎,了多越来越法方象抽的我)) | 2015-08-11 12:27

    ph牛收下膝盖!

  12. 12#
    回复此人 感谢
    超蓝 (换个马甲好好做人,请叫我暧昧) | 2015-08-11 12:52

    通俗易懂。 赞

  13. 13#
    回复此人 感谢
    luwikes (土豆你个西红柿,番茄你个马铃薯~~~) | 2015-08-11 13:25

    感谢ph牛。刚开始没看作者,通篇看完特别爽,感觉应该是个注定被雷劈的洞啊,回头一看原来是ph牛。一如既往的霸气。

  14. 14#
    回复此人 感谢
    夏殇 (不忘初心,方得始终。) | 2015-08-11 15:24

    好思路,谢谢分享。还是想请教一下用什么方法可以使压缩包解压到一半的时候出错呢?

  15. 15#
    回复此人 感谢
    Sunshie (博客http://phpinfo.me 论坛 www.itgou.club) | 2015-08-11 16:28

    6666

  16. 16#
    回复此人 感谢
    Nicky (安卓安全中文站 www.droidsec.cn) | 2015-08-11 17:13

    p牛屌屌的,而且好能吃

  17. 17#
    回复此人 感谢
    piaoye (123) | 2015-08-11 17:21

    俩大漏洞

  18. 18#
    回复此人 感谢
    qhwlpg (~~) | 2015-08-11 17:28

    思路屌啊

  19. 19#
    回复此人 感谢
    Cyrils | 2015-08-11 20:04

    好文,学习~

  20. 20#
    回复此人 感谢
    纷纭 (:-)) | 2015-08-11 22:23

    mark

  21. 21#
    回复此人 感谢
    黑吃黑 (粪土当年万户侯) | 2015-08-11 23:08

    P牛 业界良心啊

  22. 22#
    回复此人 感谢
    phith0n (我也不会难过 你不要小看我) | 2015-08-12 09:57
  23. 23#
    回复此人 感谢
    夏殇 (不忘初心,方得始终。) | 2015-08-12 11:05

    @phith0n ⊙﹏⊙‖∣认真看啦看啦。就是没看懂怎么去构造一个会解压出错的压缩包。我试着去弄了一个有问题的压缩包,只能弄到全部文件都没解压出来

  24. 24#
    回复此人 感谢
    Seven.Sea | 2015-08-12 11:26

    马=.=

  25. 25#
    回复此人 感谢
    BeenQuiver | 2015-08-12 16:18

    好文一篇

  26. 26#
    回复此人 感谢
    L.N. (http://ln.sycsec.com/) | 2015-08-12 21:01

  27. 27#
    回复此人 感谢
    suolong (永远不再败。) | 2015-08-12 22:06

    组合攻击 简直是神来之笔!

  28. 28#
    回复此人 感谢
    小杰哥 (能学则学,技多不压身。) | 2015-08-13 00:03

    压缩包有点蒙。

  29. 29#
    回复此人 感谢
    O.o | 2015-08-25 21:24

    666

  30. 30#
    回复此人 感谢
    J0kER (姿势决定成败) | 2015-08-26 14:12

    笔记很重要~

  31. 31#
    回复此人 感谢
    枪花 | 2015-08-26 14:51

    耐心也很重要

  32. 32#
    回复此人 感谢
    missy (1) | 2015-08-26 14:56

    幸福来的太突然

  33. 33#
    回复此人 感谢
    M4sk | 2015-08-26 15:20

    好文一篇

  34. 34#
    回复此人 感谢
    网监大队 | 2015-08-26 15:28

    好文一篇

  35. 35#
    回复此人 感谢
    Devi1o | 2015-08-26 15:29

    MARK!看不过代码的伤不起

  36. 36#
    回复此人 感谢
    _Evil (科普是一种公益行为) | 2015-08-27 11:27

    看了好多次 想起来两个wooyun知识点:

    WooYun: 盛大网站漏洞修复方案不完整导致可能代码执行

    http://zone.wooyun.org/content/14102

  37. 37#
    回复此人 感谢
    绯色月下 | 2015-09-02 08:30

    好文章,看完了。

添加新回复

登录 后才能参与评论.

WooYun(白帽子技术社区)

网络安全资讯、讨论,跨站师,渗透师,结界师聚集之地

登录