Skip to content

Commit

Permalink
Merge pull request #2 from tomsteele/multi-addr
Browse files Browse the repository at this point in the history
Multi addr
  • Loading branch information
tomsteele committed Apr 6, 2016
2 parents 01a47e0 + 2958718 commit b58f462
Show file tree
Hide file tree
Showing 10 changed files with 378 additions and 202 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cookiescan
*.json
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ $ ./cookiescan
##Usage##
```
$ cookiescan -h
Usage:
cookiescan [options] <target>
cookiescan -h | --help
cookiescan -v | --version
Required Arguments:
target: IP Address or Hostname
target: IP Address, Hostname, or CIDR network. May also be a a newline separated
file containing targets.
Options:
-h --help Show this message.
Expand All @@ -32,6 +34,6 @@ Options:
-c <int> Minimum confidence level to flag port as open. [default: 1]
-i <interface> Network interface to listen on.
-t <timeout> Timeout in Milliseconds to wait for a connection. [default: 400]
-j Output JSON.
-j <file> Output JSON to file.
```
File renamed without changes.
105 changes: 105 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package main

import (
"fmt"
"log"
"net"
"time"

"github.com/gosuri/uiprogress"
"github.com/miekg/pcap"
"github.com/tomsteele/cookiescan"
)

type empty struct{}
type task struct {
ip string
port int
}

func main() {
var (
options = parse()
filter = "tcp[13] == 0x11 or tcp[13] == 0x10 or tcp[13] == 0x18"
)

h, err := pcap.OpenLive(options.device, int32(320), true, 500)
if err != nil {
log.Fatal(err.Error())
}
if err = h.SetFilter(filter); err != nil {
log.Fatal(err.Error())
}
db := cookiescan.NewStore(options.ips)

var (
track = make(chan empty)
tasks = make(chan task, options.minconcurrency)
)

go func() {
for pkt, r := h.NextEx(); r >= 0; pkt, r = h.NextEx() {
select {
case <-track:
break
default:
if r == 0 {
continue
}
pkt.Decode()
if len(pkt.Headers) < 2 {
continue
}
iphdr, ok := pkt.Headers[0].(*pcap.Iphdr)
if !ok {
continue
}
if len(iphdr.SrcIp) < 4 {
continue
}
ip := fmt.Sprintf("%v.%v.%v.%v", iphdr.SrcIp[0], iphdr.SrcIp[1], iphdr.SrcIp[2], iphdr.SrcIp[3])
tcphdr, ok := pkt.Headers[1].(*pcap.Tcphdr)
if !ok {
continue
}
db.Add(ip, int(tcphdr.SrcPort), tcphdr.FlagsString())
}
}
h.Close()
}()

for i := 0; i < options.minconcurrency; i++ {
go func() {
for tsk := range tasks {
c, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", tsk.ip, tsk.port), options.timeout)
if err != nil {
continue
}
c.Close()
}
}()
}

uiprogress.Start()
bar := uiprogress.AddBar(len(options.ips) * len(options.services))
bar.AppendCompleted()
bar.PrependElapsed()

for _, ip := range options.ips {
for _, p := range options.services {
tasks <- task{ip, p}
bar.Incr()
}
}

close(tasks)
time.Sleep(time.Duration(2 * time.Second))
track <- empty{}
close(track)
uiprogress.Stop()

if options.jsonfile != "" {
db.JSON(options.minconfidence, options.jsonfile)
}
db.Tabbed(options.minconfidence)
}
158 changes: 158 additions & 0 deletions cmd/parse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package main

import (
"bufio"
"fmt"
"log"
"net"
"os"
"strconv"
"time"

"github.com/docopt/docopt-go"
"github.com/miekg/pcap"
)

const usage = `
Usage:
cookiescan [options] <target>
cookiescan -h | --help
cookiescan -v | --version
Required Arguments:
target: IP Address, Hostname, or CIDR network. May also be a a newline separated
file containing targets.
Options:
-h --help Show this message.
-v --version Show version.
-p <port ranges> Ex: -p 22; -p 1-65535, -p 80,443. [default: 1-1024]
-g <int> Amount of goroutines to spread connection attempts across. [default: 1000]
-c <int> Minimum confidence level to flag port as open. [default: 1]
-i <interface> Network interface to listen on.
-t <timeout> Timeout in Milliseconds to wait for a connection. [default: 400]
-j <file> Output JSON to file.
`

type O struct {
services []int
minconfidence int
minconcurrency int
timeout time.Duration
device string
ips []string
jsonfile string
}

func parse() *O {
args, err := docopt.Parse(usage, nil, true, "cookiescan 2.0.0", false)
if err != nil {
log.Fatalf("Error parsing usage. Error: %s\n", err.Error())
}
if err != nil {
log.Fatalf("Error parsing usage. Error: %s\n", err.Error())
}
o := &O{
jsonfile: args["-j"].(string),
}

var lines []string
hostorfile := args["<target>"].(string)
if ok, err := os.Stat(hostorfile); err == nil && ok != nil {
if lines, err = readFileLines(hostorfile); err != nil {
log.Fatalf("Error parsing input file. Error: %s\n", err.Error())
}
} else {
lines = append(lines, hostorfile)
}

if o.ips, err = linesToIPList(lines); err != nil {
log.Fatalf("Error parsing targets. Error: %s\n", err.Error())
}

if o.services, err = explode(args["-p"].(string)); err != nil {
log.Fatalf("Error parsing port string. Error %s\n", err.Error())
}

if o.minconfidence, err = strconv.Atoi(args["-c"].(string)); err != nil {
log.Fatal("Invalid argument for -c.")
}
if o.minconcurrency, err = strconv.Atoi(args["-g"].(string)); err != nil {
log.Fatal("Invalid argument for -g.")
}

ti, err := strconv.Atoi(args["-t"].(string))
if err != nil {
log.Fatal("Invalid argument for -t.")
}
o.timeout = time.Duration(ti) * time.Millisecond

if args["-i"] != nil {
o.device = args["-i"].(string)
}
if o.device == "" {
devs, err := pcap.FindAllDevs()
if err != nil {
log.Fatal("Error finding interfaces. Error: ", err)
}
if len(devs) == 0 {
log.Fatal("No interfaces found. Are you not running as root?")
}
o.device = devs[0].Name
}

return o
}

// linesToIPList processes a list of IP addresses or networks in CIDR format.
// Returning a list of all possible IP addresses.
func linesToIPList(lines []string) ([]string, error) {
ipList := []string{}
for _, line := range lines {
if net.ParseIP(line) != nil {
ipList = append(ipList, line)
} else if ip, network, err := net.ParseCIDR(line); err == nil {
for ip := ip.Mask(network.Mask); network.Contains(ip); increaseIP(ip) {
ipList = append(ipList, ip.String())
}
} else {
return ipList, fmt.Errorf("%s is not an IP Address or CIDR Network", line)
ips, err := net.LookupIP(line)
if err != nil {
return ipList, fmt.Errorf("%s is not a valid hostname", line)
}
ipList = append(ipList, ips[0].String())
}
}
return ipList, nil
}

// increases an IP by a single address.
func increaseIP(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}

// readFileLines returns all the lines in a file.
func readFileLines(path string) ([]string, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
lines := []string{}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
if scanner.Text() == "" {
continue
}
lines = append(lines, scanner.Text())
}
return lines, scanner.Err()
}
Loading

0 comments on commit b58f462

Please sign in to comment.