From 5dc1c4ee5e8cf2010447c121541cff878e18d1bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BD=B1=E8=88=9E=E8=80=85?= Date: Mon, 13 Nov 2023 17:41:54 +0800 Subject: [PATCH] Update --- Plugins/CVE-2020-0796.go | 5 ++--- Plugins/fcgiscan.go | 42 ++++++++++++++++++++-------------------- Plugins/ftp.go | 6 +++--- Plugins/icmp.go | 24 ++++++++++------------- Plugins/portscan.go | 4 ++++ Plugins/rdp.go | 13 ++++++------- Plugins/redis.go | 20 +++++++------------ Plugins/scanner.go | 2 +- Plugins/webtitle.go | 18 +++++++++-------- WebScan/WebScan.go | 2 +- WebScan/info/rules.go | 5 +++-- WebScan/lib/check.go | 5 ++++- WebScan/lib/eval.go | 10 +++++----- common/ParseIP.go | 26 ++++++++++++++++++++----- common/ParsePort.go | 3 +++ common/config.go | 2 +- common/flag.go | 2 +- 17 files changed, 103 insertions(+), 86 deletions(-) diff --git a/Plugins/CVE-2020-0796.go b/Plugins/CVE-2020-0796.go index 279aaf0..385c86d 100644 --- a/Plugins/CVE-2020-0796.go +++ b/Plugins/CVE-2020-0796.go @@ -117,13 +117,12 @@ func SmbGhostScan(info *common.HostInfo) error { buff := make([]byte, 1024) err = conn.SetReadDeadline(time.Now().Add(timeout)) n, err := conn.Read(buff) - if err != nil { + if err != nil || n == 0 { return err } - if bytes.Contains(buff[:n], []byte("Public")) == true { + if bytes.Contains(buff[:n], []byte("Public")) == true && len(buff[:n]) >= 76 && bytes.Equal(buff[72:74], []byte{0x11, 0x03}) && bytes.Equal(buff[74:76], []byte{0x02, 0x00}) { result := fmt.Sprintf("[+] %v CVE-2020-0796 SmbGhost Vulnerable", ip) common.LogSuccess(result) - } return err } diff --git a/Plugins/fcgiscan.go b/Plugins/fcgiscan.go index a217e53..11c9841 100644 --- a/Plugins/fcgiscan.go +++ b/Plugins/fcgiscan.go @@ -191,38 +191,38 @@ func New(addr string, timeout int64) (fcgi *FCGIClient, err error) { return } -func (this *FCGIClient) writeRecord(recType uint8, reqId uint16, content []byte) (err error) { - this.mutex.Lock() - defer this.mutex.Unlock() - this.buf.Reset() - this.h.init(recType, reqId, len(content)) - if err := binary.Write(&this.buf, binary.BigEndian, this.h); err != nil { +func (c *FCGIClient) writeRecord(recType uint8, reqId uint16, content []byte) (err error) { + c.mutex.Lock() + defer c.mutex.Unlock() + c.buf.Reset() + c.h.init(recType, reqId, len(content)) + if err := binary.Write(&c.buf, binary.BigEndian, c.h); err != nil { return err } - if _, err := this.buf.Write(content); err != nil { + if _, err := c.buf.Write(content); err != nil { return err } - if _, err := this.buf.Write(pad[:this.h.PaddingLength]); err != nil { + if _, err := c.buf.Write(pad[:c.h.PaddingLength]); err != nil { return err } - _, err = this.rwc.Write(this.buf.Bytes()) + _, err = c.rwc.Write(c.buf.Bytes()) return err } -func (this *FCGIClient) writeBeginRequest(reqId uint16, role uint16, flags uint8) error { +func (c *FCGIClient) writeBeginRequest(reqId uint16, role uint16, flags uint8) error { b := [8]byte{byte(role >> 8), byte(role), flags} - return this.writeRecord(FCGI_BEGIN_REQUEST, reqId, b[:]) + return c.writeRecord(FCGI_BEGIN_REQUEST, reqId, b[:]) } -func (this *FCGIClient) writeEndRequest(reqId uint16, appStatus int, protocolStatus uint8) error { +func (c *FCGIClient) writeEndRequest(reqId uint16, appStatus int, protocolStatus uint8) error { b := make([]byte, 8) binary.BigEndian.PutUint32(b, uint32(appStatus)) b[4] = protocolStatus - return this.writeRecord(FCGI_END_REQUEST, reqId, b) + return c.writeRecord(FCGI_END_REQUEST, reqId, b) } -func (this *FCGIClient) writePairs(recType uint8, reqId uint16, pairs map[string]string) error { - w := newWriter(this, recType, reqId) +func (c *FCGIClient) writePairs(recType uint8, reqId uint16, pairs map[string]string) error { + w := newWriter(c, recType, reqId) b := make([]byte, 8) for k, v := range pairs { n := encodeSize(b, uint32(len(k))) @@ -324,21 +324,21 @@ func (w *streamWriter) Close() error { return w.c.writeRecord(w.recType, w.reqId, nil) } -func (this *FCGIClient) Request(env map[string]string, reqStr string) (retout []byte, reterr []byte, err error) { +func (c *FCGIClient) Request(env map[string]string, reqStr string) (retout []byte, reterr []byte, err error) { var reqId uint16 = 1 - defer this.rwc.Close() + defer c.rwc.Close() - err = this.writeBeginRequest(reqId, uint16(FCGI_RESPONDER), 0) + err = c.writeBeginRequest(reqId, uint16(FCGI_RESPONDER), 0) if err != nil { return } - err = this.writePairs(FCGI_PARAMS, reqId, env) + err = c.writePairs(FCGI_PARAMS, reqId, env) if err != nil { return } if len(reqStr) > 0 { - err = this.writeRecord(FCGI_STDIN, reqId, []byte(reqStr)) + err = c.writeRecord(FCGI_STDIN, reqId, []byte(reqStr)) if err != nil { return } @@ -349,7 +349,7 @@ func (this *FCGIClient) Request(env map[string]string, reqStr string) (retout [] // recive untill EOF or FCGI_END_REQUEST for { - err1 = rec.read(this.rwc) + err1 = rec.read(c.rwc) if err1 != nil { if err1 != io.EOF { err = err1 diff --git a/Plugins/ftp.go b/Plugins/ftp.go index 201de83..58d0378 100644 --- a/Plugins/ftp.go +++ b/Plugins/ftp.go @@ -17,7 +17,7 @@ func FtpScan(info *common.HostInfo) (tmperr error) { if flag && err == nil { return err } else { - errlog := fmt.Sprintf("[-] ftp://%v:%v %v %v", info.Host, info.Ports, "anonymous", err) + errlog := fmt.Sprintf("[-] ftp %v:%v %v %v", info.Host, info.Ports, "anonymous", err) common.LogError(errlog) tmperr = err if common.CheckErrs(err) { @@ -32,7 +32,7 @@ func FtpScan(info *common.HostInfo) (tmperr error) { if flag && err == nil { return err } else { - errlog := fmt.Sprintf("[-] ftp://%v:%v %v %v %v", info.Host, info.Ports, user, pass, err) + errlog := fmt.Sprintf("[-] ftp %v:%v %v %v %v", info.Host, info.Ports, user, pass, err) common.LogError(errlog) tmperr = err if common.CheckErrs(err) { @@ -55,7 +55,7 @@ func FtpConn(info *common.HostInfo, user string, pass string) (flag bool, err er err = conn.Login(Username, Password) if err == nil { flag = true - result := fmt.Sprintf("[+] ftp://%v:%v:%v %v", Host, Port, Username, Password) + result := fmt.Sprintf("[+] ftp %v:%v:%v %v", Host, Port, Username, Password) dirs, err := conn.List("") //defer conn.Logout() if err == nil { diff --git a/Plugins/icmp.go b/Plugins/icmp.go index f7c153c..36acc14 100644 --- a/Plugins/icmp.go +++ b/Plugins/icmp.go @@ -15,7 +15,6 @@ import ( var ( AliveHosts []string - OS = runtime.GOOS ExistHosts = make(map[string]struct{}) livewg sync.WaitGroup ) @@ -159,10 +158,10 @@ func RunIcmp2(hostslist []string, chanHosts chan string) { func icmpalive(host string) bool { startTime := time.Now() conn, err := net.DialTimeout("ip4:icmp", host, 6*time.Second) - defer conn.Close() if err != nil { return false } + defer conn.Close() if err := conn.SetDeadline(startTime.Add(6 * time.Second)); err != nil { return false } @@ -180,17 +179,13 @@ func icmpalive(host string) bool { } func RunPing(hostslist []string, chanHosts chan string) { - var bsenv = "" - if OS != "windows" { - bsenv = "/bin/bash" - } var wg sync.WaitGroup limiter := make(chan struct{}, 50) for _, host := range hostslist { wg.Add(1) limiter <- struct{}{} go func(host string) { - if ExecCommandPing(host, bsenv) { + if ExecCommandPing(host) { livewg.Add(1) chanHosts <- host } @@ -201,14 +196,15 @@ func RunPing(hostslist []string, chanHosts chan string) { wg.Wait() } -func ExecCommandPing(ip string, bsenv string) bool { +func ExecCommandPing(ip string) bool { var command *exec.Cmd - if OS == "windows" { + switch runtime.GOOS { + case "windows": command = exec.Command("cmd", "/c", "ping -n 1 -w 1 "+ip+" && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false" - } else if OS == "linux" { - command = exec.Command(bsenv, "-c", "ping -c 1 -w 1 "+ip+" >/dev/null && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false" - } else if OS == "darwin" { - command = exec.Command(bsenv, "-c", "ping -c 1 -W 1 "+ip+" >/dev/null && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false" + case "darwin": + command = exec.Command("/bin/bash", "-c", "ping -c 1 -W 1 "+ip+" && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false" + default: //linux + command = exec.Command("/bin/bash", "-c", "ping -c 1 -w 1 "+ip+" && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false" } outinfo := bytes.Buffer{} command.Stdout = &outinfo @@ -219,7 +215,7 @@ func ExecCommandPing(ip string, bsenv string) bool { if err = command.Wait(); err != nil { return false } else { - if strings.Contains(outinfo.String(), "true") { + if strings.Contains(outinfo.String(), "true") && strings.Count(outinfo.String(), ip) > 2 { return true } else { return false diff --git a/Plugins/portscan.go b/Plugins/portscan.go index 7f9d66f..f3e6161 100644 --- a/Plugins/portscan.go +++ b/Plugins/portscan.go @@ -17,6 +17,10 @@ type Addr struct { func PortScan(hostslist []string, ports string, timeout int64) []string { var AliveAddress []string probePorts := common.ParsePort(ports) + if len(probePorts) == 0 { + fmt.Printf("[-] parse port %s error, please check your port format\n", ports) + return AliveAddress + } noPorts := common.ParsePort(common.NoPorts) if len(noPorts) > 0 { temp := map[int]struct{}{} diff --git a/Plugins/rdp.go b/Plugins/rdp.go index 68d00f8..fe08c39 100644 --- a/Plugins/rdp.go +++ b/Plugins/rdp.go @@ -36,21 +36,20 @@ func RdpScan(info *common.HostInfo) (tmperr error) { var num = 0 var all = len(common.Userdict["rdp"]) * len(common.Passwords) var mutex sync.Mutex - brlist := make(chan Brutelist, all) + brlist := make(chan Brutelist) port, _ := strconv.Atoi(info.Ports) + for i := 0; i < common.BruteThread; i++ { + wg.Add(1) + go worker(info.Host, common.Domain, port, &wg, brlist, &signal, &num, all, &mutex, common.Timeout) + } + for _, user := range common.Userdict["rdp"] { for _, pass := range common.Passwords { pass = strings.Replace(pass, "{user}", user, -1) brlist <- Brutelist{user, pass} } } - - for i := 0; i < common.BruteThread; i++ { - wg.Add(1) - go worker(info.Host, common.Domain, port, &wg, brlist, &signal, &num, all, &mutex, common.Timeout) - } - close(brlist) go func() { wg.Wait() diff --git a/Plugins/redis.go b/Plugins/redis.go index 01e2239..6f3d7b5 100644 --- a/Plugins/redis.go +++ b/Plugins/redis.go @@ -4,6 +4,7 @@ import ( "bufio" "fmt" "github.com/shadow1ng/fscan/common" + "io" "net" "os" "strings" @@ -289,20 +290,13 @@ func Readfile(filename string) (string, error) { return "", err } -func readreply(conn net.Conn) (result string, err error) { - size := 5 * 1024 - buf := make([]byte, size) - for { - count, err := conn.Read(buf) - if err != nil { - break - } - result += string(buf[0:count]) - if count < size { - break - } +func readreply(conn net.Conn) (string, error) { + conn.SetReadDeadline(time.Now().Add(time.Second)) + bytes, err := io.ReadAll(conn) + if len(bytes) > 0 { + err = nil } - return result, err + return string(bytes), err } func testwrite(conn net.Conn) (flag bool, flagCron bool, err error) { diff --git a/Plugins/scanner.go b/Plugins/scanner.go index fc55d50..1873b46 100644 --- a/Plugins/scanner.go +++ b/Plugins/scanner.go @@ -23,7 +23,7 @@ func Scan(info common.HostInfo) { web := strconv.Itoa(common.PORTList["web"]) ms17010 := strconv.Itoa(common.PORTList["ms17010"]) if len(Hosts) > 0 || len(common.HostPort) > 0 { - if common.NoPing == false && len(Hosts) > 0 { + if common.NoPing == false && len(Hosts) > 1 || common.Scantype == "icmp" { Hosts = CheckLive(Hosts, common.Ping) fmt.Println("[*] Icmp alive hosts len is:", len(Hosts)) } diff --git a/Plugins/webtitle.go b/Plugins/webtitle.go index 1047bfb..897ed19 100644 --- a/Plugins/webtitle.go +++ b/Plugins/webtitle.go @@ -26,7 +26,7 @@ func WebTitle(info *common.HostInfo) error { err, CheckData := GOWebTitle(info) info.Infostr = WebScan.InfoCheck(info.Url, &CheckData) - if !common.NoWebCan && err == nil { + if !common.NoPoc && err == nil { WebScan.WebScan(info) } else { errlog := fmt.Sprintf("[-] webtitle %v %v", info.Url, err) @@ -137,12 +137,12 @@ func geturl(info *common.HostInfo, flag int, CheckData []WebScan.CheckDatas) (er if err != nil { return err, "https", CheckData } - if !utf8.Valid(body) { - body, _ = simplifiedchinese.GBK.NewDecoder().Bytes(body) - } - CheckData = append(CheckData, WebScan.CheckDatas{Body: body, Headers: fmt.Sprintf("%s", resp.Header)}) + CheckData = append(CheckData, WebScan.CheckDatas{body, fmt.Sprintf("%s", resp.Header)}) var reurl string if flag != 2 { + if !utf8.Valid(body) { + body, _ = simplifiedchinese.GBK.NewDecoder().Bytes(body) + } title = gettitle(body) length := resp.Header.Get("Content-Length") if length == "" { @@ -208,9 +208,11 @@ func gettitle(body []byte) (title string) { if len(title) > 100 { title = title[:100] } - } - if title == "" { - title = "None" + if title == "" { + title = "\"\"" //空格 + } + } else { + title = "None" //没有title } return } diff --git a/WebScan/WebScan.go b/WebScan/WebScan.go index 99bacd6..44e88f2 100644 --- a/WebScan/WebScan.go +++ b/WebScan/WebScan.go @@ -46,7 +46,6 @@ func Execute(PocInfo common.PocInfo) { if common.Cookie != "" { req.Header.Set("Cookie", common.Cookie) } - req.Header.Set("Connection", "close") pocs := filterPoc(PocInfo.PocName) lib.CheckMultiPoc(req, pocs, common.PocNum) } @@ -67,6 +66,7 @@ func initpoc() { } } } else { + fmt.Println("[+] load poc from " + common.PocPath) err := filepath.Walk(common.PocPath, func(path string, info os.FileInfo, err error) error { if err != nil || info == nil { diff --git a/WebScan/info/rules.go b/WebScan/info/rules.go index e0103ad..939b981 100644 --- a/WebScan/info/rules.go +++ b/WebScan/info/rules.go @@ -64,7 +64,7 @@ var RuleDatas = []RuleData{ {"Nexus", "cookie", "(NX-ANTI-CSRF-TOKEN)"}, {"Harbor", "code", "(Harbor)"}, {"Harbor", "cookie", "(harbor-lang)"}, - {"禅道", "code", "(/theme/default/images/main/zt-logo.png)"}, + {"禅道", "code", "(/theme/default/images/main/zt-logo.png|/zentao/theme/zui/css/min.css)"}, {"禅道", "cookie", "(zentaosid)"}, {"协众OA", "code", "(Powered by 协众OA)"}, {"协众OA", "cookie", "(CNOAOASESSID)"}, @@ -199,7 +199,6 @@ var RuleDatas = []RuleData{ {"IBM-Lotus-Domino", "code", "(/mailjump.nsf|/domcfg.nsf|/names.nsf|/homepage.nsf)"}, {"APACHE-kylin", "code", "(url=kylin)"}, {"C-Lodop打印服务系统", "code", "(/CLodopfuncs.js|www.c-lodop.com)"}, - {"ATLASSIAN-Confluence", "code", "(Atlassian Confluence)"}, {"HFS", "code", "(href=\"http://www.rejetto.com/hfs/)"}, {"Jellyfin", "code", "(content=\"http://jellyfin.org\")"}, {"FIT2CLOUD-JumpServer-堡垒机", "code", "(JumpServer)"}, @@ -250,6 +249,8 @@ var RuleDatas = []RuleData{ {"JEECMS", "code", "(/r/cms/www/red/js/common.js|/r/cms/www/red/js/indexshow.js|Powered by JEECMS|JEECMS|/jeeadmin/jeecms/index.do)"}, {"CMS", "code", "(Powered by .*CMS)"}, {"目录遍历", "code", "(Directory listing for /)"}, + {"ATLASSIAN-Confluence", "code", "(com.atlassian.confluence)"}, + {"ATLASSIAN-Confluence", "headers", "(X-Confluence)"}, {"向日葵", "code", "({\"success\":false,\"msg\":\"Verification failure\"})"}, {"Kubernetes", "code", "(Kubernetes Dashboard|Kubernetes Enterprise Manager|Mirantis Kubernetes Engine|Kubernetes Resource Report)"}, {"WordPress", "code", "(/wp-login.php?action=lostpassword|WordPress)"}, diff --git a/WebScan/lib/check.go b/WebScan/lib/check.go index 14e8316..7dec98d 100644 --- a/WebScan/lib/check.go +++ b/WebScan/lib/check.go @@ -240,6 +240,9 @@ func optimizeCookies(rawCookie string) (output string) { } func newReverse() *Reverse { + if !common.DnsLog { + return &Reverse{} + } letters := "1234567890abcdefghijklmnopqrstuvwxyz" randSource := rand.New(rand.NewSource(time.Now().UnixNano())) sub := RandomStr(randSource, letters, 8) @@ -532,7 +535,7 @@ func evalset1(env *cel.Env, variableMap map[string]interface{}, k string, expres func CheckInfoPoc(infostr string) string { for _, poc := range info.PocDatas { - if strings.Compare(poc.Name, infostr) == 0 { + if strings.Contains(infostr, poc.Name) { return poc.Alias } } diff --git a/WebScan/lib/eval.go b/WebScan/lib/eval.go index 548024a..0f652e1 100644 --- a/WebScan/lib/eval.go +++ b/WebScan/lib/eval.go @@ -15,7 +15,6 @@ import ( "github.com/shadow1ng/fscan/common" exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" "io" - "io/ioutil" "math/rand" "net/http" "net/url" @@ -578,6 +577,7 @@ func reverseCheck(r *Reverse, timeout int64) bool { } if !bytes.Contains(resp.Body, []byte(`"data": []`)) && bytes.Contains(resp.Body, []byte(`"message": "OK"`)) { // api返回结果不为空 + fmt.Println(urlStr) return true } return false @@ -657,12 +657,12 @@ func ParseRequest(oReq *http.Request) (*Request, error) { req.ContentType = oReq.Header.Get("Content-Type") if oReq.Body == nil || oReq.Body == http.NoBody { } else { - data, err := ioutil.ReadAll(oReq.Body) + data, err := io.ReadAll(oReq.Body) if err != nil { return nil, err } req.Body = data - oReq.Body = ioutil.NopCloser(bytes.NewBuffer(data)) + oReq.Body = io.NopCloser(bytes.NewBuffer(data)) } return req, nil } @@ -677,9 +677,9 @@ func ParseResponse(oResp *http.Response) (*Response, error) { } resp.Headers = header resp.ContentType = oResp.Header.Get("Content-Type") - body, err := getRespBody(oResp) + body, _ := getRespBody(oResp) resp.Body = body - return &resp, err + return &resp, nil } func getRespBody(oResp *http.Response) (body []byte, err error) { diff --git a/common/ParseIP.go b/common/ParseIP.go index 96f2317..66084be 100644 --- a/common/ParseIP.go +++ b/common/ParseIP.go @@ -24,11 +24,21 @@ var ParseIPErr = errors.New(" host parsing error\n" + "192.168.1.1-255") func ParseIP(host string, filename string, nohosts ...string) (hosts []string, err error) { - hosts = ParseIPs(host) - if filename != "" { - var filehost []string - filehost, _ = Readipfile(filename) - hosts = append(hosts, filehost...) + if filename == "" && strings.Contains(host, ":") { + //192.168.0.0/16:80 + hostport := strings.Split(host, ":") + if len(hostport) == 2 { + host = hostport[0] + hosts = ParseIPs(host) + Ports = hostport[1] + } + } else { + hosts = ParseIPs(host) + if filename != "" { + var filehost []string + filehost, _ = Readipfile(filename) + hosts = append(hosts, filehost...) + } } if len(nohosts) > 0 { @@ -78,6 +88,12 @@ func ParseIPs(ip string) (hosts []string) { func parseIP(ip string) []string { reg := regexp.MustCompile(`[a-zA-Z]+`) switch { + case ip == "192": + return parseIP("192.168.0.0/8") + case ip == "172": + return parseIP("172.16.0.0/12") + case ip == "10": + return parseIP("10.0.0.0/8") // 扫描/8时,只扫网关和随机IP,避免扫描过多IP case strings.HasSuffix(ip, "/8"): return parseIP8(ip) diff --git a/common/ParsePort.go b/common/ParsePort.go index ae098b3..e5babeb 100644 --- a/common/ParsePort.go +++ b/common/ParsePort.go @@ -38,6 +38,9 @@ func ParsePort(ports string) (scanPorts []int) { start, _ := strconv.Atoi(port) end, _ := strconv.Atoi(upper) for i := start; i <= end; i++ { + if i > 65535 || i < 1 { + continue + } scanPorts = append(scanPorts, i) } } diff --git a/common/config.go b/common/config.go index 6cd4df1..b124086 100644 --- a/common/config.go +++ b/common/config.go @@ -97,7 +97,7 @@ var ( NoPing bool Ping bool Pocinfo PocInfo - NoWebCan bool + NoPoc bool IsBrute bool RedisFile string RedisShell string diff --git a/common/flag.go b/common/flag.go index c458ca0..450e2db 100644 --- a/common/flag.go +++ b/common/flag.go @@ -42,7 +42,7 @@ func Flag(Info *HostInfo) { flag.StringVar(&PocPath, "pocpath", "", "poc file path") flag.StringVar(&RedisFile, "rf", "", "redis file to write sshkey file (as: -rf id_rsa.pub)") flag.StringVar(&RedisShell, "rs", "", "redis shell to write cron file (as: -rs 192.168.1.1:6666)") - flag.BoolVar(&NoWebCan, "nopoc", false, "not to scan web vul") + flag.BoolVar(&NoPoc, "nopoc", false, "not to scan web vul") flag.BoolVar(&IsBrute, "nobr", false, "not to Brute password") flag.IntVar(&BruteThread, "br", 1, "Brute threads") flag.BoolVar(&NoPing, "np", false, "not to ping")