ctf-crypto刷题第一期

        换新工作以后,攻防技术接触越来越少,但是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
  1. 创建逆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]
  1. 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加密的过程:

  1. 选择两个大质数:p 和 q。
  2. 计算它们的乘积:n = p * q。
  3. 计算 Euler 函数:φ(n) = (p - 1) * (q - 1)。
  4. 选择公钥指数:e,满足 1 < e < φ(n),且 e 与 φ(n) 互质。(互质概念:例如 8 与 10 的最大公约数是 2,不是 1,因此它们并不互质;又例如 7, 10, 13 的最大公约数是 1,因此它们互质。)
  5. 计算私钥指数: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)。公式中的变量和符号解释如下:

  1. m要加密的消息(通常是一个整数)
  2. e1,e2收件人的公钥指数(每个收件人都有自己的公钥指数)
  3. n模数(公钥的一部分,通常是两个大质数的乘积)
  4. 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

情况一:如果

显然

,所以我们考虑情况二。


情况二:如果

  1. 计算密文:

  2. 找到合适的 i:

我们需要找到一个 i,使得 331+i⋅1000是一个立方数。尝试不同的 i 值:

  • 当 i=1 时:

331+1⋅1000=1331, 1331 刚好是

,所以我们找到 i=1。

  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,具体步骤如下:
  1. if n % p == 0:检查当前猜测的 p 是否是 n 的因子。如果 n 能够被 p 整除,那么 p 可能是 n 的一个素因子。
  2. q = n // p:如果 p 是 n 的因子,计算 q,即 n 除以 p。
  3. if gmpy2.is_prime(p) and gmpy2.is_prime(q):检查 p 和 q 是否都是素数。如果是,说明我们找到了正确的 p 和 q,跳出循环。
  4. 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)


 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值