["'])[^(?P=quote)]+?(?P=quote)[^`]*?))`(?P[^`]+)`】。
解釋一下:
【(?:(?:^(?:\s+)?)|(?:(?P["'])[^(?P=quote)]+?(?P=quote)[^`]*?))】
匹配開始位置或者開始位置之后有空白字符或者前面有代碼,且代碼有閉合的單雙引號。(這段PYTHON的正則中用了捕獲命名以及反向引用)
【`(?P[^`]+)`】這個就比較簡單了,匹配反引號中間的字符串。
某檢測PHP webshell的python腳本考慮欠佳。
再看看下一個列表的第一個元素。【(system|shell_exec|exec|popen)】,這個正則的意思是只要字符串里包含“system”、“shell_exec”、“exec”、“popen”這四組字符串即判定為危險字符。很明顯,這個方法太不嚴謹。如果程序員寫的代碼中,包含了這四組字符,即可被判定為危險函數。很不準確,誤報率極高。見下圖
某檢測PHP webshell的python腳本考慮欠佳。
到底什么樣的代碼是可疑的代碼?關鍵詞是什么?可疑的代碼肯定是由可以執行危險操作的函數構成,可以執行危險操作的PHP函數最重要的就是“eval”函數了,對于加密的PHP代碼(僅變形字符串,非zend等方式加密),肯定要用到“eval”函數,所以,對于不管是用哪種加密方法的代碼,肯定要用到“eval”函數。其次就是可以執行系統命令的函數了,比如上面某牛的代碼中提到的四個“system”、“shell_exec”、“exec”、“popen”。當然還有其他的,比如passthru等。PHP還支持“·”字符(ESC鍵下面那個)直接執行系統命令。我們可以把正則寫成這樣【\b(?P
eval|proc_open|popen|shell_exec|exec|passthru|system)\b\s*\(】。
檢測PHP webshell的python腳本相對較為嚴謹的匹配
解釋一下:大家都知道【\b\b】用來匹配單詞兩邊的位置的。要保證【\b\b】中間的是單詞,即使函數名前面加特殊字符,也一樣通過匹配,比如加@來屏蔽錯誤。后面的【\s*】用來匹配空白字符的,包括空格,tab鍵,次數為0到無數次。前面的【(?P)】是捕獲命名組。用來當作python代碼直接引用匹配結果的key。
還有的網友提到了,如果我把代碼放到圖片拓展名的文件里呢?那你只檢測.php,.inc的文件,還是找不到我的呀。嗯,是的,如果惡意代碼在gif、jpg、png、aaa等亂七八糟的拓展名文件里,是不能被apache、IIS等web Services解析的,必須通過include/require(_once)來引入。那么,我們只要匹配include/require(_once)后面的文件名是不是常規的“.php”、“.inc”文件。如果不是,則為可疑文件。正則如下【(?P
\b(?:include|require)(?:_once)?\b)\s*\(?\s*["'](?P .*?(?
檢測PHP WEBSHELL的python腳本較為嚴謹做法
解釋一下:先看【(?P
\b(?:include|require)(?:_once)?\b)】,【(?P )】為正則表達式的“命名捕獲”,PHP中有同樣的用法。也就是說,在這括號內的捕獲的數據,會分配到結果數組的key為“name”的value中。再看里面的【\b(?:include|require)(?:_once)?\b】,【\b\b】不解釋了,為單詞邊界位置。里面的【(?:include|require)】匹配字符串“include”、“require”兩個單詞,其中前面的【(?:)】未不分配組,用于提高效率,可以去掉【?:】變成【(include|require)】。在后面一個【(?:_once)】也是做不分配組的操作,便于提高正則表達式效率。同樣,后面的量詞是“?”代表這個組可有可無。就滿足了“include”、“include_once”、“require”、“require_once”四種情況。有的朋友可能這樣寫【(include|include_once|require|require_once)】也能實現目的。但是,為了更搞的效率,我們對這個正則做優化,針對部分字符串做分支更改,改成上面那個【\b(?:include|require)(?:_once)?\b】。 再看下面的【\s*\(?\s*["'](?P
.+?(?.+?(?)】上面介紹了,為命名捕獲,把結果放到match.group(“filename”)里。【.*?】為任意字符,后面的量詞是“忽略優先量詞”,也就是平常說的“非貪婪”。這里最少匹配零個,(防止.aa、.htaccess這種沒有文件名,只有文件拓展名的文件被引入)。后面的【(?
綜上所述,最后,鄙人給出的python代碼如下:
代碼如下:
#!/usr/bin/python
#-*- encoding:UTF-8 -*-
###
## @package
##
## @author CFC4N
## @copyright copyright (c) Www.cnxct.Com
## @Version $Id: check_php_shell.py 37 2010-07-22 09:56:28Z cfc4n $
###
import os
import sys
import re
import time
def listdir(dirs,liston='0'):
flog = open(os.getcwd()+"/check_php_shell.log","a+")
if not os.path.isdir(dirs):
print "directory %s is not exist"% (dirs)
return
lists = os.listdir(dirs)
for list in lists:
filepath = os.path.join(dirs,list)
if os.path.isdir(filepath):
if liston == '1':
listdir(filepath,'1')
elif os.path.isfile(filepath):
filename = os.path.basename(filepath)
if re.search(r"\.(?:php|inc|html?)$", filename, re.IGNORECASE):
i = 0
iname = 0
f = open(filepath)
while f:
file_contents = f.readline()
if not file_contents:
break
i += 1
match = re.search(r'''(?P\b(?:include|require)(?:_once)?\b)\s*\(?\s*["'](?P .*?(?if match:
function = match.group("function")
filename = match.group("filename")
if iname == 0:
info = '\n[%s] :\n'% (filepath)
else:
info = ''
info += '\t|-- [%s] - [%s] line [%d] \n'% (function,filename,i)
flog.write(info)
print info
iname += 1
match = re.search(r'\b(?Peval|proc_open|popen|shell_exec|exec|passthru|system)\b\s*\(', file_contents, re.IGNORECASE| re.MULTILINE)
if match:
function = match.group("function")
if iname == 0:
info = '\n[%s] :\n'% (filepath)
else:
info = ''
info += '\t|-- [%s] line [%d] \n'% (function,i)
flog.write(info)
print info
iname += 1
f.close()
flog.close()
if '__main__' == __name__:
argvnum = len(sys.argv)
liston = '0'
if argvnum == 1:
action = os.path.basename(sys.argv[0])
print "Command is like:\n %s D:\wwwroot\ \n %s D:\wwwroot\ 1 -- recurse subfolders"% (action,action)
quit()
elif argvnum == 2:
path = os.path.realpath(sys.argv[1])
listdir(path,liston)
else:
liston = sys.argv[2]
path = os.path.realpath(sys.argv[1])
listdir(path,liston)
flog = open(os.getcwd()+"/check_php_shell.log","a+")
ISOTIMEFORMAT='%Y-%m-%d %X'
now_time = time.strftime(ISOTIMEFORMAT,time.localtime())
flog.write("\n----------------------%s checked ---------------------\n"% (now_time))
flog.close()
## 最新代碼在文章結尾的鏈接里給出了。2010/07/31 更新。
僅供參考,歡迎斧正。下面截圖為掃描Discuz7.2的效果圖,當然,也有誤報。相對網上流傳的python腳本,誤報更少,更精確了。
檢測PHP WEBSHELL的python腳本的檢測結果
問:這個方法完美了嗎?可以查找目前已知的所有危險函數文件了嗎?
答:不能,如果include等引入的文件沒有拓展名,這里就匹配不到了。
問:如何解決?
答:留給你解決,聰明的你,肯定可以搞定。
PS:“`”反引號 執行命令的還沒寫,暫時沒好的辦法。容易跟SQL語句中的反引號混淆。不太好匹配。如果光匹配反引號就提示的話,那誤報太大了。待定吧。(術業有專攻,請勿因為一處不好的代碼,否定一個人的能力。你懂的。再次重申,此文只針對代碼,不針對人。其次,鄙人給出的python代碼隨便復制,隨便傳播,愛留版權就留版權,不愛留就刪了相關字符,也就是您愛干嗎干嗎。)
我先休息一會,明天再說。(前半句為三國殺曹仁的臺詞,哈。)聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com