public void TestParseRC4CryptoAPIFilePassRecord()
        {
            byte[] rc4CryptoApiFilePassRecord = new byte[]
            {
                0x2F, 0x00, 0xC8, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00,
                0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00,
                0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D,
                0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6F, 0x00, 0x73, 0x00, 0x6F, 0x00, 0x66, 0x00, 0x74, 0x00,
                0x20, 0x00, 0x45, 0x00, 0x6E, 0x00, 0x68, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x63, 0x00, 0x65, 0x00, 0x64,
                0x00, 0x20, 0x00, 0x43, 0x00, 0x72, 0x00, 0x79, 0x00, 0x70, 0x00, 0x74, 0x00, 0x6F, 0x00, 0x67, 0x00,
                0x72, 0x00, 0x61, 0x00, 0x70, 0x00, 0x68, 0x00, 0x69, 0x00, 0x63, 0x00, 0x20, 0x00, 0x50, 0x00, 0x72,
                0x00, 0x6F, 0x00, 0x76, 0x00, 0x69, 0x00, 0x64, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x76, 0x00,
                0x31, 0x00, 0x2E, 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x98, 0xC3, 0xA1, 0xA0, 0x9A,
                0xC8, 0x92, 0x3D, 0x7A, 0x5D, 0x03, 0x30, 0x34, 0xE8, 0x67, 0x64, 0xA8, 0xA9, 0x29, 0xF0, 0xA6, 0xA8,
                0xB6, 0xA1, 0x1F, 0x8C, 0x6F, 0x27, 0xB6, 0xA8, 0x82, 0xEB, 0x14, 0x00, 0x00, 0x00, 0xE8, 0xAF, 0x8B,
                0x67, 0x4E, 0x3F, 0xA7, 0xA1, 0x39, 0x9D, 0x9F, 0x2D, 0xDC, 0xB5, 0x1A, 0x33, 0x5D, 0x8A, 0xB2, 0x69
            };

            VirtualStreamReader vsr            = new VirtualStreamReader(new MemoryStream(rc4CryptoApiFilePassRecord));
            FilePass            filePassRecord = new FilePass(vsr, (RecordType)vsr.ReadUInt16(), vsr.ReadUInt16());

            byte[] filePassBytes = filePassRecord.GetBytes();

            Assert.AreEqual(rc4CryptoApiFilePassRecord.Length, filePassBytes.Length);

            Assert.IsFalse(filePassRecord.encryptionHeader.fDocProps);
            Assert.IsFalse(filePassRecord.encryptionHeader.fCryptoAPI);
            Assert.IsTrue(filePassRecord.encryptionHeader.fExternal);
            Assert.IsTrue(filePassRecord.encryptionHeader.fAES);

            for (int offset = 0; offset < rc4CryptoApiFilePassRecord.Length; offset += 1)
            {
                Assert.AreEqual(rc4CryptoApiFilePassRecord[offset], filePassBytes[offset]);
            }
        }
Esempio n. 2
0
        public FilePass CreateFilePassFromPassword(string password)
        {
            ushort key    = CreateXorKey_Method1(password);
            ushort verify = CreatePasswordVerifier_Method1(password);

            return(FilePass.CreateXORObfuscationFilePass(key, verify));
        }
