0x01 具体功能
内网WEB (OPTIONS协议探测WEB响应)
外网WEB (MASSCAN扫描端口后的资产根据指纹对用漏洞进行分类)
WEB漏洞指纹 (侵入性识别和无侵入性响应包关键词探测)
WEB漏洞利用 (授权情况下根据选项发送带有载荷的攻击包)
#linux环境
wget https://go.dev/dl/go1.23.2.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.23.2.linux-amd64.tar.gz
echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.bashrc
source ~/.bashrc
go version
go mod init search
go mod tidy
go build search.go
使用:
./search -u 10.txt -m GET -ph "/ooxx.php" -t 1000 -o cg.txt -r "xxx"
0x04 代码
package main
import (
"bufio"
"bytes"
"flag"
"fmt"
"github.com/common-nighthawk/go-figure"
"io/ioutil"
"net/http"
"os"
"regexp"
"strings"
"sync"
"time"
)
// 检查 URL 是否包含目标关键词或匹配正则表达式
func checkWebmin(url, path, method, body, keyword string, headers map[string]string, useRegex bool) (bool, error) {
// 创建一个 HTTP 客户端,设置超时时间为 10 秒
client := &http.Client{
Timeout: 8 * time.Second,
}
// 构建完整的请求 URL
fullURL := url + path
// 创建 HTTP 请求,根据是否存在 body 来设置请求体
var req *http.Request
var err error
if body != "" {
req, err = http.NewRequest(method, fullURL, bytes.NewBufferString(body))
} else {
req, err = http.NewRequest(method, fullURL, nil)
}
if err != nil {
return false, err // 请求创建失败
}
// 如果自定义了 headers,则设置请求头
for key, value := range headers {
req.Header.Set(key, value)
}
// 如果 body 不为空,默认设置 Content-Type 为表单数据格式
if body != "" {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
// 发送请求
resp, err := client.Do(req)
if err != nil {
return false, err // 请求失败
}
defer resp.Body.Close()
// 读取响应体
responseBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return false, err // 读取响应体失败
}
// 将响应体转换为字符串
bodyStr := string(responseBody)
// 根据是否使用正则表达式来匹配关键词
if useRegex {
re, err := regexp.Compile(keyword)
if err != nil {
return false, fmt.Errorf("正则表达式编译错误: %v", err)
}
if re.MatchString(bodyStr) {
return true, nil
}
} else {
if strings.Contains(bodyStr, keyword) {
return true, nil
}
}
return false, nil
}
// 工作线程函数,从任务通道中获取 URL 并处理
func worker(taskChan <-chan string, resultsChan chan<- string, wg *sync.WaitGroup, path, method, body, keyword string, headers map[string]string, useRegex bool) {
defer wg.Done()
for url := range taskChan {
// 检查 URL 是否包含协议
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
// 优先尝试 https
httpsURL := "https://" + url
if found, err := checkWebmin(httpsURL, path, method, body, keyword, headers, useRegex); found && err == nil {
fmt.Println("找到sURL:", httpsURL," ","关键词",keyword)
resultsChan <- httpsURL
continue
}
// 如果 https 失败,尝试 http
httpURL := "http://" + url
if found, err := checkWebmin(httpURL, path, method, body, keyword, headers, useRegex); found && err == nil {
fmt.Println("找到URL:", httpURL," ","关键词",keyword)
resultsChan <- httpURL
continue
}
} else {
// 如果 URL 已经包含协议,直接检查
if found, err := checkWebmin(url, path, method, body, keyword, headers, useRegex); found && err == nil {
fmt.Println("找到关键词:", url," ","关键词",keyword)
resultsChan <- url
}
}
}
}
func parseHeaders(headerStr string) map[string]string {
headers := make(map[string]string)
// 解析自定义的 headers,格式为 key:value;key:value
headerPairs := strings.Split(headerStr, ";")
for _, pair := range headerPairs {
headerParts := strings.SplitN(pair, ":", 2)
if len(headerParts) == 2 {
key := strings.TrimSpace(headerParts[0])
value := strings.TrimSpace(headerParts[1])
headers[key] = value
}
}
return headers
}
func main() {
// 处理长选项和短选项的参数
figure := figure.NewFigure("Fingerprint Scanner", "", true)
figure.Print()
urlsFile := flag.String("urls", "urls.txt", "URL 文件的路径 (-u)")
flag.StringVar(urlsFile, "u", "urls.txt", "URL 文件的路径")
numWorkers := flag.Int("threads", 10, "并发线程数 (-t)")
flag.IntVar(numWorkers, "t", 10, "并发线程数")
requestPath := flag.String("path", "", "要访问的路径 (-ph)")
flag.StringVar(requestPath, "ph", "", "要访问的路径")
requestMethod := flag.String("method", "GET", "HTTP 请求方法 (-m)")
flag.StringVar(requestMethod, "m", "GET", "HTTP 请求方法")
outputFilePath := flag.String("output", "sucss.txt", "保存结果的文件路径 (-o)")
flag.StringVar(outputFilePath, "o", "sucss.txt", "保存结果的文件路径")
// 自定义关键词或正则表达式参数
searchKeyword := flag.String("regex", "btc", "要匹配的关键词或正则表达式 (-r)")
flag.StringVar(searchKeyword, "r", "btc", "要匹配的关键词或正则表达式")
// 自定义请求 body 参数
requestBody := flag.String("body", "", "自定义请求 body (-b)")
flag.StringVar(requestBody, "b", "", "自定义请求 body")
// 自定义 header 参数
requestHeaders := flag.String("headers", "", "自定义请求头,格式为 key:value;key:value (-H)")
flag.StringVar(requestHeaders, "H", "", "自定义请求头,格式为 key:value;key:value")
// 自定义帮助信息
flag.Usage = func() {
fmt.Println("用法: search Bitcoin [选项]")
fmt.Println(" 手搓 by Reee ")
fmt.Println("选项:")
fmt.Println(" -urls, -u URL 文件的路径 (默认为 urls.txt)")
fmt.Println(" -method, -m HTTP 请求方法 (默认为 GET)")
fmt.Println(" -path, -ph 要访问的路径 (默认为 空)")
fmt.Println(" -threads, -t 并发线程数 (默认为 10)")
fmt.Println(" -output, -o 保存结果的文件路径 (默认为 sucss.txt)")
fmt.Println(" -regex, -r 要匹配的关键词或正则表达式 (默认为 btc)")
fmt.Println(" -body, -b 自定义请求 body (默认为空)")
fmt.Println(" -headers, -H 自定义请求头,格式为 key:value;key:value (默认为空)")
fmt.Println(" -h, --help 显示帮助信息")
}
flag.Parse()
// 判断是否使用正则表达式
useRegex := false
if _, err := regexp.Compile(*searchKeyword); err == nil {
useRegex = true
}
// 解析自定义的请求头
headers := parseHeaders(*requestHeaders)
// 打开 URL 文件
file, err := os.Open(*urlsFile)
if err != nil {
fmt.Println("打开 URL 文件出错:", err)
return
}
defer file.Close()
// 打开输出文件
outputFile, err := os.OpenFile(*outputFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
fmt.Println("打开输出文件出错:", err)
return
}
defer outputFile.Close()
// 创建任务和结果通道
taskChan := make(chan string, 100)
resultsChan := make(chan string, 100)
var wg sync.WaitGroup
// 启动 worker
for i := 0; i < *numWorkers; i++ {
wg.Add(1)
go worker(taskChan, resultsChan, &wg, *requestPath, *requestMethod, *requestBody, *searchKeyword, headers, useRegex)
}
// 读取 URL 并将其发送到任务通道
scanner := bufio.NewScanner(file)
go func() {
for scanner.Scan() {
url := strings.TrimSpace(scanner.Text())
if url != "" {
taskChan <- url
}
}
close(taskChan)
}()
// 处理结果并写入输出文件
go func() {
for result := range resultsChan {
outputFile.WriteString(result + "\n")
}
}()
// 等待所有 worker 完成
wg.Wait()
close(resultsChan)
// 检查读取 URL 文件时是否有错误
if err := scanner.Err(); err != nil {
fmt.Println("读取 URL 文件出错:", err)
}
}
https://patorjk.com/software/taag/#p=display&f=Star%20Wars&t=%E6%8C%87%E7%BA%B9%E6%89%AB%E6%8F%8F%E5%99%A8
0x05 功能缺陷
多线程文件锁没写,多线程可能会互斥覆盖,自己加个文件锁,另外可以优化一下线程,用CPU的核数来提高线程处理速度。
end
下期预告
继续写工具
欢迎投稿并加入我们,请联系公众号:Golden-Qianjiang