Skip to main content

CurveBall

Here's my secure search engine, which will only search for hosts it has in its trusted certificate cache.

Connect at nc socket.cryptohack.org 13382

challenge.py
#!/usr/bin/env python3
import fastecdsa
from fastecdsa.point import Point
from utils import listener

FLAG = "crypto{????????????????????????????????????}"
G = fastecdsa.curve.P256.G
assert G.x, G.y == [0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296,
0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5]

class Challenge():
def __init__(self):
self.before_input = "Welcome to my secure search engine backed by trusted certificate library!\n"
self.trusted_certs = {
'www.cryptohack.org': {
"public_key": Point(0xE9E4EBA2737E19663E993CF62DFBA4AF71C703ACA0A01CB003845178A51B859D, 0x179DF068FC5C380641DB2661121E568BB24BF13DE8A8968EF3D98CCF84DAF4A9),
"curve": "secp256r1",
"generator": [G.x, G.y]
},
'www.bing.com': {
"public_key": Point(0x3B827FF5E8EA151E6E51F8D0ABF08D90F571914A595891F9998A5BD49DFA3531, 0xAB61705C502CA0F7AA127DEC096B2BBDC9BD3B4281808B3740C320810888592A),
"curve": "secp256r1",
"generator": [G.x, G.y]
},
'www.gchq.gov.uk': {
"public_key": Point(0xDEDFC883FEEA09DE903ECCB03C756B382B2302FFA296B03E23EEDF94B9F5AF94, 0x15CEBDD07F7584DBC7B3F4DEBBA0C13ECD2D2D8B750CBF97438AF7357CEA953D),
"curve": "secp256r1",
"generator": [G.x, G.y]
}
}

def search_trusted(self, Q):
for host, cert in self.trusted_certs.items():
if Q == cert['public_key']:
return True, host
return False, None

def sign_point(self, g, d):
return g * d

def connection_host(self, packet):
d = packet['private_key']
if abs(d) == 1:
return "Private key is insecure, certificate rejected."
packet_host = packet['host']
curve = packet['curve']
g = Point(*packet['generator'])
Q = self.sign_point(g, d)
cached, host = self.search_trusted(Q)
if cached:
return host
else:
self.trusted_certs[packet_host] = {
"public_key": Q,
"curve": "secp256r1",
"generator": G
}
return "Site added to trusted connections"

def bing_it(self, s):
return f"Hey bing! Tell me about {s}"

def challenge(self, your_input):
host = self.connection_host(your_input)
if host == "www.bing.com":
return self.bing_it(FLAG)
else:
return self.bing_it(host)


listener.start_server(port=13382)

Solution

This WriteUp Solution is password protected by the flag of the challenge.
By looking at the code we can see that code is checking if private_key=1 only, so if we send private_key d' and generator G' such that `Public_key = d'G'` and public key for www.bing.com is given. So take any d' and find G'. since we know that after a certain number of additions of a point on curve the points get repeated,and this number is called order of the curve represented by `q`. So we can find G' like `G' = inverse(n,q)*Public_key`.where n is private_key.

code for the same solution is:

solve.py
from pwn import *
import json
import fastecdsa
from fastecdsa.point import Point

n=2 #can take any n we will get flag
n_inv = pow(n, -1, fastecdsa.curve.P256.G.curve.q)
G = n_inv * Point(0x3B827FF5E8EA151E6E51F8D0ABF08D90F571914A595891F9998A5BD49DFA3531, 0xAB61705C502CA0F7AA127DEC096B2BBDC9BD3B4281808B3740C320810888592A)
conn =remote("socket.cryptohack.org", 13382)
conn.recv()
conn.sendline(json.dumps({"host": "www.bing.com",
"generator": [G.x, G.y],
"curve": "secp256r1",
"private_key": n
}).encode())
print(conn.recvline().decode())

After running the above code we get the flag as crypto{Curveballing_Microsoft_CVE-2020-0601}