Intercepting http traffic

Please tell me how to intercept http requests in c#? I just need to know which sites were clicked on and that's it.


I tried using SharpPcap to intercept packets, but I do not know what to do with them next. Here is the code:

// Когда приходит пакет, вызывается это событие
private static void Program_OnPacketArrival(object sender, CaptureEventArgs e)
{
    Packet packet = Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data);
    TcpPacket tcp = (TcpPacket)packet.Extract(typeof(TcpPacket));

    if (tcp != null)
    {
        byte[] data = tcp.PayloadData;
        string res = Encoding.UTF8.GetString(data);
        Console.WriteLine(res);
    }
}

But this code prints GET headers, and then only when the site is not https. I hope I asked everything clearly. Thanks.

Author: svstnv, 2018-06-23

1 answers

For HTTP packets, parse the GET request and search for the Host parameter. But it may not be, then the site can be obtained by a request to the reverse DNS (if it is there). For HTTPS, you can't get requests without decrypting the traffic, of course, but you can try to find the SSL Handshake and see which domain the request goes to.

Example of capturing HTTP and SSL/TLS traffic on the first IPv4 interface found, using a Raw Socket (rights are required to run the administrator):

using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;

namespace ConsoleTest1
{    
    class Program
    {
        //Получает все локальные IP-адреса
        public static List<IPAddress> GetIpAddresses()
        {
            List<IPAddress> res = new List<IPAddress>(10);

            var ifs = NetworkInterface.GetAllNetworkInterfaces();

            foreach (var interf in ifs)
            {               

                var ipprop = interf.GetIPProperties();
                if (ipprop == null) continue;
                var unicast = ipprop.UnicastAddresses;
                if (unicast == null) continue;

                //находим первый Unicast-адрес
                foreach (var addr in unicast)
                {
                    if (addr.Address.AddressFamily != AddressFamily.InterNetwork) continue;
                    res.Add(addr.Address);
                    break;
                }

            }

            return res;
        }

        const byte PROTO_TCP = 6;
        const byte SSL_HANDSHAKE = 0x16;

        public class ParseResult
        {
            public string TrafficType {get;set;}
            public string Host { get; set; }            
        }

