wrong checksum, low ttl
unknown
golang
2 months ago
19 kB
6
Indexable
package main import ( "context" "errors" "flag" "fmt" "log" "net" "os" "strings" "time" "github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" "github.com/jackpal/gateway" ) const ( synTimeout = 5 * time.Second arpTimeout = 5 * time.Second defaultTTL = 64 httpPort = 80 httpUserAgent = "Raw-PCAP-HTTP-Client/1.0" packetSnapLen = 65535 promiscuousMode = false maxARPAttempts = 3 tcpSynRetries = 3 tcpFinRetries = 3 tcpAckRetries = 3 responseTimeout = 10 * time.Second initialSequenceNumber = 1000 initialWindowSize = 65535 ) type tcpClient struct { mac *net.HardwareAddr dstMac *net.HardwareAddr device string dst, gw, src net.IP handle *pcap.Handle opts gopacket.SerializeOptions buf gopacket.SerializeBuffer open []string sequenceNumber uint32 acknowledgementNumber uint32 sourcePort layers.TCPPort destinationPort layers.TCPPort ttl uint8 // TTL for IP packets, added to tcpClient struct hostname string // Hostname for HTTP Host header } func newTcpClient(targetHost string, targetIP net.IP, ttl uint8) (*tcpClient, error) { c := &tcpClient{ dst: targetIP, opts: gopacket.SerializeOptions{ FixLengths: true, ComputeChecksums: true, }, buf: gopacket.NewSerializeBuffer(), sequenceNumber: initialSequenceNumber, acknowledgementNumber: 0, sourcePort: layers.TCPPort(54321), destinationPort: layers.TCPPort(httpPort), // Still default to HTTP port, can be argument if needed ttl: ttl, // Set TTL from argument hostname: targetHost, // Store hostname for HTTP header } device, mac, gw, src, err := getInterface() if err != nil { return nil, err } log.Printf("Scanning host %v (%v) with interface %v, gateway %v, src %v", targetHost, targetIP, device, gw, src) c.gw, c.src, c.device, c.mac = *gw, *src, device, mac dstMac, err := GetARP(c.dst, c.gw, c.src, c.device, *c.mac) if err != nil { return nil, fmt.Errorf("ARP resolution failed: %w", err) } c.dstMac = dstMac handle, err := pcap.OpenLive(device, packetSnapLen, promiscuousMode, pcap.BlockForever) if err != nil { return nil, err } c.handle = handle return c, nil } func (c *tcpClient) close() { c.handle.Close() } func (c *tcpClient) send(layers ...gopacket.SerializableLayer) error { if err := gopacket.SerializeLayers(c.buf, c.opts, layers...); err != nil { return err } return c.handle.WritePacketData(c.buf.Bytes()) } func (c *tcpClient) sendTCPSYN() error { eth := &layers.Ethernet{SrcMAC: *c.mac, DstMAC: *c.dstMac, EthernetType: layers.EthernetTypeIPv4} ip := &layers.IPv4{ SrcIP: c.src, DstIP: c.dst, Version: 4, TTL: c.ttl, // Use TTL from tcpClient struct Protocol: layers.IPProtocolTCP, } tcp := &layers.TCP{ SrcPort: c.sourcePort, DstPort: c.destinationPort, SYN: true, Seq: c.sequenceNumber, Window: initialWindowSize, } if err := tcp.SetNetworkLayerForChecksum(ip); err != nil { return err } if err := c.send(eth, ip, tcp); err != nil { return err } log.Printf("TCP SYN sent to %s:%d, seq=%d", c.dst, c.destinationPort, c.sequenceNumber) return nil } func (c *tcpClient) receiveTCPSYNACK() (*layers.TCP, error) { portFilter := fmt.Sprintf("tcp and src host %s and src port %d and dst port %d and tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)", c.dst.String(), c.destinationPort, c.sourcePort) if err := c.handle.SetBPFFilter(portFilter); err != nil { return nil, fmt.Errorf("BPF filter error for SYN-ACK: %w, filter: %s", err, portFilter) } defer c.handle.SetBPFFilter("") packetSource := gopacket.NewPacketSource(c.handle, c.handle.LinkType()) start := time.Now() for time.Since(start) < synTimeout { packet, err := packetSource.NextPacket() if err != nil { continue } tcpLayer := packet.Layer(layers.LayerTypeTCP) if tcp, ok := tcpLayer.(*layers.TCP); ok && tcp.SYN && tcp.ACK && tcp.SrcPort == c.destinationPort && tcp.DstPort == c.sourcePort { log.Printf("TCP SYN-ACK received from %s:%d, ack=%d, seq=%d", c.dst, tcp.SrcPort, tcp.Ack, tcp.Seq) return tcp, nil } } return nil, fmt.Errorf("no TCP SYN-ACK response received after %v", synTimeout) } func (c *tcpClient) sendTCPACK(ackNumber, seqNumber uint32) error { eth := &layers.Ethernet{SrcMAC: *c.mac, DstMAC: *c.dstMac, EthernetType: layers.EthernetTypeIPv4} ip := &layers.IPv4{ SrcIP: c.src, DstIP: c.dst, Version: 4, TTL: c.ttl, // Use TTL from tcpClient struct Protocol: layers.IPProtocolTCP, } tcp := &layers.TCP{ SrcPort: c.sourcePort, DstPort: c.destinationPort, ACK: true, Seq: seqNumber, Ack: ackNumber, Window: initialWindowSize, } if err := tcp.SetNetworkLayerForChecksum(ip); err != nil { return err } log.Printf("Sending TCP ACK, seq=%d, ack=%d to %s:%d", seqNumber, ackNumber, c.dst, c.destinationPort) return c.send(eth, ip, tcp) } func (c *tcpClient) performTCPHandshake() error { for i := 0; i < tcpSynRetries; i++ { c.sequenceNumber = initialSequenceNumber + uint32(i) if err := c.sendTCPSYN(); err != nil { log.Printf("SYN send attempt %d failed: %v", i+1, err) continue } synAckResponse, err := c.receiveTCPSYNACK() if err == nil { c.acknowledgementNumber = synAckResponse.Seq + 1 c.sequenceNumber++ log.Printf("SYN-ACK received, server seq=%d, client ack=%d", synAckResponse.Seq, c.acknowledgementNumber) break } log.Printf("Retrying SYN... attempt %d/%d: %v", i+1, tcpSynRetries, err) time.Sleep(time.Duration(i+1) * time.Second) } if c.sequenceNumber == initialSequenceNumber { return fmt.Errorf("TCP handshake failed after %d SYN retries", tcpSynRetries) } for i := 0; i < tcpAckRetries; i++ { err := c.sendTCPACK(c.acknowledgementNumber, c.sequenceNumber) if err == nil { log.Println("TCP ACK sent successfully.") break } else { log.Printf("ACK send attempt %d failed: %v", i+1, err) if i < tcpAckRetries-1 { time.Sleep(time.Duration(i+1) * time.Second) } else { return fmt.Errorf("ACK send failed after %d retries: %w", tcpAckRetries, err) } } } if c.acknowledgementNumber == 0 { return fmt.Errorf("TCP handshake failed after %d ACK retries", tcpAckRetries) } log.Println("TCP handshake completed.") return nil } func (c *tcpClient) sendHTTPGetRequest(wrongChecksum bool, ttl uint8, hostname string) error { eth := layers.Ethernet{ SrcMAC: *c.mac, DstMAC: *c.dstMac, EthernetType: layers.EthernetTypeIPv4, } ip4 := layers.IPv4{ SrcIP: c.src, DstIP: c.dst, Version: 4, TTL: ttl, Protocol: layers.IPProtocolTCP, } tcp := layers.TCP{ SrcPort: c.sourcePort, DstPort: c.destinationPort, ACK: true, Seq: c.sequenceNumber, Ack: c.acknowledgementNumber, Window: initialWindowSize, PSH: true, } if err := tcp.SetNetworkLayerForChecksum(&ip4); err != nil { return err } httpPayload := []byte("GET / HTTP/1.1\r\nHost: " + hostname + "\r\nUser-Agent: " + httpUserAgent + "\r\nConnection: close\r\n\r\n") opts := gopacket.SerializeOptions{ FixLengths: true, ComputeChecksums: !wrongChecksum, } buffer := gopacket.NewSerializeBuffer() if err := gopacket.SerializeLayers(buffer, opts, ð, &ip4, &tcp, gopacket.Payload(httpPayload)); err != nil { return err } packetData := buffer.Bytes() if wrongChecksum { // Assuming IPv4 header is 20 bytes, TCP starts after it tcpLayer := packetData[20:] // TCP checksum is at bytes 16-17 (offset 16, 2 bytes) in TCP header checksumOffset := 16 originalChecksum := uint16(tcpLayer[checksumOffset])<<8 | uint16(tcpLayer[checksumOffset+1]) // XOR and Flip a bit in the checksum to corrupt it corruptedChecksum := originalChecksum ^ uint16(0x00FF) // Update the checksum bytes in the packet data with the corrupted value (little-endian) tcpLayer[checksumOffset] = byte(corruptedChecksum >> 8) tcpLayer[checksumOffset+1] = byte(corruptedChecksum & 0xFF) log.Printf("Original TCP Checksum: 0x%04X", originalChecksum) log.Printf("Corrupted TCP Checksum: 0x%04X", corruptedChecksum) } err := c.handle.WritePacketData(packetData) if err != nil { log.Printf("Error sending HTTP GET request to port %v: %v", c.destinationPort, err) return err } log.Printf("HTTP GET request sent to %s(%s):%d, wrongChecksum=%v", c.hostname, c.dst, c.destinationPort, wrongChecksum) return nil } func (c *tcpClient) receiveTCPResponse() (gopacket.Packet, error) { filter := fmt.Sprintf("tcp and src host %s and src port %d and dst port %d", c.dst.String(), c.destinationPort, c.sourcePort) if err := c.handle.SetBPFFilter(filter); err != nil { return nil, fmt.Errorf("BPF filter error for TCP response: %w, filter: %s", err, filter) } defer c.handle.SetBPFFilter("") packetSource := gopacket.NewPacketSource(c.handle, c.handle.LinkType()) start := time.Now() for time.Since(start) < responseTimeout { packet, err := packetSource.NextPacket() if err != nil { continue } tcpLayer := packet.Layer(layers.LayerTypeTCP) if tcp, ok := tcpLayer.(*layers.TCP); ok && tcp.DstPort == c.sourcePort && tcp.SrcPort == c.destinationPort { if tcp.RST { return nil, fmt.Errorf("TCP RST received, connection reset") } if tcp.FIN { log.Println("TCP FIN received, server closed connection") return packet, nil } appLayer := packet.ApplicationLayer() if appLayer != nil { log.Printf("TCP Response packet received, payload length: %d", len(appLayer.Payload())) return packet, nil } else { log.Println("TCP ACK or control packet received without payload, waiting for data...") } } } return nil, fmt.Errorf("no TCP response received after %v", responseTimeout) } func (c *tcpClient) sendTCPFIN() error { for i := 0; i < tcpFinRetries; i++ { eth := &layers.Ethernet{SrcMAC: *c.mac, DstMAC: *c.dstMac, EthernetType: layers.EthernetTypeIPv4} ip := &layers.IPv4{ SrcIP: c.src, DstIP: c.dst, Version: 4, TTL: c.ttl, Protocol: layers.IPProtocolTCP, } tcp := &layers.TCP{ SrcPort: c.sourcePort, DstPort: c.destinationPort, FIN: true, ACK: true, Seq: c.sequenceNumber, Ack: c.acknowledgementNumber, Window: initialWindowSize, } if err := tcp.SetNetworkLayerForChecksum(ip); err != nil { return err } if err := c.send(eth, ip, tcp); err != nil { log.Printf("Failed to send FIN packet (attempt %d): %v", i+1, err) time.Sleep(time.Duration(i+1) * time.Second) continue } log.Printf("TCP FIN sent successfully (attempt %d)", i+1) return nil } return fmt.Errorf("failed to send FIN packet after %d retries", tcpFinRetries) } func (c *tcpClient) Run() error { if err := c.performTCPHandshake(); err != nil { return fmt.Errorf("TCP handshake failed: %w", err) } if err := c.sendHTTPGetRequest(false, 4, "google.com"); err != nil { return fmt.Errorf("HTTP GET request failed: %w", err) } if err := c.sendHTTPGetRequest(false, c.ttl, c.hostname); err != nil { return fmt.Errorf("HTTP GET request failed: %w", err) } responsePacket, err := c.receiveTCPResponse() if err != nil { return fmt.Errorf("receiving TCP response failed: %w", err) } if appLayer := responsePacket.ApplicationLayer(); appLayer != nil { fmt.Printf("\n--- HTTP Response Payload ---\n%s\n--- End Payload ---\n", string(appLayer.Payload())) } else { log.Println("No application layer payload in TCP response.") } if err := c.sendTCPFIN(); err != nil { return fmt.Errorf("sending FIN packet failed: %w", err) } log.Println("Connection closed gracefully.") return nil } func GetARP(tip, gip, mip net.IP, device string, hardwareAddr net.HardwareAddr) (*net.HardwareAddr, error) { log.Println("Getting target MAC for IP:", tip) var target net.IP if inLocalNet(tip, gip) { target = tip } else { target = gip } handle, err := pcap.OpenLive(device, packetSnapLen, promiscuousMode, arpTimeout) if err != nil { return nil, fmt.Errorf("pcap.OpenLive failed: %w", err) } defer handle.Close() packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) arpChannel := make(chan net.HardwareAddr) errorChannel := make(chan error) ctx, cancel := context.WithCancel(context.Background()) defer cancel() go func() { defer close(arpChannel) defer close(errorChannel) for { select { case <-ctx.Done(): errorChannel <- fmt.Errorf("ARP search cancelled for IP %s", target) return default: packet, err := packetSource.NextPacket() if err != nil { if errors.Is(err, pcap.NextErrorTimeoutExpired) { errorChannel <- fmt.Errorf("ARP timeout for IP %s", target) continue } errorChannel <- fmt.Errorf("packetSource.NextPacket error: %w", err) continue } arpLayer := packet.Layer(layers.LayerTypeARP) if arpPacket, ok := arpLayer.(*layers.ARP); ok && arpPacket.Operation == layers.ARPReply { if net.IP(arpPacket.SourceProtAddress).Equal(target) { arpChannel <- arpPacket.SourceHwAddress return } } } } }() arpTries := 0 for arpTries < maxARPAttempts { err = sendARPRequest(handle, hardwareAddr, mip, target) if err != nil { log.Printf("Error sending ARP request: %v", err) } select { case macAddr := <-arpChannel: log.Println("ARP Response received, MAC address:", macAddr) return &macAddr, nil case err := <-errorChannel: log.Printf("ARP attempt %d error: %v", arpTries+1, err) default: time.Sleep(5 * time.Second) } arpTries++ } return nil, fmt.Errorf("failed to get MAC address for IP %s after %d attempts", target, maxARPAttempts) } func sendARPRequest(handle *pcap.Handle, srcMAC net.HardwareAddr, srcIP, dstIP net.IP) error { eth := &layers.Ethernet{ SrcMAC: srcMAC, DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, EthernetType: layers.EthernetTypeARP, } arp := &layers.ARP{ AddrType: layers.LinkTypeEthernet, Protocol: layers.EthernetTypeIPv4, HwAddressSize: uint8(6), ProtAddressSize: uint8(4), Operation: layers.ARPRequest, SourceHwAddress: srcMAC, SourceProtAddress: srcIP.To4(), DstHwAddress: net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, DstProtAddress: dstIP.To4(), } buf := gopacket.NewSerializeBuffer() opts := gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true} if err := gopacket.SerializeLayers(buf, opts, eth, arp); err != nil { return fmt.Errorf("gopacket.SerializeLayers failed: %w", err) } packetData := buf.Bytes() if err := handle.WritePacketData(packetData); err != nil { return fmt.Errorf("handle.WritePacketData failed: %w", err) } log.Println("ARP request sent for IP:", dstIP) return nil } func inLocalNet(ip, g net.IP) bool { for i, n := range ip.To4()[0:3] { if n != g.To4()[i] { return false } } return true } func getOutboundIP() net.IP { conn, err := net.Dial("udp", "8.8.8.8:80") if err != nil { return nil } defer conn.Close() localAddr := conn.LocalAddr().(*net.UDPAddr) return localAddr.IP } func getInterface() (device string, mac *net.HardwareAddr, gWip *net.IP, src *net.IP, err error) { gWipVal, err := gateway.DiscoverGateway() if err != nil { return "", nil, nil, nil, err } device, _ = selectDevice() myIP := getOutboundIP() macVal := getMAC(myIP) return device, &macVal, &gWipVal, &myIP, nil } func getMAC(ip net.IP) net.HardwareAddr { interfaces, err := net.Interfaces() if err != nil { log.Fatal(err) } for _, inf := range interfaces { if addr, err := inf.Addrs(); err == nil { for _, addr := range addr { if strings.Split(addr.String(), "/")[0] == ip.String() { return inf.HardwareAddr } } } } return net.HardwareAddr{0, 0, 0, 0, 0, 0} } func selectDevice() (device string, ip net.IP) { localIP := getOutboundIP() devices, err := pcap.FindAllDevs() if err != nil { log.Fatal(err) } for _, dev := range devices { for _, address := range dev.Addresses { if localIP != nil { if address.IP.String() == localIP.String() { log.Println("Selected device: ", dev.Description) return dev.Name, localIP } } else if address.IP.String() != "127.0.0.1" && !strings.Contains(dev.Description, "Loopback") { return dev.Name, address.IP } } } return "", nil } func main() { var host string var destIPString string var ttlValue int flag.StringVar(&host, "host", "", "Destination host (hostname or IP address, required)") flag.StringVar(&destIPString, "ip", "", "Destination IP address (optional, will resolve host if not provided)") flag.IntVar(&ttlValue, "ttl", defaultTTL, "TTL value for IP packets (optional)") flag.Parse() if host == "" { fmt.Println("Usage: go run main.go -host <hostname_or_ip> [-ip <ip_address>] [-ttl <ttl_value>]") os.Exit(1) } var destIP net.IP var err error if destIPString != "" { destIP = net.ParseIP(destIPString).To4() if destIP == nil { log.Fatalf("Invalid destination IP address: %q", destIPString) return } } else { parsedHostIP := net.ParseIP(host).To4() if parsedHostIP != nil { destIP = parsedHostIP } else { ips, err := net.LookupIP(host) if err != nil { log.Fatalf("Could not resolve hostname %q: %v", host, err) return } for _, ip := range ips { if ipv4 := ip.To4(); ipv4 != nil { destIP = ipv4 break } } if destIP == nil { log.Fatalf("No IPv4 address found for hostname %q", host) return } log.Printf("Resolved hostname %q to IP %v", host, destIP) } } if destIP == nil { log.Fatalf("Destination IP address is not determined for host %q", host) return } if ttlValue < 1 || ttlValue > 255 { log.Fatalf("Invalid TTL value: %d. TTL must be between 1 and 255", ttlValue) return } ttl := uint8(ttlValue) client, err := newTcpClient(host, destIP, ttl) if err != nil { log.Printf("Failed to create TCP client for %v (%v): %v", host, destIP, err) return } defer client.close() log.Printf("Starting TCP client for %v (%v), TTL=%d", host, destIP, ttl) if err := client.Run(); err != nil { log.Printf("TCP client error communicating with %v (%v): %v", host, destIP, err) } }
Editor is loading...
Leave a Comment