---
# System prepended metadata

title: PicoCTF - SRA
tags: [PicoCTF, Crypto, CTF]

---

# PicoCTF - SRA
###### tags: `PicoCTF` `CTF` `Crypto`

## Source code
:::spoiler Source Code
```python=
from Crypto.Util.number import getPrime, inverse, bytes_to_long
from string import ascii_letters, digits
from random import choice

pride = "".join(choice(ascii_letters + digits) for _ in range(16))
gluttony = getPrime(128)
greed = getPrime(128)
lust = gluttony * greed
sloth = 65537
envy = inverse(sloth, (gluttony - 1) * (greed - 1))

anger = pow(bytes_to_long(pride.encode()), sloth, lust)

print(f"{anger = }")
print(f"{envy = }")

print("vainglory?")
vainglory = input("> ").strip()

if vainglory == pride:
    print("Conquered!")
    with open("/challenge/flag.txt") as f:
        print(f.read())
else:
    print("Hubris!")

```
:::
## Recon
這一題也蠻有趣的，有給$e, d, c$，而我們知道$ed\equiv 1\ (mod\ \phi(n))$但目前不知道$n$是多少，這也是這一題比較難的地方，不過仔細看$p, q$的bits range只有128 bits，感覺有機會可以爆破，試想:
$$
e*d-1=\phi(n) * k=(p-1)*(q-1)*k
$$
所以我們只要先用[online tool](https://www.dcode.fr/prime-factors-decomposition)，分析所有的質因數，再暴力破解看可能的$p$有多少就可以了
:::spoiler Screenshot
![](https://hackmd.io/_uploads/BJPyZn3D3.png)
:::
## Exploit
* Note: 使用以下的script，需要利用這個[online tool](https://www.dcode.fr/prime-factors-decomposition)，然後把結果以逗號分開，再用list的方式當作input, e.g. `[2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 5, 7, 17, 19, 151, 2363909, 75519055285493, 6681450981644264152589, 118264780684392418025651473217]`
* Note2: 我寫的script沒辦法處理候選的$p$有三個以上的情況，因為我懶得寫，所以它會自動斷線再重新連線重新計算一次，以我的經驗大約3-4次就可以拿到flag了
```python=
from pwn import *
from itertools import combinations
from Crypto.Util.number import isPrime, inverse, long_to_bytes

context.arch = 'amd64'

# 這個寫法超屌，要學起來，來自Martin Carlisle大大
def sub_lists (l):
    comb = []
    for i in range(1,len(l)+1):
        comb += [list(j) for j in combinations(l, i)]
    return comb

def main():
    r = remote("saturn.picoctf.net", 64350)

    c = int(r.recvline().strip().decode().split(" ")[-1])
    d = int(r.recvline().strip().decode().split(" ")[-1])
    e = 65537
    log.info(f"c = {c}\nd = {d}")

    k_phi = d * e - 1
    print("k_phi = ", k_phi)

    k_phi_factor = eval(input())
    combos = sub_lists(k_phi_factor)

    '''Find (p-1)'''
    primes = set()
    for l in combos:
        product = 1
        # multiply them together to get p-1
        for k in l:
            product = product * k
        if product.bit_length()==128 and isPrime(product+1):
            primes.add(product+1)
    print(primes)

    if len(primes) == 2:
        phi = 1
        n = 1
        for candidate in primes:
            phi *= (candidate - 1)
            n *= candidate


        assert inverse(e, phi) == d
        print(long_to_bytes(pow(c, d, n)))
        r.sendline(long_to_bytes(pow(c, d, n)))
        r.interactive()
        r.close()
        sys.exit(0)

    else:
        r.close()
        return False

if __name__ == '__main__':
    while not main():
        main()
```
Flag: `picoCTF{7h053_51n5_4r3_n0_m0r3_2b7ad1ae}`

## Reference
[picoCTF 2023 SRA](https://youtu.be/3DPWLnrqHZ0)
[PicoCTF: SRA Challenge](https://eshard.com/posts/picoctf-sra-challenge)
[maple3142 - SRA](https://blog.maple3142.net/2023/03/29/picoctf-2023-writeups/#sra)