update webtitle

This commit is contained in:
影舞者 2022-02-17 14:37:06 +08:00
parent ed99ee0fad
commit 2ebda8baa9
2 changed files with 115 additions and 171 deletions

View File

@ -1,16 +1,13 @@
package Plugins package Plugins
import ( import (
"bytes"
"compress/gzip" "compress/gzip"
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"github.com/saintfish/chardet"
"github.com/shadow1ng/fscan/WebScan" "github.com/shadow1ng/fscan/WebScan"
"github.com/shadow1ng/fscan/WebScan/lib" "github.com/shadow1ng/fscan/WebScan/lib"
"github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common"
"golang.org/x/text/encoding/simplifiedchinese" "golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
"io" "io"
"io/ioutil" "io/ioutil"
"net" "net"
@ -19,98 +16,80 @@ import (
"regexp" "regexp"
"strings" "strings"
"time" "time"
) "unicode/utf8"
var (
Charsets = []string{"utf-8", "gbk", "gb2312"}
) )
func WebTitle(info *common.HostInfo) error { func WebTitle(info *common.HostInfo) error {
err := GOWebTitle(info) err, CheckData := GOWebTitle(info)
if err != nil { 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) errlog := fmt.Sprintf("[-] webtitle %v %v", info.Url, err)
common.LogError(errlog) common.LogError(errlog)
} }
return err return err
} }
func GOWebTitle(info *common.HostInfo) (err error, CheckData []WebScan.CheckDatas) {
//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
if info.Url == "" { if info.Url == "" {
if info.Ports == "80" { switch info.Ports {
case "80":
info.Url = fmt.Sprintf("http://%s", info.Host) info.Url = fmt.Sprintf("http://%s", info.Host)
} else if info.Ports == "443" { case "443":
info.Url = fmt.Sprintf("https://%s", info.Host) info.Url = fmt.Sprintf("https://%s", info.Host)
} else { default:
host := fmt.Sprintf("%s:%s", info.Host, info.Ports) host := fmt.Sprintf("%s:%s", info.Host, info.Ports)
protocol := GetProtocol(host, info.Timeout) protocol := GetProtocol(host, info.Timeout)
info.Url = fmt.Sprintf("%s://%s:%s", protocol, info.Host, info.Ports) info.Url = fmt.Sprintf("%s://%s:%s", protocol, info.Host, info.Ports)
} }
} else { } else {
if !strings.Contains(info.Url, "://") { 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) info.Url = fmt.Sprintf("%s://%s", protocol, info.Url)
} }
} }
err, result, CheckData := geturl(info, 1, CheckData) err, result, CheckData := geturl(info, 1, CheckData)
if err != nil && !strings.Contains(err.Error(), "EOF") { if err != nil && !strings.Contains(err.Error(), "EOF") {
return err return
} }
//有跳转
if strings.Contains(result, "://") { if strings.Contains(result, "://") {
//有跳转 info.Url = result
redirecturl, err := url.Parse(result) err, result, CheckData = geturl(info, 3, CheckData)
if err == nil { if err != nil {
info.Url = redirecturl.String() return
err, result, CheckData = geturl(info, 3, CheckData)
if err != nil {
return err
}
} }
} }
if result == "https" && !strings.HasPrefix(info.Url, "https://") { if result == "https" && !strings.HasPrefix(info.Url, "https://") {
info.Url = strings.Replace(info.Url, "http://", "https://", 1) info.Url = strings.Replace(info.Url, "http://", "https://", 1)
err, result, CheckData = geturl(info, 1, CheckData) err, result, CheckData = geturl(info, 1, CheckData)
//有跳转
if strings.Contains(result, "://") { if strings.Contains(result, "://") {
//有跳转 info.Url = result
redirecturl, err := url.Parse(result) err, result, CheckData = geturl(info, 3, CheckData)
if err == nil {
info.Url = redirecturl.String()
err, result, CheckData = geturl(info, 3, CheckData)
if err != nil {
return err
}
}
} else {
if err != nil { if err != nil {
return err return
} }
} }
} else if err != nil {
return err
} }
err, _, CheckData = geturl(info, 2, CheckData) err, _, CheckData = geturl(info, 2, CheckData)
if err != nil { if err != nil {
return err return
} }
return
info.Infostr = WebScan.InfoCheck(info.Url, CheckData)
if common.IsWebCan == false {
WebScan.WebScan(info)
}
return err
} }
func geturl(info *common.HostInfo, flag int, CheckData []WebScan.CheckDatas) (error, string, []WebScan.CheckDatas) { 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 Url := info.Url
if flag == 2 { if flag == 2 {
URL, err := url.Parse(Url) URL, err := url.Parse(Url)
@ -120,127 +99,65 @@ func geturl(info *common.HostInfo, flag int, CheckData []WebScan.CheckDatas) (er
Url += "/favicon.ico" Url += "/favicon.ico"
} }
} }
req, err := http.NewRequest("GET", Url, nil) req, err := http.NewRequest("GET", Url, nil)
if err == 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") return err, "", CheckData
req.Header.Set("Accept", "*/*") }
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9") 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")
if common.Pocinfo.Cookie != "" { req.Header.Set("Accept", "*/*")
req.Header.Set("Cookie", "rememberMe=1;"+common.Pocinfo.Cookie) req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
} else { if common.Pocinfo.Cookie != "" {
req.Header.Set("Cookie", "rememberMe=1") req.Header.Set("Cookie", "rememberMe=1;"+common.Pocinfo.Cookie)
} } else {
req.Header.Set("Connection", "close") 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 resp, err := client.Do(req)
if flag == 1 { if err != nil {
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)<title>(.*)</title>")
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)<meta.*?charset=['"]?([\w-]+)["']?.*?>`)
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, "&nbsp;", " ", -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
}
return err, "https", CheckData return err, "https", CheckData
} }
return err, "", CheckData
}
func Decodegbk(s []byte) ([]byte, error) { // GBK解码 defer resp.Body.Close()
I := bytes.NewReader(s) var title string
O := transform.NewReader(I, simplifiedchinese.GBK.NewDecoder()) body, err := getRespBody(resp)
d, e := ioutil.ReadAll(O) if err != nil {
if e != nil { return err, "https", CheckData
return nil, e
} }
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) { func getRespBody(oResp *http.Response) ([]byte, error) {
@ -272,14 +189,42 @@ func getRespBody(oResp *http.Response) ([]byte, error) {
return body, nil return body, nil
} }
func GetProtocol(host string, Timeout int64) string { func gettitle(body []byte) (title string) {
re := regexp.MustCompile("(?ims)<title>(.*)</title>")
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, "&nbsp;", " ", -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}) conn, err := tls.DialWithDialer(&net.Dialer{Timeout: time.Duration(Timeout) * time.Second}, "tcp", host, &tls.Config{InsecureSkipVerify: true})
defer func() { defer func() {
if conn != nil { if conn != nil {
conn.Close() conn.Close()
} }
}() }()
protocol := "http"
if err == nil || strings.Contains(err.Error(), "handshake failure") { if err == nil || strings.Contains(err.Error(), "handshake failure") {
protocol = "https" protocol = "https"
} }

View File

@ -13,11 +13,11 @@ type CheckDatas struct {
Headers string Headers string
} }
func InfoCheck(Url string, CheckData []CheckDatas) []string { func InfoCheck(Url string, CheckData *[]CheckDatas) []string {
var matched bool var matched bool
var infoname []string var infoname []string
for _, data := range CheckData { for _, data := range *CheckData {
for _, rule := range info.RuleDatas { for _, rule := range info.RuleDatas {
if rule.Type == "code" { if rule.Type == "code" {
matched, _ = regexp.MatchString(rule.Rule, string(data.Body)) matched, _ = regexp.MatchString(rule.Rule, string(data.Body))
@ -67,4 +67,3 @@ func removeDuplicateElement(languages []string) []string {
} }
return result return result
} }