Esempio n. 3
0
        public void GenerateFilePassBytesForPasswords()
        {
            XorObfuscation xorObfuscation = new XorObfuscation();

            byte[] xorArray  = xorObfuscation.CreateXorArray_Method1(XorObfuscation.DefaultPassword);
            string xorString = BitConverter.ToString(xorArray).Replace("-", " ");

            Console.WriteLine(xorString);

            string[] passwords = new[] { "000", "111", "222", "333", "444", "555", "5 5 5", "666", "777", "7 7 7", "888", "999", "123", "321", "987", "876", "543", "321", "135", "246", "357", "468", "579", "1234", "2020", "2021", "password", "password1", "infected", "infected2" };
            foreach (var password in passwords)
            {
                Console.WriteLine(string.Format("FilePass Bytes for {0}", password));
                FilePass fp = xorObfuscation.CreateFilePassFromPassword(password);
                Console.WriteLine(fp.ToHexDumpString(16, false, true));
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Dumps information about BIFF records that are relevant for analysis. Defaults to sheet, label, and formula data.
        /// </summary>
        /// <param name="path">Path to the XLS file to dump</param>
        /// <param name="dumpAll">Dump all BIFF records, not the most commonly used by maldocs</param>
        /// <param name="showAttrInfo">Explicitly display PtgAttr information in Formula strings. Defaults to False.</param>
        /// <param name="dumpHexBytes">Dump the byte content of each BIFF record in addition to its content summary.</param>
        /// <param name="password">XOR Obfuscation decryption password to try. Defaults to VelvetSweatshop if FilePass record is found.</param>
        /// <param name="disableDecryption">Use this flag in order to skip decryption of the file before dumping.</param>
        public static void Dump(FileInfo path, bool dumpAll = false, bool showAttrInfo = false, bool dumpHexBytes = false, string password = "******", bool disableDecryption = false)
        {
            if (path == null)
            {
                Console.WriteLine("path argument must be specified in Dump mode. Run dump -h for usage instructions.");
                return;
            }

            if (path.Exists == false)
            {
                Console.WriteLine("path file does not exist.");
                return;
            }

            WorkbookStream wbs = new WorkbookStream(path.FullName);

            if (wbs.HasPasswordToOpen() && !disableDecryption)
            {
                FilePass fpRecord = wbs.GetAllRecordsByType <FilePass>().First();

                if (fpRecord.wEncryptionType == 0 && fpRecord.xorObfuscationKey != 0)
                {
                    XorObfuscation xorObfuscation = new XorObfuscation();
                    Console.WriteLine("FilePass record found - attempting to decrypt with password " + password);
                    try
                    {
                        wbs = xorObfuscation.DecryptWorkbookStream(wbs, password);
                    }
                    catch (ArgumentException argEx)
                    {
                        Console.WriteLine("Password " + password + " does not match the verifier value of the document FilePass. Try a different password.");
                        return;
                    }
                }
                else if (fpRecord.wEncryptionType == 1 && fpRecord.vMajor > 1)
                {
                    Console.WriteLine("FilePass record for CryptoAPI Found - Currently Unsupported.");
                    string verifierSalt = BitConverter.ToString(fpRecord.encryptionVerifier.Salt).Replace("-", "");
                    string verifier     = BitConverter.ToString(fpRecord.encryptionVerifier.EncryptedVerifier).Replace("-", "");
                    string verifierHash = BitConverter.ToString(fpRecord.encryptionVerifier.EncryptedVerifierHash).Replace("-", "");
                    Console.WriteLine("Salt is: " + verifierSalt);
                    Console.WriteLine("Vrfy is: " + verifier);
                    Console.WriteLine("vHsh is: " + verifierHash);
                    Console.WriteLine("Algo is: " + string.Format("{0:x8}", fpRecord.encryptionHeader.AlgID));
                }

                else if (fpRecord.wEncryptionType == 1 && fpRecord.vMajor == 1)
                {
                    Console.WriteLine("FilePass record for RC4 Binary Document Encryption Found - Currently Unsupported.");
                }
            }

            int numBytesToDump = 0;

            if (dumpHexBytes)
            {
                numBytesToDump = 0x1000;
            }

            if (dumpAll)
            {
                List <BiffRecord> records;
                WorkbookStream    fullStream = new WorkbookStream(PtgHelper.UpdateGlobalsStreamReferences(wbs.Records));
                records = fullStream.Records;
                foreach (var record in records)
                {
                    Console.WriteLine(record.ToHexDumpString(numBytesToDump, showAttrInfo));
                }
            }
            else
            {
                string dumpString = RecordHelper.GetRelevantRecordDumpString(wbs, dumpHexBytes, showAttrInfo);
                Console.WriteLine(dumpString);
            }
        }
Esempio n. 5
0
        public byte[] TransformWorkbookBytes(byte[] bytes, ObfuscationMode mode, string password = XorObfuscation.DefaultPassword)
        {
            VirtualStreamReader vsr = new VirtualStreamReader(new MemoryStream(bytes));
            MemoryStream        ms  = new MemoryStream();
            BinaryWriter        bw  = new BinaryWriter(ms);

            while (vsr.BaseStream.Position < vsr.BaseStream.Length)
            {
                BiffHeader bh;
                bh.id = (RecordType)vsr.ReadUInt16();

                //Handle case where RecordId is empty
                if (bh.id == 0)
                {
                    break;
                }

                bh.length = vsr.ReadUInt16();

                //Taken from https://social.msdn.microsoft.com/Forums/en-US/3dadbed3-0e68-4f11-8b43-3a2328d9ebd5/xls-xor-data-transformation-method-1


                byte XorArrayIndex = (byte)((vsr.BaseStream.Position + bh.length) % 16);


                //We remove the FilePass Record for the decrypted document
                if (mode == ObfuscationMode.Decrypt && bh.id == RecordType.FilePass)
                {
                    //Skip the remaining FilePass bytes
                    ushort encryptionMode = vsr.ReadUInt16();

                    if (encryptionMode != 0)
                    {
                        throw new NotImplementedException("FilePass EncryptionMode of " + encryptionMode +
                                                          " is unsupported.");
                    }

                    ushort key    = vsr.ReadUInt16();
                    ushort verify = vsr.ReadUInt16();

                    ushort passwordVerify = CreatePasswordVerifier_Method1(password);

                    if (verify != passwordVerify)
                    {
                        throw new ArgumentException(
                                  "Incorrect decryption password. Try bruteforcing the password with another tool.");
                    }

                    continue;
                }
                ;

                bw.Write(Convert.ToUInt16(bh.id));
                bw.Write(Convert.ToUInt16(bh.length));

                //If we're encrypting, then use the byte writer for our current position rather than the read stream
                if (mode == ObfuscationMode.Encrypt)
                {
                    XorArrayIndex = (byte)((bw.BaseStream.Position + bh.length) % 16);
                }

                //Nothing to decrypt for 0 length
                if (bh.length == 0)
                {
                    continue;
                }

                switch (bh.id)
                {
                case RecordType.BOF:
                case RecordType.FilePass:
                case RecordType.UsrExcl:
                case RecordType.FileLock:
                case RecordType.InterfaceHdr:
                case RecordType.RRDInfo:
                case RecordType.RRDHead:
                    byte[] recordBytes = vsr.ReadBytes(bh.length);
                    bw.Write(recordBytes);

                    //If this is the first BOF record, we inject the appropriate FilePass record
                    if (mode == ObfuscationMode.Encrypt &&
                        bh.id == RecordType.BOF &&
                        vsr.BaseStream.Position == (bh.length + 4))
                    {
                        ushort   key           = CreateXorKey_Method1(password);
                        ushort   verify        = CreatePasswordVerifier_Method1(password);
                        FilePass filePass      = new FilePass(key, verify);
                        byte[]   filePassBytes = filePass.GetBytes();
                        bw.Write(filePassBytes);
                    }

                    continue;

                case RecordType.BoundSheet8:
                    //Special Case - don't encrypt/decrypt the lbPlyPos Field
                    uint lbPlyPos = vsr.ReadUInt32();

                    //For encryption we need to adjust this by the added FilePass record length
                    //Decryption we auto-fix afterwards, but encrypted entries don't auto-fix well
                    // if (mode == ObfuscationMode.Encrypt)
                    // {
                    //     lbPlyPos += 10;
                    // }

                    bw.Write(lbPlyPos);
                    //Since we are skipping lbPlyPos, we need to update the XorArrayIndex offset as well
                    XorArrayIndex = (byte)((XorArrayIndex + 4) % 16);
                    byte[] remainingBytes = vsr.ReadBytes(bh.length - 4);
                    if (mode == ObfuscationMode.Decrypt)
                    {
                        byte[] decryptedBytes = DecryptData_Method1(password, remainingBytes, XorArrayIndex);
                        bw.Write(decryptedBytes);
                    }
                    else
                    {
                        byte[] encryptedBytes = EncryptData_Method1(password, remainingBytes, XorArrayIndex);
                        bw.Write(encryptedBytes);
                    }
                    continue;

                default:
                    byte[] preTransformBytes = vsr.ReadBytes(bh.length);
                    if (mode == ObfuscationMode.Decrypt)
                    {
                        byte[] decBytes = DecryptData_Method1(password, preTransformBytes, XorArrayIndex);
                        bw.Write(decBytes);
                    }
                    else
                    {
                        byte[] encBytes = EncryptData_Method1(password, preTransformBytes, XorArrayIndex);
                        bw.Write(encBytes);
                    }
                    continue;
                }
            }

            return(bw.GetBytesWritten());
        }