设计想法

目标输入


功能队列


指纹规则

管理更新

name: 0example
priority: 3
nuclei_tags:
  - []
fingerprint:
  - path: /
    request_method: get
    request_headers: {}
    request_data: ''
    status_code: 0
    headers: {}
    keyword:
      - <title>Example Domain</title>
    favicon_hash: []
{
    "path": "/",
    "request_method": "get",
    "request_headers": {},
    "request_data": "",
    "status_code": 0,
    "headers": {},
    "keyword": [
      "<title>Example Domain</title>"
    ],
    "favicon_hash": [],
    "priority": 3,
    "name": "0example"
  },

指纹分类

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct V3WebFingerPrint {
    #[serde(default)]
    pub name: String,
    #[serde(default)]
    pub priority: u32,
    pub request: WebFingerPrintRequest,
    pub match_rules: WebFingerPrintMatch,
}

请求逻辑

flowchart TD
subgraph gg[结束]
结束
end
subgraph request [请求逻辑]
目标([目标])-->判断协议{是否有协议判断}
判断协议-->|有| 首页请求[首页请求]
判断协议-->|没有| 添加协议[[添加HTTPS协议]]
添加协议-->首页请求
首页请求-->是否有响应{是否有响应}
是否有响应-->|HTTPS没有响应| 添加HTTP协议[[换HTTP协议]]
添加HTTP协议-->首页请求
是否有响应-->|有响应| 生成匹配数据[[生成匹配数据]]
是否有响应-->|没有响应| 结束([结束])
生成匹配数据-->是否有跳转{是否有跳转}
是否有跳转-->|有跳转|是否超过最大跳转次数{是否超过最大跳转次数}
是否超过最大跳转次数-->|没有|继续请求[[继续请求]]
继续请求[[继续请求]]-->是否有响应{是否有响应}
是否有跳转-->|没有跳转|匹配数据列表[(添加匹配数据到列表)]
是否超过最大跳转次数 -->|超过最大跳转次数| 匹配数据列表[(添加匹配数据到列表)]
end
subgraph matcher [Web匹配逻辑]
匹配数据列表-->是否有图标Hash{是否有图标Hash}
是否有图标Hash-->|有| 匹配图标Hash指纹[[匹配图标Hash指纹]]
是否有图标Hash-->|没有| 匹配图标关键词指纹[[匹配图标关键词指纹]]
匹配图标Hash指纹-->是否有交集{是否有交集}
是否有交集-->|真|匹配到Web指纹
是否有交集-->|假|跳过
匹配图标关键词指纹-->短路求值{短路求值}
短路求值-->|真|匹配到Web指纹
短路求值-->|假|跳过
跳过-->结束
end
subgraph info [补充指纹信息]
匹配到Web指纹-->是否开启服务识别{是否开启服务识别}
是否开启服务识别-->|开启|服务识别[[补充服务信息]]
是否开启服务识别-->|没有开启|是否调用nuclei{是否调用nuclei}
服务识别-->是否调用nuclei{是否调用nuclei}
是否调用nuclei-->|调用|调用nuclei[[调用nuclei]]
是否调用nuclei-->|没有调用|结果队列[(结果队列)]
调用nuclei-->结果队列[(结果队列)]
end
subgraph result [结果处理]
结果队列-->是否开启Webhook{是否开启Webhook}
是否开启Webhook-->|开启|调用结果到Webhook服务器[[调用结果到Webhook服务器]]
是否开启Webhook-->|没有开启|是否需要保持到文件{是否需要保持到文件}
调用结果到Webhook服务器-->是否需要保持到文件{是否需要保持到文件}
是否需要保持到文件-->|是|保存到文件[[保存到文件]]
保存到文件-->打印结果到屏幕[[打印结果到屏幕]]
是否需要保持到文件-->|否|打印结果到屏幕[[打印结果到屏幕]]
打印结果到屏幕[[打印结果到屏幕]]-->结束([结束])
end

生成匹配数据

