4

记一次对Tp二开的源码审计(Php审计)

 3 years ago
source link: https://xz.aliyun.com/t/9440
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
记一次对Tp二开的源码审计(Php审计) - 先知社区

记一次对Tp二开的源码审计(Php审计)

冷水明天不熬夜了 / 2021-05-07 16:25:10 / 浏览数 4454 安全技术 WEB安全 顶(1) 踩(0)

  • 概述
    一款某单子Tp二开平台,开发者嚷嚷着要找人审计一下源码,说有预算,洞审出来之后人就没了,感觉审都审了,不做点什么不是浪费时间了,于是就发出来顺便讲一下在Tp二开情况下如何对源码进行审计,一般在拿到Tp二开的源码,首先要做的事,确认系统版本,然后利用搜索引擎寻找当前框架版本的漏洞,这次拿到手之后在确认下是Tp3.2.3的系统,其次就是查看TP的路由是默认还是说更改了,然后找到web类,对类中的代码一行一行的仔细审计,Tp3.2.3爆出的漏洞挺多的,结合前辈的各种经验,成功寻找到了开发中的雷区,这里直接贴代码。

  • 任意文件包含代码执行
    在Application\Home\Controller\VueController.class.php下,可以看到这里是这样写的。

    但是在TP3.2.3中,这是个大问题,因为display方法会直接包含这个变量中的文件,并且在Controller.class.php中的_Call类定义了如果存在_empty方法,就会优先调用,这里methed_name就是a方法类的传值,但是如果我们另调用的a类直接为我们要包含的文件的绝对路径,那么就会直接包含掉我们所给的文件。

    这里贴出详情漏洞代码

    public function _empty($methed_name){
          $this->display($methed_name);
          exit(0);
      }
    

    我们这里可以看到,当把A设置为日志的绝对路径时,会直接包含掉这个日志,从而造成任意代码执行。

  • Sql注入
    在Application\Api\Controller\AreaController.class.php下,先铺上代码。

    这里没有使用I方法,而是直接通过$_REQUEST['pid']去取得Pid的值,我们这里可以构造Exp表达式用于Where条件,然后对代码进行注入,也不知道是不是留的后门,前面都写了I,就这里非要用$_REQUEST['pid']去接受参数,构造pid[0]=exp&pid[1]= and updatexml(1,concat(0x7e,(select user())),0)可以看到成功爆出来了用户名。

    public function ajax() {
          $pid = $_REQUEST['pid'];
          $list = D('Area')->where(array('pid'=>$pid))->select();
          $html = '';
          foreach( $list as $k=>$v ) {
              $html .= '<option value="'.$v["area_id"].'">'.$v["title"].'</option>';
          }
          echo $html;
      }
    
  • Session操控
    在Application\Api\Controller\CodePayController.class.php中,就更离谱了,铺上代码。

    这里的$key,$value值都是经过$_REQUEST传参进来的,也就是说,我们可以任意的对Session进行操控,结合判断的Check_login来看,发现只是判断Session里面是否存在值。
    ```php
    public function setsession()
    {

    $key = (isset($_REQUEST['key']) && !empty($_REQUEST['key']) ) ? $_REQUEST['key'] : '';
      $value = (isset($_REQUEST['value']) && !empty($_REQUEST['value']) ) ? $_REQUEST['value'] : '';
    
      session($key,$value);
```php
function check_login(){
    if (!empty($_SESSION['user']['id'])){
        return true;
    }else{
        return false;
    }
}

还有这里写入的,我们就可以自己构造出相应的变量,从而达到未授权登录的目的。

  • 番外
    其实在TP3.2.3中,还有一种情况,可以直接调用Dispaly。

    当ThinkPHP\Library\Think\Controller.class.php中的Display为Public的情况下(默认为Protected),可以从前台控制器中直接调用Display造成执行任意代码,当然一般情况下遇不到,不过如果当一个后门还是挺好用的。

    protected function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') {
          $this->view->display($templateFile,$charset,$contentType,$content,$prefix);
      }
    
  • 总结
    如果遇到TP二开的系统,确认版本,找到控制类,结合前辈们的经验,站在巨人肩膀上对其进行审计,要是类中的代码没问题,我建议尝试寻找Tp的0day(好像某个大佬手上有Tp3.2.3的代码执行)。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK