Tags: Crypto wp.
Categories: write up.

第一次打CryptoCTF捏,只做出来两道题,还是太菜了罢(悲

Poly RSA

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from Crypto.Util.number import *
from flag import flag

def keygen(nbit = 64):
while True:
k = getRandomNBitInteger(nbit)
p = k**6 + 7*k**4 - 40*k**3 + 12*k**2 - 114*k + 31377
q = k**5 - 8*k**4 + 19*k**3 - 313*k**2 - 14*k + 14011
if isPrime(p) and isPrime(q):
return p, q

def encrypt(msg, n, e = 31337):
m = bytes_to_long(msg)
return pow(m, e, n)

p, q = keygen()
n = p * q
enc = encrypt(flag, n)
print(f'n = {n}')
print(f'enc = {enc}')

附件里的ouput给了n和c

仔细观察p,q的生成方式,发现它们都是由一个未知数k构造而成,因此对n=p*q这个式子化简,再解出k即可得到p,q

通过在线网站化简,

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from Crypto.Util.number import *
e = 31337
n = 44538727182858207226040251762322467288176239968967952269350336889655421753182750730773886813281253762528207970314694060562016861614492626112150259048393048617529867598499261392152098087985858905944606287003243
c = 37578889436345667053409195986387874079577521081198523844555524501835825138236698001996990844798291201187483119265306641889824719989940722147655181198458261772053545832559971159703922610578530282146835945192532
'''
n=44538727182858207226040251762322467288176239968967952269350336889655421753182750730773886813281253762528207970314694060562016861614492626112150259048393048617529867598499261392152098087985858905944606287003243
k=var('k')
solve([k^11-8*k^10+26*k^9-409*k^8+451*k^7+10850*k^6+44939*k^5-158301*k^4+71237*k^3-9651273*k^2-2036532*k+439623147==n],k)
'''
#k^{11}-8k^{10}+26k^9-409k^8+451k^7+10850k^6+44939k^5-158301k^4+71237k^3-9651273k^2-2036532k+439623147
k = 9291098683758154336
p = k ** 6 + 7 * k ** 4 - 40 * k ** 3 + 12 * k ** 2 - 114 * k + 31377
q = k ** 5 - 8 * k ** 4 + 19 * k ** 3 - 313 * k ** 2 - 14 * k + 14011
phi = (p-1)*(q-1)
d = inverse(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))

baphomet

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from base64 import b64encode
from flag import flag

def encrypt(msg):
ba = b64encode(msg.encode('utf-8'))
baph, key = '', ''

for b in ba.decode('utf-8'):
if b.islower():
baph += b.upper()
key += '0'
else:
baph += b.lower()
key += '1'

baph = baph.encode('utf-8')
key = int(key, 2).to_bytes(len(key) // 8, 'big')

enc = b''
for i in range(len(baph)):
enc += (baph[i] ^ key[i % len(key)]).to_bytes(1, 'big')

return enc

enc = encrypt(flag)
f = open('flag.enc', 'wb')
f.write(enc)
f.close()

这道题挺有意思,它加密的过程非常简单,base64后反转大小写再异或得到密文。但难点在于用来异或的key没有告诉你。

我感觉我的解法有点非预期。flag的前5个字符肯定是CCTF{,于是我将这一串字符base64后进行大小写转换。这样就得到了baph的一部分。

enc的长度是48bytes,所以key也位48位,但key在加密时被转换成了bytes,所以只有6位。因此加密过程中所使用的key都是6次一个循环,我们只需要取baph的前六位,根据异或关系便可以得到key

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from base64 import *
'''
with open(r"flag.enc", "rb") as f:
data = f.read() #48个byte
print(data)
#data=b'\x88R\xc3\xd9<\xb1\xad\x14\xee\xca/\xa5\xba.\x95\xfb;\xb3\xc01\xd9\x9f\n\x99\x8c.\x95\xf4 \xce\xa9$\xe9\xc9\t\xa5\x81S\xcf\xf5#\x98\x93\x0f\xc0\x9c\x7f\xc6'
'''
c = b'\x88R\xc3\xd9<\xb1\xad\x14\xee\xca/\xa5\xba.\x95\xfb;\xb3\xc01\xd9\x9f\n\x99\x8c.\x95\xf4 \xce\xa9$\xe9\xc9\t\xa5\x81S\xcf\xf5#\x98\x93\x0f\xc0\x9c\x7f\xc6'
key = '111110010110001010101101101011000100111011111111'
key = int(key, 2).to_bytes(len(key) // 8, 'big')
print(key)
baph = b''
for i in range(len(c)):
print(key)
baph+=(c[i] ^ key[i%len(key)]).to_bytes(1, 'big')
m = ''
for b in baph.decode('utf-8'):
if b.islower():
m += b.upper()
else:
m += b.lower()
flag = b64decode(m.encode('utf-8'))
print(flag)