换新工作以后,攻防技术接触越来越少,但是ctf接触越来越多,这里通过平常做题的积累来快速提升ctf的能力。首先从crypto开始:
ctfshow密码学签到
有密文,有提示,倒过来就是flag
写个python脚本,倒过来字符:}wohs.ftc{galf
original_string = "}wohs.ftc{galf"
# 使用字符串切片将字符串倒过来
reversed_string = original_string[::-1]
print(reversed_string)
最终结果:flag{ctf.show}
ctf show crypto2(jsfuck)
下载文件并解压,大概就是[](!+这些字符组合的。联想到JSFuck是一种深奥的 JavaScript 编程风格。以这种风格写成的代码中仅使用 [、]、(、)、! 和 + 六种字符。
在线解密:console.log("flag{3e858ccd79287cfe8509f15a71b4c45d}"
ctf show crypto3(颜文字解密)
解压文件后像是颜文字表情,颜文字解密
注意文件用python打开,并用latin-1显示,随后解密即可获取flag
ctf show easy_base(在线base解密)
复制密文,题目告诉你是base加密了,base解密网址:CTF在线工具-在线base编码|在线base解码|base16编码|base32编码|base64编码
4C455A5645334C44474A55484D5A42544F5132574956525A50464E464F4E4C474D4656454D334359474A554751564B4949493255535532464E42544643504A35
在线base解密,第一次base16解密成功
第二次base32解密成功
第三次base64解密成功:ctfshow{yu_ren_j1e_haPpy!!!}
ctf show 大牛的密码(脚本解密)
解压后是一个python脚本
from Crypto.Util.Padding import unpad
def swap(arr, a, b):
arr[a], arr[b] = arr[b], arr[a]
def decrypt2(c, S_BOX):
inv_S_BOX = [0] * len(S_BOX)
for i, s in enumerate(S_BOX):
inv_S_BOX[s] = i
for _ in range(16):
c = [c[i] for i in inv_S_BOX]
return c
def decrypt1(m):
enc = [m[i:i+BLOCK] for i in range(0, len(m), BLOCK)]
for i in enc:
for j in range(BLOCK-1, -1, -1):
aa = j * 7 % BLOCK
swap(i, j, aa)
return [item for sublist in enc for item in sublist]
# 加密后的数据
S_BOX = [9, 31, 32, 38, 20, 1, 22, 4, 8, 2, 11, 21, 7, 18, 46, 23, 34, 3, 19, 12, 45, 30, 27, 37, 5, 47, 28, 36, 0, 43, 39, 10, 29, 14, 40, 24, 33, 16, 17, 6, 42, 15, 26, 41, 44, 25, 35, 13]
c = [99, 111, 102, 11, 107, 49, 11, 53, 121, 48, 114, 117, 11, 95, 112, 95, 109, 115, 11, 95, 101, 95, 119, 117, 79, 123, 111, 48, 110, 95, 121, 116, 121, 125, 116, 11, 119, 11, 97, 67, 11, 11, 11, 11, 11, 99, 110, 104]
# 解密过程
decrypted2 = decrypt2(c, S_BOX)
decrypted1 = decrypt1(decrypted2)
# 去除填充
flag = unpad(bytes(decrypted1), BLOCK)
print(flag)
重点分析decrypt2和decrypt1这两个函数,先分析decrypt2
def decrypt2(c, S_BOX):
inv_S_BOX = [0] * len(S_BOX)
for i, s in enumerate(S_BOX):
inv_S_BOX[s] = i
for _ in range(16):
c = [c[i] for i in inv_S_BOX]
return c
- 创建逆S_BOX:inv_S_BOX = [0] * len(S_BOX)。
- 这行代码创建了一个与S_BOX长度相同的列表inv_S_BOX,并用0填充。这个列表将用来存储S_BOX的逆映射。
- 例如,如果S_BOX的长度是48,那么inv_S_BOX的初始状态是:
inv_S_BOX = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
2.填充逆S_BOX
for i, s in enumerate(S_BOX):
inv_S_BOX[s] = i
- 这里的enumerate(S_BOX)会生成S_BOX中每个元素的索引和值,i为索引,s为值(逆向的)。例如:
S_BOX = [9, 31, 32, 38, 20, 1, 22, 4, 8, 2, 11, 21, 7, 18, 46, 23, 34, 3, 19, 12, 45, 30, 27, 37, 5, 47, 28, 36, 0, 43, 39, 10, 29, 14, 40, 24, 33, 16, 17, 6, 42, 15, 26, 41, 44, 25, 35, 13] - 第一次循环时,i = 0, s = 9。
- 第二次循环时,i = 1, s = 31。
- 第二次循环时,i = 2, s = 32。
- 以此类推。。。
- inv_S_BOX[s] = i 将 s 的值作为索引,i 的值作为内容填充到inv_S_BOX。最终inv_S_BOX是S_BOX的逆映射。
3.填充逆S_BOX
for _ in range(16):
c = [c[i] for i in inv_S_BOX]
- c[i] for i in inv_S_BOX 表示用inv_S_BOX中的索引顺序重排c。
- 例如,如果c = [a, b, c],且inv_S_BOX = [2, 0, 1],那么这行代码将c变成:
c = [c[2], c[0], c[1]] = [c, a, b]
- 这个过程重复16次,使c恢复到原始状态。
再来分析decrypt1函数(函数其实运行完根本就没换)
def decrypt1(m):
enc = [m[i:i+BLOCK] for i in range(0, len(m), BLOCK)]
for i in enc:
for j in range(BLOCK-1, -1, -1):
aa = j * 7 % BLOCK
swap(i, j, aa)
return [item for sublist in enc for item in sublist]
- enc = [m[i:i+BLOCK] for i in range(0, len(m), BLOCK)]
- 这行代码将数据m按照BLOCK大小分成多个小块。例如,如果m是[1, 2, 3, 4, 5, 6, 7, 8]且BLOCK是4,enc就会变成:enc = [[1, 2, 3, 4], [5, 6, 7, 8]]
2.字节交换
for i in enc:
for j in range(BLOCK-1, -1, -1):
aa = j * 7 % BLOCK
swap(i, j, aa)
- 这部分代码对每个数据块进行字节交换操作。对于每个块,j从块的末尾(BLOCK-1)遍历到开头(0)。
- aa = j * 7 % BLOCK计算了aa的位置。
- swap(i, j, aa)交换块i中位置j和位置aa的元素。
例如,假设一个块是[1, 2, 3, 4],BLOCK是4:
-
- j=3时,aa = 3 * 7 % 4 = 1,所以交换位置3和位置1,块变成[1, 4, 3, 2]。
- j=2时,aa = 2 * 7 % 4 = 2,所以位置2和位置2交换(没有变化),块仍是[1, 4, 3, 2]。
- j=1时,aa = 1 * 7 % 4 = 3,所以交换位置1和位置3,块变成[1, 2, 3, 4]。
- j=0时,aa = 0 * 7 % 4 = 0,所以位置0和位置0交换(没有变化),块仍是[1, 2, 3, 4]。
- 最终的块会变回原来的顺序。
3.重组数据: return [item for sublist in enc for item in sublist]
- 最后一步是将所有块重新组合成一个列表。这个列表就是解密后的数据。
逆向脚本
#对decrypt2进行逆向即可,decrypt2(S_BOX, c)
# 加密后的数据
c = [99, 111, 102, 11, 107, 49, 11, 53, 121, 48, 114, 117, 11, 95, 112, 95, 109, 115, 11, 95, 101, 95, 119, 117, 79, 123, 111, 48, 110, 95, 121, 116, 121, 125, 116, 11, 119, 11, 97, 67, 11, 11, 11, 11, 11, 99, 110, 104]
S_BOX = [9, 31, 32, 38, 20, 1, 22, 4, 8, 2, 11, 21, 7, 18, 46, 23, 34, 3, 19, 12, 45, 30, 27, 37, 5, 47, 28, 36, 0, 43, 39, 10, 29, 14, 40, 24, 33, 16, 17, 6, 42, 15, 26, 41, 44, 25, 35, 13]
# for i in c:
# print("值"+str(S_BOX[i])+"位置:"+str(i))
# print("-"*50)
inv_c = [0] * len(c)
for j in range(16):
for i in range(len(S_BOX)):
inv_c[S_BOX[i]] = c[i]
c = inv_c
inv_c = [0] * len(c)
print(bytes(c))
ctf show crypto4(rsa)
打开题目是这个:p=447685307 q=2037 e=17
一看就像是描述RSA加密算法。
了解一下RSA加密的过程:
- 选择两个大质数:p 和 q。
- 计算它们的乘积:n = p * q。
- 计算 Euler 函数:φ(n) = (p - 1) * (q - 1)。
- 选择公钥指数:e,满足 1 < e < φ(n),且 e 与 φ(n) 互质。(互质概念:例如 8 与 10 的最大公约数是 2,不是 1,因此它们并不互质;又例如 7, 10, 13 的最大公约数是 1,因此它们互质。)
- 计算私钥指数:d,满足 d ≡ e^(-1) (mod φ(n)),即 d 是 e 在 φ(n) 模下的乘法逆元。
解密d过程:
import libnum
p=447685307
q=2037
e=17
n=p*q
# 计算 φ(n)
φ=(p-1)*(q-1)
# 计算 e 在模 φ(n) 下的逆元
d = libnum.invmod(e,φ)
print(d)
ctf show 萌新赛签到题
打开题目:Ao(mgHX^E)AN2PSBOu3qI0o,一看就是一个加密的
base64,base16,base32都不行,那就挨个base尝试
最终base85解密成功
ctf show BJDCTF2020 这是base??(自定义base解码表)
直接查看base.txt,是一串乱码,链接导入txt文件看
它给了一个码表,给了一个密文,转换一下格式:
联想题目提示了base,是不是想表达正常将密文的解密用的表替换为题目给的码表
import base64
dict = 'JKLMNOxyUVzABCDEFGH789PQIabcdefghijklmWXYZ0123456RSTnopqrstuvw+/='
nomal = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' #标准表
chipertext = 'FlZNfnF6Qol6e9w17WwQQoGYBQCgIkGTa9w3IQKw'
result = ''
# 遍历chipertext每个字符i,在dict中找到该字符的位置
for i in chipertext:
# 返回nomal中对应位置的字符
result += nomal[dict.find(i)]
print(result)
# base64解密nomal即可
decoded_bytes = base64.b64decode(result)
decoded_string = decoded_bytes.decode('utf-8')
print(decoded_string)
ctf show easyrsa1(rsa,分解n得到p,q)
下载打开就是三个参数
e = 65537
n = 1455925529734358105461406532259911790807347616464991065301847
c = 69380371057914246192606760686152233225659503366319332065009
给了n,那就在线分解获取p和q
p=1201147059438530786835365194567
q=1212112637077862917192191913841
套公式
import gmpy2
import binascii
n=1455925529734358105461406532259911790807347616464991065301847
p=1201147059438530786835365194567
q=1212112637077862917192191913841
e=65537
c=69380371057914246192606760686152233225659503366319332065009
n=p*q
# 计算 φ(n)
φ=(p-1)*(q-1)
# 计算 e 在模 φ(n) 下的逆元
d = gmpy2.invert(e,φ)
# 幂取模,结果是 m = (c^d) mod n
m = gmpy2.powmod(c,d,n)
# hex(m):这个函数将整数 m 转换为其对应的十六进制字符串表示,例如,如果 m 是 65,则 hex(m) 返回字符串 '0x41'。
# hex(m)[2:]:这里的 [2:] 是切片操作,它去掉了十六进制字符串前面的 '0x',因为在 Python 中,hex() 函数生成的字符串以 '0x' 开头。例如,'0x41' 切片后变为 '41'。
# binascii.unhexlify():这个函数将一个十六进制表示的字符串解码为原始的字节串。在这里,它接收 '41' 这样的字符串,并将其解码为字节串 b'A'。
print(binascii.unhexlify(hex(m)[2:]))
ctf show crypto5(rsa)
给你p=447685307 q=2037 e=17 c=704796792
套公式就行了
import gmpy2
p=447685307
q=2037
e=17
c=704796792
n=p*q
# 计算 φ(n)
φ=(p-1)*(q-1)
# 计算 e 在模 φ(n) 下的逆元
d = gmpy2.invert(e,φ)
# 幂取模,结果是 m = (c^d) mod n
m = gmpy2.powmod(c,d,n)
print(m)
ctf show crypto6(rabbit解密)
下载附件
尝试base64解密,出现Salted加盐提示
#utf-8
import base64
# 示例用法
encoded_string = "U2FsdGVkX19mGsGlfI3nciNVpWZZRqZO2PYjJ1ZQuRqoiknyHSWeQv8ol0uRZP94 MqeD2xz+"
decoded_bytes = base64.b64decode(encoded_string)
# 将字节转换成字符串
decoded_string = decoded_bytes.decode('latin-1')
print(decoded_string)
换个思路,需要密钥,直接挨个尝试,最终为Rabbit加密
ctf show 贝斯多少呢(base62分段)
打开题目:
8nCDq36gzGn8hf4M2HJUsn4aYcYRBSJwj4aE0hbgpzHb4aHcH1zzC9C3IL
既然是base,那就挨个尝试呗,base62可以解密,但是也就到这里了
这里最后我是卡住了,然后看了一下提示,wp说是将字符分段,然后分段进行base62解密
那我就写一个脚本分段试试,先写一个按7,8,9字符分段的脚本
str = "8nCDq36gzGn8hf4M2HJUsn4aYcYRBSJwj4aE0hbgpzHb4aHcH1zzC9C3IL"
def split_string_by_7(str):
"""
将字符串s按每7个字符进行分割
:param str: 输入的字符串
:return: 分割后的字符串列表
"""
return [str[i:i+7] for i in range(0, len(str), 7)]
def split_string_by_8(str):
"""
将字符串s按每9个字符进行分割
:param str: 输入的字符串
:return: 分割后的字符串列表
"""
return [str[i:i+8] for i in range(0, len(str), 8)]
def split_string_by_9(str):
"""
将字符串s按每9个字符进行分割
:param str: 输入的字符串
:return: 分割后的字符串列表
"""
return [str[i:i+9] for i in range(0, len(str), 9)]
# 示例用法
input_string = "8nCDq36gzGn8hf4M2HJUsn4aYcYRBSJwj4aE0hbgpzHb4aHcH1zzC9C3IL"
split_result7 = split_string_by_7(input_string)
print(f"按长度7分割的结果: {split_result7}")
print()
split_result8 = split_string_by_8(input_string)
print(f"按长度8分割的结果: {split_result8}")
print()
split_result9 = split_string_by_9(input_string)
print(f"按长度9分割的结果: {split_result9}")
挨个解密失败了
后来发现base62怎么解密也都不行,它解出来是数字,文本也解不出来,大概思路就是这样
ctf show easyrsa2(还是分解p和q,两个一样的就是p)
获取文件,可以看到题目
e = 65537
n = 23686563925537577753047229040754282953352221724154495390687358877775380147605152455537988563490716943872517593212858326146811511103311865753018329109314623702207073882884251372553225986112006827111351501044972239272200616871716325265416115038890805114829315111950319183189591283821793237999044427887934536835813526748759612963103377803089900662509399569819785571492828112437312659229879806168758843603248823629821851053775458651933952183988482163950039248487270453888288427540305542824179951734412044985364866532124803746008139763081886781361488304666575456680411806505094963425401175510416864929601220556158569443747
c = 1627484142237897613944607828268981193911417408064824540711945192035649088104133038147400224070588410335190662682231189997580084680424209495303078061205122848904648319219646588720994019249279863462981015329483724747823991513714172478886306703290044871781158393304147301058706003793357846922086994952763485999282741595204008663847963539422096343391464527068599046946279309037212859931303335507455146001390326550668531665493245293839009832468668390820282664984066399051403227990068032226382222173478078505888238749583237980643698405005689247922901342204142833875409505180847943212126302482358445768662608278731750064815
e = 65537
n = 22257605320525584078180889073523223973924192984353847137164605186956629675938929585386392327672065524338176402496414014083816446508860530887742583338880317478862512306633061601510404960095143941320847160562050524072860211772522478494742213643890027443992183362678970426046765630946644339093149139143388752794932806956589884503569175226850419271095336798456238899009883100793515744579945854481430194879360765346236418019384644095257242811629393164402498261066077339304875212250897918420427814000142751282805980632089867108525335488018940091698609890995252413007073725850396076272027183422297684667565712022199054289711
c = 2742600695441836559469553702831098375948641915409106976157840377978123912007398753623461112659796209918866985480471911393362797753624479537646802510420415039461832118018849030580675249817576926858363541683135777239322002741820145944286109172066259843766755795255913189902403644721138554935991439893850589677849639263080528599197595705927535430942463184891689410078059090474682694886420022230657661157993875931600932763824618773420077273617106297660195179922018875399174346863404710420166497017196424586116535915712965147141775026549870636328195690774259990189286665844641289108474834973710730426105047318959307995062
先分解n1为p1和q1
p1=149751992878258417619955913803349588855907883795437275015624379454686823076475394292360761230383018058515386650339444595246524276345367505681814522035068825010950620582957883108812048922184886717309007677307472277565963907119402324227023856527902596769190955018836727291623263893333224367236239361837356140243
q1=158171944628434297901073909637722153795182500207437382406943949068719041821522249518991083268349210029996372436712077867872196821502572326830142173784785697378334976861590406851563704862868317200039579262508714027560242806981225550090918382144776028695390747339519174603519115397094447596926441933797085906929
分解n2为p2和q2
p2=148629777091647844246796264243541316933219734934432518942362371402056651201924476622085034421034723763998765357939318936167411912678961237019833852640423223833408458277374583926678987391357358691970765804588287101985728943684133878401175077872266031328212861797034052872034250560671628711714389757777347537077
q2=149751992878258417619955913803349588855907883795437275015624379454686823076475394292360761230383018058515386650339444595246524276345367505681814522035068825010950620582957883108812048922184886717309007677307472277565963907119402324227023856527902596769190955018836727291623263893333224367236239361837356140243
套公式,一个一个来,直接就跑出答案来了
import gmpy2
import binascii
e = 65537
n = 23686563925537577753047229040754282953352221724154495390687358877775380147605152455537988563490716943872517593212858326146811511103311865753018329109314623702207073882884251372553225986112006827111351501044972239272200616871716325265416115038890805114829315111950319183189591283821793237999044427887934536835813526748759612963103377803089900662509399569819785571492828112437312659229879806168758843603248823629821851053775458651933952183988482163950039248487270453888288427540305542824179951734412044985364866532124803746008139763081886781361488304666575456680411806505094963425401175510416864929601220556158569443747
c = 1627484142237897613944607828268981193911417408064824540711945192035649088104133038147400224070588410335190662682231189997580084680424209495303078061205122848904648319219646588720994019249279863462981015329483724747823991513714172478886306703290044871781158393304147301058706003793357846922086994952763485999282741595204008663847963539422096343391464527068599046946279309037212859931303335507455146001390326550668531665493245293839009832468668390820282664984066399051403227990068032226382222173478078505888238749583237980643698405005689247922901342204142833875409505180847943212126302482358445768662608278731750064815
p1=149751992878258417619955913803349588855907883795437275015624379454686823076475394292360761230383018058515386650339444595246524276345367505681814522035068825010950620582957883108812048922184886717309007677307472277565963907119402324227023856527902596769190955018836727291623263893333224367236239361837356140243
q1=158171944628434297901073909637722153795182500207437382406943949068719041821522249518991083268349210029996372436712077867872196821502572326830142173784785697378334976861590406851563704862868317200039579262508714027560242806981225550090918382144776028695390747339519174603519115397094447596926441933797085906929
# 计算 φ(n)
φ=(p1-1)*(q1-1)
# 计算 e 在模 φ(n) 下的逆元
d = gmpy2.invert(e,φ)
# 幂取模,结果是 m = (c^d) mod n
m = gmpy2.powmod(c,d,n)
print(binascii.unhexlify(hex(m)[2:]))
这里其实是想考共模攻击的,就是两个e一样,n,c不同,求出n1与n2的最大公因数即为p,之后就可以得到q和d,从而求解m
ctf show easyrsa3(共模攻击,两个n一样,但e,c不同)
这里看到两个n一样,但是e和c不一样
e = 797
n = 15944475431088053285580229796309956066521520107276817969079550919586650535459242543036143360865780730044733026945488511390818947440767542658956272380389388112372084760689777141392370253850735307578445988289714647332867935525010482197724228457592150184979819463711753058569520651205113690397003146105972408452854948512223702957303406577348717348753106868356995616116867724764276234391678899662774272419841876652126127684683752880568407605083606688884120054963974930757275913447908185712204577194274834368323239143008887554264746068337709465319106886618643849961551092377843184067217615903229068010117272834602469293571
c = 11157593264920825445770016357141996124368529899750745256684450189070288181107423044846165593218013465053839661401595417236657920874113839974471883493099846397002721270590059414981101686668721548330630468951353910564696445509556956955232059386625725883038103399028010566732074011325543650672982884236951904410141077728929261477083689095161596979213961494716637502980358298944316636829309169794324394742285175377601826473276006795072518510850734941703194417926566446980262512429590253643561098275852970461913026108090608491507300365391639081555316166526932233787566053827355349022396563769697278239577184503627244170930
e = 521
n = 15944475431088053285580229796309956066521520107276817969079550919586650535459242543036143360865780730044733026945488511390818947440767542658956272380389388112372084760689777141392370253850735307578445988289714647332867935525010482197724228457592150184979819463711753058569520651205113690397003146105972408452854948512223702957303406577348717348753106868356995616116867724764276234391678899662774272419841876652126127684683752880568407605083606688884120054963974930757275913447908185712204577194274834368323239143008887554264746068337709465319106886618643849961551092377843184067217615903229068010117272834602469293571
c = 6699274351853330023117840396450375948797682409595670560999898826038378040157859939888021861338431350172193961054314487476965030228381372659733197551597730394275360811462401853988404006922710039053586471244376282019487691307865741621991977539073601368892834227191286663809236586729196876277005838495318639365575638989137572792843310915220039476722684554553337116930323671829220528562573169295901496437858327730504992799753724465760161805820723578087668737581704682158991028502143744445435775458296907671407184921683317371216729214056381292474141668027801600327187443375858394577015394108813273774641427184411887546849
使用了相同的模数n,用不同的秘钥e加密同一信息m
这里再解释一下模幂运算:
在RSA加密中,消息 m 被加密为密文 ,c 使用收件人的公钥 (e,n)。公式中的变量和符号解释如下:
- m:要加密的消息(通常是一个整数)。
- e1,e2:收件人的公钥指数(每个收件人都有自己的公钥指数)。
- n:模数(公钥的一部分,通常是两个大质数的乘积)。
- c1,c2:加密后的密文。
再解释下扩展欧几里得算法:
- 给定两个整数 e1 和 e2,扩展欧几里得算法可以找到两个整数 s1 和 s2,使得 e1s1+e2s2=gcd(e1,e2)。
- 如果 e1 和 e2 是互质的,即它们的最大公约数(gcd)为1,那么就有 e1s1+e2s2=1。这里 s1 和 s2 是整数,并且其中一个为正,一个为负。
共模脚本
import gmpy2
import binascii
e1 = 797
n = 15944475431088053285580229796309956066521520107276817969079550919586650535459242543036143360865780730044733026945488511390818947440767542658956272380389388112372084760689777141392370253850735307578445988289714647332867935525010482197724228457592150184979819463711753058569520651205113690397003146105972408452854948512223702957303406577348717348753106868356995616116867724764276234391678899662774272419841876652126127684683752880568407605083606688884120054963974930757275913447908185712204577194274834368323239143008887554264746068337709465319106886618643849961551092377843184067217615903229068010117272834602469293571
c1 = 11157593264920825445770016357141996124368529899750745256684450189070288181107423044846165593218013465053839661401595417236657920874113839974471883493099846397002721270590059414981101686668721548330630468951353910564696445509556956955232059386625725883038103399028010566732074011325543650672982884236951904410141077728929261477083689095161596979213961494716637502980358298944316636829309169794324394742285175377601826473276006795072518510850734941703194417926566446980262512429590253643561098275852970461913026108090608491507300365391639081555316166526932233787566053827355349022396563769697278239577184503627244170930
e2 = 521
c2 = 6699274351853330023117840396450375948797682409595670560999898826038378040157859939888021861338431350172193961054314487476965030228381372659733197551597730394275360811462401853988404006922710039053586471244376282019487691307865741621991977539073601368892834227191286663809236586729196876277005838495318639365575638989137572792843310915220039476722684554553337116930323671829220528562573169295901496437858327730504992799753724465760161805820723578087668737581704682158991028502143744445435775458296907671407184921683317371216729214056381292474141668027801600327187443375858394577015394108813273774641427184411887546849
s = gmpy2.gcdext(e1,e2)# 扩展欧几里得算法
m1 = gmpy2.powmod(c1,s[1],n)
m2 = gmpy2.powmod(c2,s[2],n)
m = (m1*m2)%n
print(binascii.unhexlify(hex(m)[2:]))
ctf show easyrsa4(低加密指数攻击)
打开题目,看着好像套公式就行
e = 3
n = 18970053728616609366458286067731288749022264959158403758357985915393383117963693827568809925770679353765624810804904382278845526498981422346319417938434861558291366738542079165169736232558687821709937346503480756281489775859439254614472425017554051177725143068122185961552670646275229009531528678548251873421076691650827507829859299300272683223959267661288601619845954466365134077547699819734465321345758416957265682175864227273506250707311775797983409090702086309946790711995796789417222274776215167450093735639202974148778183667502150202265175471213833685988445568819612085268917780718945472573765365588163945754761
c = 150409620528139732054476072280993764527079006992643377862720337847060335153837950368208902491767027770946661
分解n为p和q,结果发现分解不了,好像还是它自己
观察一下e发现e相对n和c来说非常小,可能考点就是低加密指数。
低加密指数
- 情况一:
当消息 m 的立方 m^3 小于模数 n 时,加密后的密文 c 等于 m 的立方,即
;
直接对密文 c 开三次方根,得到消息 m:
;
由于 m^3 < n,所以 m 必然是整数,不会出现模运算的余数问题。
- 情况二:
当消息 m 的立方 m^3 大于模数 n 时,情况稍微复杂一些。密文 c 可以表示为:
。
其中 i 是某个整数。我们需要找到合适的 i 使得 c+i⋅n 刚好是某个数的立方,具体步骤如下:
(1)确定 i:我们需要找到一个合适的整数 i,使得 c+i⋅n 是一个完全立方数。
(2)计算可能的 m:一旦找到合适的 i,我们就可以计算:
(3)开三次方根:然后对结果开三次方根,得到原始消息 m:
举例说明
假设我们有以下参数:
- n=1000
- e=3
- 消息 m=1
情况一:如果
显然
,所以我们考虑情况二。
情况二:如果
- 计算密文:
- 找到合适的 i:
我们需要找到一个 i,使得 331+i⋅1000是一个立方数。尝试不同的 i 值:
- 当 i=1 时:
331+1⋅1000=1331, 1331 刚好是
,所以我们找到 i=1。
- 计算消息:
通过这种方法,我们成功恢复了原始消息 m=11。
回到题目
①m3<n,也就是说m3=c。
②m3>n,即(m3+i·n)mod n=c(爆破i)
低加密指数脚本脚本:
import gmpy2
import binascii
e = 3
n = 18970053728616609366458286067731288749022264959158403758357985915393383117963693827568809925770679353765624810804904382278845526498981422346319417938434861558291366738542079165169736232558687821709937346503480756281489775859439254614472425017554051177725143068122185961552670646275229009531528678548251873421076691650827507829859299300272683223959267661288601619845954466365134077547699819734465321345758416957265682175864227273506250707311775797983409090702086309946790711995796789417222274776215167450093735639202974148778183667502150202265175471213833685988445568819612085268917780718945472573765365588163945754761
c = 150409620528139732054476072280993764527079006992643377862720337847060335153837950368208902491767027770946661
i=0
while True:
#gmpy2.iroot(x,n) x开n次根
#gmpy2.iroot(x, n) 返回一个元组 (root, is_exact),root代表 x 的 n 次根的整数部分;is_exact 是一个布尔值,表示 x 是否是一个完全的 n 次幂(即 root 的 n 次方是否等于 x)。
if gmpy2.iroot((c+i*n),3)[1] == True: #[1] 代表 is_exact,即一个布尔值,如果 x 是完全的 n 次幂,则 is_exact 为 True,否则为 False。
m = gmpy2.iroot((c+i*n),3)[0] #[0] 代表 root,即整数部分的 n 次根。
break
i += 1
print(binascii.unhexlify(hex(m)[2:]))
ctf show easyrsa5(套公式)
打开题目
e = 284100478693161642327695712452505468891794410301906465434604643365855064101922252698327584524956955373553355814138784402605517536436009073372339264422522610010012877243630454889127160056358637599704871937659443985644871453345576728414422489075791739731547285138648307770775155312545928721094602949588237119345
n = 468459887279781789188886188573017406548524570309663876064881031936564733341508945283407498306248145591559137207097347130203582813352382018491852922849186827279111555223982032271701972642438224730082216672110316142528108239708171781850491578433309964093293907697072741538649347894863899103340030347858867705231
c = 350429162418561525458539070186062788413426454598897326594935655762503536409897624028778814302849485850451243934994919418665502401195173255808119461832488053305530748068788500746791135053620550583421369214031040191188956888321397450005528879987036183922578645840167009612661903399312419253694928377398939392827
p=18489327396055733397216193236128138397765028288613793035021305599301380136673327250408422592244732819005905679957567952974717041052102175277835219391448987
q=25336772790324258952117622504537139442881120269760383961991795601846585772802865528712760553670210656524156997774484665833049279421936394718949688217533213
套公式获取flag
import gmpy2
import binascii
e = 284100478693161642327695712452505468891794410301906465434604643365855064101922252698327584524956955373553355814138784402605517536436009073372339264422522610010012877243630454889127160056358637599704871937659443985644871453345576728414422489075791739731547285138648307770775155312545928721094602949588237119345
n = 468459887279781789188886188573017406548524570309663876064881031936564733341508945283407498306248145591559137207097347130203582813352382018491852922849186827279111555223982032271701972642438224730082216672110316142528108239708171781850491578433309964093293907697072741538649347894863899103340030347858867705231
c = 350429162418561525458539070186062788413426454598897326594935655762503536409897624028778814302849485850451243934994919418665502401195173255808119461832488053305530748068788500746791135053620550583421369214031040191188956888321397450005528879987036183922578645840167009612661903399312419253694928377398939392827
p=18489327396055733397216193236128138397765028288613793035021305599301380136673327250408422592244732819005905679957567952974717041052102175277835219391448987
q=25336772790324258952117622504537139442881120269760383961991795601846585772802865528712760553670210656524156997774484665833049279421936394718949688217533213
# 计算 φ(n)
φ=(p-1)*(q-1)
# 计算 e 在模 φ(n) 下的逆元
d = gmpy2.invert(e,φ)
# 幂取模,结果是 m = (c^d) mod n
m = gmpy2.powmod(c,d,n)
print(binascii.unhexlify(hex(m)[2:]))
ctf show easyrsa6(脚本题,逐段分析)
打开是一个脚本
import gmpy2,libnum
from Crypto.Util.number import getPrime
from secret import flag
e = 0x10001
p = getPrime(1024)
q = gmpy2.next_prime(p)
n = p * q
print("n =",n)
m = libnum.s2n(flag)
c = pow(m,e,n)
print("c =", c)
# n = 26737417831000820542131903300607349805884383394154602685589253691058592906354935906805134188533804962897170211026684453428204518730064406526279112572388086653330354347467824800159214965211971007509161988095657918569122896402683130342348264873834798355125176339737540844380018932257326719850776549178097196650971801959829891897782953799819540258181186971887122329746532348310216818846497644520553218363336194855498009339838369114649453618101321999347367800581959933596734457081762378746706371599215668686459906553007018812297658015353803626409606707460210905216362646940355737679889912399014237502529373804288304270563
# c = 18343406988553647441155363755415469675162952205929092244387144604220598930987120971635625205531679665588524624774972379282080365368504475385813836796957675346369136362299791881988434459126442243685599469468046961707420163849755187402196540739689823324440860766040276525600017446640429559755587590377841083082073283783044180553080312093936655426279610008234238497453986740658015049273023492032325305925499263982266317509342604959809805578180715819784421086649380350482836529047761222588878122181300629226379468397199620669975860711741390226214613560571952382040172091951384219283820044879575505273602318856695503917257
这里就要逐段分析代码了
- 设定公共指数e为0x10001,也就是十六进制的65537,这是RSA加密中常用的公共指数。
- p = getPrime(1024):生成一个1024位的随机素数p
- q = gmpy2.next_prime(p):找到比p大的下一个素数q。
- n = p * q:计算n,这是RSA加密的模数,由两个大素数p和q相乘得到。
- print("n =",n):输出n的值。
- m = libnum.s2n(flag):将秘密消息flag转换为一个大整数m。
- c = pow(m, e, n):使用RSA加密公式进行加密,计算密文c。公式是c = m^e % n。
- print("c =", c):输出密文c的值。
逆向获取flag脚本
import gmpy2
import libnum
import binascii
# 已知参数
e = 0x10001
n = 26737417831000820542131903300607349805884383394154602685589253691058592906354935906805134188533804962897170211026684453428204518730064406526279112572388086653330354347467824800159214965211971007509161988095657918569122896402683130342348264873834798355125176339737540844380018932257326719850776549178097196650971801959829891897782953799819540258181186971887122329746532348310216818846497644520553218363336194855498009339838369114649453618101321999347367800581959933596734457081762378746706371599215668686459906553007018812297658015353803626409606707460210905216362646940355737679889912399014237502529373804288304270563
c = 18343406988553647441155363755415469675162952205929092244387144604220598930987120971635625205531679665588524624774972379282080365368504475385813836796957675346369136362299791881988434459126442243685599469468046961707420163849755187402196540739689823324440860766040276525600017446640429559755587590377841083082073283783044180553080312093936655426279610008234238497453986740658015049273023492032325305925499263982266317509342604959809805578180715819784421086649380350482836529047761222588878122181300629226379468397199620669975860711741390226214613560571952382040172091951384219283820044879575505273602318856695503917257
# 估计 p 和 q
p = gmpy2.mpz(gmpy2.iroot(n, 2)[0]) # 粗略估计 p 的初始值
while True:
if n % p == 0:
q = n // p
if gmpy2.is_prime(p) and gmpy2.is_prime(q):
break
p = gmpy2.next_prime(p)
# 计算 φ(n)
phi_n = (p - 1) * (q - 1)
# 计算私钥 d
d = gmpy2.invert(e, phi_n)
m = gmpy2.powmod(c,d,n)
print(binascii.unhexlify(hex(m)[2:]))
这里对关键代码讲解一下:
# 估计 p 和 q
p = gmpy2.mpz(gmpy2.iroot(n, 2)[0]) # 粗略估计 p 的初始值
while True:
if n % p == 0:
q = n // p
if gmpy2.is_prime(p) and gmpy2.is_prime(q):
break
p = gmpy2.next_prime(p)
- gmpy2.iroot(n, 2)[0] 计算 n 的平方根,并取整数部分。这是因为 p 和 q 是两个相近的素数, p≈q,所以 p 和 q 的值会在 n 的平方根附近。
- gmpy2.mpz 将结果转换为 GMP 多精度整数类型。
- 下面一个循环尝试找到 p 和 q,具体步骤如下:
- if n % p == 0:检查当前猜测的 p 是否是 n 的因子。如果 n 能够被 p 整除,那么 p 可能是 n 的一个素因子。
- q = n // p:如果 p 是 n 的因子,计算 q,即 n 除以 p。
- if gmpy2.is_prime(p) and gmpy2.is_prime(q):检查 p 和 q 是否都是素数。如果是,说明我们找到了正确的 p 和 q,跳出循环。
- p = gmpy2.next_prime(p):如果 p 不是 n 的因子,或 q 不是素数,那么尝试下一个素数 p,即 p 的下一个素数,继续循环。
ctf show easyrsa7(p_high)
再看这个题目:
e = 0x10001
p>>128<<128 = 0xd1c520d9798f811e87f4ff406941958bab8fc24b19a32c3ad89b0b73258ed3541e9ca696fd98ce15255264c39ae8c6e8db5ee89993fa44459410d30a0a8af700ae3aee8a9a1d6094f8c757d3b79a8d1147e85be34fb260a970a52826c0a92b46cefb5dfaf2b5a31edf867f8d34d2222900000000000000000000000000000000
n = 0x79e0bf9b916e59286163a1006f8cefd4c1b080387a6ddb98a3f3984569a4ebb48b22ac36dff7c98e4ebb90ffdd9c07f53a20946f57634fb01f4489fcfc8e402865e152820f3e2989d4f0b5ef1fb366f212e238881ea1da017f754d7840fc38236edba144674464b661d36cdaf52d1e5e7c3c21770c5461a7c1bc2db712a61d992ebc407738fc095cd8b6b64e7e532187b11bf78a8d3ddf52da6f6a67c7e88bef5563cac1e5ce115f3282d5ff9db02278859f63049d1b934d918f46353fea1651d96b2ddd874ec8f1e4b9d487d8849896d1c21fb64029f0d6f47e560555b009b96bfd558228929a6cdf3fb6d47a956829fb1e638fcc1bdfad4ec2c3590dea1ed3
c = 0x1b2b4f9afed5fb5f9876757e959c183c2381ca73514b1918d2f123e386bebe9832835350f17ac439ac570c9b2738f924ef49afea02922981fad702012d69ea3a3c7d1fc8efc80e541ca2622d7741090b9ccd590906ac273ffcc66a7b8c0d48b7d62d6cd6dd4cd75747c55aac28f8be3249eb255d8750482ebf492692121ab4b27b275a0f69b15baef20bf812f3cbf581786128b51694331be76f80d6fb1314d8b280eaa16c767821b9c2ba05dfde5451feef22ac3cb3dfbc88bc1501765506f0c05045184292a75c475486b680f726f44ef8ddfe3c48f75bb03c8d44198ac70e6b7c885f53000654db22c8cee8eb4f65eaeea2da13887aaf53d8c254d2945691
这里要讲解一下每一个参数:
- e = 0x10001:这是公共指数,通常取值为65537 (即十六进制的0x10001),在RSA中是一个常见的选择。
- p >> 128 << 128 = 0xd1c520d9798f811e87f4ff406941958bab8fc24b19a32c3ad89b0b73258ed3541e9ca696fd98ce15255264c39ae8c6e8db5ee89993fa44459410d30a0a8af700ae3aee8a9a1d6094f8c757d3b79a8d1147e85be34fb260a970a52826c0a92b46cefb5dfaf2b5a31edf867f8d34d2222900000000000000000000000000000000 (先右移再左移是这个一长串值)
-
- p >> 128 << 128 表示将 p 右移128位再左移128位,这样可以将低128位全部置零,即保留高位128位。
- 模数 n,它是两个大素数 p 和 q 的乘积,即 n=p×q。
- 密文c:加密后的密文 c。
理解了这个,再做这道题其实就很简单了。
# 特殊的 p 值表示
p_high = 0xd1c520d9798f811e87f4ff406941958bab8fc24b19a32c3ad89b0b73258ed3541e9ca696fd98ce15255264c39ae8c6e8db5ee89993fa44459410d30a0a8af700ae3aee8a9a1d6094f8c757d3b79a8d1147e85be34fb260a970a52826c0a92b46cefb5dfaf2b5a31edf867f8d34d22229
p = p_high << 128
但是这题的脚本我一直没跑出来,去看网上别的大神,都用到了一个工具把p跑出来
p=147305526294483975294006704928271118039370615054437206404408410848858740256154476278591035455064149531353089038270283281541411458250950936656537283482331598521457077465891874559349872035197398406708610440618635013091489698011474611145014167945729411970665381793142591665313979405475889978830728651549052207969
套公式就出来了
import gmpy2
import binascii
# 给定的参数
e = 0x10001
n = 0x79e0bf9b916e59286163a1006f8cefd4c1b080387a6ddb98a3f3984569a4ebb48b22ac36dff7c98e4ebb90ffdd9c07f53a20946f57634fb01f4489fcfc8e402865e152820f3e2989d4f0b5ef1fb366f212e238881ea1da017f754d7840fc38236edba144674464b661d36cdaf52d1e5e7c3c21770c5461a7c1bc2db712a61d992ebc407738fc095cd8b6b64e7e532187b11bf78a8d3ddf52da6f6a67c7e88bef5563cac1e5ce115f3282d5ff9db02278859f63049d1b934d918f46353fea1651d96b2ddd874ec8f1e4b9d487d8849896d1c21fb64029f0d6f47e560555b009b96bfd558228929a6cdf3fb6d47a956829fb1e638fcc1bdfad4ec2c3590dea1ed3
c = 0x1b2b4f9afed5fb5f9876757e959c183c2381ca73514b1918d2f123e386bebe9832835350f17ac439ac570c9b2738f924ef49afea02922981fad702012d69ea3a3c7d1fc8efc80e541ca2622d7741090b9ccd590906ac273ffcc66a7b8c0d48b7d62d6cd6dd4cd75747c55aac28f8be3249eb255d8750482ebf492692121ab4b27b275a0f69b15baef20bf812f3cbf581786128b51694331be76f80d6fb1314d8b280eaa16c767821b9c2ba05dfde5451feef22ac3cb3dfbc88bc1501765506f0c05045184292a75c475486b680f726f44ef8ddfe3c48f75bb03c8d44198ac70e6b7c885f53000654db22c8cee8eb4f65eaeea2da13887aaf53d8c254d2945691
# 特殊的 p 值表示
p=147305526294483975294006704928271118039370615054437206404408410848858740256154476278591035455064149531353089038270283281541411458250950936656537283482331598521457077465891874559349872035197398406708610440618635013091489698011474611145014167945729411970665381793142591665313979405475889978830728651549052207969
# 计算 q
q = n // p
# 计算 φ(n)
φ = (p - 1) * (q - 1)
# 计算 e 在模 φ(n) 下的逆元
d = gmpy2.invert(e,φ)
# 幂取模,结果是 m = (c^d) mod n
m = gmpy2.powmod(c,d,n)
print(binascii.unhexlify(hex(m)[2:]))
ctf show easyrsa8()
这题是解压下来是两个文件
利用脚本分解n和e
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from numpy import long
public = RSA.importKey(open('/Users/zhangxu/Downloads/easyrsa8/public.key').read())
n = public.n
e = public.e
print(n)
print(e)
n=10306247299477991196335954707897189353577589618180446614762218980226685668311143526740800444344046158260556585833057716406703213966249956775927205061731821632025483608182881492214855240841820024816859031176291364212054293818204399157346955465232586109199762630150640804366966946066155685218609638749171632685073
e=65537
或者用工具也能分解出n和e
套rsa解密公式
import gmpy2
from Crypto.Cipher import PKCS1_OAEP
#PKCS1 OAEP 是一种基于 RSA 和 OAEP 填充的非对称密码
from Crypto.PublicKey import RSA
e = 65537
n = 10306247299477991196335954707897189353577589618180446614762218980226685668311143526740800444344046158260556585833057716406703213966249956775927205061731821632025483608182881492214855240841820024816859031176291364212054293818204399157346955465232586109199762630150640804366966946066155685218609638749171632685073
p = 106249972159566919549855203174197828387397831115262336234662051342543151219702510584956705611794290291345944183845955839244363030579896461607496959399297130227066841321473005074379950936513608503266587950271044991876848389878395867601515004796212227929894460104645781488319246866661398816686697306692491058609
q = n//p
phi_n = (p-1)*(q-1)
d = int(gmpy2.invert(e,phi_n))
rsakey = RSA.importKey(open(r'/public.key', 'r').read())
privatekey = RSA.construct((n,e,d,p,q))
rsa = PKCS1_OAEP.new(privatekey)
m = rsa.decrypt(open(r'/flag.enc', 'rb').read())
print(m)