github.com/n00py/Slackor@v0.0.0-20200610224921-d007fcea1740/impacket/tests/misc/test_dpapi.py (about)

     1  ###############################################################################
     2  #  Tested so far: 
     3  #
     4  # MasterKey
     5  #
     6  #  Not yet:
     7  #
     8  #
     9  ################################################################################
    10  
    11  import unittest
    12  from binascii import unhexlify
    13  
    14  from impacket.dpapi import DPAPI_SYSTEM, MasterKeyFile, MasterKey, CredentialFile, DPAPI_BLOB, CREDENTIAL_BLOB, VAULT_VPOL, VAULT_VPOL_KEYS, VAULT_VCRD, VAULT_KNOWN_SCHEMAS
    15  from Cryptodome.Cipher import AES
    16  from Cryptodome.Hash import HMAC, MD4, SHA1
    17  
    18  
    19  class DPAPITests(unittest.TestCase):
    20      def setUp(self):
    21          self.machineKey = unhexlify('2bb2109db472825bfa7660fdbed62c981f08587b')
    22          self.userKey = unhexlify('458dc597034d8801fc6fe3b342817caabb81a0cb')
    23          self.sid = "S-1-5-21-1455520393-2011455520393-2019809541-4133251990-500"
    24          self.password = "Admin456"
    25          self.adminMasterKey = unhexlify('4c4a398169cc9ecc6eae0e1a70ba1dc58bfec785c4b35bd1afdf2aeb06753bca0ea3491989cb626990973f8370fd576a46c0ce2a85d995a01af6d727ff41969c')
    26          self.adminMasterKeyFile = b'\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x00a\x004\x003\x00a\x00c\x007' \
    27                                    b'\x001\x00-\x005\x002\x00d\x001\x00-\x004\x00b\x001\x005\x00-\x008\x004\x00c\x00b' \
    28                                    b'\x00-\x000\x001\x00a\x005\x00e\x007\x00f\x000\x006\x003\x005\x000\x00\x00\x00\x00' \
    29                                    b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\x00\x00\x00\x00\x00\x00\x00h\x00\x00\x00' \
    30                                    b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\x01\x00\x00\x00\x00\x00\x00\x02' \
    31                                    b'\x00\x00\x00\xd7\x086A\xa3\xfc\x10[\x87\x00\xea\xd0\x86S\x042\xc0]\x00\x00\t\x80' \
    32                                    b'\x00\x00\x03f\x00\x00!"}/=B\x08\xf9Q\xffW\xc0\xa0)\x16z\x15l\x1d\xe3\xf9\x17\xcd' \
    33                                    b'\x8elf\x98e\x9a\xcc}\xda\xb0\x11\x7fVWJ\xd3\x02\xael\x08\xf4\xach\x9c\xf9\xbbO' \
    34                                    b'\x13\x17\xe1P\xef\x99\xa8^\xae[8)\x12\x86\xf1B-\xdb\x8c\xaf\xa5@1\x90\xba\x1e' \
    35                                    b'\xd0E\x1b\xd0!C\xca\xcc\xc6h\x9a6\xe4B;\x8cM+\xd3\xd6R\xf5\xb5~\xd9\xc2\n\x9d\x02' \
    36                                    b'\x00\x00\x00\xc2\x9e\x93\xc9\xd7*\xd8\x04\xcd\x8d\xfcUAR\x01\x9d\xc0]\x00\x00\t' \
    37                                    b'\x80\x00\x00\x03f\x00\x00\xc2zU\xa7\'\xc6dj\xd8\x93\xb6\xac\xc0KQ\x8a\xea+>\xe0' \
    38                                    b'SK@\x8b\xcc\x8e-Ua1\x92\x87\x05\x12\x7f\xe4!\xe9\xa2\x01\x89\x91JD$\x9bS\xdd\x02' \
    39                                    b'\xba2%\xef3\t\x19Cu\x12S"\xd8Dr\xf4k\x809\xbc\xbaEJ\x02\x00\x00\x00\x00\x01\x00' \
    40                                    b'\x00X\x00\x00\x00\xe9\x99\xde\xe7\'K\xc0D\xa1\xbe\xf3\xf4=\xc8\xa8\x9f\x9bQ\x1d' \
    41                                    b'\x12I\xfd\xd6_\x8f9t\xc3\xfe<\x82\xa1%\x80\x8e\xaa5&\xd2\xa4\xedW\x8e\x17\x9b\xe0' \
    42                                    b'\xe5$}\x13;\x04\xea\xce\xc2\xd3(\xfa\x8f\x02\xcd\xf2\xfa=\xa2\xf9P\x07\xc6pa\x81' \
    43                                    b'\xd9y\xb1\x07Q\xcf\xb9\x160\x89\xf8\xad\xce\xc11\x10O\x1c\xfc\xd5\xb7.\xcd\x83\xe6' \
    44                                    b'\xb5\xb5:\xf4\xa3(\xd3\xc3\xa3\x1b\x1dU\xec\xd8Y\xdb\xad\xd58\x8b\xf2\xe3\xc7\xd1' \
    45                                    b'\r\xd5\x93\x97\xd4:r\x01\x8e\xf4b\x10\xed\x14h\x81\x9c>\x9b\x99\x1c\x0f\xaar\x05' \
    46                                    b'\xf7f_\x89e\xea\x80j\xcb\x92\xa3\xc3w\xc4\x1a\xed\xe9\xceu\x05\x87\xd2r\xda\xa3' \
    47                                    b'\x86\xd0\x8a\x9f\x81\xcde\xaf\xdc\x9a\x86$\xf7\xd7Eu\xc6W\xdam\x18\x8e\xc7wE4' \
    48                                    b'\x90wx&\x11/\xf3Rh\xf4\xb4=\xdd\xbe\xa4\xcbR\xf9\xf6\x15C\x02\xc90\x931\xefY$' \
    49                                    b'\x9aB\x94h4\x04\t\xb1Y\x83N\xd2\xd3\xa6|h\x04\xa4*sR\x9e\xd2pE\x1e\xc0b">\xdd\xc8' \
    50                                    b'\xef\x9cb\xf0jVP\x9aJA\x9b|\xdbx\xdd\xcbs\xd4\xdd\x95\x88\xd4\x87,LyMf\x9b\xdf' \
    51                                    b'\xb7\xc0\x0cJ52]\x8f=\x8eE\xe7\x93u\xe9\x18\xea%\xd7U\x17(0\xe4\x8c\xcb\xe1Q\xc7' \
    52                                    b'\xfa\xc3qX/.\xf0r\xd2\x9a\xb35\x8e\x18\xdb\x8e\x81\xc7x\xab\x81\xbd\xcf,\x1c\xc8x' \
    53                                    b'\x9d\xf2\x9c;\x01xo\x84\xfdx\xb4\x14G-\xd3o'
    54          self.systemMasterKey = unhexlify('682a9b8923ff4ca7ce0ef7e4cee061f0ff942cd31c7703ec60792740b2e7d0b1b5115d1ff77e10b77e189e0d6e99d5b668190ecd44fa84e82e049f406e2c2a59')
    55          self.systemMasterKeyFile = b"\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\x00a\x009\x005\x00e\x00b\x00a\x008" \
    56                                 b"\x00-\x00b\x00a\x000\x000\x00-\x004\x00e\x001\x00a\x00-\x00b\x004\x003\x00f\x00-\x005" \
    57                                 b"\x001\x00e\x00a\x003\x000\x001\x007\x001\x00d\x001\x001\x00\x00\x00\x00\x00\x00\x00" \
    58                                 b"\x00\x00\x06\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x00\x00\x00" \
    59                                 b"\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00" \
    60                                 b"\xf4/a\xea\x0c\x96G\xbf@8\x19\x89\x84R\x08\x9f\xf8C\x00\x00\x0e\x80\x00\x00\x10f\x00" \
    61                                 b"\x00\xe2D\x1d\xec\x11\xa6\xb6\xf0?\xfe\xbb\xa1\xe7\x14s\xf7\x8d\xa4jR\xb1,\xaf\xf7" \
    62                                 b"\xdf\x99%\xedj\xc8\x9d\x84\x05\n\xd1\\\xfe\x88\xecP\xec\xe2\x01\xe5\xa8\x0e\xb1\x98" \
    63                                 b"\x90\x9f\xf8\xc7\x81Q\x0fx\x85\x9b\x96\xcf\xad\xe43\xc8:\x7f?\xc1\x99&\xb0(\x0ej\x19n" \
    64                                 b"\xf1\xb0\xb5\xe1\xb3\xc1\xabBa \xdaS\xf2NY\x89\xf8\xa7\xd3\xdd\xe8j\xc4D\x90\x14\x01" \
    65                                 b"\xa6\xdfd\x07\xf5P\xd1\x97\xff'\xc9\x1a\xbb\\3\x12P\xb5\xa7\xceX\xc1\xf6\x1f\xd0\xd6V6" \
    66                                 b"\r\xf5\x8eo[_\xaa\xc69f\x1a\xa8\x94\x02\x00\x00\x00\xbd\xc1\xf9Y#W5:*>\xbc\xf8\xce" \
    67                                 b"\xdcr\xbb\xf8C\x00\x00\x0e\x80\x00\x00\x10f\x00\x00\x121\xd6~\xc6\x89\xfe\xa9\xf6" \
    68                                 b"\xdek\xd6j!\xe2\x8dT\x05#-\xf7\x1d\xea\xe5\xbf:\xb6<l\xb2\xca\xc0\x8a\xd1tV\x97\x9dr" \
    69                                 b"\xb7\r\xe1:\xfc+a\xd0T4\x16\x11\x91\xdc\xdf\xb2J\xaa\xc7\xed\x02u\xf7\x1e\xff\x9f" \
    70                                 b"\x93jU\x9a\xffK\xe60\x1b\xa9\x9df\xbd\x8e\x07\xb1\xa3%\xc7<zM\xa9q\x17\xf8\x05Q\xa3" \
    71                                 b"\xf0\xa7]\xa9\xfc\xc3|M+\xb4;Z\x9e\xf1hDF\xae\x03\x00\x00\x00\x00\x00\x00\x00\x00" \
    72                                 b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    73  
    74          self.credentialFile = b'\x01\x00\x00\x00j\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\xd0\x8c\x9d\xdf\x01\x15' \
    75                                b'\xd1\x11\x8cz\x00\xc0O\xc2\x97\xeb\x01\x00\x00\x00q\xacC:\xd1R\x15K\x84\xcb\x01\xa5' \
    76                                b'\xe7\xf0cP\x00\x00\x00 :\x00\x00\x00E\x00n\x00t\x00e\x00r\x00p\x00r\x00i\x00s\x00e' \
    77                                b'\x00 \x00C\x00r\x00e\x00d\x00e\x00n\x00t\x00i\x00a\x00l\x00 \x00D\x00a\x00t\x00a\x00' \
    78                                b'\r\x00\n\x00\x00\x00\x03f\x00\x00\xc0\x00\x00\x00\x10\x00\x00\x00X\x87\xdb\xeb\xc07' \
    79                                b'\xd8\xef\xb5\xa3\x9fi##!L\x00\x00\x00\x00\x04\x80\x00\x00\xa0\x00\x00\x00\x10\x00\x00' \
    80                                b'\x00\x92\xbe\x1f7\xa5\x80\xe5\x11\ns\x08lr\xec\xf7\xfc\xa8\x00\x00\x00\x92YL\xcd4C\xd8' \
    81                                b'\xe7[\xd8D}\xac\x9a_\n\xdc\xe7\xf2\x9ar\x84\x1fC\x87\x19\xb9\xe8y\x9c\x07LD>\xf3\xd3' \
    82                                b'\x97\x01\xb0\xfa\xf2n\xa3\xd9U_\xd3n\xd4\x80\xa5\x13\xb9$\x13\xe2\x02\x97\xb0*\xd6\xcf' \
    83                                b'\xa1\x1e\x19\xf1\x9c\xea.tq\xf3\xb4\x89*L\xd2\xd5\x91;D7\xbd\xf0\x1eF\x82\x13\xb9e\x9b' \
    84                                b'\x9a\x86w0\xb2\xb7b\x8f\xb6\t\xbe\xfb>v\x9f\x89S\x10\xe3\xe7\x0f}:\xd3\xdd\xe3B\x18c' \
    85                                b'\xf7\x85j\xe4\xfb4=\x1e\x18\x97\xa1,+i\xe5\x8b\xdfn8\xc5>\x9eysQe\x85\xfb\x0b\x01' \
    86                                b'\xd8 \xb2\x81*\x8e\xcd \xafE\x9f\x8c\xcb\x97\x89\x96\x97\xdd\x14\x00\x00\x00\xb7\xe5%' \
    87                                b'\xfdC*R\xf9\rd\x0b\x7f\xf0G\xe9C\xf3\xd3p\x8c'
    88  
    89          self.vpolFile = b"\x01\x00\x00\x00B\xc4\xf4K\x8a\x9b\xa0A\xb3\x80\xddJpM\xdb( \x00\x00\x00W\x00e\x00b\x00 " \
    90                          b"\x00C\x00r\x00e\x00d\x00e\x00n\x00t\x00i\x00a\x00l\x00s\x00\x00\x00\x01\x00\x00\x00\x00\x00" \
    91                          b"\x00\x00\x01\x00\x00\x00h\x01\x00\x00\x0b\xdas\xdd\x83\xfd\x12G\xaf\x8b\xd1S\xc7\x10\xc6\xb9" \
    92                          b"\x0b\xdas\xdd\x83\xfd\x12G\xaf\x8b\xd1S\xc7\x10\xc6\xb9D\x01\x00\x00\x01\x00\x00\x00\xd0\x8c" \
    93                          b"\x9d\xdf\x01\x15\xd1\x11\x8cz\x00\xc0O\xc2\x97\xeb\x01\x00\x00\x00Wc\xa0\t\xf5\xf3\xccJ\x9d" \
    94                          b"\x08\xd8\x86Z\xad\xe4\xac\x00\x00\x00 \x00\x00\x00\x00\x10f\x00\x00\x00\x01\x00\x00 \x00\x00" \
    95                          b"\x00\xe5\r@\x973M\xca\xdd\xb1\xca\x0cR\xb6\xaaO\xc5C\x91\x01\xd0l\xd6\x8f\xce1\xaf!\x17$L!" \
    96                          b"\xc8\x00\x00\x00\x00\x0e\x80\x00\x00\x00\x02\x00\x00 \x00\x00\x00\xd2@h\x0e\x8e\xd9$V\xa8y" \
    97                          b"\xf3\xbe\xbd\x85\x98\xb3\x1b&{\xed\xb3xx\xc6\xba\xc9\x8a\xc0s\xd4]\xeap\x00\x00\x00\x88}\x83" \
    98                          b"\x18\xc6\xc6\x00\xbc\xfe\xeb\xc4\xcb\xde\xfei>\xabo\xba\xb8=\\\ns\xb5\xdb\x97\xb9ln8B\xd9" \
    99                          b"\xc9\xd4:\x94\x9b7|\x94^\xda\x06\xe3\xdau\x0c\x02\x0c\x1bh\x8b\xac\xb8W#\x08\x0cm\xd5T+" \
   100                          b"\xc0m!U\xd7f\x9aO\xf1\xc7\x8b\xd1\x9c\x8ak._g\x01P>\xd3\xd7'\xe8j\xc4\xe4\xc7\xe4f`x\xffA" \
   101                          b"\x93#\xb5\x84\xbc\x17\x96\xa5e\xa0k\xd7p\xfc@\x00\x00\x00\xde\xb5&\xf7jZ\xac\x14Z\xd2\xb5" \
   102                          b"\xc3\xc9\x046\xb1\xb9A-~\x17)\xe9\xdcb~\xf7J+\x15\xa8\xe7N\xc5\xe5\x0b\xe3\x86\xf8\x08\\]G" \
   103                          b"\x9e;\x82\x9c\xa2\xf3\xf8s\xd9}\xdd\x00f\x97u\xe3\xeff\x05\xa4\x90\x00\x00\x00\x00"
   104  
   105          self.vcrdFile = b'\x99T\xcd<\xa8\x87\x10K\xa2\x15`\x88\x88\xdd;U\x04\x00\x00\x00\xa3\xcf\x10\xffWm\xd3\x01\xff' \
   106                          b'\xff\xff\xff\x00\x02\x00\x00$\x00\x00\x00I\x00n\x00t\x00e\x00r\x00n\x00e\x00t\x00 \x00E\x00x' \
   107                          b'\x00p\x00l\x00o\x00r\x00e\x00r\x00\x00\x000\x00\x00\x00\x01\x00\x00\x00\x80\x00\x00\x00M_{' \
   108                          b'\x18\x02\x00\x00\x00\xb5\x00\x00\x00M_{\x18\x03\x00\x00\x00\xea\x00\x00\x00M_{\x18d\x00\x00' \
   109                          b'\x00\x00\x01\x00\x00M_{\x18\x01\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\n\x00\x00\x00!' \
   110                          b'\x00\x00\x00\x00\x00e\x1c\x90\x18P\xab\xd0 0\xac!\xaf\x10\x81\xfe\xabAN#ga\xa9^I\x0e=\xffW' \
   111                          b'\xd2\xdbt\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\n\x00\x00\x00!\x00\x00\x00\x00\x99' \
   112                          b'|\xc9\x8b+\xd1\xbfF\xf2\xdd\xdd\xac\xa9\x80\xfd\x08x\x9d\xe6\xbe\x16&\xb0\'\x1ahQ\x08\x86-' \
   113                          b'\xdc~\x03\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\n\x00\x00\x00\x00\x00\x00\x00\x01\x00d' \
   114                          b'\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\n\x00\x00\x00\x00\x00\x00\x00\xb5\x00\x00\x00' \
   115                          b'\x01\x10\x00\x00\x00)\x87\xe8|\xe62\xc7\xcf\x98\xc9\xbd\xfb}"\xe4]8\x8a\x1cl\xb9\x1dP4\xc8' \
   116                          b'\xdf\xe1\x8e#b\x91\xe3\xbe\xb2bA$,\xe9\xa1\xa6\x93\xff\t\x84+\xda\xff\x9f-\'\x96O\xb9\xe9' \
   117                          b'\x15\x0f\xb8\xd4\xdbs\xa3\xb1Z\xfc\x90\x07\x01?DBQ\xd4\x1d_\x0eo?\xd3Z\xf1Z\xe7\xf8\xe4oL3' \
   118                          b'\x91\xbbB%\xef\x0f\xaf\x03*\x99\xd6\xb6\xc8\xd9\x83+e\x8b\x02l\x9fl IJ\xe2\x89~a)E\x8fL\xe4' \
   119                          b'\xfc\x9dC\x17\xb0\x14\xe9]H\xfd\x0e+:\xc5\xc7\xcb\x87\xd0S\x16\x1bu\xb4\xfc1\xce\xd8\xffb' \
   120                          b'\x0e3\xbe|\xa3\xd7<\xd1:\xf1.PUr\xe8\xfdQ\x16\xe3\xa9\rt\x14\x04\xbb\x01\x00\x00\x00\x00' \
   121                          b'\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00'
   122  
   123      def test_DPAPI_SYSTEM(self):
   124          blob = unhexlify('010000002bb2109db472825bfa7660fdbed62c981f08587b458dc597034d8801fc6fe3b342817caabb81a0cb')
   125          keys = DPAPI_SYSTEM(blob)
   126          keys.dump()
   127          self.assertEqual(self.machineKey, keys['MachineKey'])
   128          self.assertEqual(self.userKey, keys['UserKey'])
   129  
   130      def test_systemMasterKeyFile(self):
   131          mkf = MasterKeyFile(self.systemMasterKeyFile)
   132          mkf.dump()
   133          data = self.systemMasterKeyFile[len(mkf):]
   134          mk = MasterKey(data[:mkf['MasterKeyLen']])
   135          mk.dump()
   136          decryptedKey = mk.decrypt(self.userKey)
   137          self.assertEqual(decryptedKey, self.systemMasterKey)
   138  
   139      def deriveKeysFromUser(self, sid, password):
   140          # Will generate two keys, one with SHA1 and another with MD4
   141          key1 = HMAC.new(SHA1.new(password.encode('utf-16le')).digest(), (sid + '\0').encode('utf-16le'), SHA1).digest()
   142          key2 = HMAC.new(MD4.new(password.encode('utf-16le')).digest(), (sid + '\0').encode('utf-16le'), SHA1).digest()
   143  
   144          return key1, key2
   145  
   146      def atest_adminMasterKeyFile(self):
   147          # ToDo: fix this one..
   148          mkf = MasterKeyFile(self.adminMasterKeyFile)
   149          mkf.dump()
   150          data = self.adminMasterKeyFile[len(mkf):]
   151          mk = MasterKey(data[:mkf['MasterKeyLen']])
   152          mk.dump()
   153          key1, key2 = self.deriveKeysFromUser( self.sid, self.password)
   154          decryptedKey = mk.decrypt(key1)
   155          decryptedKey = mk.decrypt(key2)
   156          self.assertEqual(decryptedKey, self.adminMasterKey)
   157  
   158      def test_decryptCredential(self):
   159          credFile = CredentialFile(self.credentialFile)
   160          credFile.dump()
   161          blob = DPAPI_BLOB(credFile['Data'])
   162          decrypted = blob.decrypt(self.adminMasterKey)
   163          creds = CREDENTIAL_BLOB(decrypted)
   164          creds.dump()
   165          self.assertEqual(creds['Username'], 'david.bowie\x00'.encode('utf-16le'))
   166  
   167  
   168      def test_decryptVpol(self):
   169          vpol = VAULT_VPOL(self.vpolFile)
   170          vpol.dump()
   171          key = unhexlify('dda7cb9077756f4a5ea6291d57d5e3d3e96765885777cd6e8575f337034dfa4e58eb1ec5c97a4d9915b70130b7776aea16dc14a9486319e1849355c097b99272')
   172          blob = vpol['Blob']
   173          data = blob.decrypt(key)
   174          keys = VAULT_VPOL_KEYS(data)
   175          keys.dump()
   176          self.assertEqual(keys['Key2']['bKeyBlob']['bKey'], unhexlify('756ff73b0ee4980e2dd722fbcd0badb9a6be89590304eb6d58b6e8ab7aaaec1d'))
   177  
   178      def test_decryptVCrd(self):
   179          blob = VAULT_VCRD(self.vcrdFile)
   180          blob.dump()
   181          key = unhexlify('acf4ff323558de5514be1731598e37c1ae5a6bf9016d5906097aee46712a5fe7')
   182  
   183          cleartext = None
   184          for i, entry in enumerate(blob.attributesLen):
   185              if entry > 28:
   186                  attribute = blob.attributes[i]
   187                  if 'IV' in attribute.fields and len(attribute['IV']) == 16:
   188                      cipher = AES.new(key, AES.MODE_CBC, iv=attribute['IV'])
   189                  else:
   190                      cipher = AES.new(key, AES.MODE_CBC)
   191                  cleartext = cipher.decrypt(attribute['Data'])
   192  
   193          if cleartext is not None:
   194              # Lookup schema Friendly Name and print if we find one
   195              if blob['FriendlyName'].decode('utf-16le')[:-1] in VAULT_KNOWN_SCHEMAS:
   196                  # Found one. Cast it and print
   197                  vault = VAULT_KNOWN_SCHEMAS[blob['FriendlyName'].decode('utf-16le')[:-1]](cleartext)
   198                  vault.dump()
   199                  self.assertEqual(vault['Username'], 'CONTOSO\\Administrator\x00'.encode('utf-16le'))
   200              else:
   201                  raise Exception('No valid Schema')
   202  
   203  # Process command-line arguments.
   204  if __name__ == '__main__':
   205      suite = unittest.TestLoader().loadTestsFromTestCase(DPAPITests)
   206      unittest.TextTestRunner(verbosity=1).run(suite)