Skip to content

Commit

Permalink
Export for release
Browse files Browse the repository at this point in the history
  • Loading branch information
reteps committed Sep 23, 2024
0 parents commit da959b2
Show file tree
Hide file tree
Showing 1,170 changed files with 217,373 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Fall CTF 2024 Challenge Repo


4 changes: 4 additions & 0 deletions chals/crypto/baby_rsa/Solution/sol.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Solution

It's very easy to factor the given prime with wolfram alpha or dCode.
After you've got the factors, all you need to do is walk through the RSA decryption algorithm in the guides book.
21 changes: 21 additions & 0 deletions chals/crypto/baby_rsa/challenge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: "Baby RSA"
author: Sagnik
category: Crypto
description: |-
RSA-1024, RSA-2048, RSA-4096 exist. How about RSA-64?
**author**: Sagnik
value: 500
type: dynamic
tags:
- easy
extra:
initial: 500
decay: 150
minimum: 100
flags:
- fallctf{small_n_bad}
files:
- rsa.txt
hints:
- Keep in mind RSA normally works on 1024 bit integers at the minimum. This n is much smaller than that. Can we brute force the primes?
15 changes: 15 additions & 0 deletions chals/crypto/baby_rsa/encrypt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import binascii

flag = "small_n_bad"
flag = binascii.hexlify(flag.encode("utf-8"))
m = int(flag, 16)

p = 17378651858107286503
q = 12428326454008306487
n = p*q
print(n)

e = 17
c = pow(m, e, n)

print(hex(int(c)))
24 changes: 24 additions & 0 deletions chals/crypto/baby_rsa/primegen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from Crypto.Util.number import long_to_bytes, bytes_to_long
import random

#use the miller-rabin primality test to generate 2 random large primes
def miller_rabin(n, k=40):
if n in [2, 3]: return True
if n < 2 or n % 2 == 0: return False
r, d = 0, n - 1
while d % 2 == 0: r, d = r + 1, d // 2
def witness(a):
x = pow(a, d, n)
if x == 1 or x == n - 1: return True
return any(pow(x, 2**i, n) == n - 1 for i in range(r-1))
return all(witness(random.randint(2, n - 2)) for _ in range(k))
def generate_large_prime(bits):
gen_candidate = lambda : random.getrandbits(bits) | 1 | (1 << bits - 1)
return next(filter(miller_rabin, iter(lambda: gen_candidate(), None)))

# Generate two 1024-bit primes for RSA
prime1 = generate_large_prime(64)
prime2 = generate_large_prime(64)

print(f"p = {prime1}")
print(f"q = {prime2}")
3 changes: 3 additions & 0 deletions chals/crypto/baby_rsa/rsa.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
n = 215987558623115398761128944381942444961
e = 17
fallctf{612c0496141e3bb1fae92923929ba5f8}
20 changes: 20 additions & 0 deletions chals/crypto/baby_rsa/sol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import binascii

c = int('612c0496141e3bb1fae92923929ba5f8', 16)

# You can find these however you want (factordb, wolfram alpha, brute force, etc)
p = 17378651858107286503
q = 12428326454008306487

# public key
n = p*q
e = 17

totient = (p-1)*(q-1)

# this is "fast" in sage, use pow(e, -1, totient) in python 3.8+, cry in python < 3.8
d = pow(e, -1, totient)
print(d)

