隐蔽的背包问题

题目:

from random import shuffle
from Crypto.Util.number import getPrime
from random import choice, randint

# flag来源
flag = b"VNCTF{xxxxxxx}"
assert len(flag)<100
FLAG1=flag[:32]
FLAG2=flag[32:]

# part1
# ......

# part2
class FlagEncoder:
    def __init__(self, flag: bytes, e: int = 65537):
        self.flag = flag
        self.e = e
        self.encoded_flag = []
        self.n = None
        self.c = None

    def process(self):
        for idx, byte in enumerate(self.flag):
            self.encoded_flag.extend([idx + 0x1234] * byte)
        shuffle(self.encoded_flag)
        p, q = getPrime(1024), getPrime(1024)
        self.n = p * q
        self.c = sum(pow(m, self.e, self.n) for m in self.encoded_flag) % self.n
        print(f"{self.n = }\n{self.e = }\n{self.c = }\n")

encoder = FlagEncoder(FLAG2)
encoder.process()

'''
self.n = 16880924655573626811763865075201881594085658222047473444427295924181371341406971359787070757333746323665180258925280624345937931067302673406166527557074157053768756954809954623549764696024889104571712837947570927160960150469942624060518463231436452655059364616329589584232929658472512262657486196000339385053006838678892053410082983193195313760143294107276239320478952773774926076976118332506709002823833966693933772855520415233420873109157410013754228009873467565264170667190055496092630482018483458436328026371767734605083997033690559928072813698606007542923203397847175503893541662307450142747604801158547519780249
self.e = 65537
self.c = 9032357989989555941675564821401950498589029986516332099523507342092837051434738218296315677579902547951839735936211470189183670081413398549328213424711630953101945318953216233002076158699383482500577204410862449005374635380205765227970071715701130376936200309849157913293371540209836180873164955112090522763296400826270168187684580268049900241471974781359543289845547305509778118625872361241263888981982239852260791787315392967289385225742091913059414916109642527756161790351439311378131805693115561811434117214628348326091634314754373956682740966173046220578724814192276046560931649844628370528719818294616692090359
'''

解题思路:

  • 首先我们解读一下代码,我们知道这个extend方法的作用是将一个可迭代对象(如列表、元组等)的所有元素添加到当前列表的末尾

self.encoded_flag.extend([idx + 0x1234] * byte)

这里[idx + 0x1234] * byte表示创建一个列表,其中包含byte个相同的元素idx + 0x1234

然后extend方法将这个列表中的所有元素逐个添加到self.encoded_flag

具体示例:假设idx = 1,byte = 3,0x1234 = 4660,那么:

[idx + 0x1234] * byte = [4661, 4661, 4661]

如果self.encoded_flag之前是[100, 200],执行extend后:

self.encoded_flag = [100, 200, 4661, 4661, 4661]

  • shuffle是Python标准库random模块中的一个函数,用于随机打乱列表中元素的顺序,它的作用是将列表中的元素重新排列,使得原来的顺序变得不可预测
  • 其实这是<font style="color:rgb(77, 77, 77);">byte</font>个相同的元素,那就是个加法 a0k0 + a1k1 + ... =0 ,这其实就是背包加密的形式
  • 直接LLL算法求解即可

解答:

法1:

k = 70 #假设的长度
e = 65537
n = 16880924655573626811763865075201881594085658222047473444427295924181371341406971359787070757333746323665180258925280624345937931067302673406166527557074157053768756954809954623549764696024889104571712837947570927160960150469942624060518463231436452655059364616329589584232929658472512262657486196000339385053006838678892053410082983193195313760143294107276239320478952773774926076976118332506709002823833966693933772855520415233420873109157410013754228009873467565264170667190055496092630482018483458436328026371767734605083997033690559928072813698606007542923203397847175503893541662307450142747604801158547519780249
c = 9032357989989555941675564821401950498589029986516332099523507342092837051434738218296315677579902547951839735936211470189183670081413398549328213424711630953101945318953216233002076158699383482500577204410862449005374635380205765227970071715701130376936200309849157913293371540209836180873164955112090522763296400826270168187684580268049900241471974781359543289845547305509778118625872361241263888981982239852260791787315392967289385225742091913059414916109642527756161790351439311378131805693115561811434117214628348326091634314754373956682740966173046220578724814192276046560931649844628370528719818294616692090359
# 构建矩阵 A
A = matrix(ZZ, 1, k+1, [int(pow(i+0x1234, e, n)) for i in range(k)] + [n])
# 构建块矩阵 M
M = block_matrix(ZZ, [[1, A.T], [matrix(ZZ, 1, k+1, [0]*(k+1)), -c]])

L = M.LLL()[0]

print(L)
#(105, 48, 110, 115, 95, 79, 110, 95, 82, 101, 99, 48, 118, 101, 114, 105, 110, 103, 95, 84, 104, 101, 95, 77, 101, 115, 115, 97, 103, 101, 115, 125, 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, -1590, 0)
L0_list = list(L)

#截取前 80 个元素(如果长度足够)
L0_list_80 = L0_list[:80] if len(L0_list) >= 80 else L0_list

#过滤掉无效的ASCII码值(如负数和非打印字符)
valid_ascii_values = [value for value in L0_list_80 if 0 <= value <= 127]

characters = [chr(value) for value in valid_ascii_values]
result_string = ''.join(characters)
print("恢复的字符串:", result_string)
#恢复的字符串: i0ns_On_Rec0vering_The_Messages}

法2:

CrewCTF-2024-Public/challenges/crypto/Read between the lines/solve/solve.py at main · Thehackerscrew/CrewCTF-2024-Public

N = 70
e = 65537
n = 16880924655573626811763865075201881594085658222047473444427295924181371341406971359787070757333746323665180258925280624345937931067302673406166527557074157053768756954809954623549764696024889104571712837947570927160960150469942624060518463231436452655059364616329589584232929658472512262657486196000339385053006838678892053410082983193195313760143294107276239320478952773774926076976118332506709002823833966693933772855520415233420873109157410013754228009873467565264170667190055496092630482018483458436328026371767734605083997033690559928072813698606007542923203397847175503893541662307450142747604801158547519780249
c = 9032357989989555941675564821401950498589029986516332099523507342092837051434738218296315677579902547951839735936211470189183670081413398549328213424711630953101945318953216233002076158699383482500577204410862449005374635380205765227970071715701130376936200309849157913293371540209836180873164955112090522763296400826270168187684580268049900241471974781359543289845547305509778118625872361241263888981982239852260791787315392967289385225742091913059414916109642527756161790351439311378131805693115561811434117214628348326091634314754373956682740966173046220578724814192276046560931649844628370528719818294616692090359
cts = [pow(m + 0x1234, e, n) for m in range(N)]

R = 2 ** 1024
M = Matrix([
    [*cts, n, -c],
    *[[0] * i + [1] + [0] * (len(cts) - i + 1) for i in range(len(cts))],
    [0] * len(cts) + [0, R]
])

L = M.T.LLL()
assert L[-1][0] == 0 and L[-1][-1] == R
res = L[-1][1:-1]

flag = [v for v in res if v != 0]
print(bytes(flag).decode())
# i0ns_On_Rec0vering_The_Messages}
posted @ 2025-03-12 00:08  sevensnight  阅读(72)  评论(0)    收藏  举报