        public static ParseResult ParseIpPacket(byte[] data, IPAddress src_ip)
        {
            ushort dummy;
            byte b;

            MemoryStream ms = new MemoryStream(data);
            BinaryReader br = new BinaryReader(ms);
            uint header_len;
            uint total_len;
            IPAddress src,dst;
            string host="";
            ParseResult result;

            //parse IP packet header
            using (ms)
            using (br)
            {
                b = br.ReadByte();
                byte ver = (byte)((b & (byte)0xF0) >> 4); //IP version
                if (ver != 4)
                {
                    Console.WriteLine("Unsupported IP version: {0}", ver);
                    return null;
                }                

                byte ihl = (byte)(b & (byte)0x0F);//header length
                header_len = ihl * 4u;

                b = br.ReadByte();

                //packet length
                byte[] temp = new byte[2];
                temp[1] = br.ReadByte();
                temp[0] = br.ReadByte();
                total_len = BitConverter.ToUInt16(temp, 0);

                dummy = br.ReadUInt16();
                dummy = br.ReadUInt16();

                byte ttl = br.ReadByte();
                byte proto = br.ReadByte();

                dummy = br.ReadUInt16();

                //source IP
                temp = new byte[4];
                temp[0] = br.ReadByte();
                temp[1] = br.ReadByte();
                temp[2] = br.ReadByte();
                temp[3] = br.ReadByte();
                src = new IPAddress(temp);                

                //destination IP
                temp[0] = br.ReadByte();
                temp[1] = br.ReadByte();
                temp[2] = br.ReadByte();
                temp[3] = br.ReadByte();
                dst = new IPAddress(temp);                

                if (proto != PROTO_TCP) return null;  
            }

            //Parse TCP packet
            uint tcp_size = total_len - header_len;
            byte[] tcp_data = new byte[tcp_size];
            Array.Copy(data, header_len, tcp_data, 0, tcp_size);

            ms = new MemoryStream(tcp_data);
            br = new BinaryReader(ms);
            byte tcp_header_size;
            uint http_size;

            using (ms)
            using (br)
            {
                var src_port = br.ReadUInt16();
                var dst_port = br.ReadUInt16();                
                br.ReadUInt32();
                br.ReadUInt32();
                tcp_header_size = (byte)(br.ReadByte() >> 4);
                tcp_header_size *= 4;
                http_size = tcp_size - tcp_header_size;
            }

            byte[] http_data = new byte[http_size];
            Array.Copy(tcp_data, tcp_header_size, http_data, 0, http_size);

            //parse SSL record
            if (http_data.Length >= 5 && src.Equals(src_ip))
            {
                ms = new MemoryStream(http_data);
                br = new BinaryReader(ms);
                using (ms)
                using (br)
                {                    
                    byte record_type = br.ReadByte();
                    byte b1 = br.ReadByte();
                    byte b2 = br.ReadByte();
                    byte[] bytes = new byte[]{b2,b1};
                    ushort ssl_ver = BitConverter.ToUInt16(bytes,0);                    
                    ushort ssl_len = br.ReadUInt16();

                    if ( ((ssl_ver >= 0x0300 && ssl_ver <= 0x0304) || ssl_ver == 0x0002)
                        && (record_type == SSL_HANDSHAKE))
                    {                        
                        //пытаемся получить имя узла из обратного DNS
                        try
                        {
                            host = Dns.GetHostEntry(dst).HostName;
                        }
                        catch (SocketException)
                        {
                            host = "";
                        }

                        result = new ParseResult();
                        result.TrafficType = "SSL / TLS";
                        if (host != "") result.Host = host;                        
                        else result.Host = dst.ToString();                        
                        return result;
                    }
                }
            }

            //Parse HTTP data
            string res = Encoding.UTF8.GetString(http_data);
            string[] arr = res.Split("\n\r".ToCharArray(),StringSplitOptions.RemoveEmptyEntries);

            if (arr.Length > 2 && arr[0].StartsWith("GET") && arr[0].Contains("HTTP/"))
            {                
                //найдем поле Host
                for(int i=1;i<arr.Length;i++)
                {
                    if (arr[i].StartsWith("Host: "))
                    {
                        host = arr[i].Replace("Host: ", "");                        
                        break;
                    }
                }

                if (host == "")
                {
                    //пытаемся получить имя узла из обратного DNS
                    try
                    {
                        host = Dns.GetHostEntry(dst).HostName;
                    }
                    catch (SocketException)
                    {
                        host = "";
                    }
                }

                result = new ParseResult();
                result.TrafficType = "HTTP";
                result.Host = host;                
                return result;
            }
            return null;
        }

        static void Main(string[] args)
        {
            var mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Raw,
                       ProtocolType.IP);

            var ips = GetIpAddresses();
            IPAddress ipaddr=new IPAddress(0L);
            foreach (var ip in ips)
            {
                if (ip.GetAddressBytes()[0] != 127)
                {
                    Console.WriteLine("Interface IP: {0}",ip);
                    ipaddr = ip;
                    break;
                }
            }

            mainSocket.Bind(new IPEndPoint(ipaddr, 0));


            mainSocket.SetSocketOption(SocketOptionLevel.IP,  //Applies only to IP packets
                           SocketOptionName.HeaderIncluded, //Set the include header
                           true);                           //option to true

            byte[] byTrue = new byte[4] { 1, 0, 0, 0 };
            byte[] byOut = new byte[4];

            //Socket.IOControl is analogous to the WSAIoctl method of Winsock 2
            mainSocket.IOControl(IOControlCode.ReceiveAll,  //SIO_RCVALL of Winsock
                     byTrue, byOut);

            byte[] buffer = new byte[1024*20];
            int res;

            while (true)
            {
                try
                {
                    res = mainSocket.Receive(buffer);                    

                    ParseResult result = ParseIpPacket(buffer, ipaddr);
                    if (result != null)
                    {
                        Console.WriteLine("[{0}] {1}",result.TrafficType,result.Host);
                    }                    
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }           

        }
    }
}

Sources:

CodeProject - A Network Sniffer in C#

Wikipedia-IPv4 Protocol

Wikipedia-TCP Protocol

Cisco - SSL Introduction with Sample Transaction and Packet Exchange

 2
Author: MSDN.WhiteKnight, 2018-06-24 10:17:32