/ common / fingerprints / preload / mlfow.go
mlfow.go
 1  // Copyright (c) 2024-2026 Tencent Zhuque Lab. All rights reserved.
 2  //
 3  // Licensed under the Apache License, Version 2.0 (the "License");
 4  // you may not use this file except in compliance with the License.
 5  // You may obtain a copy of the License at
 6  //
 7  //     http://www.apache.org/licenses/LICENSE-2.0
 8  //
 9  // Unless required by applicable law or agreed to in writing, software
10  // distributed under the License is distributed on an "AS IS" BASIS,
11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  // See the License for the specific language governing permissions and
13  // limitations under the License.
14  //
15  // Requirement: Any integration or derivative work must explicitly attribute
16  // Tencent Zhuque Lab (https://github.com/Tencent/AI-Infra-Guard) in its
17  // documentation or user interface, as detailed in the NOTICE file.
18  
19  // Package preload mlflow漏洞go语言写法
20  package preload
21  
22  import (
23  	"errors"
24  	"github.com/Tencent/AI-Infra-Guard/common/utils"
25  	"github.com/Tencent/AI-Infra-Guard/pkg/httpx"
26  	"net/url"
27  	"regexp"
28  	"strings"
29  )
30  
31  // Mlflow struct implements fingerprint detection for MLflow services
32  type Mlflow struct {
33  }
34  
35  // Match checks if the given URI points to an MLflow service
36  // 通过检查页面标题来判断是否为 MLflow 服务
37  func (m Mlflow) Match(httpx *httpx.HTTPX, uri string) bool {
38  	headers := map[string]string{
39  		"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66",
40  	}
41  	resp, err := httpx.Get(uri+"/", headers)
42  	if err != nil {
43  		return false
44  	}
45  	if resp.StatusCode == 200 && strings.Contains(resp.DataStr, "<title>MLflow</title>") {
46  		return true
47  	}
48  	return false
49  }
50  
51  // GetVersion attempts to extract the MLflow version from the service
52  // 通过以下步骤获取 MLflow 版本:
53  // 1. 获取主页面
54  // 2. 提取 JS 文件路径
55  // 3. 请求 JS 文件
56  // 4. 通过正则表达式匹配版本号
57  func (m Mlflow) GetVersion(httpx *httpx.HTTPX, uri string) (string, error) {
58  	flag := `{INTERNAL_ERROR:"INTERNAL_ERROR",INVALID_PARAMETER_VALUE:"INVALID_PARAMETER_VALUE",RESOURCE_DOES_NOT_EXIST:"RESOURCE_DOES_NOT_EXIST",PERMISSION_DENIED:"PERMISSION_DENIED",RESOURCE_CONFLICT:"RESOURCE_CONFLICT"}`
59  	headers := map[string]string{
60  		"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66",
61  	}
62  	resp, err := httpx.Get(uri+"/", headers)
63  	if err != nil {
64  		return "", err
65  	}
66  	if resp.StatusCode != 200 {
67  		return "", errors.New("request code != 200")
68  	}
69  	jsPath := utils.GetMiddleText(`script defer="defer" src="`, `">`, resp.DataStr)
70  	if jsPath == "" {
71  		return "", errors.New("not found js path")
72  	}
73  	newURL, err := url.JoinPath(uri, jsPath)
74  	if err != nil {
75  		return "", err
76  	}
77  	resp2, err := httpx.Get(newURL, headers)
78  	if err != nil {
79  		return "", err
80  	}
81  	index := strings.Index(resp2.DataStr, flag)
82  	if index == -1 {
83  		return "", errors.New("not found flag")
84  	}
85  	parrern := `\d+\.\d+\.\d+`
86  	regex := regexp.MustCompile(parrern)
87  	match := regex.FindString(resp2.DataStr[index+len(flag):])
88  	return match, nil
89  }
90  
91  // Name returns the identifier for this fingerprint detector
92  func (m Mlflow) Name() string {
93  	return "mlflow"
94  }