Skip to content

Instantly share code, notes, and snippets.

@bountin
Last active August 29, 2015 14:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bountin/7206f35e89a1edc4beb2 to your computer and use it in GitHub Desktop.
Save bountin/7206f35e89a1edc4beb2 to your computer and use it in GitHub Desktop.
Attacking ECDSA with two messages in a PCAP file which have the same k - This also implements a client to test the found private key (University assignment of Internet Security 1 in the summer term of 2014)
import socket
import ecdsa
import base64
import sys
from hashlib import sha1
from ecdsa.util import string_to_number
# Fixing fucking scapy warnings - fuck python
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import PcapReader, NoPayload
# Read arguments into variables
host = sys.argv[1]
port = int(sys.argv[2])
dump_file = sys.argv[3]
key_file = sys.argv[4]
# Extract data from the public key
public = open(key_file).read()
vk = ecdsa.VerifyingKey.from_pem(public)
# Extract pcap stuff
packets = []
pcap = PcapReader(dump_file)
for pkt in pcap:
packet = pkt.payload.payload
if isinstance(pkt.payload.payload.payload, NoPayload):
continue
data = packet.payload
packets.append(data.load)
challenge1 = packets[2].strip()
response1 = packets[3].strip()
challenge2 = packets[11].strip()
response2 = packets[12].strip()
# challenge1 = 'GPivoWzCNWJdvDdswouhZTPkclBrjVxjNFHYQkneNnsDWDbsQNMzsQYEnyerBFARLGczgXExgJXLAWoHOthLTxBjXlBEOmkVmpdOFkLNIAwIZnjLCIxMAHkkZFWNIMcQYCNaEETyVRGjfMiZScAbtPUyoJmmQAFEMHApjvyGPSiZCiFGdGUPjiBKTFzqGmzJteNMcHYJ'
# challenge2 = 'NDazqEkHwSsXnTfoXBogLRxvnKAcmMqaFrEMTjAoKSnyTrpobojaHpnLNofQLLnqJtBBmcBQyxjtMYhGejQUJxkfldqWYfnLDuDaoHimbSlUyZsyHLbOEnuceuwegBtWugzgjTKxPnwzNDLfHNdANeSnRDGbcoNCjmarZVfEHQZxsFeTALRHxmKguvzJovRcxaDtFdsH'
# response1 = 'WFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWBC7jphABJsYPgeNnDAOFgVZARjr3X/1kIDlLHmG/O0J9rJ+RJmv0Gm0wwGZZPWFKg=='
# response2 = 'WFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWBC7jphABJsYPgeNnDAOFgVZARjr3X/1kBp+xhMkcZp3mA4QBk+a2R+976y1tnloqg=='
response1 = base64.b64decode(response1)
response2 = base64.b64decode(response2)
message1 = response1[:-48]
message2 = response2[:-48]
sig1 = response1[-48:]
sig2 = response2[-48:]
digest1 = sha1(challenge1).digest()
z1 = string_to_number(digest1)
digest2 = sha1(challenge2).digest()
z2 = string_to_number(digest2)
r1, s1 = ecdsa.util.sigdecode_string(sig1, vk.pubkey.order)
r2, s2 = ecdsa.util.sigdecode_string(sig2, vk.pubkey.order)
assert r1 == r2
assert vk.verify(sig1, challenge1)
assert vk.verify(sig2, challenge2)
n = vk.pubkey.generator.order()
k = (z1 - z2) * ecdsa.numbertheory.inverse_mod(s1 - s2, n)
k %= n
privateKey = (s1 * k - z1) * ecdsa.numbertheory.inverse_mod(r1, n)
privateKey %= n
sk = ecdsa.SigningKey.from_secret_exponent(privateKey)
sig = sk.privkey.sign(z1, k)
assert sig.r == r1
assert sig.s == s1
sig = sk.privkey.sign(z2, k)
assert sig.r == r2
assert sig.s == s2
conn = socket.create_connection((host, port), 4)
# Skip first two lines
data = conn.recv(2048)
if not "Please authenticate" in data:
data = conn.recv(2048)
challenge = conn.recv(2048)
challengeDigest = string_to_number(sha1(challenge.strip()).digest())
challengeSig = sk.privkey.sign(challengeDigest, k)
sigString = ecdsa.util.sigencode_string(challengeSig.r, challengeSig.s, n)
msg = base64.b64encode(message1 + sigString) + "\n"
assert len(msg) == 345
x = conn.send(msg)
assert x == 345
data = conn.recv(2048)
if not "Log out" in data:
data = conn.recv(2048)
conn.send("1\n")
secret = conn.recv(2048)
sys.stdout.write(secret.strip())
conn.send("2\n")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment