64 lines
2.3 KiB
Markdown
64 lines
2.3 KiB
Markdown
# XMASSpirit
|
|
|
|
Now that elves have taken over Santa has lost so many letters from kids all
|
|
over the world. However, there is one kid who managed to locate Santa and sent
|
|
him a letter. It seems like the XMAS spirit is so strong within this kid. He
|
|
was so smart that thought of encrypting the letter in case elves captured it.
|
|
Unfortunately, Santa has no idea about cryptography. Can you help him read the
|
|
letter?
|
|
|
|
## Flag
|
|
|
|
HTB{4ff1n3_c1ph3r_15_51mpl3_m47h5}
|
|
|
|
- See letter.pdf
|
|
|
|
## How to solve
|
|
|
|
- It's a known plaintext attack.
|
|
- The encryption works by applying `(a*byte+b)%n` for each byte of the pdf.
|
|
- Where `a` and `b` remain static across the whole file.
|
|
- The PDFv5 Header is known (`00000000: 2550 4446 2d31 2e35 0a25 e2e3 cfd3 0a37 %PDF-1.5.%.....7`)
|
|
- Constraint 1: Factor `a` has to be a number between 1..256 while not sharing a common divisor with 256
|
|
- Constraitn 2: Factor `b` has to be a number between 1..256
|
|
- So it's possible to attack the encryption by iterating and trying to create a pair (a, b) that matches the entire encrypted pdf header.
|
|
|
|
```python
|
|
def get_factors(ct:bytes, n:int=256) -> (int, int):
|
|
''' find a and b for n and ct '''
|
|
# first generate a list of all numbers without common divisor with 256
|
|
nogcds = [ x for x in range(1, n) if gcd(x, n) == 1 ]
|
|
for b in range(1, n):
|
|
for a in nogcds:
|
|
for i, enc in enumerate(header):
|
|
candidate = (a * enc + b) % n
|
|
if candidate != ct[i]: break
|
|
if(i+1 == len(header)):
|
|
print(f'Solved: a={a},b={b}')
|
|
return (a,b)
|
|
print(f'No solution found.')
|
|
return (0,0)
|
|
```
|
|
|
|
- When the factors are found, simply create a lookup table of all values and substitute each byte in the ciphertext.
|
|
|
|
```python
|
|
def decrypt(ct:bytes, lut:dict) -> bytes:
|
|
''' decrypt the file using the lookup table '''
|
|
res = b''
|
|
for byte in ct:
|
|
dec = lut[byte]
|
|
res += bytes([dec])
|
|
return res
|
|
```
|
|
## Notes
|
|
|
|
### Encryption code analysis:
|
|
- Choose a `randint` `a` from `1` to `mod`, that is not divisible by mod.
|
|
- Choose a `randint` `b` from `1` to `mod`.
|
|
- for each byte in `dt`
|
|
- calculate `(a * byte + b) % mod`
|
|
- append to output bytes
|
|
- return bytes when done
|
|
- `s_next = (a * s_prev + b) mod p` is a linear congruential generator prng
|