隐蔽的背包问题
题目:
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:
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}