You can parse the binary blobs that represent certificates stored in the Windows registry with certutil correctly, even when the Windows Explorer / GUI tells you that this is not a certificate. certutil seems to be able to handle / ignore meta data better.
Once upon a time I played with the machine Ethereal provided by hackthebox. I was most interested in anything certificate-related. As I missed some obvious clues I had to resort to registry forensics to confirm that a non-default Root CA certificate had been installed. In this case it was sufficient to read the Subject and Issuer Name, so I did not try to actually decode the full certificate.
But now I want to read all certificate fields and attributes. I know that you can do that very conveniently with powershell. But the scenario here is: What to do if access to many interesting binaries is blocked, but reg query is available. In case of the Etherreal box I had copied the reg query output from (a super cumbersome) shell to analyze it further on the attack box.
Registry keys contain long strings of hex-encoded bytes. For example, this key …
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates\ROOT\Certificates\CDD4EEAE6000AC7F40C3802C171E30148030C072
… contains this blob, bytes hex-encoded as:
5900000001000000120000005200530041002F0053004800410031000000040000000100000010000000E1C07EA0AABBD4B77B84C228117808A71400000001000000140000000EAC826040562797E52513FC2AE10A539559E4A469000000010000000E000000300C060A2B0601040182373C03020B000000010000004A0000004D006900630072006F0073006F0066007400200052006F006F007400200043006500720074006900660069006300610074006500200041007500740068006F0072006900740079000000030000000100000014000000CDD4EEAE6000AC7F40C3802C171E30148030C0720F0000000100000014000000391BE92883D52509155BFEAE27B9BD340170B76B190000000100000010000000983B132635B7E91DEEF54A6780C092695C00000001000000040000000010000020000000010000009D0500003082059930820381A003020102021079AD16A14AA0A5AD4C7358F407132E65300D06092A864886F70D0101050500305F31133011060A0992268993F22C6401191603636F6D31193017060A0992268993F22C64011916096D6963726F736F6674312D302B060355040313244D6963726F736F667420526F6F7420436572746966696361746520417574686F72697479301E170D3031303530393233313932325A170D3231303530393233323831335A305F31133011060A0992268993F22C6401191603636F6D31193017060A0992268993F22C64011916096D6963726F736F6674312D302B060355040313244D6963726F736F667420526F6F7420436572746966696361746520417574686F7269747930820222300D06092A864886F70D01010105000382020F003082020A0282020100F35DFA8067D45AA7A90C2C9020D035083C7584CDB707899C89DADECEC360FA91685A9E94712918767CC2E0C82576940E58FA043436E6DFAFF780BAE9580B2B93E59D05E3772291F734643C22911D5EE10990BC14FEFC755819E179B70792A3AE885908D89F07CA0358FC68296D32D7D2A8CB4BFCE10B48324FE6EBB8AD4FE45C6F139499DB95D575DBA81AB79491B4775BF5480C8F6A797D1470047D6DAF90F5DA70D847B7BF9B2F6CE705B7E11160AC7991147CC5D6A6E4E17ED5C37EE592D23C00B53682DE79E16DF3B56EF89F33C9CB527D739836DB8BA16BA295979BA3DEC24D26FF0696672506C8E7ACE4EE1233953199C835084E34CA7953D5B5BE6332594036C0A54E044D3DDB5B0733E458BFEF3F5364D842593557FD0F457C24044D9ED6387411972290CE684474926FD54B6FB086E3C73642A0D0FCC1C05AF9A361B9304771960A16B091C04295EF107F286AE32A1FB1E4CD033F777104C720FC490F1D4588A4D7CB7E88AD8E2DEC45DBC45104C92AFCEC869E9A11975BDECE5388E6E2B7FDAC95C22840DBEF0490DF813339D9B245A5238706A5558931BB062D600E41187D1F2EB597CB11EB15D524A594EF151489FD4B73FA325BFCD13300F95962700732EA2EAB402D7BCADD21671B30998F16AA23A841D1B06E119B36C4DE40749CE15865C1601E7A5B38C88FBB04267CD41640E5B66B6CAA86FD00BFCEC1350203010001A351304F300B0603551D0F0404030201C6300F0603551D130101FF040530030101FF301D0603551D0E041604140EAC826040562797E52513FC2AE10A539559E4A4301006092B06010401823715010403020100300D06092A864886F70D01010505000382020100C5114D033A60DD5D5211778FB2BB36C8B205BFB4B7A8D8209D5C1303B61C22FA061335B6C863D49A476F2657D255F104B1265FD6A95068A0BCD2B86ECCC3E9ACDF19CD78AC5974AC663436C41B3E6C384C330E30120DA326FE515300FFAF5A4E840D0F1FE46D052E4E854B8D6C336F54D264ABBF50AF7D7A39A037ED63030FFC1306CE1636D4543B951B51623AE54D17D40539929A27A85BAABDECBBBEE3208960716C56B3A513D06D0E237E9503ED683DF2D863B86B4DB6E830B5E1CA944BF7A2AA5D9930B23DA7C2516C28200124272B4B00B79D116B70BEB21082BC0C9B68D08D3B2487AA9928729D335F5990BDF5DE939E3A625A3439E288551DB906B0C1896B2DD769C319123684D0C9A0DAFF2F6978B2E57ADAEBD70CC0F7BD6317B8391338A2365B7BF285566A1D6462C138E2AABF5166A294F5129C6622106BF2B730922DF229F03D3B144368A2F19C2937CBCE3820256D7C67F37E24122403088147ECA59E97F518D7CFBBD5EF7696EFFDCEDB569D95A042F99758E1D73122D35F59E63E6E2200EA4384B625DBD9F3085668C0646B1D7CECB693A262576E2ED8E7588FC4314926DDDE293587F53071705B143C69BD89127DEB2EA3FED87F9E825A520A2BC1432BD930889FC810FB898DE6A18575337E6C9EDB7313646269A52F7DCA966D9FF8044D30923D6E211421C93DE0C3FD8A6B9D4AFDD1A19D9943773FB0DA
When you turn this into bytes (see python code below) and write them to a file and double-click it, the Crypto Shell Extensions tell you that this is not a certificate:This is in line with the detailed forensic analysis provided in this blog post: The blog data contain meta data that needs to be stripped off before the remaining data stored as a file are correctly recognized as a certificate.
I wanted to use a brute force / dumbed down approach: The idea has been to run certutil on the not-yet-recognized certificate file, check the output, and if says ‘incorrect’ or the like – strip off a byte, try again – loop until you have stripped off all the meta information.
However, to my surprise, the first attempt to run certutil was already successful: So in contrast to the Crypto Shell Extensions certutil seems to be able to ignore the meta data. For a quick demonstration, I am parsing local Root CA certificates (on Windows 10) with this python script:
import subprocess rootcerts_topreg = 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates\ROOT\Certificates' certfile = 'cert.crt' def runshell(cmd): sp = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) return sp.stdout.read().decode('utf8') def getstripped(s, toberemoved): out = s for t in toberemoved: out = out.replace(t, '') return out def getregquery(reg): return runshell('reg query ' + reg) def getblob(reg): out = getregquery(reg) return getstripped(out, [ reg, ' ', '\t', '\r\n', 'Blob', 'REG_BINARY' ]) print('[*] Find all root certificates in ' + rootcerts_topreg) rootcerts_regs = [ r for r in getregquery(rootcerts_topreg).split('\r\n') if r != '' ] for reg in rootcerts_regs: print('============================================================================================================') print(reg + '\n') certhex = getblob(reg) print(certhex + '\n') certbytes = bytes.fromhex(certhex) open(certfile, 'wb').write(certbytes) print(runshell('certutil ' + certfile))
Below is one item from the long output – the script loops through all certificates under \ROOT\Certificates. All certificates are parsed correctly. I am using certutil -v for verbose output.
... ============================================================================================================ HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates\ROOT\Certificates\D4DE20D05E66FC53FE1A50882C78DB2852CAE474 040000000100000010000000ACB694A59C17E0D791529BB19706A6E45900000001000000120000005200530041002F0053004800410031000000140000000100000014000000E59D5930824758CCACFA085436867B3AB5044DF0030000000100000014000000D4DE20D05E66FC53FE1A50882C78DB2852CAE4740F0000000100000014000000CE0E658AA3E847E467A147B3049191093D055E6F19000000010000001000000068CB42B035EA773E52EF50ECF50EC5295C00000001000000040000000008000020000000010000007B030000308203773082025FA0030201020204020000B9300D06092A864886F70D0101050500305A310B300906035504061302494531123010060355040A130942616C74696D6F726531133011060355040B130A43796265725472757374312230200603550403131942616C74696D6F7265204379626572547275737420526F6F74301E170D3030303531323138343630305A170D3235303531323233353930305A305A310B300906035504061302494531123010060355040A130942616C74696D6F726531133011060355040B130A43796265725472757374312230200603550403131942616C74696D6F7265204379626572547275737420526F6F7430820122300D06092A864886F70D01010105000382010F003082010A0282010100A304BB22AB983D57E826729AB579D429E2E1E89580B1B0E35B8E2B299A64DFA15DEDB009056DDB282ECE62A262FEB488DA12EB38EB219DC0412B01527B8877D31C8FC7BAB988B56A09E773E81140A7D1CCCA628D2DE58F0BA650D2A850C328EAF5AB25878A9A961CA967B83F0CD5F7F952132FC21BD57070F08FC012CA06CB9AE1D9CA337A77D6F8ECB9F16844424813D2C0C2A4AE5E60FEB6A605FCB4DD075902D459189863F5A563E0900C7D5DB2067AF385EAEBD403AE5E843E5FFF15ED69BCF939367275CF77524DF3C9902CB93DE5C923533F1F2498215C079929BDC63AECE76E863A6B97746333BD681831F0788D76BFFC9E8E5D2A86A74D90DC271A390203010001A3453043301D0603551D0E04160414E59D5930824758CCACFA085436867B3AB5044DF030120603551D130101FF040830060101FF020103300E0603551D0F0101FF040403020106300D06092A864886F70D01010505000382010100850C5D8EE46F51684205A0DDBB4F27258403BDF764FD2DD730E3A41017EBDA2929B6793F76F6191323B8100AF958A4D46170BD04616A128A17D50ABDC5BC307CD6E90C258D86404FECCCA37E38C637114FEDDD68318E4CD2B30174EEBE755E07481A7F70FF165C84C07985B805FD7FBE6511A30FC002B4F852373904D5A9317A18BFA02AF41299F7A34582E33C5EF59D9EB5C89E7C2EC8A49E4E08144B6DFD706D6B1A63BD64E61FB7CEF0F29F2EBB1BB7F250887392C2E2E3168D9A3202AB8E18DDE91011EE7E35AB90AF3E30947AD0333DA7650FF5FC8E9E62CF47442C015DBB1DB532D247D2382ED0FE81DC326A1EB5EE3CD5FCE7811D19C32442EA6339A9 ================ Certificate 0 ================ ================ Begin Nesting Level 1 ================ Element 0: X509 Certificate: Version: 3 Serial Number: 020000b9 Signature Algorithm: Algorithm ObjectId: 1.2.840.113549.1.1.5 sha1RSA Algorithm Parameters: 05 00 Issuer: CN=Baltimore CyberTrust Root OU=CyberTrust O=Baltimore C=IE Name Hash(sha1): c12f4576ed1559ecb05dba89bf9d8078e523d413 Name Hash(md5): 918ad43a9475f78bb5243de886d8103c NotBefore: 12.05.2000 19:46 NotAfter: 13.05.2025 00:59 Subject: CN=Baltimore CyberTrust Root OU=CyberTrust O=Baltimore C=IE Name Hash(sha1): c12f4576ed1559ecb05dba89bf9d8078e523d413 Name Hash(md5): 918ad43a9475f78bb5243de886d8103c Public Key Algorithm: Algorithm ObjectId: 1.2.840.113549.1.1.1 RSA Algorithm Parameters: 05 00 Public Key Length: 2048 bits Public Key: UnusedBits = 0 0000 30 82 01 0a 02 82 01 01 00 a3 04 bb 22 ab 98 3d 0010 57 e8 26 72 9a b5 79 d4 29 e2 e1 e8 95 80 b1 b0 0020 e3 5b 8e 2b 29 9a 64 df a1 5d ed b0 09 05 6d db 0030 28 2e ce 62 a2 62 fe b4 88 da 12 eb 38 eb 21 9d 0040 c0 41 2b 01 52 7b 88 77 d3 1c 8f c7 ba b9 88 b5 0050 6a 09 e7 73 e8 11 40 a7 d1 cc ca 62 8d 2d e5 8f 0060 0b a6 50 d2 a8 50 c3 28 ea f5 ab 25 87 8a 9a 96 0070 1c a9 67 b8 3f 0c d5 f7 f9 52 13 2f c2 1b d5 70 0080 70 f0 8f c0 12 ca 06 cb 9a e1 d9 ca 33 7a 77 d6 0090 f8 ec b9 f1 68 44 42 48 13 d2 c0 c2 a4 ae 5e 60 00a0 fe b6 a6 05 fc b4 dd 07 59 02 d4 59 18 98 63 f5 00b0 a5 63 e0 90 0c 7d 5d b2 06 7a f3 85 ea eb d4 03 00c0 ae 5e 84 3e 5f ff 15 ed 69 bc f9 39 36 72 75 cf 00d0 77 52 4d f3 c9 90 2c b9 3d e5 c9 23 53 3f 1f 24 00e0 98 21 5c 07 99 29 bd c6 3a ec e7 6e 86 3a 6b 97 00f0 74 63 33 bd 68 18 31 f0 78 8d 76 bf fc 9e 8e 5d 0100 2a 86 a7 4d 90 dc 27 1a 39 02 03 01 00 01 Certificate Extensions: 3 2.5.29.14: Flags = 0, Length = 16 Subject Key Identifier e59d5930824758ccacfa085436867b3ab5044df0 2.5.29.19: Flags = 1(Critical), Length = 8 Basic Constraints Subject Type=CA Path Length Constraint=3 2.5.29.15: Flags = 1(Critical), Length = 4 Key Usage Certificate Signing, Off-line CRL Signing, CRL Signing (06) Signature Algorithm: Algorithm ObjectId: 1.2.840.113549.1.1.5 sha1RSA Algorithm Parameters: 05 00 Signature: UnusedBits=0 0000 a9 39 63 ea 42 24 c3 19 1d 81 e7 fc d5 3c ee b5 0010 1e 6a 32 dc 81 fe d0 2e 38 d2 47 d2 32 b5 1d bb 0020 5d 01 2c 44 47 cf 62 9e 8e fc f5 0f 65 a7 3d 33 0030 d0 7a 94 30 3e af 90 ab 35 7e ee 11 10 e9 dd 18 0040 8e ab 02 32 9a 8d 16 e3 e2 c2 92 73 88 50 f2 b7 0050 1b bb 2e 9f f2 f0 ce b7 1f e6 64 bd 63 1a 6b 6d 0060 70 fd 6d 4b 14 08 4e 9e a4 c8 2e 7c 9e c8 b5 9e 0070 9d f5 5e 3c e3 82 45 a3 f7 99 12 f4 2a a0 bf 18 0080 7a 31 a9 d5 04 39 37 52 f8 b4 02 c0 0f a3 11 65 0090 be 7f fd 05 b8 85 79 c0 84 5c 16 ff 70 7f 1a 48 00a0 07 5e 75 be ee 74 01 b3 d2 4c 8e 31 68 dd ed 4f 00b0 11 37 c6 38 7e a3 cc ec 4f 40 86 8d 25 0c e9 d6 00c0 7c 30 bc c5 bd 0a d5 17 8a 12 6a 61 04 bd 70 61 00d0 d4 a4 58 f9 0a 10 b8 23 13 19 f6 76 3f 79 b6 29 00e0 29 da eb 17 10 a4 e3 30 d7 2d fd 64 f7 bd 03 84 00f0 25 27 4f bb dd a0 05 42 68 51 6f e4 8e 5d 0c 85 Signature matches Public Key Root Certificate: Subject matches Issuer Key Id Hash(rfc-sha1): e59d5930824758ccacfa085436867b3ab5044df0 Key Id Hash(sha1): 30a4e64fde768afced5a9084283046792c291570 Key Id Hash(bcrypt-sha1): a115d6e1c31abb3ccb58b8b7974bccaf70e7d123 Key Id Hash(bcrypt-sha256): b04d20fbedb3f9a52949035d2320a72a6d1f0c36fd9dc8f09a2c3f43fae6945e Key Id Hash(md5): 68cb42b035ea773e52ef50ecf50ec529 Key Id Hash(sha256): a67fe2a9af967cb5bffdc9ebda8f1ab5eabca254f103965277fd4ba33e27a187 Key Id Hash(pin-sha256): Y9mvm0exBk1JoQ57f9Vm28jKo5lFm/woKcVxrYxu80o= Key Id Hash(pin-sha256-hex): 63d9af9b47b1064d49a10e7b7fd566dbc8caa399459bfc2829c571ad8c6ef34a Cert Hash(md5): acb694a59c17e0d791529bb19706a6e4 Cert Hash(sha1): d4de20d05e66fc53fe1a50882c78db2852cae474 Cert Hash(sha256): 16af57a9f676b0ab126095aa5ebadef22ab31119d644ac95cd4b93dbf3f26aeb Signature Hash: ce0e658aa3e847e467a147b3049191093d055e6f ---------------- End Nesting Level 1 ---------------- CERT_SUBJECT_PUB_KEY_BIT_LENGTH_PROP_ID(92): 0x00000800 (2048) CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID(25): 68cb42b035ea773e52ef50ecf50ec529 CERT_SIGNATURE_HASH_PROP_ID(15) disallowedHash: ce0e658aa3e847e467a147b3049191093d055e6f CERT_SHA1_HASH_PROP_ID(3): d4de20d05e66fc53fe1a50882c78db2852cae474 CERT_KEY_IDENTIFIER_PROP_ID(20): e59d5930824758ccacfa085436867b3ab5044df0 CERT_SIGN_HASH_CNG_ALG_PROP_ID(89): RSA/SHA1 CERT_MD5_HASH_PROP_ID(4): acb694a59c17e0d791529bb19706a6e4 CERT_ACCESS_STATE_PROP_ID(14): AccessState = 0 Cannot find the certificate and private key for decryption. CertUtil: -dump command completed successfully. ...
Fascinating stuff. Stripping off meta data one byte at a time is reminiscent of nucleotide sequencing methodologies.
Yes – I guess reverse engineering software is similar to reversing our genetic code in many ways! I am reminded now of Douglas Hofstadters “DNA metaphors” in Gödel, Escher, Bach.