Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a valid TCP connection in Pcap.NET

Tags:

c#

pcap.net

I'm trying to create a valid TCP connection to my test server in order to simulate a GET request. Hopefully I'm pretty close to a solution.

Using Wireshark data from a real request, I've managed to get the SYN & SYN-ACK when sending one package using PacketCommunicator.SendPacket():

enter image description here

However, I can't seem to make the ACK appear.

The first packets is constructed using EthernetLayer, IpV4Layer and a TcpLayer, while the latter (currently non-working) uses the ones just mentioned + a HttpRequestLayer.

The last packets TcpLayer's ControlBits is set to TcpControlBits.Acknowledgment. Despite this, it's not showing up in WireShark like on my "real" GET requests.

Hopefully I've posted the relevant part of the code. If not - please let me know.

like image 379
Johan Avatar asked Mar 21 '23 23:03

Johan


1 Answers

Here is a draft that works (I've checked).

Please change the values used when constructing HttpGetSender instance to whatever you need.

The tricky part is to get the sequence and acknowledgement numbers right.

using System;
using System.Collections.Generic;
using PcapDotNet.Core;
using PcapDotNet.Packets;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.Http;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.Transport;

namespace SendingHttpGet
{
    internal class HttpGetSender
    {
        public HttpGetSender()
        {
        }

        public MacAddress SourceMac { get; set; }
        public MacAddress DestinationMac { get; set; }
        public IpV4Address SourceIpV4 { get; set; }
        public IpV4Address DestinationIpV4 { get; set; }
        public string Host { get; set; }

        public void Run(PacketDevice device)
        {
            using (PacketCommunicator communicator = device.Open(100, // name of the device
                                                                 PacketDeviceOpenAttributes.Promiscuous,
                                                                 // promiscuous mode
                                                                 100)) // read timeout
            {
                SendSyn(communicator);
                WaitForAck(communicator);
            }
        }

        private void WaitForAck(PacketCommunicator communicator)
        {
            communicator.SetFilter("tcp and src " + DestinationIpV4 + " and dst " + SourceIpV4 + " and src port " + _destinationPort + " and dst port " + _sourcePort);
            Packet packet;
            while (true)
            {
                if (communicator.ReceivePacket(out packet) == PacketCommunicatorReceiveResult.Ok)
                {
                    if (packet.Ethernet.IpV4.Tcp.AcknowledgmentNumber == _expectedAckNumber)
                    {
                        _seqNumber = _expectedAckNumber;
                        _ackNumber = packet.Ethernet.IpV4.Tcp.SequenceNumber + 1;
                        SendGet(communicator);
                        break;
                    }

                }
                SendSyn(communicator);
            }
            WaitForResponse(communicator);
        }

        private void WaitForResponse(PacketCommunicator communicator)
        {
            communicator.SetFilter("tcp and src " + DestinationIpV4 + " and dst " + SourceIpV4 + " and src port " + _destinationPort + " and dst port " + _sourcePort);
            Packet packet;
            while (true)
            {
                if (communicator.ReceivePacket(out packet) == PacketCommunicatorReceiveResult.Ok)
                {
                    Console.WriteLine("Expected ack number: " + _expectedAckNumber);
                    Console.WriteLine("Received ack number: " + packet.Ethernet.IpV4.Tcp.AcknowledgmentNumber);
                    if (packet.Ethernet.IpV4.Tcp.AcknowledgmentNumber == _expectedAckNumber)
                    {
                        break;
                    }

                }
                SendGet(communicator);
            }
        }

        private void SendSyn(PacketCommunicator communicator)
        {
            // Ethernet Layer
            EthernetLayer ethernetLayer = new EthernetLayer
                                              {
                                                  Source = SourceMac,
                                                  Destination = DestinationMac,
                                              };

            // IPv4 Layer
            IpV4Layer ipV4Layer = new IpV4Layer
                                      {
                                          Source = SourceIpV4,
                                          CurrentDestination = DestinationIpV4,
                                          Ttl = 128,
                                          Fragmentation =
                                              new IpV4Fragmentation(IpV4FragmentationOptions.DoNotFragment, 0),
                                          Identification = 1234,
                                      };

            // TCP Layer
            TcpLayer tcpLayer = new TcpLayer
                                    {
                                        SourcePort = _sourcePort,
                                        DestinationPort = _destinationPort,
                                        SequenceNumber = _seqNumber,
                                        ControlBits = TcpControlBits.Synchronize,
                                        Window = _windowSize,
                                    };

            communicator.SendPacket(PacketBuilder.Build(DateTime.Now, ethernetLayer, ipV4Layer, tcpLayer));
            _expectedAckNumber = _seqNumber + 1;
        }

        private void SendGet(PacketCommunicator communicator)
        {
            // Ethernet Layer
            EthernetLayer ethernetLayer = new EthernetLayer
            {
                Source = SourceMac,
                Destination = DestinationMac,
            };

            // IPv4 Layer
            IpV4Layer ipV4Layer = new IpV4Layer
            {
                Source = SourceIpV4,
                CurrentDestination = DestinationIpV4,
                Ttl = 128,
                Fragmentation =
                    new IpV4Fragmentation(IpV4FragmentationOptions.DoNotFragment, 0),
                Identification = 1235,
            };

            // TCP Layer
            TcpLayer tcpLayer = new TcpLayer
            {
                SourcePort = _sourcePort,
                DestinationPort = _destinationPort,
                SequenceNumber = _seqNumber,
                AcknowledgmentNumber = _ackNumber,
                ControlBits = TcpControlBits.Acknowledgment,
                Window = _windowSize,
            };

            // HTTP Layer
            HttpLayer httpLayer = new HttpRequestLayer
            {
                Uri = "/",
                Header = new HttpHeader(HttpField.CreateField("Host", Host)),
                Method = new HttpRequestMethod(HttpRequestKnownMethod.Get),
                Version = HttpVersion.Version11,
            };

            Packet packet = PacketBuilder.Build(DateTime.Now, ethernetLayer, ipV4Layer, tcpLayer, httpLayer);
            communicator.SendPacket(packet);
            _expectedAckNumber = (uint) (_seqNumber + packet.Ethernet.IpV4.Tcp.PayloadLength);
        }

        private ushort _sourcePort = (ushort) (4123 + new Random().Next() % 1000);
        private ushort _destinationPort = 80;
        private uint _seqNumber = (uint) new Random().Next();
        private uint _expectedAckNumber;
        private ushort _windowSize = 8192;
        private uint _ackNumber;
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            // Retrieve the device list from the local machine
            IList<LivePacketDevice> allDevices = LivePacketDevice.AllLocalMachine;

            if (allDevices.Count == 0)
            {
                Console.WriteLine("No interfaces found! Make sure WinPcap is installed.");
                return;
            }

            // Print the list
            for (int i = 0; i != allDevices.Count; ++i)
            {
                LivePacketDevice device = allDevices[i];
                Console.Write((i + 1) + ". " + device.Name);
                if (device.Description != null)
                    Console.WriteLine(" (" + device.Description + ")");
                else
                    Console.WriteLine(" (No description available)");
            }

            int deviceIndex = 0;
            do
            {
                Console.WriteLine("Enter the interface number (1-" + allDevices.Count + "):");
                string deviceIndexString = Console.ReadLine();
                if (!int.TryParse(deviceIndexString, out deviceIndex) ||
                    deviceIndex < 1 || deviceIndex > allDevices.Count)
                {
                    deviceIndex = 0;
                }
            } while (deviceIndex == 0);

            // Take the selected adapter
            PacketDevice selectedDevice = allDevices[deviceIndex - 1];

            HttpGetSender sender = new HttpGetSender
                                       {
                                           SourceMac = new MacAddress("your:host:mac:address:1:2"),
                                           DestinationMac = new MacAddress("gateway:mac:address:1:2:3"),
                                           SourceIpV4 = new IpV4Address("your.host.ip.address"),
                                           DestinationIpV4 = new IpV4Address("target.host.ip.address"),
                                           Host = "targethost.com",
                                       };

            sender.Run(selectedDevice);
        }
    }
}
like image 135
brickner Avatar answered Apr 08 '23 11:04

brickner