new: syn.scan will now perform basic tcp banner grabbing

This commit is contained in:
evilsocket 2019-04-21 15:45:32 +02:00
commit aea68460c8
No known key found for this signature in database
GPG key ID: 1564D7F30393A456
5 changed files with 160 additions and 3 deletions

View file

@ -0,0 +1,41 @@
package syn_scan
import (
"github.com/bettercap/bettercap/network"
"github.com/evilsocket/islazy/async"
)
type bannerGrabberFn func(mod *SynScanner, ip string, port int) string
type grabberJob struct {
Host *network.Endpoint
Port *OpenPort
}
var tcpBannerGrabbers = map[int]bannerGrabberFn{
80: httpGrabber,
8080: httpGrabber,
443: httpGrabber,
8443: httpGrabber,
}
func (mod *SynScanner) bannerGrabber(arg async.Job) {
job := arg.(grabberJob)
if job.Port.Proto != "tcp" {
return
}
ip := job.Host.IpAddress
port := job.Port.Port
fn, found := tcpBannerGrabbers[port]
if !found {
fn = tcpGrabber
}
mod.Debug("grabbing banner for %s:%d", ip, port)
job.Port.Banner = fn(mod, ip, port)
if job.Port.Banner != "" {
mod.Info("found banner for %s:%d -> %s", ip, port, job.Port.Banner)
}
}

View file

@ -0,0 +1,89 @@
package syn_scan
import (
"crypto/tls"
"crypto/x509"
"fmt"
"golang.org/x/net/html"
"net/http"
"strings"
"time"
)
func isTitleElement(n *html.Node) bool {
return n.Type == html.ElementNode && strings.ToLower(n.Data) == "title"
}
func searchForTitle(n *html.Node) string {
if isTitleElement(n) {
return n.FirstChild.Data
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
if result := searchForTitle(c); result != "" {
return result
}
}
return ""
}
func httpGrabber(mod *SynScanner, ip string, port int) string {
schema := "http"
timeout := time.Duration(10 * time.Second)
client := &http.Client{
Timeout: timeout,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return nil
},
}
if port == 443 || port == 8443 {
schema = "https"
client = &http.Client{
Timeout: timeout,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
return nil
},
},
},
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return nil
},
}
}
url := fmt.Sprintf("%s://%s:%d/", schema, ip, port)
resp, err := client.Get(url)
if err != nil {
mod.Debug("error while grabbing banner from %s: %v", url, err)
return ""
}
defer resp.Body.Close()
fallback := ""
for name, values := range resp.Header {
for _, value := range values {
header := strings.ToLower(name)
if len(value) > len(fallback) && (header == "x-powered-by" || header == "server") {
mod.Debug("found header %s for %s:%d -> %s", header, ip, port, value)
fallback = value
}
}
}
doc, err := html.Parse(resp.Body)
if err != nil {
mod.Debug("error while reading and parsing response from %s: %v", url, err)
return fallback
}
if title := searchForTitle(doc); title != "" {
return title
}
return fallback
}

View file

@ -13,6 +13,7 @@ import (
"github.com/malfunkt/iprange"
"github.com/evilsocket/islazy/async"
"github.com/evilsocket/islazy/str"
)
@ -35,6 +36,7 @@ type SynScanner struct {
progressEvery time.Duration
stats synScannerStats
waitGroup *sync.WaitGroup
bannerQueue *async.WorkQueue
}
func NewSynScanner(s *session.Session) *SynScanner {
@ -45,6 +47,7 @@ func NewSynScanner(s *session.Session) *SynScanner {
progressEvery: time.Duration(1) * time.Second,
}
mod.bannerQueue = async.NewQueue(4, mod.bannerGrabber)
mod.State.Store("scanning", &mod.addresses)
mod.State.Store("progress", 0.0)
@ -257,7 +260,7 @@ func (mod *SynScanner) synScan() error {
mod.Debug("sent %d bytes of SYN packet to %s for port %d", len(raw), address.String(), dstPort)
}
time.Sleep(time.Duration(10) * time.Millisecond)
time.Sleep(time.Duration(25) * time.Millisecond)
}
}
})

View file

@ -8,6 +8,8 @@ import (
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/evilsocket/islazy/async"
)
type OpenPort struct {
@ -60,13 +62,17 @@ func (mod *SynScanner) onPacket(pkt gopacket.Packet) {
}
if host != nil {
ports := host.Meta.GetOr("ports", map[int]OpenPort{}).(map[int]OpenPort)
ports := host.Meta.GetOr("ports", map[int]*OpenPort{}).(map[int]*OpenPort)
if _, found := ports[port]; !found {
ports[port] = OpenPort{
openPort := &OpenPort{
Proto: "tcp",
Port: port,
Service: network.GetServiceByPort(port, "tcp"),
}
ports[port] = openPort
mod.bannerQueue.Add(async.Job(grabberJob{host, openPort}))
}
host.Meta.Set("ports", ports)

View file

@ -0,0 +1,18 @@
package syn_scan
import (
"bufio"
"fmt"
"net"
"strings"
)
func tcpGrabber(mod *SynScanner, ip string, port int) string {
if conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", ip, port)); err == nil {
defer conn.Close()
msg, _ := bufio.NewReader(conn).ReadString('\n')
return strings.Trim(msg, "\r\n\t ")
}
return ""
}