solved_m = pow(c, d, n)
print(binascii.unhexlify(hex(int(solved_m))[2:]))
Binary file added chals/crypto/caesar_salad/Solution/image-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added chals/crypto/caesar_salad/Solution/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions chals/crypto/caesar_salad/Solution/solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Solution
the salad.txt file reads:
```
Hknai eloqi kzkn wiap, ykjoaypapqan wzeleoyejc ahep. Lkpajpe ejpanzqi lkpajpe, lkpajpe qnjw iwppeo ikhheo wlpajp qnjw. Iwppeo lwnpqneajp oajaypqo ewyqheo iwcjeo oaz zewi jwi ikjpao. Iwcjw aop iwcjw, fqopk jeoh mqeomqa rah qp. Dwy oailan oailan repwa yqnwxepqn haypqo repwa jeoe lneieo. Wqcqa anwp ldwnapnw lhwyanwp rahep fqopk ejpacan ldwoahhqo oyahaneomqa iwcjeo. Jwpkmqa: aop_wzeleoyejc_lhwpaw. Bejexqo iwcjw wqypkn hwyqo. Lknppepkn baqcewp ldwoahhqo, repwa bejexqo baheo lneieo.
Japqo pailkn eilanzeap bwyeheoe yhwoo; iwcjeo okzwhao. Ldwnapnw qhpneyeao lkoqana bwqyexqo pailkn ykiikzk hak, dwxepwooa abbeyepqn wz:H Zeypqi rahep wp ykjcqa lhwyanwp zecjeooei ap hecqhw ajei. Yhwoo ikhheo lajwpexqo: ejyalpko_oai ikhaopea_wqcqa_wzeleoyejc. Ldwoahhqo hwyqo jwoyapqn ikhaopea ez hexank jeoh lknppepkn iwteiqo ie. Pda oaynap iaoowca eo: pdeo_owhwz_pwopao_cnawp.
Yhwoo rqhlqpwpa ynwo jeoe wyyqiowj ejyalpko. Xhwjzep jqhhw iknxe mqwi lnapeqi nezeyqhqo cnwrezw zeypqi. Ykiikzk hecqhw ndkjyqo aqeoikz lkpajpe lhwyanwp bwyeheoe ikhheo. Jeoe hwyejew knjwna baheo wz jqjy qhpneyeao bnejcehhw iwteiqo. Rah jay ykjoaypapqn ykjzeiajpqi oqoyelep, wqypkn lahhajpaomqa qnjw.
```

