mirror of
https://github.com/jessfraz/dockerfiles.git
synced 2024-11-23 11:31:49 +01:00
use masscan for k8scan
Signed-off-by: Jess Frazelle <acidburn@microsoft.com>
This commit is contained in:
parent
cabc5dad9c
commit
cf4dd75b5c
182
k8scan/main.go
182
k8scan/main.go
|
@ -11,7 +11,9 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
@ -36,8 +38,11 @@ var (
|
|||
|
||||
cidr string
|
||||
|
||||
defaultPorts = intSlice{80, 443, 8001, 9001}
|
||||
ports intSlice
|
||||
defaultPorts = intSlice{80, 443, 8001, 9001}
|
||||
originalPorts string
|
||||
ports intSlice
|
||||
|
||||
useMasscan bool
|
||||
|
||||
mailgunDomain string
|
||||
mailgunAPIKey string
|
||||
|
@ -62,6 +67,8 @@ func (i *intSlice) String() (out string) {
|
|||
}
|
||||
|
||||
func (i *intSlice) Set(value string) error {
|
||||
originalPorts = value
|
||||
|
||||
// Set the default if nothing was given.
|
||||
if len(value) <= 0 {
|
||||
*i = defaultPorts
|
||||
|
@ -110,6 +117,8 @@ func init() {
|
|||
flag.StringVar(&cidr, "cidr", defaultCIDR, "IP CIDR to scan")
|
||||
flag.Var(&ports, "ports", fmt.Sprintf("Ports to scan (ex. 80-443 or 80,443,8080 or 1-20,22,80-443) (default %q)", defaultPorts.String()))
|
||||
|
||||
flag.BoolVar(&useMasscan, "masscan", true, "Use masscan binary for scanning (this is faster than using pure golang)")
|
||||
|
||||
flag.StringVar(&mailgunAPIKey, "mailgun-api-key", "", "Mailgun API Key to use for sending email (optional)")
|
||||
flag.StringVar(&mailgunDomain, "mailgun-domain", "", "Mailgun Domain to use for sending email (optional)")
|
||||
flag.StringVar(&emailRecipient, "email-recipient", "", "Recipient for email notifications (optional)")
|
||||
|
@ -122,10 +131,15 @@ func init() {
|
|||
|
||||
flag.Parse()
|
||||
|
||||
// set log level
|
||||
// Set the log level.
|
||||
if debug {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
|
||||
// Set the default ports.
|
||||
if len(ports) <= 0 {
|
||||
ports = defaultPorts
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
@ -145,29 +159,56 @@ func main() {
|
|||
log.SetFlags(0)
|
||||
log.SetOutput(ioutil.Discard)
|
||||
|
||||
logrus.Infof("Scanning for Kubernetes Dashboards and API Servers on %s over port range %#v", cidr, ports)
|
||||
logrus.Infof("Scanning for Kubernetes Dashboards and API Servers on %s over port range %s", cidr, originalPorts)
|
||||
if len(mailgunDomain) > 0 && len(mailgunAPIKey) > 0 && len(emailRecipient) > 0 {
|
||||
logrus.Infof("Using Mailgun Domain %s, API Key %s to send emails to %s", mailgunDomain, mailgunAPIKey, emailRecipient)
|
||||
}
|
||||
logrus.Infof("This may take a bit...")
|
||||
|
||||
startTime := time.Now()
|
||||
var (
|
||||
startTime = time.Now()
|
||||
wg sync.WaitGroup
|
||||
)
|
||||
|
||||
ip, ipnet, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
if useMasscan {
|
||||
m, err := doMasscan()
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
|
||||
for _, port := range ports {
|
||||
wg.Add(1)
|
||||
go func(ip string, port int) {
|
||||
defer wg.Done()
|
||||
for _, result := range m {
|
||||
for _, port := range result.Ports {
|
||||
wg.Add(1)
|
||||
go func(ip string, port int) {
|
||||
defer wg.Done()
|
||||
|
||||
scanIP(ip, port)
|
||||
scanIP(ip, port)
|
||||
|
||||
}(ip.String(), port)
|
||||
}(result.IP, port.Port)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ip, ipnet, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
|
||||
for _, port := range ports {
|
||||
wg.Add(1)
|
||||
go func(ip string, port int) {
|
||||
defer wg.Done()
|
||||
|
||||
// Check if the port is open.
|
||||
ok := portOpen(ip, port)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
scanIP(ip, port)
|
||||
|
||||
}(ip.String(), port)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,12 +219,6 @@ func main() {
|
|||
}
|
||||
|
||||
func scanIP(ip string, port int) {
|
||||
// Check if the port is open.
|
||||
ok := portOpen(ip, port)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if it's a kubernetes dashboard.
|
||||
ok, uri := isKubernetesDashboard(ip, port)
|
||||
if !ok {
|
||||
|
@ -286,6 +321,58 @@ type OrganizationJSON struct {
|
|||
Reference string `json:"$,omitempty"`
|
||||
}
|
||||
|
||||
// MasscanResult holds the masscan results data struct.
|
||||
// Looks like:
|
||||
// [
|
||||
// {
|
||||
// "ip": "104.198.238.41",
|
||||
// "timestamp": "1531524211",
|
||||
// "ports": [
|
||||
// {
|
||||
// "port": 22,
|
||||
// "proto": "tcp",
|
||||
// "status": "open",
|
||||
// "reason": "syn-ack",
|
||||
// "ttl": 56
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// ...
|
||||
// ]
|
||||
type MasscanResult struct {
|
||||
IP string `json:"ip,omitempty"`
|
||||
Timestamp MasscanTime `json:"timestamp,omitempty"`
|
||||
Ports []MasscanPort `json:"ports,omitempty"`
|
||||
}
|
||||
|
||||
// MasscanPort defines the data struct for a masscan port.
|
||||
type MasscanPort struct {
|
||||
Port int `json:"port,omitempty"`
|
||||
Protocol string `json:"proto,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
TTL int `json:"ttl,omitempty"`
|
||||
}
|
||||
|
||||
// MasscanTime is the time format returned by masscan.
|
||||
type MasscanTime struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets MasscanTime correctly from a string.
|
||||
func (t *MasscanTime) UnmarshalJSON(b []byte) error {
|
||||
s := strings.Trim(strings.TrimSpace(string(b)), `"`)
|
||||
|
||||
i, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*t = MasscanTime{time.Unix(i, 0)}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getIPInfo(ip string) (b ARINResponse, err error) {
|
||||
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf(arinAPIEndpoint, ip), nil)
|
||||
if err != nil {
|
||||
|
@ -346,3 +433,52 @@ ARIN: %s
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func doMasscan() ([]MasscanResult, error) {
|
||||
// Create a temporary directory for the output.
|
||||
dir, err := ioutil.TempDir(os.TempDir(), "masscan")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating temporary directory failed: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
file := filepath.Join(dir, "scan.json")
|
||||
|
||||
cmd := exec.Command("masscan",
|
||||
fmt.Sprintf("-p%s", ports.String()),
|
||||
cidr,
|
||||
"--output-format", "json",
|
||||
"--output-file", file,
|
||||
"--rate", "1000000",
|
||||
"--exclude", "255.255.255.255",
|
||||
)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
logrus.Infof("Running masscan command: `%s`", strings.Join(cmd.Args, " "))
|
||||
if err := cmd.Run(); err != nil {
|
||||
return nil, fmt.Errorf("running masscan failed: %v", err)
|
||||
}
|
||||
|
||||
b, err := cleanMasscanOutputFile(file)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cleaning up masscan file failed: %v", err)
|
||||
}
|
||||
|
||||
m := []MasscanResult{}
|
||||
if err := json.Unmarshal(b, &m); err != nil {
|
||||
return nil, fmt.Errorf("unmarshal json failed: %v", err)
|
||||
}
|
||||
|
||||
logrus.Debugf("masscan result: %#v", m)
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func cleanMasscanOutputFile(file string) ([]byte, error) {
|
||||
b, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []byte(strings.TrimSuffix(strings.TrimSpace(string(b)), ",\n]") + "]"), nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user