Skip to content

Commit

Permalink
Merge pull request #31 from stevenaldinger/feature/nmap-protocol-scan
Browse files Browse the repository at this point in the history
add nmap protocol detection
  • Loading branch information
stevenaldinger committed Mar 23, 2019
2 parents c3520c3 + 5dbe3e7 commit 6cffcb1
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 0 deletions.
4 changes: 4 additions & 0 deletions build/ci/drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ steps:
when:
branch:
- master
event:
- push
- name: build-kali
image: plugins/docker
settings:
Expand All @@ -67,3 +69,5 @@ steps:
when:
branch:
- master
event:
- push
24 changes: 24 additions & 0 deletions examples/nmap-protocols.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// environment variable config
variable "target_host" {
type = "string"
}

resource "nmap_protocol_detection" "nmap" {
host = "${var.target_host}"
type = "protocol_detection"
}

resource "metasploit" "metasploit" {
for_each = "${nmap.ssh}"
exploit = "auxiliary/scanner/ssh/ssh_login"
options = {
RHOSTS = "${var.target_host}"
RPORT = "${each.key}"
USERPASS_FILE = "/usr/share/metasploit-framework/data/wordlists/root_userpass.txt"
}
}

resource "sslscan" "sslscan" {
for_each = "${nmap.https}"
host = "${var.target_host}"
}
3 changes: 3 additions & 0 deletions internal/app/decker/plugins/nmap_protocol_detection/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# nmap decker plugin

