diff --git a/README.md b/README.md
index f930322..4f86442 100644
--- a/README.md
+++ b/README.md
@@ -20,15 +20,15 @@ URLFinder更专注于提取页面中的JS与URL链接,提取的数据更完善
## 功能说明
-1.提取页面与JS中的JS及URL链接(URL深入一层,JS深入三层 防止抓偏),以及部分敏感信息
+1.提取页面与JS中的JS及URL链接,以及部分敏感信息
2.提取到的链接会显示状态码、响应大小、标题等(带cookie操作时请使用-m 3 安全模式,防止误操作)
3.提取批量URL
-4.yml配置Headers请求头、代理
+4.yml配置Headers请求头、代理、抓取规则等
5.结果导出到csv、json、html
-6.记录抓取来源,便于手动分析(-o 导出才有)
+6.记录抓取来源,便于手动分析(-o 导出才有)
7.指定抓取域名
-8.指定baseurl路径(指定目录拼接)
-9.设置代理
+8.指定baseurl路径(指定目录拼接)
+9.使用代理ip
10.对404链接Fuzz(测试版,有问题提issue)
结果会优先显示输入的url顶级域名,其他域名不做区分显示在 other
@@ -36,14 +36,12 @@ URLFinder更专注于提取页面中的JS与URL链接,提取的数据更完善
## 使用截图
-[![0.jpg](https://github.com/pingc0y/URLFinder/img/0.jpg)](https://github.com/pingc0y/URLFinder/img/1.jpg)
-[![1.jpg](https://github.com/pingc0y/URLFinder/img/1.jpg)](https://github.com/pingc0y/URLFinder/img/2.jpg)
-[![2.jpg](https://github.com/pingc0y/URLFinder/img/2.jpg)](https://github.com/pingc0y/URLFinder/img/3.jpg)
-[![3.jpg](https://github.com/pingc0y/URLFinder/img/3.jpg)](https://github.com/pingc0y/URLFinder/img/4.jpg)
-[![4.jpg](https://github.com/pingc0y/URLFinder/img/4.jpg)](https://github.com/pingc0y/URLFinder/img/5.jpg)
-[![5.jpg](https://github.com/pingc0y/URLFinder/img/5.jpg)](https://github.com/pingc0y/URLFinder/img/6.jpg)
-
-
+[![0.jpg](https://github.com/pingc0y/URLFinder/raw/master/img/0.jpg)](https://github.com/pingc0y/URLFinder/raw/master/img/0.jpg)
+[![1.jpg](https://github.com/pingc0y/URLFinder/raw/master/img/1.jpg)](https://github.com/pingc0y/URLFinder/raw/master/img/1.jpg)
+[![2.jpg](https://github.com/pingc0y/URLFinder/raw/master/img/2.jpg)](https://github.com/pingc0y/URLFinder/raw/master/img/2.jpg)
+[![3.jpg](https://github.com/pingc0y/URLFinder/raw/master/img/3.jpg)](https://github.com/pingc0y/URLFinder/raw/master/img/3.jpg)
+[![4.jpg](https://github.com/pingc0y/URLFinder/raw/master/img/4.jpg)](https://github.com/pingc0y/URLFinder/raw/master/img/4.jpg)
+[![5.jpg](https://github.com/pingc0y/URLFinder/raw/master/img/5.jpg)](https://github.com/pingc0y/URLFinder/raw/master/img/5.jpg)
## 使用教程
单url时使用
@@ -67,7 +65,7 @@ URLFinder.exe -s all -m 2 -f url.txt -o d:/
-i 加载yaml配置文件(不存在时,会在当前目录创建一个默认yaml配置文件)
-m 抓取模式:
1 正常抓取(默认)
- 2 深入抓取 (url只深入一层,防止抓偏)
+ 2 深入抓取 (URL深入一层 JS深入三层 防止抓偏)
3 安全深入抓取(过滤delete,remove等敏感路由)
-o 结果导出到csv文件,需指定导出文件目录(.代表当前目录)
-s 显示指定状态码,all为显示全部
@@ -91,34 +89,38 @@ go build -ldflags "-s -w" -o ./URLFinder-windows-amd64.exe
SET CGO_ENABLED=0
SET GOOS=windows
SET GOARCH=386
-go build -ldflags "-s -w" -o ../URLFinder-windows-386.exe
+go build -ldflags "-s -w" -o ./URLFinder-windows-386.exe
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
-go build -ldflags "-s -w" -o ../URLFinder-linux-amd64
+go build -ldflags "-s -w" -o ./URLFinder-linux-amd64
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=arm64
-go build -ldflags "-s -w" -o ../URLFinder-linux-arm64
+go build -ldflags "-s -w" -o ./URLFinder-linux-arm64
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=386
-go build -ldflags "-s -w" -o ../URLFinder-linux-386
+go build -ldflags "-s -w" -o ./URLFinder-linux-386
SET CGO_ENABLED=0
SET GOOS=darwin
SET GOARCH=amd64
-go build -ldflags "-s -w" -o ../URLFinder-macos-amd64
+go build -ldflags "-s -w" -o ./URLFinder-macos-amd64
SET CGO_ENABLED=0
SET GOOS=darwin
SET GOARCH=arm64
-go build -ldflags "-s -w" -o ../URLFinder-macos-arm64
+go build -ldflags "-s -w" -o ./URLFinder-macos-arm64
```
## 更新说明
+2023/2/3
+新增 域名信息展示
+变化 -i配置文件可配置抓取规则等
+
2023/1/29
新增 -b 设置baseurl路径
新增 -o json、html格式导出
diff --git a/URLFinder-linux-386 b/URLFinder-linux-386
index 94e583a..545147d 100644
Binary files a/URLFinder-linux-386 and b/URLFinder-linux-386 differ
diff --git a/URLFinder-linux-amd64 b/URLFinder-linux-amd64
index ff64942..3b1d26c 100644
Binary files a/URLFinder-linux-amd64 and b/URLFinder-linux-amd64 differ
diff --git a/URLFinder-linux-arm64 b/URLFinder-linux-arm64
index 5bacd99..1424135 100644
Binary files a/URLFinder-linux-arm64 and b/URLFinder-linux-arm64 differ
diff --git a/URLFinder-macos-amd64 b/URLFinder-macos-amd64
index ff64942..3b1d26c 100644
Binary files a/URLFinder-macos-amd64 and b/URLFinder-macos-amd64 differ
diff --git a/URLFinder-macos-arm64 b/URLFinder-macos-arm64
index 31e4245..7a547ee 100644
Binary files a/URLFinder-macos-arm64 and b/URLFinder-macos-arm64 differ
diff --git a/URLFinder-windows-386.exe b/URLFinder-windows-386.exe
index 60ab89b..a07e8bf 100644
Binary files a/URLFinder-windows-386.exe and b/URLFinder-windows-386.exe differ
diff --git a/URLFinder-windows-amd64.exe b/URLFinder-windows-amd64.exe
index 2283612..84b6e64 100644
Binary files a/URLFinder-windows-amd64.exe and b/URLFinder-windows-amd64.exe differ
diff --git a/cmd/cmd.go b/cmd/cmd.go
new file mode 100644
index 0000000..ebcd7f2
--- /dev/null
+++ b/cmd/cmd.go
@@ -0,0 +1,62 @@
+package cmd
+
+import (
+ "flag"
+ "fmt"
+ "github.com/gookit/color"
+ "os"
+)
+
+var (
+ h bool
+ I bool
+ M int
+ S string
+ U string
+ D string
+ C string
+ A string
+ b string
+ F string
+ O string
+ X string
+ T = 50
+ Z int
+)
+
+func init() {
+ flag.StringVar(&A, "a", "", "set user-agent\n设置user-agent请求头")
+ flag.StringVar(&b, "b", "", "set baseurl\n设置baseurl路径")
+ flag.StringVar(&C, "c", "", "set cookie\n设置cookie")
+ flag.StringVar(&D, "d", "", "set domainName\n指定获取的域名")
+ flag.StringVar(&F, "f", "", "set urlFile\n批量抓取url,指定文件路径")
+ flag.BoolVar(&h, "h", false, "this help\n帮助信息")
+ flag.BoolVar(&I, "i", false, "set configFile\n加载yaml配置文件(不存在时,会在当前目录创建一个默认yaml配置文件)")
+ flag.IntVar(&M, "m", 1, "set mode\n抓取模式 \n 1 normal\n 正常抓取(默认) \n 2 thorough\n 深入抓取 (url深入一层,js深入三层,防止抓偏) \n 3 security\n 安全深入抓取(过滤delete,remove等敏感路由) \n ")
+ flag.StringVar(&O, "o", "", "set outFile\n结果导出到csv文件,需指定导出文件目录(.代表当前目录)")
+ flag.StringVar(&S, "s", "", "set Status\n显示指定状态码,all为显示全部(多个状态码用,隔开)")
+ flag.IntVar(&T, "t", 50, "set thread\n设置线程数(默认50)\n")
+ flag.StringVar(&U, "u", "", "set Url\n目标URL")
+ flag.StringVar(&X, "x", "", "set httpProxy\n设置代理,格式: http://username:password@127.0.0.1:8809")
+ flag.IntVar(&Z, "z", 0, "set Fuzz\n对404链接进行fuzz(只对主域名下的链接生效,需要与-s一起使用) \n 1 decreasing\n 目录递减fuzz \n 2 2combination\n 2级目录组合fuzz(适合少量链接使用) \n 3 3combination\n 3级目录组合fuzz(适合少量链接使用) \n")
+
+ // 改变默认的 Usage
+ flag.Usage = usage
+}
+func usage() {
+ fmt.Fprintf(os.Stderr, `Usage: URLFinder [-a user-agent] [-b baseurl] [-c cookie] [-d domainName] [-f urlFile] [-h help] [-i configFile] [-m mode] [-o outFile] [-s Status] [-t thread] [-u Url] [-x httpProxy] [-z fuzz]
+
+Options:
+`)
+ flag.PrintDefaults()
+}
+
+func Parse() {
+ color.LightCyan.Println(" __ __ ___ _ _ \n /\\ /\\ /__\\ / / / __(_)_ __ __| | ___ _ __ \n/ / \\ \\/ \\/// / / _\\ | | '_ \\ / _` |/ _ \\ '__|\n\\ \\_/ / _ \\ /___ / | | | | | (_| | __/ | \n \\___/\\/ \\_\\____\\/ |_|_| |_|\\__,_|\\___|_| \n\nBy: pingc0y\nUpdateTime: 2023/2/3\nGithub: https://github.com/pingc0y/URLFinder \n")
+ flag.Parse()
+ if h || (U == "" && F == "") {
+ flag.Usage()
+ os.Exit(0)
+ }
+
+}
diff --git a/config/config.go b/config/config.go
new file mode 100644
index 0000000..9e2aca8
--- /dev/null
+++ b/config/config.go
@@ -0,0 +1,109 @@
+package config
+
+import (
+ "fmt"
+ "github.com/pingc0y/URLFinder/cmd"
+ "github.com/pingc0y/URLFinder/mode"
+ "gopkg.in/yaml.v3"
+ "os"
+ "strings"
+ "sync"
+)
+
+var Conf mode.Config
+var Progress = 1
+var FuzzNum int
+
+var (
+ Risks = []string{"remove", "delete", "insert", "update", "logout"}
+
+ JsFuzzPath = []string{
+ "login.js",
+ "app.js",
+ "main.js",
+ "config.js",
+ "admin.js",
+ "info.js",
+ "open.js",
+ "user.js",
+ "input.js",
+ "list.js",
+ "upload.js",
+ }
+ JsFind = []string{
+ ".(https{0,1}:[-a-zA-Z0-9()@:%_\\+.~#?&//=]{2,250}?[-a-zA-Z0-9()@:%_\\+.~#?&//=]{3}[.]js)",
+ "[\",',‘,“]\\s{0,6}(/{0,1}[-a-zA-Z0-9()@:%_\\+.~#?&//=]{2,250}?[-a-zA-Z0-9()@:%_\\+.~#?&//=]{3}[.]js)",
+ "=\\s{0,6}[\",',’,”]{0,1}\\s{0,6}(/{0,1}[-a-zA-Z0-9()@:%_\\+.~#?&//=]{2,250}?[-a-zA-Z0-9()@:%_\\+.~#?&//=]{3}[.]js)",
+ }
+ UrlFind = []string{
+ "[\",',‘,“]\\s{0,6}(https{0,1}:[-a-zA-Z0-9()@:%_\\+.~#?&//=]{2,250}?)\\s{0,6}[\",',‘,“]",
+ "=\\s{0,6}(https{0,1}:[-a-zA-Z0-9()@:%_\\+.~#?&//=]{2,250})",
+ "[\",',‘,“]\\s{0,6}([#,.]{0,2}/[-a-zA-Z0-9()@:%_\\+.~#?&//=]{2,250}?)\\s{0,6}[\",',‘,“]",
+ "\"([-a-zA-Z0-9()@:%_\\+.~#?&//=]+?[/]{1}[-a-zA-Z0-9()@:%_\\+.~#?&//=]+?)\"",
+ "href\\s{0,6}=\\s{0,6}[\",',‘,“]{0,1}\\s{0,6}([-a-zA-Z0-9()@:%_\\+.~#?&//=]{2,250})|action\\s{0,6}=\\s{0,6}[\",',‘,“]{0,1}\\s{0,6}([-a-zA-Z0-9()@:%_\\+.~#?&//=]{2,250})",
+ }
+
+ JsFiler = []string{
+ "www\\.w3\\.org",
+ "example\\.com",
+ }
+ UrlFiler = []string{
+ "\\.js\\?|\\.css\\?|\\.jpeg\\?|\\.jpg\\?|\\.png\\?|.gif\\?|www\\.w3\\.org|example\\.com|\\<|\\>|\\{|\\}|\\[|\\]|\\||\\^|;|/js/|\\.src|\\.replace|\\.url|\\.att|\\.href|location\\.href|javascript:|location:|application/x-www-form-urlencoded|\\.createObject|:location|\\.path|\\*#__PURE__\\*|\\*\\$0\\*|\\n",
+ ".*\\.js$|.*\\.css$|.*\\.scss$|.*,$|.*\\.jpeg$|.*\\.jpg$|.*\\.png&|.*\\.gif&|.*\\.ico$|.*\\.svg$|.*\\.vue$|.*\\.ts$",
+ }
+
+ Phone = []string{"['\"](1(3([0-35-9]\\d|4[1-8])|4[14-9]\\d|5([\\d]\\d|7[1-79])|66\\d|7[2-35-8]\\d|8\\d{2}|9[89]\\d)\\d{7})['\"]"}
+ Email = []string{"['\"]([\\w!#$%&'*+=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?)['\"]"}
+ IDcard = []string{"['\"]((\\d{8}(0\\d|10|11|12)([0-2]\\d|30|31)\\d{3}$)|(\\d{6}(18|19|20)\\d{2}(0[1-9]|10|11|12)([0-2]\\d|30|31)\\d{3}(\\d|X|x)))['\"]"}
+ Jwt = []string{"['\"](ey[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9._-]{10,}|ey[A-Za-z0-9_\\/+-]{10,}\\.[A-Za-z0-9._\\/+-]{10,})['\"]"}
+)
+
+var (
+ Lock sync.Mutex
+ Wg sync.WaitGroup
+ Mux sync.Mutex
+ Ch = make(chan int, 50)
+ Jsch = make(chan int, 50/2)
+ Urlch = make(chan int, 50/2)
+)
+
+// 读取配置文件
+func GetConfig(path string) {
+ con := &mode.Config{}
+ if f, err := os.Open(path); err != nil {
+ if strings.Contains(err.Error(), "The system cannot find the file specified") || strings.Contains(err.Error(), "no such file or directory") {
+ con.Headers = map[string]string{"Cookie": cmd.C, "User-Agent": `Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36 SE 2.X MetaSr 1.0`, "Accept": "*/*"}
+ con.Proxy = ""
+ con.JsFind = JsFind
+ con.UrlFind = UrlFind
+ con.JsFiler = JsFiler
+ con.UrlFiler = UrlFiler
+ con.JsFuzzPath = JsFuzzPath
+ con.InfoFind = map[string][]string{"Phone": Phone, "Email": Email, "IDcard": IDcard, "Jwt": Jwt}
+ data, err2 := yaml.Marshal(con)
+ err2 = os.WriteFile(path, data, 0644)
+ if err2 != nil {
+ fmt.Println(err)
+ } else {
+ fmt.Println("未找到配置文件,已在当面目录下创建配置文件: config.yaml")
+ }
+ } else {
+ fmt.Println("配置文件错误,请尝试重新生成配置文件")
+ fmt.Println(err)
+ }
+ os.Exit(1)
+ } else {
+ yaml.NewDecoder(f).Decode(con)
+ Conf = *con
+ JsFind = con.JsFind
+ UrlFind = con.UrlFind
+ JsFiler = con.JsFiler
+ UrlFiler = con.UrlFiler
+ JsFuzzPath = con.JsFuzzPath
+ Phone = con.InfoFind["Phone"]
+ Email = con.InfoFind["Email"]
+ IDcard = con.InfoFind["IDcard"]
+ Jwt = con.InfoFind["Jwt"]
+ }
+
+}
diff --git a/crawler/crawler.go b/crawler/crawler.go
new file mode 100644
index 0000000..b548b08
--- /dev/null
+++ b/crawler/crawler.go
@@ -0,0 +1,133 @@
+package crawler
+
+import (
+ "crypto/tls"
+ "fmt"
+ "github.com/pingc0y/URLFinder/cmd"
+ "github.com/pingc0y/URLFinder/config"
+ "github.com/pingc0y/URLFinder/result"
+ "github.com/pingc0y/URLFinder/util"
+ "io"
+ "net/http"
+ "net/url"
+ "os"
+ "regexp"
+ "strings"
+ "time"
+)
+
+// 蜘蛛抓取页面内容
+func Spider(u string, num int) {
+ var is bool
+ fmt.Printf("\rSpider %d", config.Progress)
+ config.Mux.Lock()
+ config.Progress++
+ config.Mux.Unlock()
+ //标记完成
+ defer func() {
+ config.Wg.Done()
+ if !is {
+ <-config.Ch
+ }
+
+ }()
+ u, _ = url.QueryUnescape(u)
+ if num > 1 && cmd.D != "" && !strings.Contains(u, cmd.D) {
+ return
+ }
+ if GetEndUrl(u) {
+ return
+ }
+ if cmd.M == 3 {
+ for _, v := range config.Risks {
+ if strings.Contains(u, v) {
+ return
+ }
+ }
+ }
+ AppendEndUrl(u)
+
+ tr := &http.Transport{
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+ }
+
+ //配置代理
+ if cmd.X != "" {
+ proxyUrl, parseErr := url.Parse(config.Conf.Proxy)
+ if parseErr != nil {
+ fmt.Println("代理地址错误: \n" + parseErr.Error())
+ os.Exit(1)
+ }
+ tr.Proxy = http.ProxyURL(proxyUrl)
+ }
+ //加载yaml配置(proxy)
+ if cmd.I {
+ util.SetProxyConfig(tr)
+ }
+ client := &http.Client{Timeout: 10 * time.Second, Transport: tr}
+ request, err := http.NewRequest("GET", u, nil)
+ if err != nil {
+ return
+ }
+ //增加header选项
+ request.Header.Add("Cookie", cmd.C)
+ request.Header.Add("User-Agent", util.GetUserAgent())
+ request.Header.Add("Accept", "*/*")
+ //加载yaml配置(headers)
+ if cmd.I {
+ util.SetHeadersConfig(&request.Header)
+ }
+ //处理返回结果
+ response, err := client.Do(request)
+ if err != nil {
+ return
+ } else {
+ defer response.Body.Close()
+
+ }
+
+ //提取url用于拼接其他url或js
+ dataBytes, err := io.ReadAll(response.Body)
+ if err != nil {
+ return
+ }
+ path := response.Request.URL.Path
+ host := response.Request.URL.Host
+ scheme := response.Request.URL.Scheme
+ source := scheme + "://" + host + path
+
+ //字节数组 转换成 字符串
+ result := string(dataBytes)
+ //处理base标签
+ re := regexp.MustCompile("base.{1,5}href.{1,5}(http.+?//[^\\s]+?)[\",',‘,“]")
+ base := re.FindAllStringSubmatch(result, -1)
+ if len(base) > 0 {
+ host = regexp.MustCompile("http.*?//([^/]+)").FindAllStringSubmatch(base[0][1], -1)[0][1]
+ scheme = regexp.MustCompile("(http.*?)://").FindAllStringSubmatch(base[0][1], -1)[0][1]
+ paths := regexp.MustCompile("http.*?//.*?(/.*)").FindAllStringSubmatch(base[0][1], -1)
+ if len(paths) > 0 {
+ path = paths[0][1]
+ } else {
+ path = "/"
+ }
+ }
+ <-config.Ch
+ is = true
+
+ //提取js
+ jsFind(result, host, scheme, path, source, num)
+ //提取url
+ urlFind(result, host, scheme, path, source, num)
+ //提取信息
+ infoFind(result, source)
+
+}
+
+// 打印Validate进度
+func PrintProgress() {
+ num := len(result.ResultJs) + len(result.ResultUrl)
+ fmt.Printf("\rValidate %.0f%%", float64(config.Progress+1)/float64(num+1)*100)
+ config.Mux.Lock()
+ config.Progress++
+ config.Mux.Unlock()
+}
diff --git a/crawler/filter.go b/crawler/filter.go
new file mode 100644
index 0000000..2c42f3a
--- /dev/null
+++ b/crawler/filter.go
@@ -0,0 +1,74 @@
+package crawler
+
+import (
+ "github.com/pingc0y/URLFinder/config"
+ "net/url"
+ "regexp"
+ "strings"
+)
+
+// 过滤JS
+func jsFilter(str [][]string) [][]string {
+
+ //对不需要的数据过滤
+ for i := range str {
+ str[i][0], _ = url.QueryUnescape(str[i][1])
+ str[i][0] = strings.Replace(str[i][0], " ", "", -1)
+ str[i][0] = strings.Replace(str[i][0], "\\/", "/", -1)
+ str[i][0] = strings.Replace(str[i][0], "%3A", ":", -1)
+ str[i][0] = strings.Replace(str[i][0], "%2F", "/", -1)
+
+ //去除不是.js的链接
+ if !strings.HasSuffix(str[i][0], ".js") && !strings.Contains(str[i][0], ".js?") {
+ str[i][0] = ""
+ }
+
+ //过滤配置的黑名单
+ for i2 := range config.JsFiler {
+ re := regexp.MustCompile(config.JsFiler[i2])
+ is := re.MatchString(str[i][0])
+ if is {
+ str[i][0] = ""
+ }
+ }
+
+ }
+ return str
+
+}
+
+// 过滤URL
+func urlFilter(str [][]string) [][]string {
+
+ //对不需要的数据过滤
+ for i := range str {
+ str[i][0], _ = url.QueryUnescape(str[i][1])
+ str[i][0] = strings.Replace(str[i][0], " ", "", -1)
+ str[i][0] = strings.Replace(str[i][0], "\\/", "/", -1)
+ str[i][0] = strings.Replace(str[i][0], "%3A", ":", -1)
+ str[i][0] = strings.Replace(str[i][0], "%2F", "/", -1)
+
+ //去除不存在字符串和数字的url,判断为错误数据
+ match, _ := regexp.MatchString("[a-zA-Z]+|[0-9]+", str[i][0])
+ if !match {
+ str[i][0] = ""
+ }
+
+ //对抓到的域名做处理
+ re := regexp.MustCompile("([a-z0-9\\-]+\\.)+([a-z0-9\\-]+\\.[a-z0-9\\-]+)(:[0-9]+)?").FindAllString(str[i][0], 1)
+ if len(re) != 0 && !strings.HasPrefix(str[i][0], "http") && !strings.HasPrefix(str[i][0], "/") {
+ str[i][0] = "http://" + str[i][0]
+ }
+
+ //过滤配置的黑名单
+ for i2 := range config.UrlFiler {
+ re := regexp.MustCompile(config.UrlFiler[i2])
+ is := re.MatchString(str[i][0])
+ if is {
+ str[i][0] = ""
+ }
+ }
+
+ }
+ return str
+}
diff --git a/crawler/find.go b/crawler/find.go
new file mode 100644
index 0000000..d04abf8
--- /dev/null
+++ b/crawler/find.go
@@ -0,0 +1,195 @@
+package crawler
+
+import (
+ "github.com/pingc0y/URLFinder/cmd"
+ "github.com/pingc0y/URLFinder/config"
+ "github.com/pingc0y/URLFinder/mode"
+ "github.com/pingc0y/URLFinder/result"
+ "regexp"
+ "strings"
+)
+
+// 分析内容中的js
+func jsFind(cont, host, scheme, path, source string, num int) {
+ var cata string
+ care := regexp.MustCompile("/.*/{1}|/")
+ catae := care.FindAllString(path, -1)
+ if len(catae) == 0 {
+ cata = "/"
+ } else {
+ cata = catae[0]
+ }
+ //js匹配正则
+ host = scheme + "://" + host
+ for _, re := range config.JsFind {
+ reg := regexp.MustCompile(re)
+ jss := reg.FindAllStringSubmatch(cont, -1)
+ //return
+ jss = jsFilter(jss)
+ //循环提取js放到结果中
+ for _, js := range jss {
+ if js[0] == "" {
+ continue
+ }
+ if strings.HasPrefix(js[0], "https:") || strings.HasPrefix(js[0], "http:") {
+ AppendJs(js[0], source)
+ if num < 5 && (cmd.M == 2 || cmd.M == 3) {
+ config.Wg.Add(1)
+ config.Ch <- 1
+ go Spider(js[0], num+1)
+ }
+ } else if strings.HasPrefix(js[0], "//") {
+ AppendJs(scheme+":"+js[0], source)
+ if num < 5 && (cmd.M == 2 || cmd.M == 3) {
+ config.Wg.Add(1)
+ config.Ch <- 1
+ go Spider(scheme+":"+js[0], num+1)
+ }
+
+ } else if strings.HasPrefix(js[0], "/") {
+ AppendJs(host+js[0], source)
+ if num < 5 && (cmd.M == 2 || cmd.M == 3) {
+ config.Wg.Add(1)
+ config.Ch <- 1
+ go Spider(host+js[0], num+1)
+ }
+ } else if strings.HasPrefix(js[0], "./") {
+ AppendJs(host+"/"+js[0], source)
+ if num < 5 && (cmd.M == 2 || cmd.M == 3) {
+ config.Wg.Add(1)
+ config.Ch <- 1
+ go Spider(host+"/"+js[0], num+1)
+ }
+ } else {
+ AppendJs(host+cata+js[0], source)
+ if num < 5 && (cmd.M == 2 || cmd.M == 3) {
+ config.Wg.Add(1)
+ config.Ch <- 1
+ go Spider(host+cata+js[0], num+1)
+ }
+ }
+ }
+
+ }
+
+}
+
+// 分析内容中的url
+func urlFind(cont, host, scheme, path, source string, num int) {
+ var cata string
+ care := regexp.MustCompile("/.*/{1}|/")
+ catae := care.FindAllString(path, -1)
+ if len(catae) == 0 {
+ cata = "/"
+ } else {
+ cata = catae[0]
+ }
+ host = scheme + "://" + host
+
+ //url匹配正则
+
+ for _, re := range config.UrlFind {
+ reg := regexp.MustCompile(re)
+ urls := reg.FindAllStringSubmatch(cont, -1)
+ //fmt.Println(urls)
+ urls = urlFilter(urls)
+
+ //循环提取url放到结果中
+ for _, url := range urls {
+ if url[0] == "" {
+ continue
+ }
+ if strings.HasPrefix(url[0], "https:") || strings.HasPrefix(url[0], "http:") {
+ AppendUrl(url[0], source)
+ if num < 2 && (cmd.M == 2 || cmd.M == 3) {
+ config.Wg.Add(1)
+ config.Ch <- 1
+ go Spider(url[0], num+1)
+ }
+ } else if strings.HasPrefix(url[0], "//") {
+ AppendUrl(scheme+":"+url[0], source)
+ if num < 2 && (cmd.M == 2 || cmd.M == 3) {
+ config.Wg.Add(1)
+ config.Ch <- 1
+ go Spider(scheme+":"+url[0], num+1)
+ }
+ } else if strings.HasPrefix(url[0], "/") {
+ urlz := ""
+ if cmd.D != "" {
+ urlz = cmd.D + url[0]
+ } else {
+ urlz = host + url[0]
+ }
+ AppendUrl(urlz, source)
+ if num < 2 && (cmd.M == 2 || cmd.M == 3) {
+ config.Wg.Add(1)
+ config.Ch <- 1
+ go Spider(urlz, num+1)
+ }
+ } else if !strings.HasSuffix(source, ".js") {
+ urlz := ""
+ if cmd.D != "" {
+ if strings.HasSuffix(cmd.D, "/") {
+ urlz = cmd.D + url[0]
+ } else {
+ urlz = cmd.D + "/" + url[0]
+ }
+ } else {
+ urlz = host + cata + url[0]
+ }
+ AppendUrl(urlz, source)
+ if num < 2 && (cmd.M == 2 || cmd.M == 3) {
+ config.Wg.Add(1)
+ config.Ch <- 1
+ go Spider(urlz, num+1)
+ }
+ } else if strings.HasSuffix(source, ".js") {
+ AppendUrl(result.Jsinurl[host+path]+url[0], source)
+ if num < 2 && (cmd.M == 2 || cmd.M == 3) {
+ config.Wg.Add(1)
+ config.Ch <- 1
+ go Spider(result.Jsinurl[host+path]+url[0], num+1)
+ }
+ }
+ }
+ }
+}
+
+// 分析内容中的敏感信息
+func infoFind(cont, source string) {
+ info := mode.Info{}
+ //手机号码
+ for i := range config.Phone {
+ phones := regexp.MustCompile(config.Phone[i]).FindAllStringSubmatch(cont, -1)
+ for i := range phones {
+ info.Phone = append(info.Phone, phones[i][1])
+ }
+ }
+
+ for i := range config.Email {
+ emails := regexp.MustCompile(config.Email[i]).FindAllStringSubmatch(cont, -1)
+ for i := range emails {
+ info.Email = append(info.Email, emails[i][1])
+ }
+ }
+
+ for i := range config.IDcard {
+ IDcards := regexp.MustCompile(config.IDcard[i]).FindAllStringSubmatch(cont, -1)
+ for i := range IDcards {
+ info.IDcard = append(info.IDcard, IDcards[i][1])
+ }
+ }
+
+ for i := range config.Jwt {
+ Jwts := regexp.MustCompile(config.Jwt[i]).FindAllStringSubmatch(cont, -1)
+ for i := range Jwts {
+ info.JWT = append(info.JWT, Jwts[i][1])
+ }
+ }
+
+ info.Source = source
+ if len(info.Phone) != 0 || len(info.IDcard) != 0 || len(info.JWT) != 0 || len(info.Email) != 0 {
+ AppendInfo(info)
+ }
+
+}
diff --git a/crawler/fuzz/jsFuzz.go b/crawler/fuzz/jsFuzz.go
new file mode 100644
index 0000000..80fb61b
--- /dev/null
+++ b/crawler/fuzz/jsFuzz.go
@@ -0,0 +1,33 @@
+package fuzz
+
+import (
+ "github.com/pingc0y/URLFinder/config"
+ "github.com/pingc0y/URLFinder/mode"
+ "github.com/pingc0y/URLFinder/result"
+ "github.com/pingc0y/URLFinder/util"
+ "regexp"
+)
+
+func JsFuzz() {
+
+ paths := []string{}
+ for i := range result.ResultJs {
+ re := regexp.MustCompile("(.+/)[^/]+.js").FindAllStringSubmatch(result.ResultJs[i].Url, -1)
+ if len(re) != 0 {
+ paths = append(paths, re[0][1])
+ }
+ re2 := regexp.MustCompile("(https{0,1}://([a-z0-9\\-]+\\.)*([a-z0-9\\-]+\\.[a-z0-9\\-]+)(:[0-9]+)?/)").FindAllStringSubmatch(result.ResultJs[i].Url, -1)
+ if len(re2) != 0 {
+ paths = append(paths, re2[0][1])
+ }
+ }
+ paths = util.UniqueArr(paths)
+ for i := range paths {
+ for i2 := range config.JsFuzzPath {
+ result.ResultJs = append(result.ResultJs, mode.Link{
+ Url: paths[i] + config.JsFuzzPath[i2],
+ Source: "Fuzz",
+ })
+ }
+ }
+}
diff --git a/src/fuzz.go b/crawler/fuzz/urlFuzz.go
similarity index 64%
rename from src/fuzz.go
rename to crawler/fuzz/urlFuzz.go
index 2c3920b..2797e8d 100644
--- a/src/fuzz.go
+++ b/crawler/fuzz/urlFuzz.go
@@ -1,8 +1,13 @@
-package main
+package fuzz
import (
"crypto/tls"
"fmt"
+ "github.com/pingc0y/URLFinder/cmd"
+ "github.com/pingc0y/URLFinder/config"
+ "github.com/pingc0y/URLFinder/mode"
+ "github.com/pingc0y/URLFinder/result"
+ "github.com/pingc0y/URLFinder/util"
"io"
"net/http"
"net/url"
@@ -13,23 +18,23 @@ import (
"time"
)
-// fuzz
-func fuzz() {
+// Fuzz
+func UrlFuzz() {
var host string
re := regexp.MustCompile("([a-z0-9\\-]+\\.)*([a-z0-9\\-]+\\.[a-z0-9\\-]+)(:[0-9]+)?")
- hosts := re.FindAllString(u, 1)
+ hosts := re.FindAllString(cmd.U, 1)
if len(hosts) == 0 {
- host = u
+ host = cmd.U
} else {
host = hosts[0]
}
- if d != "" {
- host = d
+ if cmd.D != "" {
+ host = cmd.D
}
- disposes, _ := urlDispose(append(resultUrl, Link{Url: u, Status: "200", Size: "0"}), host, "")
- if z == 2 || z == 3 {
+ disposes, _ := util.UrlDispose(append(result.ResultUrl, mode.Link{Url: cmd.U, Status: "200", Size: "0"}), host, "")
+ if cmd.Z == 2 || cmd.Z == 3 {
fuzz2(disposes)
- } else if z != 0 {
+ } else if cmd.Z != 0 {
fuzz1(disposes)
}
fmt.Println("\rFuzz OK ")
@@ -38,12 +43,12 @@ func fuzz() {
// fuzz请求
func fuzzGet(u string) {
defer func() {
- wg.Done()
- <-ch
- printFuzz()
+ config.Wg.Done()
+ <-config.Ch
+ util.PrintFuzz()
}()
- if m == 3 {
- for _, v := range risks {
+ if cmd.M == 3 {
+ for _, v := range config.Risks {
if strings.Contains(u, v) {
return
}
@@ -53,8 +58,8 @@ func fuzzGet(u string) {
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
//配置代理
- if x != "" {
- proxyUrl, parseErr := url.Parse(conf.Proxy)
+ if cmd.X != "" {
+ proxyUrl, parseErr := url.Parse(config.Conf.Proxy)
if parseErr != nil {
fmt.Println("代理地址错误: \n" + parseErr.Error())
os.Exit(1)
@@ -62,8 +67,8 @@ func fuzzGet(u string) {
tr.Proxy = http.ProxyURL(proxyUrl)
}
//加载yaml配置(proxy)
- if I {
- SetProxyConfig(tr)
+ if cmd.I {
+ util.SetProxyConfig(tr)
}
client := &http.Client{Timeout: 10 * time.Second, Transport: tr}
request, err := http.NewRequest("GET", u, nil)
@@ -71,12 +76,12 @@ func fuzzGet(u string) {
return
}
//增加header选项
- request.Header.Add("Cookie", c)
- request.Header.Add("User-Agent", ua)
+ request.Header.Add("Cookie", cmd.C)
+ request.Header.Add("User-Agent", util.GetUserAgent())
request.Header.Add("Accept", "*/*")
//加载yaml配置
- if I {
- SetHeadersConfig(&request.Header)
+ if cmd.I {
+ util.SetHeadersConfig(&request.Header)
}
//处理返回结果
response, err := client.Do(request)
@@ -86,7 +91,7 @@ func fuzzGet(u string) {
defer response.Body.Close()
}
code := response.StatusCode
- if strings.Contains(s, strconv.Itoa(code)) || s == "all" {
+ if strings.Contains(cmd.S, strconv.Itoa(code)) || cmd.S == "all" {
var length int
dataBytes, err := io.ReadAll(response.Body)
if err != nil {
@@ -97,17 +102,17 @@ func fuzzGet(u string) {
body := string(dataBytes)
re := regexp.MustCompile("
(.*?)")
title := re.FindAllStringSubmatch(body, -1)
- lock.Lock()
+ config.Lock.Lock()
if len(title) != 0 {
- fuzzs = append(fuzzs, Link{Url: u, Status: strconv.Itoa(code), Size: strconv.Itoa(length), Title: title[0][1], Source: "Fuzz"})
+ result.Fuzzs = append(result.Fuzzs, mode.Link{Url: u, Status: strconv.Itoa(code), Size: strconv.Itoa(length), Title: title[0][1], Source: "Fuzz"})
} else {
- fuzzs = append(fuzzs, Link{Url: u, Status: strconv.Itoa(code), Size: strconv.Itoa(length), Title: "", Source: "Fuzz"})
+ result.Fuzzs = append(result.Fuzzs, mode.Link{Url: u, Status: strconv.Itoa(code), Size: strconv.Itoa(length), Title: "", Source: "Fuzz"})
}
- lock.Unlock()
+ config.Lock.Unlock()
}
}
-func fuzz1(disposes []Link) {
+func fuzz1(disposes []mode.Link) {
dispose404 := []string{}
for _, v := range disposes {
if v.Status == "404" {
@@ -154,21 +159,21 @@ func fuzz1(disposes []Link) {
}
}
}
- fuzz1s = uniqueArr(fuzz1s)
- fuzzNum = len(fuzz1s)
- progress = 1
- fmt.Printf("Start %d Fuzz...\n", fuzzNum)
+ fuzz1s = util.UniqueArr(fuzz1s)
+ config.FuzzNum = len(fuzz1s)
+ config.Progress = 1
+ fmt.Printf("Start %d Fuzz...\n", config.FuzzNum)
fmt.Printf("\r ")
for _, v := range fuzz1s {
- wg.Add(1)
- ch <- 1
+ config.Wg.Add(1)
+ config.Ch <- 1
go fuzzGet(v)
}
- wg.Wait()
- fuzzs = del404(fuzzs)
+ config.Wg.Wait()
+ result.Fuzzs = util.Del404(result.Fuzzs)
}
-func fuzz2(disposes []Link) {
+func fuzz2(disposes []mode.Link) {
disposex := []string{}
dispose404 := []string{}
for _, v := range disposes {
@@ -187,20 +192,20 @@ func fuzz2(disposes []Link) {
}
}
- dispose, _ := pathExtract(disposex)
- _, targets := pathExtract(dispose404)
+ dispose, _ := util.PathExtract(disposex)
+ _, targets := util.PathExtract(dispose404)
- fuzzNum = len(dispose) * len(targets)
- progress = 1
+ config.FuzzNum = len(dispose) * len(targets)
+ config.Progress = 1
fmt.Printf("Start %d Fuzz...\n", len(dispose)*len(targets))
fmt.Printf("\r ")
for _, v := range dispose {
for _, vv := range targets {
- wg.Add(1)
- ch <- 1
+ config.Wg.Add(1)
+ config.Ch <- 1
go fuzzGet(v + vv)
}
}
- wg.Wait()
- fuzzs = del404(fuzzs)
+ config.Wg.Wait()
+ result.Fuzzs = util.Del404(result.Fuzzs)
}
diff --git a/crawler/run.go b/crawler/run.go
new file mode 100644
index 0000000..3985434
--- /dev/null
+++ b/crawler/run.go
@@ -0,0 +1,196 @@
+package crawler
+
+import (
+ "bufio"
+ "fmt"
+ "github.com/gookit/color"
+ "github.com/pingc0y/URLFinder/cmd"
+ "github.com/pingc0y/URLFinder/config"
+ "github.com/pingc0y/URLFinder/crawler/fuzz"
+ "github.com/pingc0y/URLFinder/mode"
+ "github.com/pingc0y/URLFinder/result"
+ "github.com/pingc0y/URLFinder/util"
+ "io"
+ "os"
+ "regexp"
+ "strings"
+ "time"
+)
+
+func start(u string) {
+ result.Jsinurl = make(map[string]string)
+ result.Jstourl = make(map[string]string)
+ result.Urltourl = make(map[string]string)
+ result.Infos = []mode.Info{}
+ fmt.Println("Start Spider URL: " + color.LightBlue.Sprintf(u))
+ config.Wg.Add(1)
+ config.Ch <- 1
+ go Spider(u, 1)
+ config.Wg.Wait()
+ config.Progress = 1
+ fmt.Printf("\rSpider OK \n")
+ result.ResultUrl = util.RemoveRepeatElement(result.ResultUrl)
+ result.ResultJs = util.RemoveRepeatElement(result.ResultJs)
+ if cmd.S != "" {
+ fmt.Printf("Start %d Validate...\n", len(result.ResultUrl)+len(result.ResultJs))
+ fmt.Printf("\r ")
+ fuzz.JsFuzz()
+ //验证JS状态
+ for i, s := range result.ResultJs {
+ config.Wg.Add(1)
+ config.Jsch <- 1
+ go JsState(s.Url, i, result.ResultJs[i].Source)
+ }
+ //验证URL状态
+ for i, s := range result.ResultUrl {
+ config.Wg.Add(1)
+ config.Urlch <- 1
+ go UrlState(s.Url, i)
+ }
+ config.Wg.Wait()
+
+ time.Sleep(1 * time.Second)
+ fmt.Printf("\r ")
+ fmt.Printf("\rValidate OK \n")
+
+ if cmd.Z != 0 {
+ fuzz.UrlFuzz()
+ time.Sleep(1 * time.Second)
+ }
+ }
+ AddSource()
+
+ //打印还是输出
+ if len(cmd.O) > 0 {
+ result.OutFileJson()
+ result.OutFileCsv()
+ result.OutFileHtml()
+ } else {
+ result.Print()
+ }
+}
+
+func Run() {
+
+ if cmd.O != "" {
+ if !util.IsDir(cmd.O) {
+ return
+ }
+ }
+ if cmd.I {
+ config.GetConfig("config.yaml")
+ } else {
+
+ }
+ if cmd.T != 50 {
+ config.Ch = make(chan int, cmd.T+1)
+ config.Jsch = make(chan int, cmd.T/2+1)
+ config.Urlch = make(chan int, cmd.T/2+1)
+ }
+ if cmd.F != "" {
+ // 创建句柄
+ fi, err := os.Open(cmd.F)
+ if err != nil {
+ panic(err)
+ }
+ r := bufio.NewReader(fi) // 创建 Reader
+ for {
+ result.ResultJs = nil
+ result.ResultUrl = nil
+ result.EndUrl = nil
+ result.Domains = nil
+
+ lineBytes, err := r.ReadBytes('\n')
+ //去掉字符串首尾空白字符,返回字符串
+ line := strings.TrimSpace(string(lineBytes))
+ cmd.U = line
+ start(cmd.U)
+
+ if err == io.EOF {
+ break
+ }
+ fmt.Println("----------------------------------------")
+
+ }
+ return
+ }
+ start(cmd.U)
+}
+
+func AppendJs(url string, urltjs string) {
+ config.Lock.Lock()
+ defer config.Lock.Unlock()
+ url = strings.Replace(url, "/./", "/", -1)
+ for _, eachItem := range result.ResultJs {
+ if eachItem.Url == url {
+ return
+ }
+ }
+ result.ResultJs = append(result.ResultJs, mode.Link{Url: url})
+ if strings.HasSuffix(urltjs, ".js") {
+ result.Jsinurl[url] = result.Jsinurl[urltjs]
+ } else {
+ re := regexp.MustCompile("[a-zA-z]+://[^\\s]*/|[a-zA-z]+://[^\\s]*")
+ u := re.FindAllStringSubmatch(urltjs, -1)
+ result.Jsinurl[url] = u[0][0]
+ }
+ if cmd.O != "" {
+ result.Jstourl[url] = urltjs
+ }
+
+}
+
+func AppendUrl(url string, urlturl string) {
+ config.Lock.Lock()
+ defer config.Lock.Unlock()
+ url = strings.Replace(url, "/./", "/", -1)
+ for _, eachItem := range result.ResultUrl {
+ if eachItem.Url == url {
+ return
+ }
+ }
+ result.ResultUrl = append(result.ResultUrl, mode.Link{Url: url})
+ if cmd.O != "" {
+ result.Urltourl[url] = urlturl
+ }
+}
+
+func AppendInfo(info mode.Info) {
+ config.Lock.Lock()
+ defer config.Lock.Unlock()
+ result.Infos = append(result.Infos, info)
+}
+
+func AppendEndUrl(url string) {
+ config.Lock.Lock()
+ defer config.Lock.Unlock()
+ for _, eachItem := range result.EndUrl {
+ if eachItem == url {
+ return
+ }
+ }
+ result.EndUrl = append(result.EndUrl, url)
+
+}
+
+func GetEndUrl(url string) bool {
+ config.Lock.Lock()
+ defer config.Lock.Unlock()
+ for _, eachItem := range result.EndUrl {
+ if eachItem == url {
+ return true
+ }
+ }
+ return false
+
+}
+
+func AddSource() {
+ for i := range result.ResultJs {
+ result.ResultJs[i].Source = result.Jstourl[result.ResultJs[i].Url]
+ }
+ for i := range result.ResultUrl {
+ result.ResultUrl[i].Source = result.Urltourl[result.ResultUrl[i].Url]
+ }
+
+}
diff --git a/crawler/state.go b/crawler/state.go
new file mode 100644
index 0000000..ab5c29c
--- /dev/null
+++ b/crawler/state.go
@@ -0,0 +1,187 @@
+package crawler
+
+import (
+ "crypto/tls"
+ "fmt"
+ "github.com/pingc0y/URLFinder/cmd"
+ "github.com/pingc0y/URLFinder/config"
+ "github.com/pingc0y/URLFinder/mode"
+ "github.com/pingc0y/URLFinder/result"
+ "github.com/pingc0y/URLFinder/util"
+ "io"
+ "net/http"
+ "net/url"
+ "os"
+ "regexp"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// 检测js访问状态码
+func JsState(u string, i int, sou string) {
+ defer func() {
+ config.Wg.Done()
+ <-config.Jsch
+ PrintProgress()
+ }()
+ if cmd.S == "" {
+ result.ResultJs[i].Url = u
+ return
+ }
+ if cmd.M == 3 {
+ for _, v := range config.Risks {
+ if strings.Contains(u, v) {
+ result.ResultJs[i] = mode.Link{Url: u, Status: "疑似危险路由"}
+ return
+ }
+ }
+ }
+
+ tr := &http.Transport{
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+ }
+ //配置代理
+ if cmd.X != "" {
+ proxyUrl, parseErr := url.Parse(config.Conf.Proxy)
+ if parseErr != nil {
+ fmt.Println("代理地址错误: \n" + parseErr.Error())
+ os.Exit(1)
+ }
+ tr.Proxy = http.ProxyURL(proxyUrl)
+ }
+ //加载yaml配置(proxy)
+ if cmd.I {
+ util.SetProxyConfig(tr)
+ }
+ client := &http.Client{Timeout: 15 * time.Second, Transport: tr}
+ request, err := http.NewRequest("GET", u, nil)
+ if err != nil {
+ result.ResultJs[i].Url = ""
+ return
+ }
+
+ //增加header选项
+ request.Header.Add("Cookie", cmd.C)
+ request.Header.Add("User-Agent", util.GetUserAgent())
+ request.Header.Add("Accept", "*/*")
+ //加载yaml配置
+ if cmd.I {
+ util.SetHeadersConfig(&request.Header)
+ }
+
+ //处理返回结果
+ response, err := client.Do(request)
+ if err != nil {
+ if strings.Contains(err.Error(), "Client.Timeout") && cmd.S == "" {
+ result.ResultJs[i] = mode.Link{Url: u, Status: "timeout", Size: "0"}
+
+ } else {
+ result.ResultJs[i].Url = ""
+ }
+ return
+ } else {
+ defer response.Body.Close()
+ }
+
+ code := response.StatusCode
+ if strings.Contains(cmd.S, strconv.Itoa(code)) || cmd.S == "all" && (sou != "Fuzz" && code == 200) {
+ var length int
+ dataBytes, err := io.ReadAll(response.Body)
+ if err != nil {
+ length = 0
+ } else {
+ length = len(dataBytes)
+ }
+ result.ResultJs[i] = mode.Link{Url: u, Status: strconv.Itoa(code), Size: strconv.Itoa(length)}
+ } else {
+ result.ResultJs[i].Url = ""
+ }
+}
+
+// 检测url访问状态码
+func UrlState(u string, i int) {
+
+ defer func() {
+ config.Wg.Done()
+ <-config.Urlch
+ PrintProgress()
+ }()
+ if cmd.S == "" {
+ result.ResultUrl[i].Url = u
+ return
+ }
+ if cmd.M == 3 {
+ for _, v := range config.Risks {
+ if strings.Contains(u, v) {
+ result.ResultUrl[i] = mode.Link{Url: u, Status: "0", Size: "0", Title: "疑似危险路由,已跳过验证"}
+ return
+ }
+ }
+ }
+
+ tr := &http.Transport{
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+ }
+ //配置代理
+ if cmd.X != "" {
+ proxyUrl, parseErr := url.Parse(config.Conf.Proxy)
+ if parseErr != nil {
+ fmt.Println("代理地址错误: \n" + parseErr.Error())
+ os.Exit(1)
+ }
+ tr.Proxy = http.ProxyURL(proxyUrl)
+ }
+ //加载yaml配置(proxy)
+ if cmd.I {
+ util.SetProxyConfig(tr)
+ }
+ client := &http.Client{Timeout: 15 * time.Second, Transport: tr}
+ request, err := http.NewRequest("GET", u, nil)
+ if err != nil {
+ result.ResultUrl[i].Url = ""
+ return
+ }
+ //增加header选项
+ request.Header.Add("Cookie", cmd.C)
+ request.Header.Add("User-Agent", util.GetUserAgent())
+ request.Header.Add("Accept", "*/*")
+ //加载yaml配置
+ if cmd.I {
+ util.SetHeadersConfig(&request.Header)
+ }
+ //处理返回结果
+ response, err := client.Do(request)
+
+ if err != nil {
+ if strings.Contains(err.Error(), "Client.Timeout") && cmd.S == "all" {
+ result.ResultUrl[i] = mode.Link{Url: u, Status: "timeout", Size: "0"}
+ } else {
+ result.ResultUrl[i].Url = ""
+ }
+ return
+ } else {
+ defer response.Body.Close()
+ }
+
+ code := response.StatusCode
+ if strings.Contains(cmd.S, strconv.Itoa(code)) || cmd.S == "all" {
+ var length int
+ dataBytes, err := io.ReadAll(response.Body)
+ if err != nil {
+ length = 0
+ } else {
+ length = len(dataBytes)
+ }
+ body := string(dataBytes)
+ re := regexp.MustCompile("<[tT]itle>(.*?)[tT]itle>")
+ title := re.FindAllStringSubmatch(body, -1)
+ if len(title) != 0 {
+ result.ResultUrl[i] = mode.Link{Url: u, Status: strconv.Itoa(code), Size: strconv.Itoa(length), Title: title[0][1]}
+ } else {
+ result.ResultUrl[i] = mode.Link{Url: u, Status: strconv.Itoa(code), Size: strconv.Itoa(length)}
+ }
+ } else {
+ result.ResultUrl[i].Url = ""
+ }
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..440e39a
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,13 @@
+module github.com/pingc0y/URLFinder
+
+go 1.19
+
+require (
+ github.com/gookit/color v1.5.2
+ gopkg.in/yaml.v3 v3.0.1
+)
+
+require (
+ github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
+ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 // indirect
+)
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..88fd258
--- /dev/null
+++ b/main.go
@@ -0,0 +1,11 @@
+package main
+
+import (
+ "github.com/pingc0y/URLFinder/cmd"
+ "github.com/pingc0y/URLFinder/crawler"
+)
+
+func main() {
+ cmd.Parse()
+ crawler.Run()
+}
diff --git a/mode/mode.go b/mode/mode.go
new file mode 100644
index 0000000..e795d1e
--- /dev/null
+++ b/mode/mode.go
@@ -0,0 +1,31 @@
+package mode
+
+type Config struct {
+ Headers map[string]string `yaml:"headers"`
+ Proxy string `yaml:"proxy"`
+
+ JsFind []string `yaml:"jsFind"`
+ UrlFind []string `yaml:"urlFind"`
+ InfoFind map[string][]string `yaml:"infoFiler"`
+
+ JsFiler []string `yaml:"jsFiler"`
+ UrlFiler []string `yaml:"urlFiler"`
+
+ JsFuzzPath []string `yaml:"jsFuzzPath"`
+}
+
+type Link struct {
+ Url string
+ Status string
+ Size string
+ Title string
+ Source string
+}
+
+type Info struct {
+ Phone []string
+ Email []string
+ IDcard []string
+ JWT []string
+ Source string
+}
diff --git a/result/report.html b/result/report.html
new file mode 100644
index 0000000..56e4d17
--- /dev/null
+++ b/result/report.html
@@ -0,0 +1,956 @@
+
+
+
+
+
+
+ URLFinder
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/result.go b/result/result.go
similarity index 53%
rename from src/result.go
rename to result/result.go
index 8e68a40..2bee2d6 100644
--- a/src/result.go
+++ b/result/result.go
@@ -1,12 +1,14 @@
-package main
+package result
import (
"bufio"
_ "embed"
-
"encoding/json"
"fmt"
"github.com/gookit/color"
+ "github.com/pingc0y/URLFinder/cmd"
+ "github.com/pingc0y/URLFinder/mode"
+ "github.com/pingc0y/URLFinder/util"
"log"
"os"
"regexp"
@@ -17,7 +19,20 @@ import (
//go:embed report.html
var html string
-func outHtmlString(link Link) string {
+var (
+ ResultJs []mode.Link
+ ResultUrl []mode.Link
+ Fuzzs []mode.Link
+ Infos []mode.Info
+
+ EndUrl []string
+ Jsinurl map[string]string
+ Jstourl map[string]string
+ Urltourl map[string]string
+ Domains []string
+)
+
+func outHtmlString(link mode.Link) string {
ht := `
@@ -33,7 +48,7 @@ func outHtmlString(link Link) string {
` + link.Title + `
|
-
+
` + link.Source + `
|
`
@@ -56,40 +71,49 @@ func outHtmlInfoString(ty, val, sou string) string {
return ht
}
+func outHtmlDomainString(domain string) string {
+ ht := `
+
+ ` + domain + `
+ |
+
`
+ return ht
+}
+
// 导出csv
-func outFileCsv() {
- addSource()
+func OutFileCsv() {
//获取域名
var host string
re := regexp.MustCompile("([a-z0-9\\-]+\\.)*([a-z0-9\\-]+\\.[a-z0-9\\-]+)(:[0-9]+)?")
- hosts := re.FindAllString(u, 1)
+ hosts := re.FindAllString(cmd.U, 1)
if len(hosts) == 0 {
- host = u
+ host = cmd.U
} else {
host = hosts[0]
}
//抓取的域名优先排序
- if s != "" {
- resultUrl = SelectSort(resultUrl)
- resultJs = SelectSort(resultJs)
+ if cmd.S != "" {
+ ResultUrl = util.SelectSort(ResultUrl)
+ ResultJs = util.SelectSort(ResultJs)
}
- resultJsHost, resultJsOther := urlDispose(resultJs, host, getHost(u))
- resultUrlHost, resultUrlOther := urlDispose(resultUrl, host, getHost(u))
+ ResultJsHost, ResultJsOther := util.UrlDispose(ResultJs, host, util.GetHost(cmd.U))
+ ResultUrlHost, ResultUrlOther := util.UrlDispose(ResultUrl, host, util.GetHost(cmd.U))
+ Domains = util.GetDomains(util.MergeArray(ResultJs, ResultUrl))
//输出到文件
if strings.Contains(host, ":") {
host = strings.Replace(host, ":", ":", -1)
}
//在当前文件夹创建文件夹
- err := os.MkdirAll(o+"/"+host, 0644)
+ err := os.MkdirAll(cmd.O+"/"+host, 0644)
if err != nil {
- fmt.Printf(o+"/"+host+" 目录创建失败 :%s", err)
+ fmt.Printf(cmd.O+"/"+host+" 目录创建失败 :%s", err)
return
}
//多相同url处理
- fileName := o + "/" + host + "/" + host + ".csv"
- for fileNum := 1; exists(fileName); fileNum++ {
- fileName = o + "/" + host + "/" + host + "(" + strconv.Itoa(fileNum) + ").csv"
+ fileName := cmd.O + "/" + host + "/" + host + ".csv"
+ for fileNum := 1; util.Exists(fileName); fileNum++ {
+ fileName = cmd.O + "/" + host + "/" + host + "(" + strconv.Itoa(fileNum) + ").csv"
}
file, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY, os.ModePerm)
@@ -102,121 +126,127 @@ func outFileCsv() {
defer file.Close()
writer := bufio.NewWriter(file)
- if s == "" {
+ if cmd.S == "" {
writer.WriteString("url,Source\n")
} else {
writer.WriteString("url,Status,Size,Title,Source\n")
}
- if d == "" {
- writer.WriteString(strconv.Itoa(len(resultJsHost)) + " JS to " + getHost(u) + "\n")
+ if cmd.D == "" {
+ writer.WriteString(strconv.Itoa(len(ResultJsHost)) + " JS to " + util.GetHost(cmd.U) + "\n")
} else {
- writer.WriteString(strconv.Itoa(len(resultJsHost)+len(resultJsOther)) + " JS to " + d + "\n")
+ writer.WriteString(strconv.Itoa(len(ResultJsHost)+len(ResultJsOther)) + " JS to " + cmd.D + "\n")
}
- for _, j := range resultJsHost {
- if s != "" {
+ for _, j := range ResultJsHost {
+ if cmd.S != "" {
writer.WriteString(fmt.Sprintf("\"%s\",\"%s\",\"%s\",,\"%s\"\n", j.Url, j.Status, j.Size, j.Source))
} else {
writer.WriteString(fmt.Sprintf("\"%s\",\"%s\"\n", j.Url, j.Source))
}
}
- if d == "" {
- writer.WriteString("\n" + strconv.Itoa(len(resultJsOther)) + " JS to Other\n")
+ if cmd.D == "" {
+ writer.WriteString("\n" + strconv.Itoa(len(ResultJsOther)) + " JS to Other\n")
}
- for _, j := range resultJsOther {
- if s != "" {
+ for _, j := range ResultJsOther {
+ if cmd.S != "" {
writer.WriteString(fmt.Sprintf("\"%s\",\"%s\",\"%s\",,\"%s\"\n", j.Url, j.Status, j.Size, j.Source))
} else {
writer.WriteString(fmt.Sprintf("\"%s\",\"%s\"\n", j.Url, j.Source))
}
}
writer.WriteString("\n\n")
- if d == "" {
- writer.WriteString(strconv.Itoa(len(resultUrlHost)) + " URL to " + getHost(u) + "\n")
+ if cmd.D == "" {
+ writer.WriteString(strconv.Itoa(len(ResultUrlHost)) + " URL to " + util.GetHost(cmd.U) + "\n")
} else {
- writer.WriteString(strconv.Itoa(len(resultUrlHost)+len(resultUrlOther)) + " URL to " + d + "\n")
+ writer.WriteString(strconv.Itoa(len(ResultUrlHost)+len(ResultUrlOther)) + " URL to " + cmd.D + "\n")
}
- for _, u := range resultUrlHost {
- if s != "" {
+ for _, u := range ResultUrlHost {
+ if cmd.S != "" {
writer.WriteString(fmt.Sprintf("\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n", u.Url, u.Status, u.Size, u.Title, u.Source))
} else {
writer.WriteString(fmt.Sprintf("\"%s\",\"%s\",\n", u.Url, u.Source))
}
}
- if d == "" {
- writer.WriteString("\n" + strconv.Itoa(len(resultUrlOther)) + " URL to Other\n")
+ if cmd.D == "" {
+ writer.WriteString("\n" + strconv.Itoa(len(ResultUrlOther)) + " URL to Other\n")
}
- for _, u := range resultUrlOther {
- if s != "" {
+ for _, u := range ResultUrlOther {
+ if cmd.S != "" {
writer.WriteString(fmt.Sprintf("\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n", u.Url, u.Status, u.Size, u.Title, u.Source))
} else {
writer.WriteString(fmt.Sprintf("\"%s\",\"%s\"\n", u.Url, u.Source))
}
}
- if s != "" && z != 0 {
- writer.WriteString("\n" + strconv.Itoa(len(fuzzs)) + " URL to Fuzz\n")
- fuzzs = SelectSort(fuzzs)
- for _, u := range fuzzs {
+ if cmd.S != "" && cmd.Z != 0 {
+ writer.WriteString("\n" + strconv.Itoa(len(Fuzzs)) + " URL to Fuzz\n")
+ Fuzzs = util.SelectSort(Fuzzs)
+ for _, u := range Fuzzs {
writer.WriteString(fmt.Sprintf("\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n", u.Url, u.Status, u.Size, u.Title, "Fuzz"))
}
}
+ writer.WriteString("\n" + strconv.Itoa(len(Domains)) + " Domain\n")
+ for _, u := range Domains {
+ writer.WriteString(fmt.Sprintf("\"%s\"\n", u))
+ }
+
writer.WriteString("\n Phone \n")
- for i := range infos {
- for i2 := range infos[i].Phone {
- writer.WriteString(fmt.Sprintf("\"%s\",\"%s\"\n", infos[i].Phone[i2], infos[i].Source))
+ for i := range Infos {
+ for i2 := range Infos[i].Phone {
+ writer.WriteString(fmt.Sprintf("\"%s\",\"%s\"\n", Infos[i].Phone[i2], Infos[i].Source))
}
}
writer.WriteString("\n Email \n")
- for i := range infos {
- for i2 := range infos[i].Email {
- writer.WriteString(fmt.Sprintf("\"%s\",\"%s\"\n", infos[i].Email[i2], infos[i].Source))
+ for i := range Infos {
+ for i2 := range Infos[i].Email {
+ writer.WriteString(fmt.Sprintf("\"%s\",\"%s\"\n", Infos[i].Email[i2], Infos[i].Source))
}
}
writer.WriteString("\n IDcard \n")
- for i := range infos {
- for i2 := range infos[i].IDcard {
- writer.WriteString(fmt.Sprintf("\"%s\",\"%s\"\n", infos[i].IDcard[i2], infos[i].Source))
+ for i := range Infos {
+ for i2 := range Infos[i].IDcard {
+ writer.WriteString(fmt.Sprintf("\"%s\",\"%s\"\n", Infos[i].IDcard[i2], Infos[i].Source))
}
}
writer.WriteString("\n JWT \n")
- for i := range infos {
- for i2 := range infos[i].JWT {
- writer.WriteString(fmt.Sprintf("\"%s\",\"%s\"\n", infos[i].JWT[i2], infos[i].Source))
+ for i := range Infos {
+ for i2 := range Infos[i].JWT {
+ writer.WriteString(fmt.Sprintf("\"%s\",\"%s\"\n", Infos[i].JWT[i2], Infos[i].Source))
}
}
writer.Flush() //内容是先写到缓存对,所以需要调用flush将缓存对数据真正写到文件中
- fmt.Println(strconv.Itoa(len(resultJsHost)+len(resultJsOther))+"JS + "+strconv.Itoa(len(resultUrlHost)+len(resultUrlOther))+"URL --> ", file.Name())
+ fmt.Println(strconv.Itoa(len(ResultJsHost)+len(ResultJsOther))+"JS + "+strconv.Itoa(len(ResultUrlHost)+len(ResultUrlOther))+"URL --> ", file.Name())
return
}
// 导出json
-func outFileJson() {
- addSource()
+func OutFileJson() {
jsons := make(map[string]interface{})
var info map[string][]map[string]string
//获取域名
var host string
re := regexp.MustCompile("([a-z0-9\\-]+\\.)*([a-z0-9\\-]+\\.[a-z0-9\\-]+)(:[0-9]+)?")
- hosts := re.FindAllString(u, 1)
+ hosts := re.FindAllString(cmd.U, 1)
if len(hosts) == 0 {
- host = u
+ host = cmd.U
} else {
host = hosts[0]
}
//抓取的域名优先排序
- if s != "" {
- resultUrl = SelectSort(resultUrl)
- resultJs = SelectSort(resultJs)
+ if cmd.S != "" {
+ ResultUrl = util.SelectSort(ResultUrl)
+ ResultJs = util.SelectSort(ResultJs)
}
- resultJsHost, resultJsOther := urlDispose(resultJs, host, getHost(u))
- resultUrlHost, resultUrlOther := urlDispose(resultUrl, host, getHost(u))
- if len(infos) > 0 {
+ ResultJsHost, ResultJsOther := util.UrlDispose(ResultJs, host, util.GetHost(cmd.U))
+ ResultUrlHost, ResultUrlOther := util.UrlDispose(ResultUrl, host, util.GetHost(cmd.U))
+ Domains = util.GetDomains(util.MergeArray(ResultJs, ResultUrl))
+
+ if len(Infos) > 0 {
info = make(map[string][]map[string]string)
info["IDcard"] = nil
info["JWT"] = nil
@@ -224,18 +254,18 @@ func outFileJson() {
info["Phone"] = nil
}
- for i := range infos {
- for i2 := range infos[i].IDcard {
- info["IDcard"] = append(info["IDcard"], map[string]string{"IDcard": infos[i].JWT[i2], "Source": infos[i].Source})
+ for i := range Infos {
+ for i2 := range Infos[i].IDcard {
+ info["IDcard"] = append(info["IDcard"], map[string]string{"IDcard": Infos[i].JWT[i2], "Source": Infos[i].Source})
}
- for i2 := range infos[i].JWT {
- info["JWT"] = append(info["JWT"], map[string]string{"JWT": infos[i].JWT[i2], "Source": infos[i].Source})
+ for i2 := range Infos[i].JWT {
+ info["JWT"] = append(info["JWT"], map[string]string{"JWT": Infos[i].JWT[i2], "Source": Infos[i].Source})
}
- for i2 := range infos[i].Email {
- info["Email"] = append(info["Email"], map[string]string{"Email": infos[i].Email[i2], "Source": infos[i].Source})
+ for i2 := range Infos[i].Email {
+ info["Email"] = append(info["Email"], map[string]string{"Email": Infos[i].Email[i2], "Source": Infos[i].Source})
}
- for i2 := range infos[i].Phone {
- info["Phone"] = append(info["Phone"], map[string]string{"Phone": infos[i].Phone[i2], "Source": infos[i].Source})
+ for i2 := range Infos[i].Phone {
+ info["Phone"] = append(info["Phone"], map[string]string{"Phone": Infos[i].Phone[i2], "Source": Infos[i].Source})
}
}
@@ -244,15 +274,15 @@ func outFileJson() {
host = strings.Replace(host, ":", ":", -1)
}
//在当前文件夹创建文件夹
- err := os.MkdirAll(o+"/"+host, 0644)
+ err := os.MkdirAll(cmd.O+"/"+host, 0644)
if err != nil {
- fmt.Printf(o+"/"+host+" 目录创建失败 :%s", err)
+ fmt.Printf(cmd.O+"/"+host+" 目录创建失败 :%s", err)
return
}
//多相同url处理
- fileName := o + "/" + host + "/" + host + ".json"
- for fileNum := 1; exists(fileName); fileNum++ {
- fileName = o + "/" + host + "/" + host + "(" + strconv.Itoa(fileNum) + ").json"
+ fileName := cmd.O + "/" + host + "/" + host + ".json"
+ for fileNum := 1; util.Exists(fileName); fileNum++ {
+ fileName = cmd.O + "/" + host + "/" + host + "(" + strconv.Itoa(fileNum) + ").json"
}
file, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY, 0644)
@@ -260,17 +290,18 @@ func outFileJson() {
log.Printf("创建失败:%s", err)
return
}
- if d == "" {
- jsons["jsOther"] = resultJsOther
- jsons["urlOther"] = resultUrlOther
+ if cmd.D == "" {
+ jsons["jsOther"] = ResultJsOther
+ jsons["urlOther"] = ResultUrlOther
}
- jsons["js"] = resultJsHost
- jsons["url"] = resultUrlHost
+ jsons["js"] = ResultJsHost
+ jsons["url"] = ResultUrlHost
jsons["info"] = info
- jsons["fuzz"] = fuzzs
- if s != "" && z != 0 {
- fuzzs = SelectSort(fuzzs)
- jsons["fuzz"] = fuzzs
+ jsons["fuzz"] = Fuzzs
+ jsons["domain"] = Domains
+ if cmd.S != "" && cmd.Z != 0 {
+ Fuzzs = util.SelectSort(Fuzzs)
+ jsons["fuzz"] = Fuzzs
}
defer file.Close()
@@ -288,44 +319,44 @@ func outFileJson() {
if err != nil {
log.Println("json保存失败:", err)
}
- fmt.Println(strconv.Itoa(len(resultJsHost)+len(resultJsOther))+"JS + "+strconv.Itoa(len(resultUrlHost)+len(resultUrlOther))+"URL --> ", file.Name())
+ fmt.Println(strconv.Itoa(len(ResultJsHost)+len(ResultJsOther))+"JS + "+strconv.Itoa(len(ResultUrlHost)+len(ResultUrlOther))+"URL --> ", file.Name())
return
}
// 导出html
-func outFileHtml() {
- addSource()
+func OutFileHtml() {
//获取域名
var host string
re := regexp.MustCompile("([a-z0-9\\-]+\\.)*([a-z0-9\\-]+\\.[a-z0-9\\-]+)(:[0-9]+)?")
- hosts := re.FindAllString(u, 1)
+ hosts := re.FindAllString(cmd.U, 1)
if len(hosts) == 0 {
- host = u
+ host = cmd.U
} else {
host = hosts[0]
}
//抓取的域名优先排序
- if s != "" {
- resultUrl = SelectSort(resultUrl)
- resultJs = SelectSort(resultJs)
+ if cmd.S != "" {
+ ResultUrl = util.SelectSort(ResultUrl)
+ ResultJs = util.SelectSort(ResultJs)
}
- resultJsHost, resultJsOther := urlDispose(resultJs, host, getHost(u))
- resultUrlHost, resultUrlOther := urlDispose(resultUrl, host, getHost(u))
+ ResultJsHost, ResultJsOther := util.UrlDispose(ResultJs, host, util.GetHost(cmd.U))
+ ResultUrlHost, ResultUrlOther := util.UrlDispose(ResultUrl, host, util.GetHost(cmd.U))
+ Domains = util.GetDomains(util.MergeArray(ResultJs, ResultUrl))
//输出到文件
if strings.Contains(host, ":") {
host = strings.Replace(host, ":", ":", -1)
}
//在当前文件夹创建文件夹
- err := os.MkdirAll(o+"/"+host, 0644)
+ err := os.MkdirAll(cmd.O+"/"+host, 0644)
if err != nil {
- fmt.Printf(o+"/"+host+" 目录创建失败 :%s", err)
+ fmt.Printf(cmd.O+"/"+host+" 目录创建失败 :%s", err)
return
}
//多相同url处理
- fileName := o + "/" + host + "/" + host + ".html"
- for fileNum := 1; exists(fileName); fileNum++ {
- fileName = o + "/" + host + "/" + host + "(" + strconv.Itoa(fileNum) + ").html"
+ fileName := cmd.O + "/" + host + "/" + host + ".html"
+ for fileNum := 1; util.Exists(fileName); fileNum++ {
+ fileName = cmd.O + "/" + host + "/" + host + "(" + strconv.Itoa(fileNum) + ").html"
}
file, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY, os.ModePerm)
@@ -339,116 +370,122 @@ func outFileHtml() {
writer := bufio.NewWriter(file)
- if d == "" {
- html = strings.Replace(html, "{urlHost}", getHost(u), -1)
+ if cmd.D == "" {
+ html = strings.Replace(html, "{urlHost}", util.GetHost(cmd.U), -1)
} else {
- html = strings.Replace(html, "{urlHost}", d, -1)
+ html = strings.Replace(html, "{urlHost}", cmd.D, -1)
}
- var resultJsHostStr string
- for _, j := range resultJsHost {
- resultJsHostStr += outHtmlString(j)
+ var ResultJsHostStr string
+ for _, j := range ResultJsHost {
+ ResultJsHostStr += outHtmlString(j)
}
- html = strings.Replace(html, "{JS}", resultJsHostStr, -1)
+ html = strings.Replace(html, "{JS}", ResultJsHostStr, -1)
- var resultJsOtherStr string
- for _, j := range resultJsOther {
- resultJsOtherStr += outHtmlString(j)
+ var ResultJsOtherStr string
+ for _, j := range ResultJsOther {
+ ResultJsOtherStr += outHtmlString(j)
}
- html = strings.Replace(html, "{JSOther}", resultJsOtherStr, -1)
+ html = strings.Replace(html, "{JSOther}", ResultJsOtherStr, -1)
- var resultUrlHostStr string
- for _, u := range resultUrlHost {
- resultUrlHostStr += outHtmlString(u)
+ var ResultUrlHostStr string
+ for _, u := range ResultUrlHost {
+ ResultUrlHostStr += outHtmlString(u)
}
- html = strings.Replace(html, "{URL}", resultUrlHostStr, -1)
+ html = strings.Replace(html, "{URL}", ResultUrlHostStr, -1)
- var resultUrlOtherStr string
- for _, u := range resultUrlOther {
- resultUrlOtherStr += outHtmlString(u)
+ var ResultUrlOtherStr string
+ for _, u := range ResultUrlOther {
+ ResultUrlOtherStr += outHtmlString(u)
}
- html = strings.Replace(html, "{URLOther}", resultUrlOtherStr, -1)
+ html = strings.Replace(html, "{URLOther}", ResultUrlOtherStr, -1)
- var fuzzsStr string
- if s != "" && z != 0 {
- fuzzs = SelectSort(fuzzs)
- for _, u := range fuzzs {
- fuzzsStr += outHtmlString(u)
+ var FuzzsStr string
+ if cmd.S != "" && cmd.Z != 0 {
+ Fuzzs = util.SelectSort(Fuzzs)
+ for _, u := range Fuzzs {
+ FuzzsStr += outHtmlString(u)
}
}
- html = strings.Replace(html, "{Fuzz}", fuzzsStr, -1)
+ html = strings.Replace(html, "{Fuzz}", FuzzsStr, -1)
- var infoStr string
- for i := range infos {
- for i2 := range infos[i].Phone {
- infoStr += outHtmlInfoString("Phone", infos[i].Phone[i2], infos[i].Source)
+ var DomainsStr string
+ for _, u := range Domains {
+ DomainsStr += outHtmlDomainString(u)
+ }
+ html = strings.Replace(html, "{Domains}", DomainsStr, -1)
+
+ var Infostr string
+ for i := range Infos {
+ for i2 := range Infos[i].Phone {
+ Infostr += outHtmlInfoString("Phone", Infos[i].Phone[i2], Infos[i].Source)
}
}
- for i := range infos {
- for i2 := range infos[i].Email {
- infoStr += outHtmlInfoString("Email", infos[i].Email[i2], infos[i].Source)
+ for i := range Infos {
+ for i2 := range Infos[i].Email {
+ Infostr += outHtmlInfoString("Email", Infos[i].Email[i2], Infos[i].Source)
}
}
- for i := range infos {
- for i2 := range infos[i].IDcard {
- infoStr += outHtmlInfoString("IDcard", infos[i].IDcard[i2], infos[i].Source)
+ for i := range Infos {
+ for i2 := range Infos[i].IDcard {
+ Infostr += outHtmlInfoString("IDcard", Infos[i].IDcard[i2], Infos[i].Source)
}
}
- for i := range infos {
- for i2 := range infos[i].JWT {
- infoStr += outHtmlInfoString("JWT", infos[i].JWT[i2], infos[i].Source)
+ for i := range Infos {
+ for i2 := range Infos[i].JWT {
+ Infostr += outHtmlInfoString("JWT", Infos[i].JWT[i2], Infos[i].Source)
}
}
- html = strings.Replace(html, "{Info}", infoStr, -1)
+ html = strings.Replace(html, "{Info}", Infostr, -1)
writer.WriteString(html)
writer.Flush() //内容是先写到缓存对,所以需要调用flush将缓存对数据真正写到文件中
- fmt.Println(strconv.Itoa(len(resultJsHost)+len(resultJsOther))+"JS + "+strconv.Itoa(len(resultUrlHost)+len(resultUrlOther))+"URL --> ", file.Name())
+ fmt.Println(strconv.Itoa(len(ResultJsHost)+len(ResultJsOther))+"JS + "+strconv.Itoa(len(ResultUrlHost)+len(ResultUrlOther))+"URL --> ", file.Name())
return
}
// 打印
-func print() {
+func Print() {
//获取域名
var host string
re := regexp.MustCompile("([a-z0-9\\-]+\\.)*([a-z0-9\\-]+\\.[a-z0-9\\-]+)(:[0-9]+)?")
- hosts := re.FindAllString(u, 1)
+ hosts := re.FindAllString(cmd.U, 1)
if len(hosts) == 0 {
- host = u
+ host = cmd.U
} else {
host = hosts[0]
}
//打印JS
- if s != "" {
- resultJs = SelectSort(resultJs)
- resultUrl = SelectSort(resultUrl)
+ if cmd.S != "" {
+ ResultJs = util.SelectSort(ResultJs)
+ ResultUrl = util.SelectSort(ResultUrl)
}
//抓取的域名优先排序
- resultJsHost, resultJsOther := urlDispose(resultJs, host, getHost(u))
- resultUrlHost, resultUrlOther := urlDispose(resultUrl, host, getHost(u))
-
+ ResultJsHost, ResultJsOther := util.UrlDispose(ResultJs, host, util.GetHost(cmd.U))
+ ResultUrlHost, ResultUrlOther := util.UrlDispose(ResultUrl, host, util.GetHost(cmd.U))
+ Domains = util.GetDomains(util.MergeArray(ResultJs, ResultUrl))
var ulen string
- if len(resultUrl) != 0 {
+ if len(ResultUrl) != 0 {
uleni := 0
- for _, u := range resultUrl {
+ for _, u := range ResultUrl {
uleni += len(u.Url)
}
- ulen = strconv.Itoa(uleni/len(resultUrl) + 10)
+ ulen = strconv.Itoa(uleni/len(ResultUrl) + 10)
}
var jlen string
- if len(resultJs) != 0 {
+ if len(ResultJs) != 0 {
jleni := 0
- for _, j := range resultJs {
+ for _, j := range ResultJs {
jleni += len(j.Url)
}
- jlen = strconv.Itoa(jleni/len(resultJs) + 10)
+ jlen = strconv.Itoa(jleni/len(ResultJs) + 10)
}
- if d == "" {
- fmt.Println(strconv.Itoa(len(resultJsHost)) + " JS to " + getHost(u))
+ if cmd.D == "" {
+ fmt.Println(strconv.Itoa(len(ResultJsHost)) + " JS to " + util.GetHost(cmd.U))
} else {
- fmt.Println(strconv.Itoa(len(resultJsHost)+len(resultJsOther)) + " JS to " + d)
+ fmt.Println(strconv.Itoa(len(ResultJsHost)+len(ResultJsOther)) + " JS to " + cmd.D)
}
- for _, j := range resultJsHost {
- if s != "" {
+ for _, j := range ResultJsHost {
+ if cmd.S != "" {
if strings.HasPrefix(j.Status, "2") {
fmt.Printf(color.LightBlue.Sprintf("%-"+jlen+"s", j.Url) + color.LightGreen.Sprintf(" [ Status: %s, Size: %s ]\n", j.Status, j.Size))
} else if strings.HasPrefix(j.Status, "3") {
@@ -456,15 +493,15 @@ func print() {
} else {
fmt.Printf(color.LightBlue.Sprintf("%-"+jlen+"s", j.Url) + color.LightRed.Sprintf(" [ Status: %s, Size: %s ]\n", j.Status, j.Size))
}
- } else if s == "" {
+ } else if cmd.S == "" {
fmt.Printf(color.LightBlue.Sprintf(j.Url) + "\n")
}
}
- if d == "" {
- fmt.Println("\n" + strconv.Itoa(len(resultJsOther)) + " JS to Other")
+ if cmd.D == "" {
+ fmt.Println("\n" + strconv.Itoa(len(ResultJsOther)) + " JS to Other")
}
- for _, j := range resultJsOther {
- if s != "" {
+ for _, j := range ResultJsOther {
+ if cmd.S != "" {
if strings.HasPrefix(j.Status, "2") {
fmt.Printf(color.LightBlue.Sprintf("%-"+jlen+"s", j.Url) + color.LightGreen.Sprintf(" [ Status: %s, Size: %s ]\n", j.Status, j.Size))
} else if strings.HasPrefix(j.Status, "3") {
@@ -477,17 +514,16 @@ func print() {
}
}
- //打印URL
- fmt.Println("\n\n")
+ fmt.Println("\n ")
- if d == "" {
- fmt.Println(strconv.Itoa(len(resultUrlHost)) + " URL to " + getHost(u))
+ if cmd.D == "" {
+ fmt.Println(strconv.Itoa(len(ResultUrlHost)) + " URL to " + util.GetHost(cmd.U))
} else {
- fmt.Println(strconv.Itoa(len(resultUrlHost)+len(resultUrlOther)) + " URL to " + d)
+ fmt.Println(strconv.Itoa(len(ResultUrlHost)+len(ResultUrlOther)) + " URL to " + cmd.D)
}
- for _, u := range resultUrlHost {
- if s != "" && len(u.Title) != 0 {
+ for _, u := range ResultUrlHost {
+ if cmd.S != "" && len(u.Title) != 0 {
if u.Status == "疑似危险路由" {
fmt.Printf(color.LightBlue.Sprintf("%-"+ulen+"s", u.Url) + color.LightGreen.Sprintf(" [ %s ]\n", u.Status))
} else if strings.HasPrefix(u.Status, "2") {
@@ -497,7 +533,7 @@ func print() {
} else {
fmt.Printf(color.LightBlue.Sprintf("%-"+ulen+"s", u.Url) + color.LightRed.Sprintf(" [ Status: %s, Size: %s, Title: %s ]\n", u.Status, u.Size, u.Title))
}
- } else if s != "" {
+ } else if cmd.S != "" {
if strings.HasPrefix(u.Status, "2") {
fmt.Printf(color.LightBlue.Sprintf("%-"+ulen+"s", u.Url) + color.LightGreen.Sprintf(" [ Status: %s, Size: %s ]\n", u.Status, u.Size))
} else if strings.HasPrefix(u.Status, "3") {
@@ -509,11 +545,11 @@ func print() {
fmt.Printf(color.LightBlue.Sprintf(u.Url) + "\n")
}
}
- if d == "" {
- fmt.Println("\n" + strconv.Itoa(len(resultUrlOther)) + " URL to Other")
+ if cmd.D == "" {
+ fmt.Println("\n" + strconv.Itoa(len(ResultUrlOther)) + " URL to Other")
}
- for _, u := range resultUrlOther {
- if s != "" && len(u.Title) != 0 {
+ for _, u := range ResultUrlOther {
+ if cmd.S != "" && len(u.Title) != 0 {
if u.Status == "疑似危险路由" {
fmt.Printf(color.LightBlue.Sprintf("%-"+ulen+"s", u.Url) + color.LightGreen.Sprintf(" [ %s ]\n", u.Status))
} else if strings.HasPrefix(u.Status, "2") {
@@ -523,7 +559,7 @@ func print() {
} else {
fmt.Printf(color.LightBlue.Sprintf("%-"+ulen+"s", u.Url) + color.LightRed.Sprintf(" [ Status: %s, Size: %s, Title: %s ]\n", u.Status, u.Size, u.Title))
}
- } else if s != "" {
+ } else if cmd.S != "" {
if strings.HasPrefix(u.Status, "2") {
fmt.Printf(color.LightBlue.Sprintf("%-"+ulen+"s", u.Url) + color.LightGreen.Sprintf(" [ Status: %s, Size: %s ]\n", u.Status, u.Size))
} else if strings.HasPrefix(u.Status, "3") {
@@ -536,10 +572,10 @@ func print() {
}
}
- if s != "" && z != 0 {
- fmt.Println("\n" + strconv.Itoa(len(fuzzs)) + " URL to Fuzz")
- fuzzs = SelectSort(fuzzs)
- for _, u := range fuzzs {
+ if cmd.S != "" && cmd.Z != 0 {
+ fmt.Println("\n" + strconv.Itoa(len(Fuzzs)) + " URL to Fuzz")
+ Fuzzs = util.SelectSort(Fuzzs)
+ for _, u := range Fuzzs {
if len(u.Title) != 0 {
if u.Status == "疑似危险路由" {
fmt.Printf(color.LightBlue.Sprintf("%-"+ulen+"s", u.Url) + color.LightGreen.Sprintf(" [ %s ]\n", u.Status))
@@ -561,29 +597,38 @@ func print() {
}
}
}
- fmt.Println("\n Phone ")
- for i := range infos {
- for i2 := range infos[i].Phone {
- fmt.Printf(color.LightBlue.Sprintf("%-10s", infos[i].Phone[i2]) + color.LightGreen.Sprintf(" [ %s ]\n", infos[i].Source))
- }
+ fmt.Println("\n" + strconv.Itoa(len(Domains)) + " Domain")
+ for _, u := range Domains {
+ fmt.Printf(color.LightBlue.Sprintf("%s \n", u))
+
}
- fmt.Println("\n Email ")
- for i := range infos {
- for i2 := range infos[i].Email {
- fmt.Printf(color.LightBlue.Sprintf("%-10s", infos[i].Email[i2]))
+
+ if len(Infos) > 0 {
+ fmt.Println("\n Phone ")
+ for i := range Infos {
+ for i2 := range Infos[i].Phone {
+ fmt.Printf(color.LightBlue.Sprintf("%-10s", Infos[i].Phone[i2]) + color.LightGreen.Sprintf(" [ %s ]\n", Infos[i].Source))
+ }
}
- }
- fmt.Println("\n IDcard ")
- for i := range infos {
- for i2 := range infos[i].IDcard {
- fmt.Printf(color.LightBlue.Sprintf("%-10s", infos[i].IDcard[i2]))
+ fmt.Println("\n Email ")
+ for i := range Infos {
+ for i2 := range Infos[i].Email {
+ fmt.Printf(color.LightBlue.Sprintf("%-10s", Infos[i].Email[i2]) + color.LightGreen.Sprintf(" [ %s ]\n", Infos[i].Source))
+ }
}
- }
- fmt.Println("\n JWT ")
- for i := range infos {
- for i2 := range infos[i].JWT {
- fmt.Printf(color.LightBlue.Sprintf("%-10s", infos[i].JWT[i2]))
+ fmt.Println("\n IDcard ")
+ for i := range Infos {
+ for i2 := range Infos[i].IDcard {
+ fmt.Printf(color.LightBlue.Sprintf("%-10s", Infos[i].IDcard[i2]) + color.LightGreen.Sprintf(" [ %s ]\n", Infos[i].Source))
+ }
}
+ fmt.Println("\n JWT ")
+ for i := range Infos {
+ for i2 := range Infos[i].JWT {
+ fmt.Printf(color.LightBlue.Sprintf("%-10s", Infos[i].JWT[i2]) + color.LightGreen.Sprintf(" [ %s ]\n", Infos[i].Source))
+ }
+ }
+
}
}
diff --git a/src/config.yaml b/src/config.yaml
deleted file mode 100644
index 06acccd..0000000
--- a/src/config.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-headers:
- Accept: "*/*"
- Cookie: ""
- User-Agent: "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
-proxy: ""
-
-
-
-
-
diff --git a/src/crawler.go b/src/crawler.go
deleted file mode 100644
index 3728fa8..0000000
--- a/src/crawler.go
+++ /dev/null
@@ -1,593 +0,0 @@
-package main
-
-import (
- "crypto/tls"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "os"
- "regexp"
- "strconv"
- "strings"
- "time"
-)
-
-type config struct {
- Headers map[string]string `yaml:"headers"`
- Proxy string `yaml:"proxy"`
-}
-
-var (
- risks = []string{"remove", "delete", "insert", "update", "logout"}
- fuzzs = []Link{}
- fuzzNum int
-)
-var ua = "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
-
-var conf config
-
-// 蜘蛛抓取页面内容
-func spider(u string, num int) {
- var is bool
- fmt.Printf("\rSpider %d", progress)
- mux.Lock()
- progress++
- mux.Unlock()
- //标记完成
- defer func() {
- wg.Done()
- if !is {
- <-ch
- }
-
- }()
- u, _ = url.QueryUnescape(u)
- if num > 1 && d != "" && !strings.Contains(u, d) {
- return
- }
- if getEndUrl(u) {
- return
- }
- if m == 3 {
- for _, v := range risks {
- if strings.Contains(u, v) {
- return
- }
- }
- }
- appendEndUrl(u)
-
- tr := &http.Transport{
- TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
- }
-
- //配置代理
- if x != "" {
- proxyUrl, parseErr := url.Parse(conf.Proxy)
- if parseErr != nil {
- fmt.Println("代理地址错误: \n" + parseErr.Error())
- os.Exit(1)
- }
- tr.Proxy = http.ProxyURL(proxyUrl)
- }
- //加载yaml配置(proxy)
- if I {
- SetProxyConfig(tr)
- }
- client := &http.Client{Timeout: 10 * time.Second, Transport: tr}
- request, err := http.NewRequest("GET", u, nil)
- if err != nil {
- return
- }
- //增加header选项
- request.Header.Add("Cookie", c)
- request.Header.Add("User-Agent", ua)
- request.Header.Add("Accept", "*/*")
- //加载yaml配置(headers)
- if I {
- SetHeadersConfig(&request.Header)
- }
- //处理返回结果
- response, err := client.Do(request)
- if err != nil {
- return
- } else {
- defer response.Body.Close()
-
- }
-
- //提取url用于拼接其他url或js
- dataBytes, err := io.ReadAll(response.Body)
- if err != nil {
- return
- }
- path := response.Request.URL.Path
- host := response.Request.URL.Host
- scheme := response.Request.URL.Scheme
- source := scheme + "://" + host + path
-
- //字节数组 转换成 字符串
- result := string(dataBytes)
- //处理base标签
- re := regexp.MustCompile("base.{1,5}href.{1,5}(http.+?//[^\\s]+?)[\",',‘,“]")
- base := re.FindAllStringSubmatch(result, -1)
- if len(base) > 0 {
- host = regexp.MustCompile("http.*?//([^/]+)").FindAllStringSubmatch(base[0][1], -1)[0][1]
- scheme = regexp.MustCompile("(http.*?)://").FindAllStringSubmatch(base[0][1], -1)[0][1]
- paths := regexp.MustCompile("http.*?//.*?(/.*)").FindAllStringSubmatch(base[0][1], -1)
- if len(paths) > 0 {
- path = paths[0][1]
- } else {
- path = "/"
- }
- }
- <-ch
- is = true
-
- //提取js
- jsFind(result, host, scheme, path, source, num)
- //提取url
- urlFind(result, host, scheme, path, source, num)
- //提取信息
- infoFind(result, source)
-
-}
-
-// 分析内容中的js
-func jsFind(cont, host, scheme, path, source string, num int) {
- var cata string
- care := regexp.MustCompile("/.*/{1}|/")
- catae := care.FindAllString(path, -1)
- if len(catae) == 0 {
- cata = "/"
- } else {
- cata = catae[0]
- }
- //js匹配正则
- res := []string{
- ".(https{0,1}:[-a-zA-Z0-9()@:%_\\+.~#?&//=]{2,250}?[-a-zA-Z0-9()@:%_\\+.~#?&//=]{3}[.]js)",
- "[\",',‘,“]\\s{0,6}(/{0,1}[-a-zA-Z0-9()@:%_\\+.~#?&//=]{2,250}?[-a-zA-Z0-9()@:%_\\+.~#?&//=]{3}[.]js)",
- "=\\s{0,6}[\",',’,”]{0,1}\\s{0,6}(/{0,1}[-a-zA-Z0-9()@:%_\\+.~#?&//=]{2,250}?[-a-zA-Z0-9()@:%_\\+.~#?&//=]{3}[.]js)",
- }
- host = scheme + "://" + host
- for _, re := range res {
- reg := regexp.MustCompile(re)
- jss := reg.FindAllStringSubmatch(cont, -1)
- //return
- jss = jsFilter(jss)
- //循环提取js放到结果中
- for _, js := range jss {
- if js[0] == "" {
- continue
- }
- if strings.HasPrefix(js[0], "https:") || strings.HasPrefix(js[0], "http:") {
- appendJs(js[0], source)
- if num < 5 && (m == 2 || m == 3) {
- wg.Add(1)
- ch <- 1
- go spider(js[0], num+1)
- }
- } else if strings.HasPrefix(js[0], "//") {
- appendJs(scheme+":"+js[0], source)
- if num < 5 && (m == 2 || m == 3) {
- wg.Add(1)
- ch <- 1
- go spider(scheme+":"+js[0], num+1)
- }
-
- } else if strings.HasPrefix(js[0], "/") {
- appendJs(host+js[0], source)
- if num < 5 && (m == 2 || m == 3) {
- wg.Add(1)
- ch <- 1
- go spider(host+js[0], num+1)
- }
- } else if strings.HasPrefix(js[0], "./") {
- appendJs(host+"/"+js[0], source)
- if num < 5 && (m == 2 || m == 3) {
- wg.Add(1)
- ch <- 1
- go spider(host+"/"+js[0], num+1)
- }
- } else {
- appendJs(host+cata+js[0], source)
- if num < 5 && (m == 2 || m == 3) {
- wg.Add(1)
- ch <- 1
- go spider(host+cata+js[0], num+1)
- }
- }
- }
-
- }
-
-}
-
-// 分析内容中的url
-func urlFind(cont, host, scheme, path, source string, num int) {
- var cata string
- care := regexp.MustCompile("/.*/{1}|/")
- catae := care.FindAllString(path, -1)
- if len(catae) == 0 {
- cata = "/"
- } else {
- cata = catae[0]
- }
- host = scheme + "://" + host
-
- //url匹配正则
- res := []string{
- "[\",',‘,“]\\s{0,6}(https{0,1}:[-a-zA-Z0-9()@:%_\\+.~#?&//=]{2,250}?)\\s{0,6}[\",',‘,“]",
- "=\\s{0,6}(https{0,1}:[-a-zA-Z0-9()@:%_\\+.~#?&//=]{2,250})",
- "[\",',‘,“]\\s{0,6}([#,.]{0,2}/[-a-zA-Z0-9()@:%_\\+.~#?&//=]{2,250}?)\\s{0,6}[\",',‘,“]",
- "\"([-a-zA-Z0-9()@:%_\\+.~#?&//=]+?[/]{1}[-a-zA-Z0-9()@:%_\\+.~#?&//=]+?)\"",
- "href\\s{0,6}=\\s{0,6}[\",',‘,“]{0,1}\\s{0,6}([-a-zA-Z0-9()@:%_\\+.~#?&//=]{2,250})|action\\s{0,6}=\\s{0,6}[\",',‘,“]{0,1}\\s{0,6}([-a-zA-Z0-9()@:%_\\+.~#?&//=]{2,250})",
- }
- for _, re := range res {
- reg := regexp.MustCompile(re)
- urls := reg.FindAllStringSubmatch(cont, -1)
- //fmt.Println(urls)
- urls = urlFilter(urls)
-
- //循环提取url放到结果中
- for _, url := range urls {
- if url[0] == "" {
- continue
- }
- if strings.HasPrefix(url[0], "https:") || strings.HasPrefix(url[0], "http:") {
- appendUrl(url[0], source)
- if num < 2 && (m == 2 || m == 3) {
- wg.Add(1)
- ch <- 1
- go spider(url[0], num+1)
- }
- } else if strings.HasPrefix(url[0], "//") {
- appendUrl(scheme+":"+url[0], source)
- if num < 2 && (m == 2 || m == 3) {
- wg.Add(1)
- ch <- 1
- go spider(scheme+":"+url[0], num+1)
- }
- } else if strings.HasPrefix(url[0], "/") {
- urlz := ""
- if b != "" {
- urlz = b + url[0]
- } else {
- urlz = host + url[0]
- }
- appendUrl(urlz, source)
- if num < 2 && (m == 2 || m == 3) {
- wg.Add(1)
- ch <- 1
- go spider(urlz, num+1)
- }
- } else if !strings.HasSuffix(source, ".js") {
- urlz := ""
- if b != "" {
- if strings.HasSuffix(b, "/") {
- urlz = b + url[0]
- } else {
- urlz = b + "/" + url[0]
- }
- } else {
- urlz = host + cata + url[0]
- }
- appendUrl(urlz, source)
- if num < 2 && (m == 2 || m == 3) {
- wg.Add(1)
- ch <- 1
- go spider(urlz, num+1)
- }
- } else if strings.HasSuffix(source, ".js") {
- appendUrl(jsinurl[host+path]+url[0], source)
- if num < 2 && (m == 2 || m == 3) {
- wg.Add(1)
- ch <- 1
- go spider(jsinurl[host+path]+url[0], num+1)
- }
- }
- }
- }
-}
-
-// 分析内容中的敏感信息
-func infoFind(cont, source string) {
- //手机号码
- phone := "['\"](1(3([0-35-9]\\d|4[1-8])|4[14-9]\\d|5([\\d]\\d|7[1-79])|66\\d|7[2-35-8]\\d|8\\d{2}|9[89]\\d)\\d{7})['\"]"
- email := "['\"]([\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?)['\"]"
- IDcard := "['\"]((\\d{8}(0\\d|10|11|12)([0-2]\\d|30|31)\\d{3}$)|(\\d{6}(18|19|20)\\d{2}(0[1-9]|10|11|12)([0-2]\\d|30|31)\\d{3}(\\d|X|x)))['\"]"
- jwt := "['\"](ey[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9._-]{10,}|ey[A-Za-z0-9_\\/+-]{10,}\\.[A-Za-z0-9._\\/+-]{10,})['\"]"
- phones := regexp.MustCompile(phone).FindAllStringSubmatch(cont, -1)
- emails := regexp.MustCompile(email).FindAllStringSubmatch(cont, -1)
- IDcards := regexp.MustCompile(IDcard).FindAllStringSubmatch(cont, -1)
- jwts := regexp.MustCompile(jwt).FindAllStringSubmatch(cont, -1)
- info := Info{}
- for i := range phones {
- info.Phone = append(info.Phone, phones[i][1])
- }
- for i := range emails {
- info.Email = append(info.Email, emails[i][1])
- }
- for i := range IDcards {
- info.IDcard = append(info.IDcard, IDcards[i][1])
- }
- for i := range jwts {
- info.JWT = append(info.JWT, jwts[i][1])
- }
- info.Source = source
- if len(info.Phone) != 0 || len(info.IDcard) != 0 || len(info.JWT) != 0 || len(info.Email) != 0 {
- appendInfo(info)
- }
-
-}
-
-// 过滤JS
-func jsFilter(str [][]string) [][]string {
-
- //对不需要的数据过滤
- for i := range str {
- str[i][0], _ = url.QueryUnescape(str[i][1])
- str[i][0] = strings.Replace(str[i][0], " ", "", -1)
- str[i][0] = strings.Replace(str[i][0], "\\/", "/", -1)
- str[i][0] = strings.Replace(str[i][0], "%3A", ":", -1)
- str[i][0] = strings.Replace(str[i][0], "%2F", "/", -1)
-
- match, _ := regexp.MatchString("[.]js", str[i][0])
- if !match {
- str[i][0] = ""
- }
- //过滤指定字段
- fstr := []string{"www.w3.org", "example.com", "github.com"}
- for _, v := range fstr {
- if strings.Contains(str[i][0], v) {
- str[i][0] = ""
- }
- }
-
- }
- return str
-
-}
-
-// jsfuzz
-func jsFuzz() {
- jsFuzzFile := []string{
- "login.js",
- "app.js",
- "main.js",
- "config.js",
- "admin.js",
- "info.js",
- "open.js",
- "user.js",
- "input.js",
- "list.js",
- "upload.js"}
- paths := []string{}
- for i := range resultJs {
- re := regexp.MustCompile("(.+/)[^/]+.js").FindAllStringSubmatch(resultJs[i].Url, -1)
- if len(re) != 0 {
- paths = append(paths, re[0][1])
- }
- }
- paths = uniqueArr(paths)
- for i := range paths {
- for i2 := range jsFuzzFile {
- resultJs = append(resultJs, Link{
- Url: paths[i] + jsFuzzFile[i2],
- Source: "Fuzz",
- })
- }
- }
-}
-
-// 过滤URL
-func urlFilter(str [][]string) [][]string {
-
- //对不需要的数据过滤
- for i := range str {
- str[i][0], _ = url.QueryUnescape(str[i][1])
- str[i][0] = strings.Replace(str[i][0], " ", "", -1)
- str[i][0] = strings.Replace(str[i][0], "\\/", "/", -1)
- str[i][0] = strings.Replace(str[i][0], "%3A", ":", -1)
- str[i][0] = strings.Replace(str[i][0], "%2F", "/", -1)
-
- //过滤包含指定内容
- fstr := []string{".js?", ".css?", ".jpeg?", ".jpg?", ".png?", ".gif?", "github.com", "www.w3.org", "example.com", "<", ">", "{", "}", "[", "]", "|", "^", ";", "/js/", ".src", ".replace", ".url", ".att", ".href", "location.href", "javascript:", "location:", ".createObject", ":location", ".path", "*#__PURE__*", "*$0*", "\\n"}
- for _, v := range fstr {
- if strings.Contains(str[i][0], v) {
- str[i][0] = ""
- }
- }
-
- match, _ := regexp.MatchString("[a-zA-Z]+|[0-9]+", str[i][0])
- if !match {
- str[i][0] = ""
- }
- //过滤指定后缀
- zstr := []string{".js", ".css", ".scss", ",", ".jpeg", ".jpg", ".png", ".gif", ".ico", ".svg", ".vue", ".ts"}
-
- for _, v := range zstr {
- if strings.HasSuffix(str[i][0], v) {
- str[i][0] = ""
- }
- }
- //对抓到的域名做处理
- re := regexp.MustCompile("([a-z0-9\\-]+\\.)+([a-z0-9\\-]+\\.[a-z0-9\\-]+)(:[0-9]+)?").FindAllString(str[i][0], 1)
- if len(re) != 0 && !strings.HasPrefix(str[i][0], "http") && !strings.HasPrefix(str[i][0], "/") {
- str[i][0] = "http://" + str[i][0]
- }
-
- }
- return str
-}
-
-// 检测js访问状态码
-func jsState(u string, i int, sou string) {
- defer func() {
- wg.Done()
- <-jsch
- printProgress()
- }()
- if s == "" {
- resultJs[i].Url = u
- return
- }
- if m == 3 {
- for _, v := range risks {
- if strings.Contains(u, v) {
- resultJs[i] = Link{Url: u, Status: "疑似危险路由"}
- return
- }
- }
- }
-
- tr := &http.Transport{
- TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
- }
- //配置代理
- //配置代理
- if x != "" {
- proxyUrl, parseErr := url.Parse(conf.Proxy)
- if parseErr != nil {
- fmt.Println("代理地址错误: \n" + parseErr.Error())
- os.Exit(1)
- }
- tr.Proxy = http.ProxyURL(proxyUrl)
- }
- //加载yaml配置(proxy)
- if I {
- SetProxyConfig(tr)
- }
- client := &http.Client{Timeout: 15 * time.Second, Transport: tr}
- request, err := http.NewRequest("GET", u, nil)
- if err != nil {
- resultJs[i].Url = ""
- return
- }
-
- //增加header选项
- request.Header.Add("Cookie", c)
- request.Header.Add("User-Agent", ua)
- request.Header.Add("Accept", "*/*")
- //加载yaml配置
- if I {
- SetHeadersConfig(&request.Header)
- }
-
- //处理返回结果
- response, err := client.Do(request)
- if err != nil {
- if strings.Contains(err.Error(), "Client.Timeout") && s == "" {
- resultJs[i] = Link{Url: u, Status: "timeout", Size: "0"}
-
- } else {
- resultJs[i].Url = ""
- }
- return
- } else {
- defer response.Body.Close()
- }
-
- code := response.StatusCode
- if strings.Contains(s, strconv.Itoa(code)) || s == "all" && (sou != "Fuzz" && code == 200) {
- var length int
- dataBytes, err := io.ReadAll(response.Body)
- if err != nil {
- length = 0
- } else {
- length = len(dataBytes)
- }
- resultJs[i] = Link{Url: u, Status: strconv.Itoa(code), Size: strconv.Itoa(length)}
- } else {
- resultJs[i].Url = ""
- }
-}
-
-// 检测url访问状态码
-func urlState(u string, i int) {
-
- defer func() {
- wg.Done()
- <-urlch
- printProgress()
- }()
- if s == "" {
- resultUrl[i].Url = u
- return
- }
- if m == 3 {
- for _, v := range risks {
- if strings.Contains(u, v) {
- resultUrl[i] = Link{Url: u, Status: "0", Size: "0", Title: "疑似危险路由,已跳过验证"}
- return
- }
- }
- }
-
- tr := &http.Transport{
- TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
- }
- //配置代理
- if x != "" {
- proxyUrl, parseErr := url.Parse(conf.Proxy)
- if parseErr != nil {
- fmt.Println("代理地址错误: \n" + parseErr.Error())
- os.Exit(1)
- }
- tr.Proxy = http.ProxyURL(proxyUrl)
- }
- //加载yaml配置(proxy)
- if I {
- SetProxyConfig(tr)
- }
- client := &http.Client{Timeout: 15 * time.Second, Transport: tr}
- request, err := http.NewRequest("GET", u, nil)
- if err != nil {
- resultUrl[i].Url = ""
- return
- }
- //增加header选项
- request.Header.Add("Cookie", c)
- request.Header.Add("User-Agent", ua)
- request.Header.Add("Accept", "*/*")
- //加载yaml配置
- if I {
- SetHeadersConfig(&request.Header)
- }
- //处理返回结果
- response, err := client.Do(request)
-
- if err != nil {
- if strings.Contains(err.Error(), "Client.Timeout") && s == "all" {
- resultUrl[i] = Link{Url: u, Status: "timeout", Size: "0"}
- } else {
- resultUrl[i].Url = ""
- }
- return
- } else {
- defer response.Body.Close()
- }
-
- code := response.StatusCode
- if strings.Contains(s, strconv.Itoa(code)) || s == "all" {
- var length int
- dataBytes, err := io.ReadAll(response.Body)
- if err != nil {
- length = 0
- } else {
- length = len(dataBytes)
- }
- body := string(dataBytes)
- re := regexp.MustCompile("<[tT]itle>(.*?)[tT]itle>")
- title := re.FindAllStringSubmatch(body, -1)
- if len(title) != 0 {
- resultUrl[i] = Link{Url: u, Status: strconv.Itoa(code), Size: strconv.Itoa(length), Title: title[0][1]}
- } else {
- resultUrl[i] = Link{Url: u, Status: strconv.Itoa(code), Size: strconv.Itoa(length)}
- }
- } else {
- resultUrl[i].Url = ""
- }
-}
diff --git a/src/main.go b/src/main.go
deleted file mode 100644
index 017a9b1..0000000
--- a/src/main.go
+++ /dev/null
@@ -1,204 +0,0 @@
-package main
-
-import (
- "bufio"
- "flag"
- "fmt"
- "github.com/gookit/color"
- "io"
- "os"
- "strings"
- "sync"
- "time"
-)
-
-var (
- lock sync.Mutex
- wg sync.WaitGroup
- mux sync.Mutex
- ch = make(chan int, t)
- jsch = make(chan int, t/2)
- urlch = make(chan int, t/2)
-)
-
-type Link struct {
- Url string
- Status string
- Size string
- Title string
- Source string
-}
-
-type Info struct {
- Phone []string
- Email []string
- IDcard []string
- JWT []string
- Source string
-}
-
-var progress = 1
-var (
- resultJs []Link
- resultUrl []Link
- infos []Info
- endUrl []string
- jsinurl map[string]string
- jstourl map[string]string
- urltourl map[string]string
-)
-
-var (
- h bool
- I bool
- m int
- s string
- u string
- d string
- c string
- a string
- b string
- f string
- o string
- x string
- t = 50
- z int
-)
-
-func init() {
- flag.StringVar(&a, "a", "", "set user-agent\n设置user-agent请求头")
- flag.StringVar(&b, "b", "", "set baseurl\n设置baseurl路径")
- flag.StringVar(&c, "c", "", "set cookie\n设置cookie")
- flag.StringVar(&d, "d", "", "set domainName\n指定获取的域名")
- flag.StringVar(&f, "f", "", "set urlFile\n批量抓取url,指定文件路径")
- flag.BoolVar(&h, "h", false, "this help\n帮助信息")
- flag.BoolVar(&I, "i", false, "set configFile\n加载yaml配置文件(不存在时,会在当前目录创建一个默认yaml配置文件)")
- flag.IntVar(&m, "m", 1, "set mode\n抓取模式 \n 1 normal\n 正常抓取(默认) \n 2 thorough\n 深入抓取 (url只深入一层,防止抓偏) \n 3 security\n 安全深入抓取(过滤delete,remove等敏感路由) \n ")
- flag.StringVar(&o, "o", "", "set outFile\n结果导出到csv文件,需指定导出文件目录(.代表当前目录)")
- flag.StringVar(&s, "s", "", "set Status\n显示指定状态码,all为显示全部(多个状态码用,隔开)")
- flag.IntVar(&t, "t", 50, "set thread\n设置线程数(默认50)\n")
- flag.StringVar(&u, "u", "", "set Url\n目标URL")
- flag.StringVar(&x, "x", "", "set httpProxy\n设置代理,格式: http://username:password@127.0.0.1:8809")
- flag.IntVar(&z, "z", 0, "set Fuzz\n对404链接进行fuzz(只对主域名下的链接生效,需要与-s一起使用) \n 1 decreasing\n 目录递减fuzz \n 2 2combination\n 2级目录组合fuzz(适合少量链接使用) \n 3 3combination\n 3级目录组合fuzz(适合少量链接使用) \n")
-
- // 改变默认的 Usage
- flag.Usage = usage
-}
-func usage() {
- fmt.Fprintf(os.Stderr, `URLFinder 2023/1/29 by pingc0y
-Usage: URLFinder [-a user-agent] [-b baseurl] [-c cookie] [-d domainName] [-f urlFile] [-h help] [-i configFile] [-m mode] [-o outFile] [-s Status] [-t thread] [-u Url] [-x httpProxy] [-z fuzz]
-
-Options:
-`)
- flag.PrintDefaults()
-}
-
-func main() {
- flag.Parse()
- if h {
- flag.Usage()
- return
- }
- if u == "" && f == "" {
- flag.Usage()
- return
- }
- color.LightCyan.Println(" __ __ ___ _ _ \n /\\ /\\ /__\\ / / / __(_)_ __ __| | ___ _ __ \n/ / \\ \\/ \\/// / / _\\ | | '_ \\ / _` |/ _ \\ '__|\n\\ \\_/ / _ \\ /___ / | | | | | (_| | __/ | \n \\___/\\/ \\_\\____\\/ |_|_| |_|\\__,_|\\___|_| \n\nBy: pingc0y\nUpdateTime: 2023/1/29\nGithub: https://github.com/pingc0y/URLFinder \n")
- if a != "" {
- ua = a
- }
- if o != "" {
- if !IsDir(o) {
- return
- }
- }
- if I {
- GetConfig("config.yaml")
- }
- if t != 50 {
- ch = make(chan int, t+1)
- jsch = make(chan int, t/2+1)
- urlch = make(chan int, t/2+1)
- }
- if f != "" {
- // 创建句柄
- fi, err := os.Open(f)
- if err != nil {
- panic(err)
- }
- r := bufio.NewReader(fi) // 创建 Reader
- for {
- resultJs = nil
- resultUrl = nil
- endUrl = nil
-
- lineBytes, err := r.ReadBytes('\n')
- //去掉字符串首尾空白字符,返回字符串
- line := strings.TrimSpace(string(lineBytes))
- u = line
- start(u)
-
- if err == io.EOF {
- break
- }
- fmt.Println("----------------------------------------")
-
- }
- return
- }
- start(u)
-}
-
-func start(u string) {
-
- jsinurl = make(map[string]string)
- jstourl = make(map[string]string)
- urltourl = make(map[string]string)
- infos = []Info{}
- fmt.Println("Start Spider URL: " + color.LightBlue.Sprintf(u))
- wg.Add(1)
- ch <- 1
- go spider(u, 1)
- wg.Wait()
- progress = 1
- fmt.Printf("\rSpider OK \n")
- resultUrl = RemoveRepeatElement(resultUrl)
- resultJs = RemoveRepeatElement(resultJs)
- if s != "" {
- fmt.Printf("Start %d Validate...\n", len(resultUrl)+len(resultJs))
- fmt.Printf("\r ")
- jsFuzz()
- //验证JS状态
- for i, s := range resultJs {
- wg.Add(1)
- jsch <- 1
- go jsState(s.Url, i, resultJs[i].Source)
- }
- //验证URL状态
- for i, s := range resultUrl {
- wg.Add(1)
- urlch <- 1
- go urlState(s.Url, i)
- }
- wg.Wait()
-
- time.Sleep(1 * time.Second)
- fmt.Printf("\r ")
- fmt.Printf("\rValidate OK \n")
-
- if z != 0 {
- fuzz()
- time.Sleep(1 * time.Second)
- }
- }
-
- //打印还是输出
- if len(o) > 0 {
- outFileJson()
- outFileCsv()
- outFileHtml()
-
- } else {
- print()
- }
-}
diff --git a/src/report.html b/src/report.html
deleted file mode 100644
index bf1334c..0000000
--- a/src/report.html
+++ /dev/null
@@ -1,795 +0,0 @@
-
-
-
-
-
-
- URLFinder
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/utils.go b/util/utils.go
similarity index 55%
rename from src/utils.go
rename to util/utils.go
index 98fa9e5..1c5945f 100644
--- a/src/utils.go
+++ b/util/utils.go
@@ -1,8 +1,11 @@
-package main
+package util
import (
"fmt"
- "gopkg.in/yaml.v2"
+ "github.com/pingc0y/URLFinder/cmd"
+ "github.com/pingc0y/URLFinder/config"
+ "github.com/pingc0y/URLFinder/mode"
+ "math/rand"
"net/http"
"net/url"
"os"
@@ -21,8 +24,18 @@ func IsDir(path string) bool {
return s.IsDir()
}
+// MergeArray 合并数组
+func MergeArray(dest []mode.Link, src []mode.Link) (result []mode.Link) {
+ result = make([]mode.Link, len(dest)+len(src))
+ //将第一个数组传入result
+ copy(result, dest)
+ //将第二个数组接在尾部,也就是 len(dest):
+ copy(result[len(dest):], src)
+ return
+}
+
// 对结果进行状态码排序
-func SelectSort(arr []Link) []Link {
+func SelectSort(arr []mode.Link) []mode.Link {
length := len(arr)
var sort []int
for _, v := range arr {
@@ -53,10 +66,10 @@ func SelectSort(arr []Link) []Link {
}
// 对结果进行URL排序
-func urlDispose(arr []Link, url, host string) ([]Link, []Link) {
- var urls []Link
- var urlts []Link
- var other []Link
+func UrlDispose(arr []mode.Link, url, host string) ([]mode.Link, []mode.Link) {
+ var urls []mode.Link
+ var urlts []mode.Link
+ var other []mode.Link
for _, v := range arr {
if strings.Contains(v.Url, url) {
urls = append(urls, v)
@@ -76,8 +89,29 @@ func urlDispose(arr []Link, url, host string) ([]Link, []Link) {
return RemoveRepeatElement(urls), RemoveRepeatElement(other)
}
+// 处理Headers配置
+func SetHeadersConfig(header *http.Header) *http.Header {
+ for k, v := range config.Conf.Headers {
+ header.Add(k, v)
+ }
+ return header
+}
+
+// 设置proxy配置
+func SetProxyConfig(tr *http.Transport) *http.Transport {
+ if len(config.Conf.Proxy) > 0 {
+ proxyUrl, parseErr := url.Parse(config.Conf.Proxy)
+ if parseErr != nil {
+ fmt.Println("代理地址错误: \n" + parseErr.Error())
+ os.Exit(1)
+ }
+ tr.Proxy = http.ProxyURL(proxyUrl)
+ }
+ return tr
+}
+
// 提取顶级域名
-func getHost(u string) string {
+func GetHost(u string) string {
re := regexp.MustCompile("([a-z0-9\\-]+\\.)*([a-z0-9\\-]+\\.[a-z0-9\\-]+)(:[0-9]+)?")
var host string
@@ -113,15 +147,15 @@ func getHost(u string) string {
}
// 去重+去除错误url
-func RemoveRepeatElement(list []Link) []Link {
+func RemoveRepeatElement(list []mode.Link) []mode.Link {
// 创建一个临时map用来存储数组元素
temp := make(map[string]bool)
- var list2 []Link
+ var list2 []mode.Link
index := 0
for _, v := range list {
//处理-d参数
- if d != "" {
+ if cmd.D != "" {
v.Url = domainNameFilter(v.Url)
}
if len(v.Url) > 10 {
@@ -143,68 +177,12 @@ func RemoveRepeatElement(list []Link) []Link {
return list2
}
-// 读取配置文件
-func GetConfig(path string) {
- con := &config{}
- if f, err := os.Open(path); err != nil {
- if strings.Contains(err.Error(), "The system cannot find the file specified") || strings.Contains(err.Error(), "no such file or directory") {
-
- con.Headers = map[string]string{"Cookie": c, "User-Agent": ua, "Accept": "*/*"}
- con.Proxy = ""
- data, err2 := yaml.Marshal(con)
- err2 = os.WriteFile(path, data, 0644)
- if err2 != nil {
- fmt.Println(err)
- } else {
- fmt.Println("未找到配置文件,已在当面目录下创建配置文件: config.yaml")
- }
- } else {
- fmt.Println("配置文件错误,请尝试重新生成配置文件")
- fmt.Println(err)
- }
- os.Exit(1)
- } else {
- yaml.NewDecoder(f).Decode(con)
- conf = *con
- }
-}
-
-// 处理Headers配置
-func SetHeadersConfig(header *http.Header) *http.Header {
- for k, v := range conf.Headers {
- header.Add(k, v)
- }
- return header
-}
-
-// proxy
-func SetProxyConfig(tr *http.Transport) *http.Transport {
- if len(conf.Proxy) > 0 {
- proxyUrl, parseErr := url.Parse(conf.Proxy)
- if parseErr != nil {
- fmt.Println("代理地址错误: \n" + parseErr.Error())
- os.Exit(1)
- }
- tr.Proxy = http.ProxyURL(proxyUrl)
- }
- return tr
-}
-
-// 打印Validate进度
-func printProgress() {
- num := len(resultJs) + len(resultUrl)
- fmt.Printf("\rValidate %.0f%%", float64(progress+1)/float64(num+1)*100)
- mux.Lock()
- progress++
- mux.Unlock()
-}
-
// 打印Fuzz进度
-func printFuzz() {
- fmt.Printf("\rFuzz %.0f%%", float64(progress+1)/float64(fuzzNum+1)*100)
- mux.Lock()
- progress++
- mux.Unlock()
+func PrintFuzz() {
+ fmt.Printf("\rFuzz %.0f%%", float64(config.Progress+1)/float64(config.FuzzNum+1)*100)
+ config.Mux.Lock()
+ config.Progress++
+ config.Mux.Unlock()
}
// 处理-d
@@ -212,7 +190,7 @@ func domainNameFilter(url string) string {
re := regexp.MustCompile("://([a-z0-9\\-]+\\.)*([a-z0-9\\-]+\\.[a-z0-9\\-]+)(:[0-9]+)?")
hosts := re.FindAllString(url, 1)
if len(hosts) != 0 {
- if !strings.Contains(hosts[0], d) {
+ if !strings.Contains(hosts[0], cmd.D) {
url = ""
}
}
@@ -220,7 +198,7 @@ func domainNameFilter(url string) string {
}
// 文件是否存在
-func exists(path string) bool {
+func Exists(path string) bool {
_, err := os.Stat(path) //os.Stat获取文件信息
if err != nil {
if os.IsExist(err) {
@@ -232,7 +210,7 @@ func exists(path string) bool {
}
// 数组去重
-func uniqueArr(arr []string) []string {
+func UniqueArr(arr []string) []string {
newArr := make([]string, 0)
tempArr := make(map[string]bool, len(newArr))
for _, v := range arr {
@@ -244,8 +222,20 @@ func uniqueArr(arr []string) []string {
return newArr
}
+func GetDomains(lis []mode.Link) []string {
+ var urls []string
+ for i := range lis {
+ re := regexp.MustCompile("([a-z0-9\\-]+\\.)*([a-z0-9\\-]+\\.[a-z0-9\\-]+)(:[0-9]+)?")
+ hosts := re.FindAllString(lis[i].Url, 1)
+ if len(hosts) > 0 {
+ urls = append(urls, hosts[0])
+ }
+ }
+ return UniqueArr(urls)
+}
+
// 提取fuzz的目录结构
-func pathExtract(urls []string) ([]string, []string) {
+func PathExtract(urls []string) ([]string, []string) {
var catalogues []string
var targets []string
if len(urls) == 0 {
@@ -270,8 +260,8 @@ func pathExtract(urls []string) ([]string, []string) {
}
targets = append(targets, "upload")
- catalogues = uniqueArr(catalogues)
- targets = uniqueArr(targets)
+ catalogues = UniqueArr(catalogues)
+ targets = UniqueArr(targets)
url1 := catalogues
url2 := []string{}
url3 := []string{}
@@ -283,7 +273,7 @@ func pathExtract(urls []string) ([]string, []string) {
}
}
}
- if z == 3 {
+ if cmd.Z == 3 {
for _, v1 := range url1 {
for _, v3 := range url2 {
if !strings.Contains(v3, v1) {
@@ -295,14 +285,14 @@ func pathExtract(urls []string) ([]string, []string) {
for i := range url1 {
url1[i] = "/" + url1[i]
}
- if z == 3 {
+ if cmd.Z == 3 {
path = make([]string, len(url1)+len(url2)+len(url3))
} else {
path = make([]string, len(url1)+len(url2))
}
copy(path, url1)
copy(path[len(url1):], url2)
- if z == 3 {
+ if cmd.Z == 3 {
copy(path[len(url1)+len(url2):], url3)
}
for i := range path {
@@ -313,7 +303,7 @@ func pathExtract(urls []string) ([]string, []string) {
}
// 去除状态码非404的404链接
-func del404(urls []Link) []Link {
+func Del404(urls []mode.Link) []mode.Link {
is := make(map[int]int)
//根据长度分别存放
for _, v := range urls {
@@ -324,7 +314,7 @@ func del404(urls []Link) []Link {
is[len(v.Size)] = 1
}
}
- res := []Link{}
+ res := []mode.Link{}
//如果某个长度的数量大于全部的3分之2,那么就判定它是404页面
for i, v := range is {
if v > len(urls)/2 {
@@ -339,80 +329,40 @@ func del404(urls []Link) []Link {
}
-func appendJs(url string, urltjs string) {
- lock.Lock()
- defer lock.Unlock()
- url = strings.Replace(url, "/./", "/", -1)
- for _, eachItem := range resultJs {
- if eachItem.Url == url {
- return
- }
- }
- resultJs = append(resultJs, Link{Url: url})
- if strings.HasSuffix(urltjs, ".js") {
- jsinurl[url] = jsinurl[urltjs]
- } else {
- re := regexp.MustCompile("[a-zA-z]+://[^\\s]*/|[a-zA-z]+://[^\\s]*")
- u := re.FindAllStringSubmatch(urltjs, -1)
- jsinurl[url] = u[0][0]
- }
- if o != "" {
- jstourl[url] = urltjs
- }
-
-}
-
-func appendUrl(url string, urlturl string) {
- lock.Lock()
- defer lock.Unlock()
- url = strings.Replace(url, "/./", "/", -1)
- for _, eachItem := range resultUrl {
- if eachItem.Url == url {
- return
- }
- }
- resultUrl = append(resultUrl, Link{Url: url})
- if o != "" {
- urltourl[url] = urlturl
- }
-}
-
-func appendInfo(info Info) {
- lock.Lock()
- defer lock.Unlock()
- infos = append(infos, info)
-}
-
-func appendEndUrl(url string) {
- lock.Lock()
- defer lock.Unlock()
- for _, eachItem := range endUrl {
- if eachItem == url {
- return
- }
- }
- endUrl = append(endUrl, url)
-
-}
-
-func getEndUrl(url string) bool {
- lock.Lock()
- defer lock.Unlock()
- for _, eachItem := range endUrl {
- if eachItem == url {
- return true
- }
- }
- return false
-
-}
+var (
+
+ // for each request, a random UA will be selected from this list
+ uas = [...]string{
+ "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.68 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.5249.61 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.62 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.107 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.121 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.88 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.98 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.98 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.63 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.106 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.87 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.82 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36 Edg/99.0.1150.46",
+ "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36 SE 2.X MetaSr 1.0",
+ "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3883.400 QQBrowser/10.8.4559.400",
+ }
+
+ nuas = len(uas)
+)
-func addSource() {
- for i := range resultJs {
- resultJs[i].Source = jstourl[resultJs[i].Url]
+func GetUserAgent() string {
+ if cmd.A == "" {
+ cmd.A = uas[rand.Intn(nuas)]
}
- for i := range resultUrl {
- resultUrl[i].Source = urltourl[resultUrl[i].Url]
- }
-
+ return cmd.A
}