Skip to content

Commit

Permalink
Add port number to CSV input and output (#397)
Browse files Browse the repository at this point in the history
* Add port to csv input and output JSON.

* fix null pointer deref

---------

Co-authored-by: AnthraX <[email protected]>
  • Loading branch information
AnthraX1 and AnthraX1 authored Feb 18, 2024
1 parent 7363919 commit 7c933df
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 15 deletions.
41 changes: 32 additions & 9 deletions input.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,31 @@ import (
"fmt"
"io"
"net"
"strconv"
"strings"

log "github.com/sirupsen/logrus"
)

// ParseCSVTarget takes a record from a CSV-format input file and
// returns the specified ipnet, domain, and tag, or an error.
// returns the specified ipnet, domain, tag and port or an error.
//
// ZGrab2 input files have three fields:
// IP, DOMAIN, TAG
// ZGrab2 input files have four fields:
//
// IP, DOMAIN, TAG, PORT
//
// Each line specifies a target to scan by its IP address, domain
// name, or both, as well as an optional tag used to determine which
// name or both, as well as an optional tag used to determine which
// scanners will be invoked.
//
// Port number has been added to the end of the line for compatibility reasons.
// A CIDR block may be provided in the IP field, in which case the
// framework expands the record into targets for every address in the
// block.
//
// Trailing empty fields may be omitted.
// Comment lines begin with #, and empty lines are ignored.
//
func ParseCSVTarget(fields []string) (ipnet *net.IPNet, domain string, tag string, err error) {
func ParseCSVTarget(fields []string) (ipnet *net.IPNet, domain string, tag string, port string, err error) {
for i := range fields {
fields[i] = strings.TrimSpace(fields[i])
}
Expand All @@ -47,7 +49,11 @@ func ParseCSVTarget(fields []string) (ipnet *net.IPNet, domain string, tag strin
if len(fields) > 2 {
tag = fields[2]
}
// Use string for port to allow empty port
if len(fields) > 3 {
port = fields[3]
}
if len(fields) > 4 {
err = fmt.Errorf("too many fields: %q", fields)
return
}
Expand Down Expand Up @@ -102,24 +108,41 @@ func GetTargetsCSV(source io.Reader, ch chan<- ScanTarget) error {
if len(fields) == 0 {
continue
}
ipnet, domain, tag, err := ParseCSVTarget(fields)
ipnet, domain, tag, port, err := ParseCSVTarget(fields)
if err != nil {
log.Errorf("parse error, skipping: %v", err)
continue
}
var ip net.IP
var port_uint uint
if port != "" {
port_int, err := strconv.Atoi(port)
port_uint = uint(port_int)
if err != nil {
log.Errorf("parse error, skipping: %v", err)
continue
}
}
if ipnet != nil {
if ipnet.Mask != nil {
// expand CIDR block into one target for each IP
for ip = ipnet.IP.Mask(ipnet.Mask); ipnet.Contains(ip); incrementIP(ip) {
ch <- ScanTarget{IP: duplicateIP(ip), Domain: domain, Tag: tag}
if port == "" {
ch <- ScanTarget{IP: duplicateIP(ip), Domain: domain, Tag: tag}
} else {
ch <- ScanTarget{IP: duplicateIP(ip), Domain: domain, Tag: tag, Port: &port_uint}
}
}
continue
} else {
ip = ipnet.IP
}
}
ch <- ScanTarget{IP: ip, Domain: domain, Tag: tag}
if port == "" {
ch <- ScanTarget{IP: ip, Domain: domain, Tag: tag}
} else {
ch <- ScanTarget{IP: ip, Domain: domain, Tag: tag, Port: &port_uint}
}
}
return nil
}
Expand Down
34 changes: 29 additions & 5 deletions input_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,27 @@ func TestParseCSVTarget(t *testing.T) {
ipnet *net.IPNet
domain string
tag string
port string
success bool
}{
// IP DOMAIN TAG PORT
{
fields: []string{"10.0.0.1", "example.com", "tag", "443"},
ipnet: parseIP("10.0.0.1"),
domain: "example.com",
tag: "tag",
port: "443",
success: true,
},
// IP DOMAIN TAG PORT
{
fields: []string{"10.0.0.1", "example.com", "tag"},
ipnet: parseIP("10.0.0.1"),
domain: "example.com",
tag: "tag",
port: "",
success: true,
},
// IP DOMAIN TAG
{
fields: []string{"10.0.0.1", "example.com", "tag"},
Expand Down Expand Up @@ -129,14 +148,14 @@ func TestParseCSVTarget(t *testing.T) {
}

for _, test := range tests {
ipnet, domain, tag, err := ParseCSVTarget(test.fields)
ipnet, domain, tag, port, err := ParseCSVTarget(test.fields)
if (err == nil) != test.success {
t.Errorf("wrong error status (got err=%v, success should be %v): %q", err, test.success, test.fields)
return
}
if err == nil {
if ipnetString(ipnet) != ipnetString(test.ipnet) || domain != test.domain || tag != test.tag {
t.Errorf("wrong result (got %v,%v,%v; expected %v,%v,%v): %q", ipnetString(ipnet), domain, tag, ipnetString(test.ipnet), test.domain, test.tag, test.fields)
if ipnetString(ipnet) != ipnetString(test.ipnet) || domain != test.domain || tag != test.tag || port != test.port {
t.Errorf("wrong result (got %v,%v,%v,%v ; expected %v,%v,%v,%v): %q", ipnetString(ipnet), domain, tag, port, ipnetString(test.ipnet), test.domain, test.tag, test.port, test.fields)
return
}
}
Expand All @@ -150,8 +169,11 @@ func TestGetTargetsCSV(t *testing.T) {
10.0.0.1
,example.com
example.com
2.2.2.2/30,, tag`

2.2.2.2/30,, tag
10.0.0.1,example.com,tag,443
10.0.0.1,,,443
`
port := uint(443)
expected := []ScanTarget{
ScanTarget{IP: net.ParseIP("10.0.0.1"), Domain: "example.com", Tag: "tag"},
ScanTarget{IP: net.ParseIP("10.0.0.1"), Domain: "example.com"},
Expand All @@ -162,6 +184,8 @@ example.com
ScanTarget{IP: net.ParseIP("2.2.2.1"), Tag: "tag"},
ScanTarget{IP: net.ParseIP("2.2.2.2"), Tag: "tag"},
ScanTarget{IP: net.ParseIP("2.2.2.3"), Tag: "tag"},
ScanTarget{IP: net.ParseIP("10.0.0.1"), Domain: "example.com", Tag: "tag", Port: &port},
ScanTarget{IP: net.ParseIP("10.0.0.1"), Port: &port},
}

ch := make(chan ScanTarget, 0)
Expand Down
7 changes: 6 additions & 1 deletion processing.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
// Grab contains all scan responses for a single host
type Grab struct {
IP string `json:"ip,omitempty"`
Port uint `json:"port,omitempty"`
Domain string `json:"domain,omitempty"`
Data map[string]ScanResponse `json:"data,omitempty"`
}
Expand Down Expand Up @@ -117,12 +118,16 @@ func (target *ScanTarget) OpenUDP(flags *BaseFlags, udp *UDPFlags) (net.Conn, er
// scan responses.
func BuildGrabFromInputResponse(t *ScanTarget, responses map[string]ScanResponse) *Grab {
var ipstr string

var port uint
if t.IP != nil {
ipstr = t.IP.String()
}
if t.Port != nil {
port = *t.Port
}
return &Grab{
IP: ipstr,
Port: port,
Domain: t.Domain,
Data: responses,
}
Expand Down

0 comments on commit 7c933df

Please sign in to comment.