new: basic ipv6 support

This commit is contained in:
Simone Margaritelli 2021-04-03 18:42:14 +02:00
parent d0b5c34763
commit bef4c6abaa
8 changed files with 115 additions and 35 deletions

View file

@ -55,6 +55,11 @@ func httpGrabber(mod *SynScanner, ip string, port int) string {
} }
} }
// https://stackoverflow.com/questions/12260003/connect-returns-invalid-argument-with-ipv6-address
if strings.Contains(ip, ":") {
ip = fmt.Sprintf("[%s%%25%s]", ip, mod.Session.Interface.Name())
}
url := fmt.Sprintf("%s://%s:%d/", schema, ip, port) url := fmt.Sprintf("%s://%s:%d/", schema, ip, port)
resp, err := client.Get(url) resp, err := client.Get(url)
if err != nil { if err != nil {

View file

@ -167,6 +167,12 @@ type scanJob struct {
func (mod *SynScanner) scanWorker(job async.Job) { func (mod *SynScanner) scanWorker(job async.Job) {
scan := job.(scanJob) scan := job.(scanJob)
fromHW := mod.Session.Interface.HW
fromIP := mod.Session.Interface.IP
if scan.Address.To4() == nil {
fromIP = mod.Session.Interface.IPv6
}
for dstPort := mod.startPort; dstPort < mod.endPort+1; dstPort++ { for dstPort := mod.startPort; dstPort < mod.endPort+1; dstPort++ {
if !mod.Running() { if !mod.Running() {
break break
@ -174,7 +180,7 @@ func (mod *SynScanner) scanWorker(job async.Job) {
atomic.AddUint64(&mod.stats.doneProbes, 1) atomic.AddUint64(&mod.stats.doneProbes, 1)
err, raw := packets.NewTCPSyn(mod.Session.Interface.IP, mod.Session.Interface.HW, scan.Address, scan.Mac, synSourcePort, dstPort) err, raw := packets.NewTCPSyn(fromIP, fromHW, scan.Address, scan.Mac, synSourcePort, dstPort)
if err != nil { if err != nil {
mod.Error("error creating SYN packet: %s", err) mod.Error("error creating SYN packet: %s", err)
continue continue

View file

@ -2,18 +2,30 @@ package syn_scan
import ( import (
"fmt" "fmt"
"net"
"strconv" "strconv"
"strings"
"github.com/evilsocket/islazy/str" "github.com/evilsocket/islazy/str"
"github.com/malfunkt/iprange" "github.com/malfunkt/iprange"
) )
func (mod *SynScanner) parseTargets(arg string) error { func (mod *SynScanner) parseTargets(arg string) error {
if list, err := iprange.Parse(arg); err != nil { if strings.Contains(arg, ":") {
return fmt.Errorf("error while parsing IP range '%s': %s", arg, err) // parse as IPv6 address
if ip := net.ParseIP(arg); ip == nil {
return fmt.Errorf("error while parsing IPv6 '%s'", arg)
} else {
mod.addresses = []net.IP{ip}
}
} else { } else {
mod.addresses = list.Expand() if list, err := iprange.Parse(arg); err != nil {
return fmt.Errorf("error while parsing IP range '%s': %s", arg, err)
} else {
mod.addresses = list.Expand()
}
} }
return nil return nil
} }

View file

@ -24,26 +24,40 @@ func (mod *SynScanner) onPacket(pkt gopacket.Packet) {
} }
var eth layers.Ethernet var eth layers.Ethernet
var ip layers.IPv4 var ip4 layers.IPv4
var ip6 layers.IPv6
var tcp layers.TCP var tcp layers.TCP
foundLayerTypes := []gopacket.LayerType{}
isIPv6 := false
foundLayerTypes := []gopacket.LayerType{}
parser := gopacket.NewDecodingLayerParser( parser := gopacket.NewDecodingLayerParser(
layers.LayerTypeEthernet, layers.LayerTypeEthernet,
&eth, &eth,
&ip, &ip4,
&tcp, &tcp,
) )
err := parser.DecodeLayers(pkt.Data(), &foundLayerTypes) err := parser.DecodeLayers(pkt.Data(), &foundLayerTypes)
if err != nil { if err != nil {
return // try ipv6
parser := gopacket.NewDecodingLayerParser(
layers.LayerTypeEthernet,
&eth,
&ip6,
&tcp,
)
err = parser.DecodeLayers(pkt.Data(), &foundLayerTypes)
if err != nil {
return
}
isIPv6 = true
} }
if tcp.DstPort == synSourcePort && tcp.SYN && tcp.ACK { if tcp.DstPort == synSourcePort && tcp.SYN && tcp.ACK {
atomic.AddUint64(&mod.stats.openPorts, 1) atomic.AddUint64(&mod.stats.openPorts, 1)
from := ip.SrcIP.String()
port := int(tcp.SrcPort) port := int(tcp.SrcPort)
openPort := &OpenPort{ openPort := &OpenPort{
@ -53,12 +67,28 @@ func (mod *SynScanner) onPacket(pkt gopacket.Packet) {
} }
var host *network.Endpoint var host *network.Endpoint
if ip.SrcIP.Equal(mod.Session.Interface.IP) {
host = mod.Session.Interface from := ""
} else if ip.SrcIP.Equal(mod.Session.Gateway.IP) {
host = mod.Session.Gateway if isIPv6 {
from = ip6.SrcIP.String()
if ip6.SrcIP.Equal(mod.Session.Interface.IPv6) {
host = mod.Session.Interface
} else if ip6.SrcIP.Equal(mod.Session.Gateway.IPv6) {
host = mod.Session.Gateway
} else {
host = mod.Session.Lan.GetByIp(from)
}
} else { } else {
host = mod.Session.Lan.GetByIp(from) from = ip4.SrcIP.String()
if ip4.SrcIP.Equal(mod.Session.Interface.IP) {
host = mod.Session.Interface
} else if ip4.SrcIP.Equal(mod.Session.Gateway.IP) {
host = mod.Session.Gateway
} else {
host = mod.Session.Lan.GetByIp(from)
}
} }
if host != nil { if host != nil {

View file

@ -2,7 +2,7 @@ package network
import "regexp" import "regexp"
var ArpTableParser = regexp.MustCompile(`^([\d\.]+)\s+dev\s+(\w+)\s+\w+\s+([a-f0-9:]{17})\s+\w+$`) var ArpTableParser = regexp.MustCompile(`^([a-f\d\.:]+)\s+dev\s+(\w+)\s+\w+\s+([a-f0-9:]{17})\s+\w+$`)
var ArpTableTokens = 4 var ArpTableTokens = 4
var ArpTableTokenIndex = []int{1, 3, 2} var ArpTableTokenIndex = []int{1, 3, 2}
var ArpCmd = "ip" var ArpCmd = "ip"

View file

@ -153,7 +153,7 @@ func (lan *LAN) shouldIgnore(ip, mac string) bool {
} }
// skip everything which is not in our subnet (multicast noise) // skip everything which is not in our subnet (multicast noise)
addr := net.ParseIP(ip) addr := net.ParseIP(ip)
return !lan.iface.Net.Contains(addr) return addr.To4() != nil && !lan.iface.Net.Contains(addr)
} }
func (lan *LAN) Has(ip string) bool { func (lan *LAN) Has(ip string) bool {

View file

@ -6,24 +6,50 @@ import (
) )
func NewTCPSyn(from net.IP, from_hw net.HardwareAddr, to net.IP, to_hw net.HardwareAddr, srcPort int, dstPort int) (error, []byte) { func NewTCPSyn(from net.IP, from_hw net.HardwareAddr, to net.IP, to_hw net.HardwareAddr, srcPort int, dstPort int) (error, []byte) {
eth := layers.Ethernet{ from4 := from.To4()
SrcMAC: from_hw, to4 := to.To4()
DstMAC: to_hw,
EthernetType: layers.EthernetTypeIPv4,
}
ip4 := layers.IPv4{
Protocol: layers.IPProtocolTCP,
Version: 4,
TTL: 64,
SrcIP: from,
DstIP: to,
}
tcp := layers.TCP{
SrcPort: layers.TCPPort(srcPort),
DstPort: layers.TCPPort(dstPort),
SYN: true,
}
tcp.SetNetworkLayerForChecksum(&ip4)
return Serialize(&eth, &ip4, &tcp) if from4 != nil && to4 != nil {
eth := layers.Ethernet{
SrcMAC: from_hw,
DstMAC: to_hw,
EthernetType: layers.EthernetTypeIPv4,
}
ip4 := layers.IPv4{
Protocol: layers.IPProtocolTCP,
Version: 4,
TTL: 64,
SrcIP: from,
DstIP: to,
}
tcp := layers.TCP{
SrcPort: layers.TCPPort(srcPort),
DstPort: layers.TCPPort(dstPort),
SYN: true,
}
tcp.SetNetworkLayerForChecksum(&ip4)
return Serialize(&eth, &ip4, &tcp)
} else {
eth := layers.Ethernet{
SrcMAC: from_hw,
DstMAC: to_hw,
EthernetType: layers.EthernetTypeIPv6,
}
ip6 := layers.IPv6{
Version: 6,
NextHeader: layers.IPProtocolTCP,
HopLimit: 64,
SrcIP: from,
DstIP: to,
}
tcp := layers.TCP{
SrcPort: layers.TCPPort(srcPort),
DstPort: layers.TCPPort(dstPort),
SYN: true,
}
tcp.SetNetworkLayerForChecksum(&ip6)
return Serialize(&eth, &ip6, &tcp)
}
} }

View file

@ -16,6 +16,7 @@ import (
const ( const (
IPv4Validator = `^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$` IPv4Validator = `^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$`
IPv6Validator = `^[:a-fA-F0-9]{6,}$` IPv6Validator = `^[:a-fA-F0-9]{6,}$`
IPValidator = `^[\.:a-fA-F0-9]{6,}$`
) )
type ModuleHandler struct { type ModuleHandler struct {