pub struct RawData {
    pub url: Url,
    pub path: String,
    pub headers: reqwest::header::HeaderMap,
    pub status_code: reqwest::StatusCode,
    pub text: String,
    pub favicon: HashMap<String, String>,
    pub next_url: Option<Url>,
}
pub fn get_title(text: &str) -> String {
    for titles in Document::from(text).find(Name("title")) {
        if !titles.text().is_empty() {
            return titles.text();
        }
    }
    for titles in Document::from(text).find(Name("meta")) {
        if titles.attr("property") == Some("title") {
            return titles.attr("content").unwrap_or_default().to_string();
        }
    }
    String::new()
}
fn get_favicon_link(text: &str, base_url: &Url) -> HashSet<Url> {
    let mut icon_links = HashSet::new();
    for links in Document::from(text).find(Name("link")) {
        if let (Some(rel), Some(href)) = (links.attr("rel"), links.attr("href")) {
            if ["icon", "shortcut icon"].contains(&rel) {
                if href.starts_with("http://") || href.starts_with("https://") {
                    let favicon_url = Url::parse(href).unwrap_or_else(|_| base_url.clone());
                    icon_links.insert(favicon_url);
                } else {
                    let favicon_url = base_url.join(href).unwrap_or_else(|_| base_url.clone());
                    icon_links.insert(favicon_url);
                }
            }
        }
    }
    if let Ok(favicon_url) = base_url.join("/favicon.ico") {
        icon_links.insert(favicon_url);
    }
    icon_links
}
 fn get_next_jump(headers: &HeaderMap, url: &Url, text: &str) -> Option<Url> {
    let mut next_url_list = Vec::new();
    if let Some(location) = headers
        .get(LOCATION)
        .and_then(|location| location.to_str().ok())
    {
        next_url_list.push(location.to_string());
    }
    if next_url_list.is_empty() {
        for metas in Document::from(text).find(Name("meta")) {
            if let (Some(url),Some(http_equiv)) = (metas.attr("url"),metas.attr("http-equiv")) {
                if http_equiv == "refresh"{
                    next_url_list.push(url.to_string());
                }
            }
        }
    }
    if next_url_list.is_empty() && text.len() <= 1024 {
        for reg in RE_COMPILE_BY_JUMP.iter() {
            if let Some(x) = reg.captures(text) {
                let mut u = x.name("name").map_or("", |m| m.as_str()).to_string();
                u = u.replace('\\'', "").replace('\\"', "");
                next_url_list.push(u);
            }
        }
    }
    if let Some(next_url) = next_url_list.into_iter().next() {
        return if next_url.starts_with("http://") || next_url.starts_with("https://") {
            match Url::parse(&next_url) {
                Ok(next_path) => Some(next_path),
                Err(_) => None,
            }
        } else if let Ok(next_path) = url.join(&next_url) {
            Some(next_path)
        } else {
            None
        };
    };
    None
}

网页编码

lazy_static! {    static ref RE_COMPILE_BY_CHARSET: Regex =        Regex::new(r#"(?im)charset="(.*?)"|charset=(.*?)""#).expect("RE_COMPILE_BY_CHARSET");}

单元测试

#[tokio::test]
    async fn test_send_requests() {
        let test_url = Url::parse("<https://httpbin.org/>").unwrap();
        let fingerprint = WebFingerPrintRequest {
            path: String::from("/"),
            request_method: String::from("GET"),
            request_headers: Default::default(),
            request_data: Str
ing::from(""),
        };
        let timeout = 10_u64;
        let request_config = RequestOption::new(&timeout, "");
        let res = send_requests(&test_url, &fingerprint, &request_config)
            .await
            .unwrap();
        assert!(res.text().await.unwrap().contains("swagger-ui"));
    }

badssl.com

GitHub Action

https://github.com/0x727/FingerprintHub

指纹更新

https://github.com/0x727/ObserverWard

指纹审核

flowchart TD
subgraph add [添加指纹]
打开issue添加指纹([打开issue添加指纹])-->解析issue内容{是否符合格式要求}
解析issue内容-->|符合| 验证指纹[验证指纹]
解析issue内容-->|不符合| 提示并且关闭issue[[提示并且关闭issue]]
提示并且关闭issue-->gg[[结束]]
验证指纹-->是否识别成功{是否识别成功}
是否识别成功-->|是| 待审核标签[[待审核标签]]
是否识别成功-->|否| 修改yaml指纹[[评论修改yaml指纹]]
修改yaml指纹-->验证指纹[[验证指纹]]
待审核标签-->是否审核通过[[是否审核通过]]
是否审核通过-->|是| 通过标签[[通过标签]]
是否审核通过-->|否| 原因[[原因]]
通过标签-->合并请求[[合并请求]]
end
Powered by Kali-Team