Skip to content

Commit

Permalink
Add Challenges and Writeups
Browse files Browse the repository at this point in the history
  • Loading branch information
RohitNarayananM committed Nov 13, 2024
1 parent c09376f commit 8ad5d74
Show file tree
Hide file tree
Showing 816 changed files with 257,979 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Crypto/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Crypto Challenges

| Sl No | Challenge Name | Author |
| ----- | -------------------------- | ------ |
| 1 | [mde5](mde5) | - |
| 2 | [noncense](noncense) | - |
| 3 | [placeholder](placeholder) | - |
| 4 | [samsara](samsara) | - |
21 changes: 21 additions & 0 deletions Crypto/mde5/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

# mde5

### Challenge Description

Is something broken? Probably.

### Short Writeup

+ The Hash algorithm uses DES encryption, and the data is fed as the key.
+ Since DES has parity bits for the key that are disregarded, its possible to cause a collision
+ This lets us get a reused nonce on two ECDSA signatures.
+ We calculate the private key, and sign the message.

### Flag

icc{https://www.youtube.com/watch?v=xFnc00wpAPg}

### Author

**-**
53 changes: 53 additions & 0 deletions Crypto/mde5/admin/solve.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from math import gcd
from ecdsa.curves import SECP128r1
from ecdsa import SigningKey, VerifyingKey
from util import MD5

def solve_congruence(a, b, m):
"""
Solves a congruence of the form ax = b mod m.
:param a: the parameter a
:param b: the parameter b
:param m: the modulus m
:return: a generator generating solutions for x
"""
g = gcd(a, m)
a //= g
b //= g
n = m // g
for i in range(g):
yield (pow(a, -1, n) * b + i * n) % m

def attack(n, r, m1, m2, s1, s2):
"""
Recovers the nonce and private key from two messages signed using the same nonce.
:param n: the order of the elliptic curve
:param m1: the first message
:param r1: the signature of the first message
:param s1: the signature of the first message
:param m2: the second message
:param r2: the signature of the second message
:param s2: the signature of the second message
:return: generates tuples containing the possible nonce and private key
"""
for k in solve_congruence(int(s1 - s2), int(m1 - m2), int(n)):
for x in solve_congruence(int(r), int(k * s1 - m1), int(n)):
yield int(k), int(x)


m1 = MD5(bytes.fromhex(input())).digest()
sig1 = bytes.fromhex(input())
m2 = MD5(bytes.fromhex(input())).digest()
sig2 = bytes.fromhex(input())
r1, s1 = int.from_bytes(sig1[:16], 'big'), int.from_bytes(sig1[16:], 'big')
r2, s2 = int.from_bytes(sig2[:16], 'big'), int.from_bytes(sig2[16:], 'big')
m1 = int.from_bytes(m1, 'big')
m2 = int.from_bytes(m2, 'big')
m3 = bytes.fromhex(input())
for k, x in attack(SECP128r1.order, r1, m1, m2, s1, s2):
sk = SigningKey.from_secret_exponent(x, curve=SECP128r1, hashfunc=MD5)
vk = sk.verifying_key
print(vk)
sig = sk.sign(m3, k=k)
print(sig.hex())

17 changes: 17 additions & 0 deletions Crypto/mde5/deployment/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM ubuntu:20.04
RUN apt-get -q -y update && \
apt-get -q -y install \
python3-dev \
python3-pip

COPY requirements.txt .
RUN pip3 install -r requirements.txt

COPY ./ynetd .
COPY ./files/* ./

RUN chmod +x ynetd
RUN chmod +x main.py

EXPOSE 1337
CMD ./ynetd -p 1337 "./main.py"
1 change: 1 addition & 0 deletions Crypto/mde5/deployment/files/flag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
flag = "icc{https://www.youtube.com/watch?v=xFnc00wpAPg}"
42 changes: 42 additions & 0 deletions Crypto/mde5/deployment/files/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/bin/python3

from util import *
from flag import flag
from ecdsa.curves import SECP128r1
from ecdsa import SigningKey, VerifyingKey
import os
import sys

key = os.urandom(16)

def negentropy(*args, **kwargs):
return HMAC(key, inp_data).digest()

sk = SigningKey.generate(curve=SECP128r1, hashfunc=MD5)
vk = sk.verifying_key

seen = set()
try:
print("Hello. I sign stuff. Can you sign stuff?")
for _ in range(2):
inp_data = bytes.fromhex(input())
if inp_data in seen:
sys.exit()
seen.add(inp_data)
if len(inp_data) != 8:
sys.exit()
rand_data = os.urandom(16)
sig = sk.sign(rand_data, entropy=negentropy)
assert vk.verify(sig, rand_data)
print("Data:", rand_data.hex())
print("Signature:", sig.hex())

chall = os.urandom(16)
print("Sign this: ")
print(chall.hex())
sig = bytes.fromhex(input("> "))
if vk.verify(sig, chall):
print(flag)

except:
print("I am not okay")
95 changes: 95 additions & 0 deletions Crypto/mde5/deployment/files/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from Crypto.Cipher import DES

class MD5:
shifts = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]

K = [3614090360, 3905402710, 606105819, 3250441966, 4118548399, 1200080426, 2821735955, 4249261313, 1770035416, 2336552879, 4294925233, 2304563134, 1804603682, 4254626195, 2792965006, 1236535329, 4129170786, 3225465664, 643717713, 3921069994, 3593408605, 38016083, 3634488961, 3889429448, 568446438, 3275163606, 4107603335, 1163531501, 2850285829, 4243563512, 1735328473, 2368359562, 4294588738, 2272392833, 1839030562, 4259657740, 2763975236, 1272893353, 4139469664, 3200236656, 681279174, 3936430074, 3572445317, 76029189, 3654602809, 3873151461, 530742520, 3299628645, 4096336452, 1126891415, 2878612391, 4237533241, 1700485571, 2399980690, 4293915773, 2240044497, 1873313359, 4264355552, 2734768916, 1309151649, 4149444226, 3174756917, 718787259, 3951481745]

def __init__(self, data=None):
self.name = 'MD5'
self.a0 = 0x67452301
self.b0 = 0xefcdab89
self.c0 = 0x98badcfe
self.d0 = 0x10325476
if data:
self.update(data)

def update(self, data):
self.data = self.pad(bytes(data))
for i in range(0, len(self.data), 64):
self.process_block(self.data[i:i+64])

def digest(self):
return b''.join(int.to_bytes(x, 4, 'little') for x in (self.a0, self.b0, self.c0, self.d0))

def pad(self, data):
result = data + b'\x80'
while len(result) % 64 != 56:
result += b'\x00'
return result + int.to_bytes(len(data) * 8, 8, 'little')

@staticmethod
def F(b,c,d):
return (b & c) | (~b & d)
@staticmethod
def G(b,c,d):
return (b & d) | (c & ~d)
@staticmethod
def H(b,c,d):
return b ^ c ^ d
@staticmethod
def I(b,c,d):
return c ^ (b | ~d)
@staticmethod
def leftrotate(x, c):
return (x << c) | (x >> (32 - c))

def process_block(self, block):
try:
assert len(block) == 64
except AssertionError:
print(block)
M = [int.from_bytes(block[i:i+4], 'little') for i in range(0, 64, 4)]
A = self.a0
B = self.b0
C = self.c0
D = self.d0
for i in range(64):
if 0 <= i <= 15:
f = MD5.F(B, C, D)
g = i
elif 16 <= i <= 31:
f = MD5.G(B, C, D)
g = (5*i + 1) % 16
elif 32 <= i <= 47:
f = MD5.H(B, C, D)
g = (3*i + 5) % 16
elif 48 <= i <= 63:
f = MD5.I(B, C, D)
g = (7*i) % 16
f = (f + A + self.K[i] + M[g]) & 0xffffffff
A = D
D = C
C = B
B = (B + MD5.leftrotate(f, self.shifts[i])) & 0xffffffff
self.a0 = (self.a0 + A) & 0xffffffff
self.b0 = (self.b0 + B) & 0xffffffff
self.c0 = (self.c0 + C) & 0xffffffff
self.d0 = (self.d0 + D) & 0xffffffff

class HMAC:
def __init__(self, key, data):
self.key = key
self.data = data
self.name = 'HMAC'

def digest(self):
key = MD5(self.key).digest()
return DES.new(self.data[:8], DES.MODE_ECB).encrypt(key)

def hexdigest(self):
return self.digest().hex()

2 changes: 2 additions & 0 deletions Crypto/mde5/deployment/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ecdsa
pycryptodome
Binary file added Crypto/mde5/deployment/ynetd
Binary file not shown.
42 changes: 42 additions & 0 deletions Crypto/mde5/handout/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/bin/python3

from util import *
from flag import flag
from ecdsa.curves import SECP128r1
from ecdsa import SigningKey, VerifyingKey
import os
import sys

key = os.urandom(16)

def negentropy(*args, **kwargs):
return HMAC(key, inp_data).digest()

sk = SigningKey.generate(curve=SECP128r1, hashfunc=MD5)
vk = sk.verifying_key

seen = set()
try:
print("Hello. I sign stuff. Can you sign stuff?")
for _ in range(2):
inp_data = bytes.fromhex(input())
if inp_data in seen:
sys.exit()
seen.add(inp_data)
if len(inp_data) != 8:
sys.exit()
rand_data = os.urandom(16)
sig = sk.sign(rand_data, entropy=negentropy)
assert vk.verify(sig, rand_data)
print("Data:", rand_data.hex())
print("Signature:", sig.hex())

chall = os.urandom(16)
print("Sign this: ")
print(chall.hex())
sig = bytes.fromhex(input("> "))
if vk.verify(sig, chall):
print(flag)

except:
print("I am not okay")
95 changes: 95 additions & 0 deletions Crypto/mde5/handout/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from Crypto.Cipher import DES

class MD5:
shifts = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]

K = [3614090360, 3905402710, 606105819, 3250441966, 4118548399, 1200080426, 2821735955, 4249261313, 1770035416, 2336552879, 4294925233, 2304563134, 1804603682, 4254626195, 2792965006, 1236535329, 4129170786, 3225465664, 643717713, 3921069994, 3593408605, 38016083, 3634488961, 3889429448, 568446438, 3275163606, 4107603335, 1163531501, 2850285829, 4243563512, 1735328473, 2368359562, 4294588738, 2272392833, 1839030562, 4259657740, 2763975236, 1272893353, 4139469664, 3200236656, 681279174, 3936430074, 3572445317, 76029189, 3654602809, 3873151461, 530742520, 3299628645, 4096336452, 1126891415, 2878612391, 4237533241, 1700485571, 2399980690, 4293915773, 2240044497, 1873313359, 4264355552, 2734768916, 1309151649, 4149444226, 3174756917, 718787259, 3951481745]

def __init__(self, data=None):
self.name = 'MD5'
self.a0 = 0x67452301
self.b0 = 0xefcdab89
self.c0 = 0x98badcfe
self.d0 = 0x10325476
if data:
self.update(data)

def update(self, data):
self.data = self.pad(bytes(data))
for i in range(0, len(self.data), 64):
self.process_block(self.data[i:i+64])

def digest(self):
return b''.join(int.to_bytes(x, 4, 'little') for x in (self.a0, self.b0, self.c0, self.d0))

def pad(self, data):
result = data + b'\x80'
while len(result) % 64 != 56:
result += b'\x00'
return result + int.to_bytes(len(data) * 8, 8, 'little')

@staticmethod
def F(b,c,d):
return (b & c) | (~b & d)
@staticmethod
def G(b,c,d):
return (b & d) | (c & ~d)
@staticmethod
def H(b,c,d):
return b ^ c ^ d
@staticmethod
def I(b,c,d):
return c ^ (b | ~d)
@staticmethod
def leftrotate(x, c):
return (x << c) | (x >> (32 - c))

def process_block(self, block):
try:
assert len(block) == 64
except AssertionError:
print(block)
M = [int.from_bytes(block[i:i+4], 'little') for i in range(0, 64, 4)]
A = self.a0
B = self.b0
C = self.c0
D = self.d0
for i in range(64):
if 0 <= i <= 15:
f = MD5.F(B, C, D)
g = i
elif 16 <= i <= 31:
f = MD5.G(B, C, D)
g = (5*i + 1) % 16
elif 32 <= i <= 47:
f = MD5.H(B, C, D)
g = (3*i + 5) % 16
elif 48 <= i <= 63:
f = MD5.I(B, C, D)
g = (7*i) % 16
f = (f + A + self.K[i] + M[g]) & 0xffffffff
A = D
D = C
C = B
B = (B + MD5.leftrotate(f, self.shifts[i])) & 0xffffffff
self.a0 = (self.a0 + A) & 0xffffffff
self.b0 = (self.b0 + B) & 0xffffffff
self.c0 = (self.c0 + C) & 0xffffffff
self.d0 = (self.d0 + D) & 0xffffffff

class HMAC:
def __init__(self, key, data):
self.key = key
self.data = data
self.name = 'HMAC'

def digest(self):
key = MD5(self.key).digest()
return DES.new(self.data[:8], DES.MODE_ECB).encrypt(key)

def hexdigest(self):
return self.digest().hex()

Loading

0 comments on commit 8ad5d74

Please sign in to comment.