[network mapper](https://nmap.org/)
176 changes: 176 additions & 0 deletions internal/app/decker/plugins/nmap_protocol_detection/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package main

import (
"bufio"
"fmt"
"github.com/stevenaldinger/decker/pkg/gocty"
"github.com/zclconf/go-cty/cty"
"os"
"os/exec"
"strconv"
"strings"
)

func stringToLines(s string) (lines []string, err error) {
scanner := bufio.NewScanner(strings.NewReader(s))
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
err = scanner.Err()
return lines, err
}

// https://www.dotnetperls.com/duplicates-go
func removeDuplicates(elements []string) []string {
encountered := map[string]bool{}

// Create a map of all unique elements.
for v:= range elements {
encountered[elements[v]] = true
}

// Place all keys from the map into a slice.
result := []string{}
for key, _ := range encountered {
result = append(result, key)
}
return result
}

type plugin string

// --- wants input: ---
// inputsMap{
// "host": "example.com",
// }
//
// --- gives output: ---
// resultsMap{
// "raw_output": "...",
// }
func (p plugin) Run(inputsMap, resultsMap *map[string]cty.Value) {
var (
cmdOut []byte
err error
cmdArgs []string
outputByLine []string
services []string
servicesMap map[string] []string
)

decoder := gocty.Decoder{}
encoder := gocty.Encoder{}
servicesMap = map[string][]string{}

targetHost := decoder.GetString((*inputsMap)["host"])
scanType := decoder.GetString((*inputsMap)["type"])

cmdName := "nmap"
if scanType == "protocol_detection" {
cmdArgs = []string{"-O", "-oG", "-", targetHost}
} else {
cmdArgs = []string{targetHost}
}

if cmdOut, err = exec.Command(cmdName, cmdArgs...).Output(); err != nil {
fmt.Fprintln(os.Stderr, "There was an error running nmap command: ", err)
return
}

output := string(cmdOut)

if scanType == "protocol_detection" {
// Host: 93.184.216.34 () Status: Up
// Host: 93.184.216.34 () Ports: 80/open/tcp//http///, 443/open/tcp//https///, 1935/closed/tcp//rtmp/// Ignored State: filtered (997) Seq Index: 252 IP ID Seq: Randomized
// # Nmap done at Mon Mar 11 19:02:34 2019 -- 1 IP address (1 host up) scanned in 8.76 seconds

// fmt.Println("Output:", output)

if outputByLine, err = stringToLines(output); err != nil {
fmt.Fprintln(os.Stderr, "Error occured while converting nmap protocol to array of strings: ", err)
return
}

splitOutput := strings.Split(outputByLine[2], "Ports: ")
portsOpen := splitOutput[1]
portsOpenArray := strings.Split(portsOpen, ",")

for _, portInfo := range portsOpenArray {
// fmt.Println("Port:", portInfo)

portInfoSplit := strings.Split(portInfo, "/")
// fmt.Println("Len(portInfoSplit):", len(portInfoSplit))
parsedPort := portInfoSplit[0]
parsedState := portInfoSplit[1]
parsedTransportProtocol := portInfoSplit[2]
parsedServiceProtocol := portInfoSplit[4]
// fmt.Println("Port:", parsedPort)
// fmt.Println("State:", parsedState)
// fmt.Println("Transport:", parsedTransportProtocol)
// fmt.Println("Service:", parsedServiceProtocol)
portInfoMap := map[string]cty.Value{
"port": encoder.StringVal(parsedPort),
"state": encoder.StringVal(parsedState),
"transport": encoder.StringVal(parsedTransportProtocol),
"service": encoder.StringVal(parsedServiceProtocol),
}

(*resultsMap)[parsedPort] = encoder.MapVal(portInfoMap)
// (*resultsMap)[parsedPort] = encoder.StringVal(parsedServiceProtocol)

if _, ok := servicesMap[parsedServiceProtocol]; !ok {
servicesMap[parsedServiceProtocol] = []string{}
}
servicesMap[parsedServiceProtocol] = removeDuplicates(append(servicesMap[parsedServiceProtocol], parsedPort))
services = append(services, parsedServiceProtocol)
}

services = removeDuplicates(services)

// set everything that's not open to false so value is defined in HCL configs
for i := 1; i <= 30000; i++ {
if _, ok := (*resultsMap)[strconv.Itoa(i)]; !ok {
portInfoMap := map[string]cty.Value{
"port": encoder.StringVal(strconv.Itoa(i)),
"state": encoder.StringVal("closed"),
"transport": encoder.StringVal(""),
"service": encoder.StringVal(""),
}

(*resultsMap)[strconv.Itoa(i)] = encoder.MapVal(portInfoMap)
// (*resultsMap)[strconv.Itoa(i)] = encoder.StringVal("")
}
}

var servicesCty = []cty.Value{}
for _, service := range services {
servicesCty = append(servicesCty, encoder.StringVal(service))

var portsWithServiceCty = []cty.Value{}
for _, port := range servicesMap[service] {
portsWithServiceCty = append(portsWithServiceCty, encoder.StringVal(port))
}
(*resultsMap)[service] = encoder.ListVal(portsWithServiceCty)
}

(*resultsMap)["services"] = encoder.ListVal(servicesCty)
}
// } else {
// portInfoMap := map[string]cty.Value{
// "port": encoder.StringVal(strconv.Itoa(i)),
// "state": encoder.StringVal("closed"),
// "transport": encoder.StringVal(""),
// "service": encoder.StringVal(""),
// }
// (*resultsMap)[strconv.Itoa(i)] = encoder.MapVal(portInfoMap)
// (*resultsMap)["protocol"] = encoder.StringVal("")
// }

(*resultsMap)["raw_output"] = encoder.StringVal(output)
}

// Plugin is an implementation of github.com/stevenaldinger/decker/pkg/plugins.Plugin
// All this includes is a single function, "Run(*map[string]string, *map[string]string)"
// which takes a map of inputs and an empty map of outputs that the Plugin
// is expected to populate
var Plugin plugin
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// inputs must be given in the main config spec
// if no default is given, considered to be required
// input "arguments" {
// type = "list"
// default = []
// }
input "type" {
type = "string"
default = "port_scan"
}

input "host" {
type = "string"
default = "example.com"
}

input "plugin_enabled" {
type = "string"
default = "true"
}

// outputs the plugin will return
output "raw_output" {
type = "string"
}
5 changes: 5 additions & 0 deletions pkg/gocty/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ func (*Encoder) ListVal(val []cty.Value) cty.Value {
return cty.ListVal(val)
}

// ListVal takes a map of cty values and returns a cty value of type list.
func (*Encoder) MapVal(val map[string]cty.Value) cty.Value {
return cty.ObjectVal(val)
}

// BoolVal takes a boolean and returns a cty value.
func (*Encoder) BoolVal(val bool) cty.Value {
return cty.BoolVal(val)
Expand Down

0 comments on commit 6cffcb1

Please sign in to comment.