diff --git a/Plugins/webtitle.go b/Plugins/webtitle.go index a38a583..f132f20 100644 --- a/Plugins/webtitle.go +++ b/Plugins/webtitle.go @@ -1,16 +1,13 @@ package Plugins import ( - "bytes" "compress/gzip" "crypto/tls" "fmt" - "github.com/saintfish/chardet" "github.com/shadow1ng/fscan/WebScan" "github.com/shadow1ng/fscan/WebScan/lib" "github.com/shadow1ng/fscan/common" "golang.org/x/text/encoding/simplifiedchinese" - "golang.org/x/text/transform" "io" "io/ioutil" "net" @@ -19,98 +16,80 @@ import ( "regexp" "strings" "time" -) - -var ( - Charsets = []string{"utf-8", "gbk", "gb2312"} + "unicode/utf8" ) func WebTitle(info *common.HostInfo) error { - err := GOWebTitle(info) - if err != nil { + err, CheckData := GOWebTitle(info) + info.Infostr = WebScan.InfoCheck(info.Url, &CheckData) + if common.IsWebCan == false && err == nil { + WebScan.WebScan(info) + } else { errlog := fmt.Sprintf("[-] webtitle %v %v", info.Url, err) common.LogError(errlog) } return err } - -//flag 1 first try -//flag 2 /favicon.ico -//flag 3 302 -//flag 4 400 -> https - -func GOWebTitle(info *common.HostInfo) error { - var CheckData []WebScan.CheckDatas +func GOWebTitle(info *common.HostInfo) (err error, CheckData []WebScan.CheckDatas) { if info.Url == "" { - if info.Ports == "80" { + switch info.Ports { + case "80": info.Url = fmt.Sprintf("http://%s", info.Host) - } else if info.Ports == "443" { + case "443": info.Url = fmt.Sprintf("https://%s", info.Host) - } else { + default: host := fmt.Sprintf("%s:%s", info.Host, info.Ports) protocol := GetProtocol(host, info.Timeout) info.Url = fmt.Sprintf("%s://%s:%s", protocol, info.Host, info.Ports) } } else { if !strings.Contains(info.Url, "://") { - protocol := GetProtocol(info.Url, info.Timeout) + host := strings.Split(info.Url, "/")[0] + protocol := GetProtocol(host, info.Timeout) info.Url = fmt.Sprintf("%s://%s", protocol, info.Url) } } err, result, CheckData := geturl(info, 1, CheckData) if err != nil && !strings.Contains(err.Error(), "EOF") { - return err + return } + //有跳转 if strings.Contains(result, "://") { - //有跳转 - redirecturl, err := url.Parse(result) - if err == nil { - info.Url = redirecturl.String() - err, result, CheckData = geturl(info, 3, CheckData) - if err != nil { - return err - } + info.Url = result + err, result, CheckData = geturl(info, 3, CheckData) + if err != nil { + return } } if result == "https" && !strings.HasPrefix(info.Url, "https://") { info.Url = strings.Replace(info.Url, "http://", "https://", 1) err, result, CheckData = geturl(info, 1, CheckData) + //有跳转 if strings.Contains(result, "://") { - //有跳转 - redirecturl, err := url.Parse(result) - if err == nil { - info.Url = redirecturl.String() - err, result, CheckData = geturl(info, 3, CheckData) - if err != nil { - return err - } - } - } else { + info.Url = result + err, result, CheckData = geturl(info, 3, CheckData) if err != nil { - return err + return } } - } else if err != nil { - return err } err, _, CheckData = geturl(info, 2, CheckData) if err != nil { - return err + return } - - info.Infostr = WebScan.InfoCheck(info.Url, CheckData) - - if common.IsWebCan == false { - WebScan.WebScan(info) - } - return err + return } func geturl(info *common.HostInfo, flag int, CheckData []WebScan.CheckDatas) (error, string, []WebScan.CheckDatas) { + //flag 1 first try + //flag 2 /favicon.ico + //flag 3 302 + //flag 4 400 -> https + Url := info.Url if flag == 2 { URL, err := url.Parse(Url) @@ -120,127 +99,65 @@ func geturl(info *common.HostInfo, flag int, CheckData []WebScan.CheckDatas) (er Url += "/favicon.ico" } } - req, err := http.NewRequest("GET", Url, nil) - if err == nil { - req.Header.Set("User-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1468.0 Safari/537.36") - req.Header.Set("Accept", "*/*") - req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9") - if common.Pocinfo.Cookie != "" { - req.Header.Set("Cookie", "rememberMe=1;"+common.Pocinfo.Cookie) - } else { - req.Header.Set("Cookie", "rememberMe=1") - } - req.Header.Set("Connection", "close") + if err != nil { + return err, "", CheckData + } + req.Header.Set("User-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1468.0 Safari/537.36") + req.Header.Set("Accept", "*/*") + req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9") + if common.Pocinfo.Cookie != "" { + req.Header.Set("Cookie", "rememberMe=1;"+common.Pocinfo.Cookie) + } else { + req.Header.Set("Cookie", "rememberMe=1") + } + req.Header.Set("Connection", "close") + var client *http.Client + if flag == 1 { + client = lib.ClientNoRedirect + } else { + client = lib.Client + } - var client *http.Client - if flag == 1 { - client = lib.ClientNoRedirect - } else { - client = lib.Client - } - - resp, err := client.Do(req) - if err == nil { - defer resp.Body.Close() - var title string - var text []byte - body, err := getRespBody(resp) - if err != nil { - return err, "https", CheckData - } - if flag != 2 { - re := regexp.MustCompile("(?ims)(.*)") - find := re.FindSubmatch(body) - if len(find) > 1 { - text = find[1] - GetEncoding := func() string { // 判断Content-Type - r1, err := regexp.Compile(`(?im)charset=\s*?([\w-]+)`) - if err != nil { - return "" - } - headerCharset := r1.FindString(resp.Header.Get("Content-Type")) - if headerCharset != "" { - for _, v := range Charsets { // headers 编码优先,所以放在前面 - if strings.Contains(strings.ToLower(headerCharset), v) == true { - return v - } - } - } - - r2, err := regexp.Compile(`(?im)`) - if err != nil { - return "" - } - htmlCharset := r2.FindString(string(body)) - if htmlCharset != "" { - for _, v := range Charsets { - if strings.Contains(strings.ToLower(htmlCharset), v) == true { - return v - } - } - } - return "" - } - encode := GetEncoding() - //_, encode1, _ := charset.DetermineEncoding(body, "") - var encode2 string - detector := chardet.NewTextDetector() - detectorstr, _ := detector.DetectBest(body) - if detectorstr != nil { - encode2 = detectorstr.Charset - } - if encode == "gbk" || encode == "gb2312" || strings.Contains(strings.ToLower(encode2), "gb") { - titleGBK, err := Decodegbk(text) - if err == nil { - title = string(titleGBK) - } - } else { - title = string(text) - } - } else { - title = "None" - } - title = strings.Trim(title, "\r\n \t") - title = strings.Replace(title, "\n", "", -1) - title = strings.Replace(title, "\r", "", -1) - title = strings.Replace(title, " ", " ", -1) - if len(title) > 100 { - title = title[:100] - } - if title == "" { - title = "None" - } - length := resp.Header.Get("Content-Length") - if length == "" { - length = fmt.Sprintf("%v", len(body)) - } - result := fmt.Sprintf("[*] WebTitle:%-25v code:%-3v len:%-6v title:%v", resp.Request.URL, resp.StatusCode, length, title) - common.LogSuccess(result) - } - CheckData = append(CheckData, WebScan.CheckDatas{body, fmt.Sprintf("%s", resp.Header)}) - redirURL, err1 := resp.Location() - if err1 == nil { - return nil, redirURL.String(), CheckData - } - if resp.StatusCode == 400 && !strings.HasPrefix(info.Url, "https") { - return err, "https", CheckData - } - return err, "", CheckData - } + resp, err := client.Do(req) + if err != nil { return err, "https", CheckData } - return err, "", CheckData -} -func Decodegbk(s []byte) ([]byte, error) { // GBK解码 - I := bytes.NewReader(s) - O := transform.NewReader(I, simplifiedchinese.GBK.NewDecoder()) - d, e := ioutil.ReadAll(O) - if e != nil { - return nil, e + defer resp.Body.Close() + var title string + body, err := getRespBody(resp) + if err != nil { + return err, "https", CheckData } - return d, nil + if !utf8.Valid(body) { + body, _ = simplifiedchinese.GBK.NewDecoder().Bytes(body) + } + CheckData = append(CheckData, WebScan.CheckDatas{body, fmt.Sprintf("%s", resp.Header)}) + var reurl string + if flag != 2 { + title = gettitle(body) + length := resp.Header.Get("Content-Length") + if length == "" { + length = fmt.Sprintf("%v", len(body)) + } + redirURL, err1 := resp.Location() + if err1 == nil { + reurl = redirURL.String() + } + result := fmt.Sprintf("[*] WebTitle:%-25v code:%-3v len:%-6v title:%v", resp.Request.URL, resp.StatusCode, length, title) + if reurl != "" { + result += fmt.Sprintf(" 跳转url: %s", reurl) + } + common.LogSuccess(result) + } + if reurl != "" { + return nil, reurl, CheckData + } + if resp.StatusCode == 400 && !strings.HasPrefix(info.Url, "https") { + return nil, "https", CheckData + } + return nil, "", CheckData } func getRespBody(oResp *http.Response) ([]byte, error) { @@ -272,14 +189,42 @@ func getRespBody(oResp *http.Response) ([]byte, error) { return body, nil } -func GetProtocol(host string, Timeout int64) string { +func gettitle(body []byte) (title string) { + re := regexp.MustCompile("(?ims)(.*)") + find := re.FindSubmatch(body) + if len(find) > 1 { + title = string(find[1]) + title = strings.TrimSpace(title) + title = strings.Replace(title, "\n", "", -1) + title = strings.Replace(title, "\r", "", -1) + title = strings.Replace(title, " ", " ", -1) + if len(title) > 100 { + title = title[:100] + } + } + if title == "" { + title = "None" + } + return +} + +func GetProtocol(host string, Timeout int64) (protocol string) { + protocol = "http" + //如果端口是80或443,跳过Protocol判断 + if strings.HasSuffix(host, ":80") || !strings.Contains(host, ":") { + return + } else if strings.HasSuffix(host, ":443") { + protocol = "https" + return + } + conn, err := tls.DialWithDialer(&net.Dialer{Timeout: time.Duration(Timeout) * time.Second}, "tcp", host, &tls.Config{InsecureSkipVerify: true}) defer func() { if conn != nil { conn.Close() } }() - protocol := "http" + if err == nil || strings.Contains(err.Error(), "handshake failure") { protocol = "https" } diff --git a/WebScan/InfoScan.go b/WebScan/InfoScan.go index 472719a..88878a3 100644 --- a/WebScan/InfoScan.go +++ b/WebScan/InfoScan.go @@ -13,11 +13,11 @@ type CheckDatas struct { Headers string } -func InfoCheck(Url string, CheckData []CheckDatas) []string { +func InfoCheck(Url string, CheckData *[]CheckDatas) []string { var matched bool var infoname []string - for _, data := range CheckData { + for _, data := range *CheckData { for _, rule := range info.RuleDatas { if rule.Type == "code" { matched, _ = regexp.MatchString(rule.Rule, string(data.Body)) @@ -67,4 +67,3 @@ func removeDuplicateElement(languages []string) []string { } return result } -