前言

第一次打CTF,crypto的Tutorial部分涉及两题,RSA101和RC Four,结果是一题也没整出来。。好歹也是研究了一下午的真题,决定在比赛结束后看看大佬写的write up

链接传送门

正文

RSA101

题目如下

题目1-1

题目的代码如下

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
from base64 import b64encode, b64decode
from Crypto.Util.number import getStrongPrime, bytes_to_long, long_to_bytes
from os import system

p = getStrongPrime(512)
q = getStrongPrime(512)
n = p * q
e = 65537
d = pow(e, -1, (p - 1) * (q - 1))

print("[RSA parameters]")
print("n =", hex(n))
print("e =", hex(e))

def sign(msg):
m = bytes_to_long(msg)
s = pow(m, d, n)
return long_to_bytes(s)

def verify(s):
s = bytes_to_long(s)
v = pow(s, e, n)
return long_to_bytes(v)

def welcome():
print("\nWelcome to command signer/executor.")
print("Menu : 1. Verify and run a command")
print(" 2. Sign a command")
print(" 3. Exit")

while True:
welcome()
sel = input(" > ").strip()
if sel == "1":
sgn = input("Signed command: ").strip()
sgn = b64decode(sgn)
cmd = verify(sgn)

commands = ["ls -l", "pwd", "id", "cat flag"]
if cmd.decode() in commands:
system(cmd)
else:
print("Possible commands: ", commands)

elif sel == "2":
cmd = input("Base64 encoded command to sign: ")
cmd = b64decode(cmd)
if cmd == "cat flag":
print("It's forbidden.")
else:
print("Signed command:", b64encode(sign(cmd)).decode())

elif sel == "3":
print("bye.")
exit()

else:
print("Invalid selection.")

我对代码的理解是:

1、引用了base64crypto.util.number,os这三个库

2、随机生成两个512比特的大素数p和q,因此n的值随着每次运行而变化

3、定义了函数名为sign的函数,msg为参数,在函数体中m是把参数msg从bytes(字节串,以二进制存储)转为long整型,s=m^d^ mod n,返回的是s的bytes型,而v=s^e^ mod n,返回的也是v的bytes型。

4、如果在交互式窗口输入1,要输入已被签名过的命令(Signed command),对这个命令进行b64decode解密,在运用"ls -l", "pwd", "id", "cat flag"这些命令,可以将字符串转化成命令在服务器上运行;

如果在交互式窗口输入2,用Base64对命令进行签名sign加密,在对命令cmd用base64解密,如果解密后的cmd==cat flag,则输出It's forbidden.,否则输出Signed command:

如果在交互式窗口输入3,输出“bye”后退出运行;

如果在交互式窗口输入不为1,2,3,就输出“Invalid selection.”


在学习大佬的write up后对代码理解的更正:

如果在交互式窗口输入1,会对输入的指令先base64解密,然后再RSA加密,如果两次加密后的内容cmd.decode() in commands,那么就会执行commands里面的操作;

输入2,就是对第一部分的逆向操作,但是不能输入cat flag

别忘了题目还给了服务器The server is running at: nc rsa101.sstf.site 1104.

关于如何与服务器交互,在kali中代码如下:

1
nc rsa101.sstf.site 1104

以输入ls -l为例,得到用base64加密后的字符串bHMgLWw=

输入2,生成签名过的命令

输入1,运行签名后的命令

结果是没有得到cat flag

假如直接输入cat flag,也没法执行

从给出的def出发

转化一下平常用的表达,把c分解成m1m2两个因数,m1m2≡cm^e^ mod n

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
c = bytes_to_long(b'cat flag')
print(c)
m1=103
m2=69525558883514113
m1=b64encode(long_to_bytes(m1))
m2=b64encode(long_to_bytes(m2))
print(m1,m2)

# m1='Zw=='
# m2='9wEgoA/3AQ=='

#signed_m1='MCDC7xSQfPRr134uRAa/ZjuUSATaI3I4FHjJNMEI7P+xLh4fqn02FpKm84OL7Su8rdz1Paj98a9KKLZZyfn+vhWPLgcOval7zBE/HfzUDMpbmp+lYojP/2+9T2mlhn8xo2PuzAVtofLTxplaC4a5d2e+UK7pXDza02QXBcmoGGM='
#signed_m2='QqgBF18BT48Wi6unKtwVMh1yNaYCMnI3j1EJCLSfTsM9WsX89KGhJRKGmK8sudoSKjFMz1mDPLrl9xgbTn9ROUyU4w5J3ffVcW/+UNYzTFlpfwAT5obMQb1ALJdtr8uuO/XlPABRFExIQqAy1/Efx90avDrMxoJFeb082DMonlQ='

m1=bytes_to_long(b64decode('MCDC7xSQfPRr134uRAa/ZjuUSATaI3I4FHjJNMEI7P+xLh4fqn02FpKm84OL7Su8rdz1Paj98a9KKLZZyfn+vhWPLgcOval7zBE/HfzUDMpbmp+lYojP/2+9T2mlhn8xo2PuzAVtofLTxplaC4a5d2e+UK7pXDza02QXBcmoGGM='))
#print(m1)
m2=bytes_to_long(b64decode('QqgBF18BT48Wi6unKtwVMh1yNaYCMnI3j1EJCLSfTsM9WsX89KGhJRKGmK8sudoSKjFMz1mDPLrl9xgbTn9ROUyU4w5J3ffVcW/+UNYzTFlpfwAT5obMQb1ALJdtr8uuO/XlPABRFExIQqAy1/Efx90avDrMxoJFeb082DMonlQ='))
#print(m2)

n=0xbefe9a8bb0f6af7ea24a58eb2fc349749cb88cf1f27181f2125e387eed8eca9550c81b3f292dfdf0fabad04bbfa83195ea9c48b7d7d8eded8783b8a00b7310d4642cf34b5944acb259df89c3b2069168aa4a064c8cacfb521ddee9f261c579b1ab15762ebc8a34bd6e26e17289bcf8e8201b2bb54cfb9ec7a6b2e3cfcc0606a7
e = 0x10001
c=(m1*m2)%n
c=long_to_bytes(c)
c = b64encode(c)
print(c)

得到的c是

1
b'9wEgoA/3AQ==' b'qoCIiqa35CtJ1A7Hjln1NEzzv7Noh0kNFiPDEY2TrRLkxooCoxbnJ3XpcR5IekFa8imQv9gfLO99++eZNRSZBN0UQaxYkvDrqX4XTipNfp0SGBBlkUkj8Y7COWs5IqtE76inZCSTJmMMv8OZU4AbEI6N3s25/EdNhhwu27dYU0o='

在输入签名验证

搜狗截图20210822172149