If we go to [CyberChef](https://gchq.github.io/CyberChef/),
we have a tool that can reverse any text by the entered enough.

We can change the rotation amount through the drop down until we get something that might look readable.
Upon using amt "4", we see some text that reads "Lorem ipsum..."
![alt text](image.png)
Now while this isn't english like we would normally expect, Lorem Ipsum texts are latin placeholders, and so any time we see the text show up, we know we found the right amount. Sure enough, if we scroll down the output, we see:

![alt text](image-1.png)
Thus, our flag is `fallctf{this_salad_tastes_great}`
26 changes: 26 additions & 0 deletions chals/crypto/caesar_salad/challenge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: "Caesar Salad"
author: Sagnik
category: Crypto
description: |-
Can you find the secret sauce? I hid it with this amazing salad.
Flag is of the format fallctf{secret message},
where the secret message should be contained in the decrypted text
**author**: Sagnik
value: 500
type: dynamic
tags:
- beginner
extra:
initial: 500
decay: 150
minimum: 100
flags:
- fallctf{this_salad_tastes_great}
files:
- salad.txt
hints:
- This is a classic [Caesar Cipher](https://en.wikipedia.org/wiki/Caesar_cipher)
- Check out [Cyber Chef](https://gchq.github.io/CyberChef/) for a helpful tool!
3 changes: 3 additions & 0 deletions chals/crypto/caesar_salad/salad.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Hknai eloqi kzkn wiap, ykjoaypapqan wzeleoyejc ahep. Lkpajpe ejpanzqi lkpajpe, lkpajpe qnjw iwppeo ikhheo wlpajp qnjw. Iwppeo lwnpqneajp oajaypqo ewyqheo iwcjeo oaz zewi jwi ikjpao. Iwcjw aop iwcjw, fqopk jeoh mqeomqa rah qp. Dwy oailan oailan repwa yqnwxepqn haypqo repwa jeoe lneieo. Wqcqa anwp ldwnapnw lhwyanwp rahep fqopk ejpacan ldwoahhqo oyahaneomqa iwcjeo. Jwpkmqa: aop_wzeleoyejc_lhwpaw. Bejexqo iwcjw wqypkn hwyqo. Lknppepkn baqcewp ldwoahhqo, repwa bejexqo baheo lneieo.
Japqo pailkn eilanzeap bwyeheoe yhwoo; iwcjeo okzwhao. Ldwnapnw qhpneyeao lkoqana bwqyexqo pailkn ykiikzk hak, dwxepwooa abbeyepqn wz:H Zeypqi rahep wp ykjcqa lhwyanwp zecjeooei ap hecqhw ajei. Yhwoo ikhheo lajwpexqo: ejyalpko_oai ikhaopea_wqcqa_wzeleoyejc. Ldwoahhqo hwyqo jwoyapqn ikhaopea ez hexank jeoh lknppepkn iwteiqo ie. Pda oaynap iaoowca eo: pdeo_owhwz_pwopao_cnawp.
Yhwoo rqhlqpwpa ynwo jeoe wyyqiowj ejyalpko. Xhwjzep jqhhw iknxe mqwi lnapeqi nezeyqhqo cnwrezw zeypqi. Ykiikzk hecqhw ndkjyqo aqeoikz lkpajpe lhwyanwp bwyeheoe ikhheo. Jeoe hwyejew knjwna baheo wz jqjy qhpneyeao bnejcehhw iwteiqo. Rah jay ykjoaypapqn ykjzeiajpqi oqoyelep, wqypkn lahhajpaomqa qnjw.
13 changes: 13 additions & 0 deletions chals/crypto/curveball/Solution/sol.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Solution

Given Alice's x coordinate, it isn't too difficult to extract the $y$ coordinate, as we know it must be on the defined Elliptic curve. Without sage, you can do this by calculating
$$y^2 = x^3 + ax + b$$
directly, and then doing a modular square root operation. This is done using the mod_sqrt function, which checks if $y^2$ is a quadratic residue mod $p$ (easy as $p$ is $3 \mod 4$),
and if so, does
$$\left(y^2\right)^{\frac{p+1}{4}} \mod p$$

This should give one of the two possible points that could be the secret.

If you do use sage, the challenge becomes much easier. All you need to do is define the Elliptic curve object `E` using the params given and then call `E.lift_x(Q_a_x)` to find Alice's 2 possible $y$ coords, either from which you can find either shared secret through calculating the points on the curve corresponding to $S = [n_B]Q_a$

Either point works, as the x-coordinate is all you need.
32 changes: 32 additions & 0 deletions chals/crypto/curveball/challenge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: "Curveball"
author: Sagnik
category: Crypto
description: |-
Hi there Bob! Let's say you wanted to send a handshake to Alice. You choose a curve
`y^2 = (x^3 + ax + b) mod p` and generator point `G(G_x, G_y)`.
Now Alice was going to send you her public point Q_a, but it seems that the transmission glitched, and
you only got her x coordinate, `Q_a_x`. Can you still get your shared secret?
**Note**: The actual shared secret for the decryptor would be the SHA-256 hash of the x coordinate of the shared secret.
So that would be `sha256(S_x)`
**Note**: There is two shared secrets you can arrive at, only one of them will work.
**author**: Sagnik
value: 500
type: dynamic
tags:
- hard
extra:
initial: 500
decay: 150
minimum: 100
flags:
- fallctf{n0t_s0_s3cr3t_anYm0r3}
files:
- decryptor.py
- client.json
hints:
- See [ECDH](https://cryptobook.nakov.com/asymmetric-key-ciphers/ecdh-key-exchange) for more info about the protocol.
- Is it possible to get back Alice's y coordinate?
17 changes: 17 additions & 0 deletions chals/crypto/curveball/client.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"ecdhke_client": {
"iv": "e7646ff19954f0db69379d8dc902abbc",
"ciphertext": "a2bd63234c90778210edbb62d67ec020154187652a57636549e21f52ed6c965c",
"curve_params": {
"a": 123001240123101920407,
"b": 2390490212093,
"p": 269123855285160332211801709888382470147,
"G_x": 141223464919893415164492319302044521923,
"G_y": 105945507900846830121381021840356606089
},
"given": {
"Q_a_x": 19299658936035824596857706134874824001,
"n_B": 853735663
}
}
}
32 changes: 32 additions & 0 deletions chals/crypto/curveball/decryptor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import hashlib


def is_pkcs7_padded(message):
padding = message[-message[-1]:]
return all(padding[i] == len(padding) for i in range(0, len(padding)))


def decrypt_flag(shared_secret: int, iv: str, ciphertext: str):
# Derive AES key from shared secret
sha1 = hashlib.sha1()
sha1.update(str(shared_secret).encode('ascii'))
key = sha1.digest()[:16]
# Decrypt flag
ciphertext = bytes.fromhex(ciphertext)
iv = bytes.fromhex(iv)
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)

if is_pkcs7_padded(plaintext):
return unpad(plaintext, 16).decode('ascii')
else:
return plaintext.decode('ascii')


shared_secret = '?' #the sha256 hash of the 2 coordinates of the shared secret concatenated together, SHA-256(S_x|S_y)
iv = '?' #from ecdhke client
ciphertext = '?' #from ecdhke client

print(decrypt_flag(shared_secret, iv, ciphertext))
29 changes: 29 additions & 0 deletions chals/crypto/curveball/encryptor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import hashlib
import os

def encrypt_flag(shared_secret: int, iv: str, flag: str):
# Derive AES key from shared secret
sha1 = hashlib.sha1()
sha1.update(str(shared_secret).encode('ascii'))
key = sha1.digest()[:16]

# Encrypt the flag
cipher = AES.new(key, AES.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(flag.encode('ascii'), 16))

return ciphertext.hex()

shared_secret = 'df700d2f1344ef3bdc60394e643af298fe7983f34f73da973797ecfb4a790575' # Replace with your actual shared secret
iv = os.urandom(16) # Randomly generate a 16-byte IV

# Flag to encrypt
flag = "fallctf{n0t_s0_s3cr3t_anYm0r3}"

# Encrypt the flag
ciphertext = encrypt_flag(shared_secret, iv, flag)

# Print the IV and encrypted flag in hexadecimal format
print("IV:", iv.hex())
print("Encrypted flag:", ciphertext)
84 changes: 84 additions & 0 deletions chals/crypto/curveball/find_secret.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
## The solution file.
import hashlib
def modinv(a, p):
""" Return the modular inverse of a mod p using the extended Euclidean algorithm """
if a == 0:
return 0
lm, hm = 1, 0
low, high = a % p, p
while low > 1:
ratio = high // low
nm, new = hm - lm * ratio, high - low * ratio
lm, low, hm, high = nm, new, lm, low
return lm % p

def elliptic_curve_add(P, Q, a, p):
""" Add two points P and Q on an elliptic curve with given parameters """
if P is None:
return Q
if Q is None:
return P
if P == Q: # Point doubling
x1, y1 = P
if y1 == 0:
return None # Point at infinity
lam = (3 * x1**2 + a) * modinv(2 * y1, p) % p
else: # General point addition
x1, y1 = P
x2, y2 = Q
if x1 == x2 and y1 != y2:
return None # P + Q = O (point at infinity)
lam = (y2 - y1) * modinv(x2 - x1, p) % p

x3 = (lam**2 - x1 - (x2 if P != Q else x1)) % p
y3 = (lam * (x1 - x3) - (y1 if P != Q else y1)) % p

return (x3, y3)

def legendre_symbol(a, p):
""" Compute the Legendre symbol a|p. Returns 1 if a is a quadratic residue mod p, -1 otherwise """
return pow(a, (p - 1) // 2, p)

# calculate modular square root from y using legendre symbol
def mod_sqrt(a, p):
""" Compute the modular square root of a mod p, if it exists """
if legendre_symbol(a, p) != 1:
return None # no sqrt exists
if a == 0:
return 0
if p % 4 == 3:
return pow(a, (p + 1) // 4, p)
# For general case where p % 4 != 3, use Tonelli-Shanks or other methods
raise NotImplementedError("General modular square root not implemented")

def elliptic_curve_mult(P, k, a=123001240123101920407, p=269123855285160332211801709888382470147):
""" Perform scalar multiplication using the double-and-add method """
result = None # Start with the point at infinity
addend = P

while k > 0:
if k & 1:
result = elliptic_curve_add(result, addend, a, p)
addend = elliptic_curve_add(addend, addend, a, p)
k >>= 1

return result

# Curve parameters
a = 123001240123101920407
b = 2390490212093
p = 269123855285160332211801709888382470147
G = (141223464919893415164492319302044521923, 105945507900846830121381021840356606089)


Q_a_x = 19299658936035824596857706134874824001
y_squared = (Q_a_x**3 + a * Q_a_x + b) % p
y = mod_sqrt(y_squared, p)
Q_a = (Q_a_x, y)

#secret:
n_B = 853735663
S = elliptic_curve_mult(Q_a, n_B)
print(f"The shared secret S(x, y) = {S}")
secret = hashlib.sha256(f"{S[0]}".encode('utf-8')).hexdigest()
print(f"Shared secret to use: {secret}")
Loading

0 comments on commit da959b2

Please sign in to comment.