Parse Certificates Stored in the Windows Registry

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.


...

2 Comments Add yours

  1. Peter Mander says:

    Fascinating stuff. Stripping off meta data one byte at a time is reminiscent of nucleotide sequencing methodologies.

    1. elkement says:

      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.

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.