
网站被入侵后清理了一遍,过几天又发现新马。原因多半是清理不彻底——只删了明面上的文件,藏在图片里、伪装成正常库文件的WebShell没揪出来。人工逐个文件看?几千个文件看到眼瞎。让AI写个扫描脚本,按特征全盘扫一遍,是效率最高的做法。
先想清楚WebShell长什么样。一句话木马的核心特征:执行代码的危险函数(eval、assert、system、exec、shell_exec、passthru)+ 接收外部输入($_POST、$_REQUEST、$_GET、$_COOKIE)+ 常见变形(base64_decode、str_rot13、字符串拼接、create_function)。光查扩展名没用——攻击者会把马改成.jpg、.png甚至没有扩展名。所以扫描要按内容特征来。
把特征告诉AI,让它写扫描脚本。提示词里明确:扫描目录、要匹配的特征、输出要求。下面这个Python脚本就是典型的AI产物,你只要理解它的思路——正则匹配高危函数组合,命中就打印文件路径和行号。
<pre style="background-color:#282c34;color:#abb2bf;padding:16px 20px;border-radius:8px;overflow-x:auto;font-family:Consolas,'Courier New',monospace;font-size:14px;line-height:1.7;margin:16px 0;-webkit-overflow-scrolling:touch;"><code style="font-family:inherit;"><span style="color:#7f848e;font-style:italic"># webshell_scan.py —— 按内容特征扫描上传目录</span>
import os, re
SCAN_DIR = <span style="color:#98c379">"/var/www/html/uploads"</span>
<span style="color:#7f848e;font-style:italic"># 高危特征:危险函数 + 可变参数/编码变形</span>
patterns = [
re.<span style="color:#61afef">compile</span>(r<span style="color:#98c379">'(eval|assert)\s*\(\s*\$_(POST|REQUEST|GET|COOKIE)'</span>, re.I),
re.<span style="color:#61afef">compile</span>(r<span style="color:#98c379">'(system|exec|shell_exec|passthru|popen)\s*\(\s*\$_(POST|REQUEST|GET|COOKIE)'</span>, re.I),
re.<span style="color:#61afef">compile</span>(r<span style="color:#98c379">'base64_decode\s*\(\s*["\']'</span>, re.I),
re.<span style="color:#61afef">compile</span>(r<span style="color:#98c379">'@\s*(eval|assert)\s*\('</span>, re.I),
re.<span style="color:#61afef">compile</span>(r<span style="color:#98c379">'create_function\s*\('</span>, re.I),
]
<span style="color:#c678dd">for</span> root, dirs, files in os.<span style="color:#61afef">walk</span>(SCAN_DIR):
<span style="color:#c678dd">for</span> f in files:
path = os.path.<span style="color:#61afef">join</span>(root, f)
<span style="color:#c678dd">try</span>:
with <span style="color:#61afef">open</span>(path, <span style="color:#98c379">'rb'</span>) <span style="color:#c678dd">as</span> fp:
data = fp.<span style="color:#61afef">read</span>()
except <span style="color:#e6c07b">Exception</span>:
<span style="color:#c678dd">continue</span>
<span style="color:#7f848e;font-style:italic"># 跳过真正的图片文件</span>
<span style="color:#c678dd">if</span> data[:<span style="color:#d19a66">3</span>] == b<span style="color:#98c379">'\xff\xd8\xff'</span> <span style="color:#c678dd">or</span> data[:<span style="color:#d19a66">8</span>] == b<span style="color:#98c379">'\x89PNG\r\n\x1a\n'</span>:
<span style="color:#c678dd">continue</span>
<span style="color:#c678dd">try</span>:
text = data.<span style="color:#61afef">decode</span>(<span style="color:#98c379">'utf-8'</span>, errors=<span style="color:#98c379">'ignore'</span>)
except <span style="color:#e6c07b">Exception</span>:
<span style="color:#c678dd">continue</span>
<span style="color:#c678dd">for</span> i, pat in <span style="color:#61afef">enumerate</span>(patterns):
m = pat.<span style="color:#61afef">search</span>(text)
<span style="color:#c678dd">if</span> m:
line = text[:m.<span style="color:#61afef">start</span>()].<span style="color:#61afef">count</span>(<span style="color:#98c379">'\n'</span>) + <span style="color:#d19a66">1</span>
<span style="color:#c678dd">print</span>(f<span style="color:#98c379">"[!] {path}:{line} 命中特征{i+1}: {m.group()[:60]}"</span>)
<span style="color:#c678dd">break</span></code></pre>
扫描结果要人工复核,AI写的特征正则可能有误报——比如某些正常代码里也有base64_decode(微信支付回调验签就常用)。命中列表拿出来,逐个打开看上下文,确认是马再删。删之前先备份,万一误删了正常文件还有退路。
另外两个维度别漏:一是文件修改时间,入侵时间点之后被改动的文件全部重点查;二是上传目录的权限,WebShell多半是从上传漏洞进来的,扫完马顺手把上传目录的脚本执行权限禁了(Nginx下location配置deny php),不然明天还会有一批新马等你扫。
<pre style="background-color:#282c34;color:#abb2bf;padding:16px 20px;border-radius:8px;overflow-x:auto;font-family:Consolas,'Courier New',monospace;font-size:14px;line-height:1.7;margin:16px 0;-webkit-overflow-scrolling:touch;"><code style="font-family:inherit;"><span style="color:#7f848e;font-style:italic"># Nginx:uploads目录禁止执行PHP(WebShell最常见入口)</span>
location ~ ^/uploads/.*\.(php|php5|phtml|asp|aspx|jsp|cgi|pl)$ {
deny all;
<span style="color:#c678dd">return</span> <span style="color:#d19a66">403</span>;
}
<span style="color:#7f848e;font-style:italic"># 定时扫描(每天凌晨4点)</span>
<span style="color:#d19a66">0</span> <span style="color:#d19a66">4</span> * * * python3 /root/webshell_scan.py >> /<span style="color:#c678dd">var</span>/log/webshell_scan.log <span style="color:#d19a66">2</span>>&<span style="color:#d19a66">1</span></code></pre>
申请创业报道,分享创业好点子。点击此处,共同探讨创业新机遇!

