1[LitCTF 2023]梦想是红色的 (初级)
2[BJDCTF 2020]base??
dict的意思是字典,再结合题目,base,可能是base的字典,但是于base64字典不同
可以用给的字典替换base64的字典
my_dict={0: 'J', 1: 'K', 2: 'L', 3: 'M', 4: 'N', 5: 'O', 6: 'x', 7: 'y', 8: 'U', 9: 'V', 10: 'z', 11: 'A', 12: 'B', 13: 'C', 14: 'D', 15: 'E', 16: 'F', 17: 'G', 18: 'H', 19: '7', 20: '8', 21: '9', 22: 'P', 23: 'Q', 24: 'I', 25: 'a', 26: 'b', 27: 'c', 28: 'd', 29: 'e', 30: 'f', 31: 'g', 32: 'h', 33: 'i', 34: 'j', 35: 'k', 36: 'l', 37: 'm', 38: 'W', 39: 'X', 40: 'Y', 41: 'Z', 42: '0', 43: '1', 44: '2', 45: '3', 46: '4', 47: '5', 48: '6', 49: 'R', 50: 'S', 51: 'T', 52: 'n', 53: 'o', 54: 'p', 55: 'q', 56: 'r', 57: 's', 58: 't', 59: 'u', 60: 'v', 61: 'w', 62: '+', 63: '/', 64: '='}
keys=''
for key in my_dict:
keys+=my_dict[key]
print("keys=",keys)
string1=keys[:64]
print("string1=",string1)
import base64
import string
str1='FlZNfnF6Qol6e9w17WwQQoGYBQCgIkGTa9w3IQKw'
string2='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'##标准的 base64 字符串 string2
print(base64.b64decode(str1.translate(str.maketrans(string1,string2))))
print("映射",(str.maketrans(string1,string2)))
print("映射2",(str1.translate(str.maketrans(string1,string2))))
'''
`str.maketrans(string1, string2)` 方法用于创建一个映射表,其中 `string1` 是原始字符集,`string2` 是目标字符集。这个方法返回一个映射表,该表可以用于 `str.translate()` 方法来进行字符替换。
这里的映射原理是将 `string1` 中的每个字符映射到 `string2` 中的对应位置的字符上,实现一一对应的替换关系。具体来说,如果 `string1` 和 `string2` 的长度不同,那么将会以较短的字符串长度为准,多余的字符将被忽略。
举个简单的例子:
假设有两个字符串 `string1 = "ABC"` 和 `string2 = "XYZ"`,那么映射关系就是:
- 将字符 `'A'` 替换为 `'X'`
- 将字符 `'B'` 替换为 `'Y'`
- 将字符 `'C'` 替换为 `'Z'`
如果我们使用 `str.maketrans(string1, string2)`,它将返回一个映射表,该表可以将字符串中的 `'A'` 替换为 `'X'`,`'B'` 替换为 `'Y'`,`'C'` 替换为 `'Z'`。
这个映射表可以用于 `str.translate()` 方法,用来对字符串进行替换操作,实现自定义的字符映射关系。
'''
my_dict是一个字典,keys初始为空字符,然后通过一个循环遍历‘my_dict’中的键,并将每个键对应的值添加到 keys
中,形成一个字符串。
keys
变量包含了通过 my_dict
字典中的值构建的字符串,取了 keys
字符串的前64个字符并将其赋值给 string1
变量。
导入了 Python 的内置库 base64
和 string
。
base64
库用于处理 Base64 编码,而 string
库包含了标准的 ASCII 字符串。
定义了两个字符串 str1
和 string2
。str1
是一个 Base64 编码的字符串,string2
是标准的 Base64 字符串,它包含了字符集 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"。
3.[SWPUCTF 2021 新生赛]traditional
首先,让我们先了解一下八卦与二进制的对应关系
根据二进制数的规定:有,用1表示;无,用0表示。我们可以得出八卦各卦阳爻和阴爻的二进制数。下面我们写出八卦各卦阳爻的二进制数(即有阳爻为1,无阳爻为0):
坤:黑黑黑,卦符阴阴阴,二进制数为000
艮:黑黑白,卦符阴阴阳,二进制数为001
坎:黑白黑,卦符阴阳阴,二进制数为010
巽:黑黑白,卦符阴阳阳,二进制数为011
震:白黑黑,卦符阳阴阴,二进制数为100
离:白黑白,卦符阳阴阳,二进制数为101
兑:白白黑,卦符阳阳阴,二进制数为110
乾:白白白,卦符阳阳阳,二进制数为111
即字典为,dict = {'乾':'111','巽':'110','离':'101','艮':'100','兑':'011','坎':'010','震':'001','坤':'000'}
需要把八卦序列转换为ASCII字符串
dict = {'乾':'111','巽':'110','离':'101','艮':'100','兑':'011','坎':'010','震':'001','坤':'000'} #替换字典
c= '震坤艮 震艮震 坤巽坤 坤巽震 震巽兑 震艮震 震离艮 震离艮' #给定的八卦序列
t=c.split(' ') #split方法用于拆分字符串并将其存储在列表中。内置方法返回字符串中的单词列表,使用“分隔符” 作为分隔符字符串
f=''
for i in range(len(t)):
s = ''
for j in range(len(t[i])):
k=t[i][j]
a=dict[k] #找到第i组每个八卦对应的二进制
s+=a #将第i组所有八卦对应的二进制相加
ch=chr(int(s,2)) #int(s,2)将二进制转化为十进制,chr()将该值对应到ASCII字符
f+=ch
print(f)
代码创建了一个字典 dict
,将每个八卦对应的二进制编码存储起来。
然后,代码将给定的八卦序列拆分为单个八卦,并对每个八卦进行遍历。在遍历的过程中,找到每个八卦对应的二进制编码,并将它们相加起来。
接着,使用 int(s, 2)
将二进制字符串转换为十进制整数,然后使用 chr()
函数将其转换为相应的 ASCII 字符。
最后,将所有字符组合起来形成最终的 ASCII 字符串。
返回:Da01sall
4. [LitCTF 2023]Hex?Hex!(初级)
通过ASCII16进制解码就可以得到flag
在Python中,可以使用内置函数hex()
和int()
实现十进制与十六进制的转换。
使用hex()
函数可以将十进制数转换为十六进制。该函数接受一个十进制整数作为输入,返回对应的十六进制字符串。
decimal = 666 #十进制数
hexadecimal = hex(decimal) #十进制转换为十六进制
print(hexadecimal) #输出十六进制
输出
使用int()
函数可以将十六进制数转换为十进制。该函数接受一个十六进制字符串作为输入,返回对应的十进制整数。
hexadecimal = "0x29a"
decimal = int(hexadecimal, 16)
print(decimal) # 输出:666
5.[SWPUCTF 2021 新生赛]crypto2
from gmpy2 import *
from Crypto.Util.number import *
flag = '***************'
p = getPrime(512)
q = getPrime(512)
m1 = bytes_to_long(bytes(flag.encode()))
n = p*q
e1 = getPrime(32)
e2 = getPrime(32)
print()
flag1 = pow(m1,e1,n)
flag2 = pow(m1,e2,n)
print('flag1= '+str(flag1))
print('flag2= '+str(flag2))
print('e1= ' +str(e1))
print('e2= '+str(e2))
print('n= '+str(n))
#flag1= 100156221476910922393504870369139942732039899485715044553913743347065883159136513788649486841774544271396690778274591792200052614669235485675534653358596366535073802301361391007325520975043321423979924560272762579823233787671688669418622502663507796640233829689484044539829008058686075845762979657345727814280
#flag2= 86203582128388484129915298832227259690596162850520078142152482846864345432564143608324463705492416009896246993950991615005717737886323630334871790740288140033046061512799892371429864110237909925611745163785768204802056985016447086450491884472899152778839120484475953828199840871689380584162839244393022471075
#e1= 3247473589
#e2= 3698409173
#n= 103606706829811720151309965777670519601112877713318435398103278099344725459597221064867089950867125892545997503531556048610968847926307322033117328614701432100084574953706259773711412853364463950703468142791390129671097834871371125741564434710151190962389213898270025272913761067078391308880995594218009110313
源码分析:
一个rsa的加密流程。
引用了两个库gmpy2和Crypto.Util.number。
p和q是随机生成的两个512位数,计算了n。生成32位的随机素数e1,e2,作为RSA加密算法的公钥。最后,将明文 flag 使用 bytes_to_long() 函数转换为长整数 m1,然后分别使用不同的公钥指数 e1 和 e2 对其进行 RSA 加密,得到了密文 flag1 和 flag2。
pow函数是通常用于快速计算模幂。
flag1 = pow(m1,e1,n)
flag2 = pow(m1,e2,n)
先计算m1的e1次方,在对m1的e1次方对n取模。
而m1= bytes_to_long(bytes(flag.encode()))
bytes_to_long()
函数是 Crypto.Util.number 模块中的函数,用于将字节表示的数据转换为长整数表示。
m1就是将flag转换的字符串。
所以要求flag就先求m1,而我们已经知道了flag1,flag2,e1,e2,n。
我们拥有两个使用相同模数n但不同公钥指数加密的密文flag1,flag2。可以使用RSA 的共模攻击(CRT 攻击)。通过扩展欧几里得算法(Extended Euclidean Algorithm),我们可以计算出一个系数,使得两个公钥指数的线性组合等于 1。然后,我们使用这个系数将两个密文解密并恢复出原始明文。
代码脚本:
from gmpy2 import *
from Crypto.Util.number import *
from gmpy2 import gmpy2
flag1 = 100156221476910922393504870369139942732039899485715044553913743347065883159136513788649486841774544271396690778274591792200052614669235485675534653358596366535073802301361391007325520975043321423979924560272762579823233787671688669418622502663507796640233829689484044539829008058686075845762979657345727814280
flag2 = 86203582128388484129915298832227259690596162850520078142152482846864345432564143608324463705492416009896246993950991615005717737886323630334871790740288140033046061512799892371429864110237909925611745163785768204802056985016447086450491884472899152778839120484475953828199840871689380584162839244393022471075
e1 = 3247473589
e2 = 3698409173
n = 103606706829811720151309965777670519601112877713318435398103278099344725459597221064867089950867125892545997503531556048610968847926307322033117328614701432100084574953706259773711412853364463950703468142791390129671097834871371125741564434710151190962389213898270025272913761067078391308880995594218009110313
def rsa_gong_N_def(e1, e2, c1, c2, n):
e1, e2, c1, c2, n = int(e1), int(e2), int(c1), int(c2), int(n)
s = gmpy2.gcdext(e1, e2) # 扩展欧几里得算法 t*e1+z*e2=1,求出t和z
t = s[1]
z = s[2]
if t < 0: # 要求c的s次幂,就要先计算c的模反元素c2r,然后求c2r的-s2次幂
t = - t
c1 = gmpy2.invert(c1, n) # 求c1的逆元
elif z < 0:
z = -z
c2 = gmpy2.invert(c2, n)
m = (pow(c1, t, n) * pow(c2, z, n)) % n # (c1^s1*c2^s2)%n=m%n=m
return m
result = rsa_gong_N_def(e1, e2, flag1, flag2, n)
print(long_to_bytes(result))
该脚本需要用到Crypto.Util.number。需要安装pycryptodome,而且\site-packages下的crypto也需要更改为Crypto,因为在pycryptodome库里面所引用的crypto是c字母大写的。
int函数将所有输入参数转换为整数,以确保一致性。
共模攻击:
共模攻击(Common Modulus Attack)是一种针对使用相同模数但不同公钥指数的RSA加密系统的攻击方法。在共模攻击中,攻击者通过对一组密文进行分析,可以获取明文或密钥信息。
RSA加密过程中,密文c由明文m加密得到,公钥为e和模数n,加密过程如下:
𝑐=𝑚的𝑒次方 mod 𝑛
当使用相同模数 𝑛n,但不同的公钥指数 𝑒1e1 和 𝑒2e2 进行加密时,我们有两个密文:
𝑐1=𝑚的𝑒1次方 mod 𝑛
𝑐2=𝑚的𝑒2 次方mod 𝑛
如果e1和e2互质,则可以利用中国剩余定理从c1和c2中还原出m的值。具体步骤如下:
- 使用扩展欧几里得算法求出e1和e2的模反元素d1和d2;
- 计算 𝑥=𝑐1的𝑑1 次方mod 𝑛和 𝑦=𝑐2的𝑑2 次方mod 𝑛;
- 使用中国剩余定理,根据 𝑥x 和 𝑦y 还原出 𝑚m 的值。
给我们的题目就是:
flag1=m1的e1次方mod n
flag2=m1的e2次方mod n
最后得到flag:
NSSCTF{xxxxx******xxxxx}
6.[羊城杯 2021]Bigrsa
from Crypto.Util.number import *
from flag import *
n1 = 103835296409081751860770535514746586815395898427260334325680313648369132661057840680823295512236948953370895568419721331170834557812541468309298819497267746892814583806423027167382825479157951365823085639078738847647634406841331307035593810712914545347201619004253602692127370265833092082543067153606828049061
n2 = 115383198584677147487556014336448310721853841168758012445634182814180314480501828927160071015197089456042472185850893847370481817325868824076245290735749717384769661698895000176441497242371873981353689607711146852891551491168528799814311992471449640014501858763495472267168224015665906627382490565507927272073
e = 65537
m = bytes_to_long(flag)
c = pow(m, e, n1)
c = pow(c, e, n2)
print("c = %d" % c)
# output
# c = 60406168302768860804211220055708551816238816061772464557956985699400782163597251861675967909246187833328847989530950308053492202064477410641014045601986036822451416365957817685047102703301347664879870026582087365822433436251615243854347490600004857861059245403674349457345319269266645006969222744554974358264
首先,它导入了所需的库以及一个名为 flag
的模块,然后设置了两个不同的 模数n1
和 n2
,以及一个公钥指数 e
。接下来,它将明文 flag
转换为整数 m
,然后使用第一个模数n1
和公钥e对其进行加密,再使用第二个模数n2
和e对结果进行再加密,最后打印出最终的密文 c
。
我们要求的是明文flag。
首先要考虑n1和n2是否互质,可以求最大公约数。
import gmpy2
n1 = 103835296409081751860770535514746586815395898427260334325680313648369132661057840680823295512236948953370895568419721331170834557812541468309298819497267746892814583806423027167382825479157951365823085639078738847647634406841331307035593810712914545347201619004253602692127370265833092082543067153606828049061
n2 = 115383198584677147487556014336448310721853841168758012445634182814180314480501828927160071015197089456042472185850893847370481817325868824076245290735749717384769661698895000176441497242371873981353689607711146852891551491168528799814311992471449640014501858763495472267168224015665906627382490565507927272073
a = gmpy2.gcd(n1, n2)
print("最大公约数:",a)
如果最大公约数大于1,那么n1和n2就不互质。
不互质(注意:"互质"和"互素"这两个术语在数学上是等价的,都表示两个数的最大公约数为 1,也就是除了 1 之外没有其他公共因子。它们的含义是一致的。)
import gmpy2
from Crypto.Util.number import *
# output
c=60406168302768860804211220055708551816238816061772464557956985699400782163597251861675967909246187833328847989530950308053492202064477410641014045601986036822451416365957817685047102703301347664879870026582087365822433436251615243854347490600004857861059245403674349457345319269266645006969222744554974358264
e=65537
n1=103835296409081751860770535514746586815395898427260334325680313648369132661057840680823295512236948953370895568419721331170834557812541468309298819497267746892814583806423027167382825479157951365823085639078738847647634406841331307035593810712914545347201619004253602692127370265833092082543067153606828049061
n2=115383198584677147487556014336448310721853841168758012445634182814180314480501828927160071015197089456042472185850893847370481817325868824076245290735749717384769661698895000176441497242371873981353689607711146852891551491168528799814311992471449640014501858763495472267168224015665906627382490565507927272073
q=gmpy2.gcd(n1,n2)
q1=n1//q
q2=n2//q
d1=gmpy2.invert(e,(q1-1)*(q-1))
d2=gmpy2.invert(e,(q2-1)*(q-1))
m1=pow(c,d2,n2)
m2=pow(m1,d1,n1)
flag=''
flag=long_to_bytes(m2)
print(flag)
导入了gmpy2和Crypto.Util.number两个库,c,e,n1,n2。
计算模数 n1
和 n2
的最大公约数 q
,然后计算出两个模数的素数因子 p
和 q
。
接着,根据CRT的原理,分别计算了在模数 p-1
和 q-1
下的RSA私钥 d1
和 d2
。
最后,使用CRT的解密流程:先用模数 p
下的RSA私钥 d1
解密密文 c
得到中间结果 m1
,再用模数 q
下的RSA私钥 d2
解密 m1
得到最终结果 m2
,然后将其转换为字节串,即为明文。
输出:
7. [SWPU 2020]happy
('c=', '0x7a7e031f14f6b6c3292d11a41161d2491ce8bcdc67ef1baa9eL')
('e=', '0x872a335')
#q + q*p^3 =1285367317452089980789441829580397855321901891350429414413655782431779727560841427444135440068248152908241981758331600586
#qp + q *p^2 = 1109691832903289208389283296592510864729403914873734836011311325874120780079555500202475594
给了c和e
from gmpy2 import *
from Crypto.Util.number import *
c=0x7a7e031f14f6b6c3292d11a41161d2491ce8bcdc67ef1baa9e
e=0x872a335
k1=1285367317452089980789441829580397855321901891350429414413655782431779727560841427444135440068248152908241981758331600586
k2= 1109691832903289208389283296592510864729403914873734836011311325874120780079555500202475594
k3=gcd(k1,k2)
p=k2//k3
q=k3//(1+p)
n=p*q
phi=(p-1)*(q-1)
d=invert(e,phi)
flag=pow(c,d,n)
m=long_to_bytes(flag)
print(m)
用gmpy2 库来处理大整数和 RSA 运算,并使用了 Crypto.Util.number 中的一些函数来处理字节序列和整数之间的转换。定义密文 c、公钥 e,以及 k1 和 k2 这两个因子。然后找到k1和k2的最大公约数k3,用它们得到了p和q,进而计算了n和 𝜙(𝑛)。接下来,求出私钥d,并用它对密文c进行解密,得到了明文 m。最后,将明文m转换为字节序列flag,并打印出来。
输出: