H/NCTF2025复现


MISC

乱成一锅粥了

题目描述:

1
小肖望着乱成一锅粥的电脑心如死灰,既然乱成一锅粥不妨低头将它喝下(flag为H&NCTF{})

流量文件http导出对象,导出9个zip文件

查看里面txt文件名均为数字的md5值

按顺序提取txt内容连接,发现为iV开头的base64,即png图片的base64的形式,输出png文件

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
from hashlib import md5
from base64 import b64decode
import os

# 指定工作目录(修改为你的实际路径)
WORK_DIR = r"D:\\tmp\\zhou\\x\\"

def main():
# 检查工作目录是否存在
if not os.path.exists(WORK_DIR):
print(f"错误: 工作目录 '{WORK_DIR}' 不存在")
return

# 创建输出目录
output_dir = os.path.join(WORK_DIR, 'output')
os.makedirs(output_dir, exist_ok=True)

# 获取工作目录下的所有子目录
existing_folders = {
name for name in os.listdir(WORK_DIR)
if os.path.isdir(os.path.join(WORK_DIR, name))
}

print(f"找到以下文件夹: {existing_folders}")

# 处理每个文件夹
for folder_name in existing_folders:
output_path = os.path.join(output_dir, f'{folder_name}.png')
input_dir = os.path.join(WORK_DIR, folder_name)

# 收集所有txt文件内容
all_contents = []

# 处理1到50的文件
for i in range(1, 51):
# 生成MD5哈希
h1 = str(i).zfill(2).encode()
h2 = md5(h1).hexdigest()

file_path = os.path.join(input_dir, f'{h2}.txt')

# 检查文件是否存在
if os.path.isfile(file_path):
try:
with open(file_path, 'r') as f:
all_contents.append(f.read())
except Exception as e:
print(f"警告: 读取文件 '{file_path}' 时出错: {e}")
else:
print(f"警告: 文件 '{file_path}' 不存在")

# 如果没有内容,跳过此文件夹
if not all_contents:
print(f"警告: 文件夹 '{folder_name}' 中没有有效文件,跳过")
continue

# 拼接内容并解码
combined_content = ''.join(all_contents)

try:
decoded_data = b64decode(combined_content)
except Exception as e:
print(f"错误: 解码文件夹 '{folder_name}' 的数据时出错: {e}")
continue

# 写入PNG文件
try:
with open(output_path, 'wb') as f:
f.write(decoded_data)
print(f"成功生成: {output_path}")
except Exception as e:
print(f"错误: 写入文件 '{output_path}' 时出错: {e}")

if __name__ == "__main__":
main()

运行得到

拼接二维码并扫描二维码

最后flag为

1
H&NCTF{This_wont_be_difficult_for_you}

星辉骑士

题目描述:

1
艾米莉安最近跟着比利迷恋上了星徽骑士,于是找店长借了影片来观看,观看之后,他准备在他的小屋贴上星辉骑士,他手上这份海报好像有些不同,你能帮它找找是哪里的问题吗?(flag为H&NCTF{})

下载附件

改后缀.zip,解压压缩包,在D:\tmp\星辉骑士\星辉骑士\word\media找到flag.zip

伪加密破解

垃圾邮件解密,在999.txt解密得到flag

最后flag为

1
H&NCTF{0231265452-you-kn*w-spanmimic}

芙宁娜的图片

题目描述:

1
旅行者在追踪丘丘人的时候无意间找到了一张关于芙宁娜的老照片,派蒙拿起的时候感觉比普通的照片的重,发现后面有一行字,但你们都不会丘丘人语,推断这张图片这和丘丘人的下一步动作有关,你能帮旅行者破译出这个图片的信息吗?(flag为H&NCTF{})

下载附件

zsteg一把梭

得到key:H&N2025

查看txt文件

brainfuck解密

维吉尼亚解密

最后flag为

1
H&NCTF{Y0u_recognised_the_Chuchu's_plot.}

谁动了黑线?

题目描述:

1
你接到一份神秘交易数据,隐藏着一条错综复杂的“黑线”,请破解其中隐藏的秘密 (最后的flag包上H&NCTF{}提交)

hint:

1
2
3
尝试还原“真正”的交易链,关键在hash

flag内容为一段有意义的字符串

下载附件

最后一列tx_hash是base58,base58解码后,是8位数字+8位字符串的形式,拼接顺序

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import pandas as pd
from io import StringIO

# Load the CSV
try:
df = pd.read_csv('D:\\tmp\\sheidongleheixian\\sheidongleheixian.csv')
except FileNotFoundError:
print("错误:找不到CSV文件,请确保文件路径正确。")
exit(1)
except Exception as e:
print(f"读取CSV文件时发生错误:{e}")
exit(1)

# Base58 decode implementation
alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'

def b58decode(s):
"""将Base58编码的字符串解码为字节"""
num = 0
for char in s:
try:
num = num * 58 + alphabet.index(char)
except ValueError:
raise ValueError(f"无效的Base58字符: {char}")
byte_length = (num.bit_length() + 7) // 8
return num.to_bytes(byte_length, 'big')

# 解码tx_hash并提取信息
try:
df['decoded'] = df['tx_hash'].apply(lambda h: b58decode(h).decode('ascii'))
except UnicodeDecodeError as e:
print(f"解码过程中发生Unicode错误:{e}")
print("提示:可能某些tx_hash无法正确解码为ASCII字符串。")
exit(1)
except Exception as e:
print(f"处理tx_hash时发生错误:{e}")
exit(1)

df['idx'] = df['decoded'].str[2:8].astype(int)
df['tail'] = df['decoded'].str[8:]

# 重构隐藏消息
x = df.sort_values('idx')['tail'].tolist()
decoded_message = []
for k in x:
if k[0].islower() or k[1].islower() or k[2].islower() or k[3].islower():
decoded_message.append(k[:4])

print("解码后的隐藏消息:")
print(''.join(decoded_message))

运行得到

最后flag为

1
H&NCTF{little_dog_is_Aomr!!}

crypto

ez-factor

题目描述:

1
哈基坤的签到题++

下载附件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from Crypto.Util.number import *
import uuid

rbits = 248
Nbits = 1024

p = getPrime(Nbits // 2)
q = getPrime(Nbits // 2)
N = p * q
r = getPrime(rbits)
hint = getPrime(Nbits // 2) * p + r
R = 2^rbits
e=0x10001
n=p*q
phi=(p-1)*(q-1)
flag = b'H&NCTF{' + str(uuid.uuid4()).encode() + b'}'
m=bytes_to_long(flag)
c=pow(m,e,n)
print("N=",N)
print("hint=",hint)
print(c)
N= 155296910351777777627285876776027672037304214686081903889658107735147953235249881743173605221986234177656859035013052546413190754332500394269777193023877978003355429490308124928931570682439681040003000706677272854316717486111569389104048561440718904998206734429111757045421158512642953817797000794436498517023
hint= 128897771799394706729823046048701824275008016021807110909858536932196768365642942957519868584739269771824527061163774807292614556912712491005558619713483097387272219068456556103195796986984219731534200739471016634325466080225824620962675943991114643524066815621081841013085256358885072412548162291376467189508
c=32491252910483344435013657252642812908631157928805388324401451221153787566144288668394161348411375877874802225033713208225889209706188963141818204000519335320453645771183991984871397145401449116355563131852618397832704991151874545202796217273448326885185155844071725702118012339804747838515195046843936285308

考点:ACD(近似公约数)问题

参考

2024-高校密码挑战赛赛题一-wp-crypto | 糖醋小鸡块的blog

k 是 512 位,r 只有 248 ,构造格,能够规约出的小根上界约为243bit,爆破5bit

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
from Crypto.Util.number import *
from tqdm import *
from itertools import *
from multiprocessing import Pool

################################################ gen data
e = 65537
N = 155296910351777777627285876776027672037304214686081903889658107735147953235249881743173605221986234177656859035013052546413190754332500394269777193023877978003355429490308124928931570682439681040003000706677272854316717486111569389104048561440718904998206734429111757045421158512642953817797000794436498517023
hint= 128897771799394706729823046048701824275008016021807110909858536932196768365642942957519868584739269771824527061163774807292614556912712491005558619713483097387272219068456556103195796986984219731534200739471016634325466080225824620962675943991114643524066815621081841013085256358885072412548162291376467189508
c = 32491252910483344435013657252642812908631157928805388324401451221153787566144288668394161348411375877874802225033713208225889209706188963141818204000519335320453645771183991984871397145401449116355563131852618397832704991151874545202796217273448326885185155844071725702118012339804747838515195046843936285308
m = 1
rho = 243
a = ["pad"] + [hint]


def attack(ii):
a = ["pad"] + [hint - 2^243*ii]

################################################ params
t,k = 20,10
R = 2^rho
indices = []
for i in product([i for i in range(t+1)] , repeat=m):
if(sum(list(i)) <= t):
indices.append(["pad"] + list(i))


################################################ attack
PR = ZZ[tuple(f"X{i}" for i in range(m))]
X = ["pad"] + list(PR.gens())
poly = []
monomials=set()
for i in indices:
f = 1
for ij in range(1,len(i)):
f *= (X[ij] - a[ij])^i[ij]
l = max(k-sum(i[1:]),0)
f *= N^l
poly.append(f)
for mono in f.monomials():
monomials.add(mono)


################################################# LLL and resultant to find roots
L = Matrix(ZZ,len(poly),len(monomials))
monomials = sorted(monomials)
for row,shift in enumerate(poly):
for col,monomial in enumerate(monomials):
L[row,col] = shift.monomial_coefficient(monomial)*monomial(*([R]*m))


res = L.LLL()
vec1 = res[0]

h = 0
for idx,monomial in enumerate(monomials):
h += (vec1[idx] // monomial(*([R]*m))) * monomial
h = h.change_ring(ZZ)
res1 = h.monic().roots()

if(res1 != []):
print(ii,res1)

lists = [i for i in range(2^5)]
with Pool(64) as pool:
r = list(pool.imap(attack, lists[::-1]))

运行得到

任意取一组都能恢复r

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import gmpy2
from Crypto.Util.number import long_to_bytes
N= 155296910351777777627285876776027672037304214686081903889658107735147953235249881743173605221986234177656859035013052546413190754332500394269777193023877978003355429490308124928931570682439681040003000706677272854316717486111569389104048561440718904998206734429111757045421158512642953817797000794436498517023
hint= 128897771799394706729823046048701824275008016021807110909858536932196768365642942957519868584739269771824527061163774807292614556912712491005558619713483097387272219068456556103195796986984219731534200739471016634325466080225824620962675943991114643524066815621081841013085256358885072412548162291376467189508
c=32491252910483344435013657252642812908631157928805388324401451221153787566144288668394161348411375877874802225033713208225889209706188963141818204000519335320453645771183991984871397145401449116355563131852618397832704991151874545202796217273448326885185155844071725702118012339804747838515195046843936285308
ii=21
res=13554422673199035891677873264057443320343601269005368232165269523764733091
r=ii*(2**243)+res
p=gmpy2.gcd(hint-r,N)
q=N//p
e=65537
phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
m=pow(c,d,N)
print(long_to_bytes(m))

运行得到

最后flag为

1
H&NCTF{ac354aae-cb6b-4bd1-a9cd-090812b8f93e}

ez-factor-pro

题目描述:

1
哈基坤的签到+1QAQ!

下载附件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from Crypto.Util.number import *
from Crypto.Util.Padding import *
from gmssl.sm4 import CryptSM4, SM4_ENCRYPT
from hashlib import sha256
from random import *
import uuid
rbits = 252
Nbits = 1024

p = getPrime(Nbits//2)
q = getPrime(Nbits//2)
N = p*q
r = getPrime(rbits)
hint = getPrime(Nbits// 2)*p+r
R = 2^rbits
flag = b'H&NCTF{'+str(uuid.uuid4()).encode()+b'}'
leak=p*q*r
r_bytes = long_to_bytes(leak)
iv = r_bytes[:16] if len(r_bytes) >= 16 else r_bytes + b'\0'*(16-len(r_bytes))
key = sha256(str(p + q + r).encode()).digest()[:16]
crypt_sm4 = CryptSM4()
crypt_sm4.set_key(key, SM4_ENCRYPT)
padded_flag = pad(flag, 16)
c = crypt_sm4.crypt_cbc(iv, padded_flag)
print("N=",N)
print("hint=",hint)
print(c)
#N = 133196604547992363575584257705624404667968600447626367604523982016247386106677898877957513177151872429736948168642977575860754686097638795690422242542292618145151312000412007125887631130667228632902437183933840195380816196093162319293698836053406176957297330716990340998802156803899579713165154526610395279999
#hint = 88154421894117450591552142051149160480833170266148800195422578353703847455418496231944089437130332162458102290491849331143073163240148813116171275432632366729218612063176137204570648617681911344674042091585091104687596255488609263266272373788618920171331355912434290259151350333219719321509782517693267379786
#c = 476922b694c764725338cca99d99c7471ec448d6bf60de797eb7cc6e71253221035eb577075f9658ac7f1a40747778ac261787baad21ee567256872fa9400c37

和上一题同理,只不过是爆破9个bit

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
from Crypto.Util.number import *
from tqdm import *
from itertools import *
from multiprocessing import Pool

################################################ gen data

N = 133196604547992363575584257705624404667968600447626367604523982016247386106677898877957513177151872429736948168642977575860754686097638795690422242542292618145151312000412007125887631130667228632902437183933840195380816196093162319293698836053406176957297330716990340998802156803899579713165154526610395279999
c = 0x476922b694c764725338cca99d99c7471ec448d6bf60de797eb7cc6e71253221035eb577075f9658ac7f1a40747778ac261787baad21ee567256872fa9400c37
m = 1
rho = 243
a = ["pad"] + [88154421894117450591552142051149160480833170266148800195422578353703847455418496231944089437130332162458102290491849331143073163240148813116171275432632366729218612063176137204570648617681911344674042091585091104687596255488609263266272373788618920171331355912434290259151350333219719321509782517693267379786]


def attack(ii):
a = ["pad"] + [88154421894117450591552142051149160480833170266148800195422578353703847455418496231944089437130332162458102290491849331143073163240148813116171275432632366729218612063176137204570648617681911344674042091585091104687596255488609263266272373788618920171331355912434290259151350333219719321509782517693267379786 - 2^243*ii]

################################################ params
t,k = 20,10
R = 2^rho
indices = []
for i in product([i for i in range(t+1)] , repeat=m):
if(sum(list(i)) <= t):
indices.append(["pad"] + list(i))


################################################ attack
PR = ZZ[tuple(f"X{i}" for i in range(m))]
X = ["pad"] + list(PR.gens())
poly = []
monomials=set()
for i in indices:
f = 1
for ij in range(1,len(i)):
f *= (X[ij] - a[ij])^i[ij]
l = max(k-sum(i[1:]),0)
f *= N^l
poly.append(f)
for mono in f.monomials():
monomials.add(mono)


################################################# LLL and resultant to find roots
L = Matrix(ZZ,len(poly),len(monomials))
monomials = sorted(monomials)
for row,shift in enumerate(poly):
for col,monomial in enumerate(monomials):
L[row,col] = shift.monomial_coefficient(monomial)*monomial(*([R]*m))


res = L.LLL()
vec1 = res[0]

h = 0
for idx,monomial in enumerate(monomials):
h += (vec1[idx] // monomial(*([R]*m))) * monomial
h = h.change_ring(ZZ)
res1 = h.monic().roots()

if(res1 != []):
print(ii,res1)

lists = [i for i in range(2^9)]
with Pool(64) as pool:
r = list(pool.imap(attack, lists[::-1]))

运行得到

同理还是恢复r

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import gmpy2
from Crypto.Util.number import long_to_bytes

# 给定参数
N = 133196604547992363575584257705624404667968600447626367604523982016247386106677898877957513177151872429736948168642977575860754686097638795690422242542292618145151312000412007125887631130667228632902437183933840195380816196093162319293698836053406176957297330716990340998802156803899579713165154526610395279999
hint = 88154421894117450591552142051149160480833170266148800195422578353703847455418496231944089437130332162458102290491849331143073163240148813116171275432632366729218612063176137204570648617681911344674042091585091104687596255488609263266272373788618920171331355912434290259151350333219719321509782517693267379786
c = 0x476922b694c764725338cca99d99c7471ec448d6bf60de797eb7cc6e71253221035eb577075f9658ac7f1a40747778ac261787baad21ee567256872fa9400c37
ii = 506
res = 14154387562606904198827209207379555465002348385457546116180255002270538669

# 计算r并分解N
r = ii * (2**243) + res
p = gmpy2.gcd(hint - r, N)
q = N // p
assert N == p * q, "因式分解验证失败"
print("p =", p)
print("q =", q)

运行得到

得到p,q,然后解SM4-CBC即可

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from Crypto.Util.number import *
from gmssl.sm4 import CryptSM4, SM4_DECRYPT
from hashlib import sha256
from Crypto.Util.Padding import unpad

# 已知参数
p = 10028729313926419703025256508152026623108338149091078764973884312717908184535793132629646141453659427095349436587466628835078575518082248569520191060305909
q = 13281503606147647246708380767428957306516210204292257132138079387068505557520151605985669600345608943780007813758130736816723511421069886664561045223935011
N = p * q
r = 7166351305785506670352015492214713707534657162937963088592442157834795391917
c = bytes.fromhex("476922b694c764725338cca99d99c7471ec448d6bf60de797eb7cc6e71253221035eb577075f9658ac7f1a40747778ac261787baad21ee567256872fa9400c37")

# 计算 IV
leak = N * r
r_bytes = long_to_bytes(leak)
iv = r_bytes[:16] # SM4的IV是16字节

# 计算 Key
sum_pqr = p + q + r
key = sha256(str(sum_pqr).encode()).digest()[:16]

# SM4-CBC 解密
crypt_sm4 = CryptSM4()
crypt_sm4.set_key(key, SM4_DECRYPT)
decrypted = crypt_sm4.crypt_cbc(iv, c)
flag = unpad(decrypted, 16) # 移除填充

print("Flag:", flag.decode())

运行得到

最后flag为

1
H&NCTF{ac354aae-cb6b-4bd1-a9cd-090812b8f93e}

lcgp

题目描述:

1
哈基坤只会出签到题

下载附件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from Crypto.Util.number import *
import gmpy2
import random
n = getPrime(1024)
flag = b'H&NCTF{' + str(uuid.uuid4()).encode() + b'}'
flag=bytes_to_long(flag)
e = 2024
c=pow(e, flag, n)

class LCG:
def __init__(self, seed, a, b, m):
self.seed = seed
self.a = a
self.b = b
self.m = m

def generate(self):
self.seed = (self.a * self.seed + self.b) % self.m
return self.seed

lcg = LCG(c, getPrime(256), getPrime(256), getPrime(2048))
random = [lcg.generate() for _ in range(5)]

print(random)
print("n=",n)
#[11250327355112956284720719987943941825496074893551827972877616718074592862130806975889275745497426515405562887727117008818863728803549848574821067056997423443681347885027000632462241968640893471352200125748453396098854283137158609264944692129301617338233670002547470932851350750870478630955328653729176440142198779254117385657086615711880537380965161180532127926250520546846863536247569437, 1289730679860726245234376434590068355673648326448223956572444944595048952808106413165882424967688302988257332835229651422892728384363094065438370663362237241013242843898967355558977974152917458085812489310623200114007728021151551927660975648884448177346441902806386690751359848832912607313329587047853601875294089502467524598036474193845319703759478494109845743765770254308199331552085163360820459311523382612948322756700518669154345145757700392164795583041949318636, 147853940073845086740348793965278392144198492906678575722238097853659884813579087132349845941828785238545905768867483183634111847434793587821166882679621234634787376562998606494582491550592596838027522285263597247798608351871499848571767008878373891341861704004755752362146031951465205665840079918938797056361771851047994530311215961536936283541887169156535180878864233663699607369701462321037824218572445283037132205269900255514050653933970174340553425147148993214797622395988788709572605943994223528210919230924346860415844639247799805670459, 7426988179463569301750073197586782838200202717435911385357661153208197570200804485303362695962843396307030986052311117232622043073376409347836815567322367321085387874196758434280075897513536063432730099103786733447352512984165432175254784494400699821500026196293994318206774720213317148132311223050562359314735977091536842516316149049281012797103790472349557847649282356393682360276814293256129426440381745354969522053841093229320186679875177247919985804406150542514337515002645320320069788390314900121917747534146857716743377658436154645197488134340819076585888700553005062311578963869641978771532330577371974731136, 10389979373355413148376869524987139791217158307590828693700943753512488757973725227850725013905113587408391654379552713436220790487026223039058296951420273907725324214990441639760825661323514381671141482079783647253661594138658677104054180912818864005556386671430082941396497098166887200556959866845325602873713813206312644590812141400536476615405444030140762980665885244721798105034497461675317071497925846844396796854201566038890503298824928152263774446268093725702310124363765630370263370678902342200494544961012407826314577564991676315451785987248633724138137813024481818431889574317602521878974976264742037227074]
#n=604805773885048132038788501528078428693141138274580426531445179173412328238102786863592612653315029009606622583856638282837864213048342883583286440071990592001905867027978355755042060684149344414810835371740304319571184567860694439564098306766474576403800046937218588251809179787769286393579687694925268985445059

考点:lcg+dlp

先用lcg的5个输出恢复lcg的参数seed得到密文c

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import math
import gmpy2

random = [
11250327355112956284720719987943941825496074893551827972877616718074592862130806975889275745497426515405562887727117008818863728803549848574821067056997423443681347885027000632462241968640893471352200125748453396098854283137158609264944692129301617338233670002547470932851350750870478630955328653729176440142198779254117385657086615711880537380965161180532127926250520546846863536247569437,
1289730679860726245234376434590068355673648326448223956572444944595048952808106413165882424967688302988257332835229651422892728384363094065438370663362237241013242843898967355558977974152917458085812489310623200114007728021151551927660975648884448177346441902806386690751359848832912607313329587047853601875294089502467524598036474193845319703759478494109845743765770254308199331552085163360820459311523382612948322756700518669154345145757700392164795583041949318636,
147853940073845086740348793965278392144198492906678575722238097853659884813579087132349845941828785238545905768867483183634111847434793587821166882679621234634787376562998606494582491550592596838027522285263597247798608351871499848571767008878373891341861704004755752362146031951465205665840079918938797056361771851047994530311215961536936283541887169156535180878864233663699607369701462321037824218572445283037132205269900255514050653933970174340553425147148993214797622395988788709572605943994223528210919230924346860415844639247799805670459,
7426988179463569301750073197586782838200202717435911385357661153208197570200804485303362695962843396307030986052311117232622043073376409347836815567322367321085387874196758434280075897513536063432730099103786733447352512984165432175254784494400699821500026196293994318206774720213317148132311223050562359314735977091536842516316149049281012797103790472349557847649282356393682360276814293256129426440381745354969522053841093229320186679875177247919985804406150542514337515002645320320069788390314900121917747534146857716743377658436154645197488134340819076585888700553005062311578963869641978771532330577371974731136,
10389979373355413148376869524987139791217158307590828693700943753512488757973725227850725013905113587408391654379552713436220790487026223039058296951420273907725324214990441639760825661323514381671141482079783647253661594138658677104054180912818864005556386671430082941396497098166887200556959866845325602873713813206312644590812141400536476615405444030140762980665885244721798105034497461675317071497925846844396796854201566038890503298824928152263774446268093725702310124363765630370263370678902342200494544961012407826314577564991676315451785987248633724138137813024481818431889574317602521878974976264742037227074
]
n = 604805773885048132038788501528078428693141138274580426531445179173412328238102786863592612653315029009606622583856638282837864213048342883583286440071990592001905867027978355755042060684149344414810835371740304319571184567860694439564098306766474576403800046937218588251809179787769286393579687694925268985445059

s1, s2, s3, s4, s5 = random

T = (s2 - s3)**2 - (s1 - s2)*(s3 - s4)
U = (s3 - s4)**2 - (s2 - s3)*(s4 - s5)
M = math.gcd(T, U)

# Remove small factors
temp = M
for i in range(2, 10**6):
while temp % i == 0:
temp //= i

# Check if temp is prime and 2048 bits
if temp.bit_length() == 2048 and gmpy2.is_prime(temp):
m = temp
else:
# If not, try the next largest factor (for simplicity, but might need factorization)
m = temp # assuming temp is prime

diff1 = s2 - s1
diff2 = s3 - s2
inv_diff2 = gmpy2.invert(diff2, m)
c = (s1 - diff1 * diff1 * inv_diff2) % m

# Ensure c is within the expected range [0, n-1]
if c < n:
c_seed = c
else:
c_seed = c - m

print(f"Recovered seed c: {c_seed}")

然后再解一个DLP(离散对数)问题

exp:

1
2
3
4
5
6
7
8
from Crypto.Util.number import *
n = 604805773885048132038788501528078428693141138274580426531445179173412328238102786863592612653315029009606622583856638282837864213048342883583286440071990592001905867027978355755042060684149344414810835371740304319571184567860694439564098306766474576403800046937218588251809179787769286393579687694925268985445059
e = 2024
c = 98136663393066487319477131255488756533037186459124433869847045986870213783395243380337142782779765255670853582334927187474123853371504168896312528278296763527266828907487342102002206806408616944398694810398049626860321901229014612541564249969665358849039818103044159048535403863928440335143886672949700153798350
G=Zmod(n)
e=G(e)
c=G(c)
print(long_to_bytes(discrete_log(c,e)))

运行得到

最后flag为

1
H&NCTF{7ecf4c8c-e6a5-45c7-b7de-2fecc31d8511}

哈基coke

题目描述:

1
哈基人完成这个签到吧

下载附件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

import matplotlib.pyplot as plt
import cv2
import numpy as np
from PIL import Image
def arnold_encode(image, shuffle_times, a, b):
""" Arnold shuffle for rgb image
Args:
image: input original rgb image
shuffle_times: how many times to shuffle
Returns:
Arnold encode image
"""
arnold_image = np.zeros(shape=image.shape)

h, w = image.shape[0], image.shape[1]
N = h

for time in range(shuffle_times):
for ori_x in range(h):
for ori_y in range(w):

new_x = (1*ori_x + b*ori_y)% N
new_y = (a*ori_x + (a*b+1)*ori_y) % N

arnold_image[new_x, new_y, :] = image[ori_x, ori_y, :]

image = np.copy(arnold_image)

cv2.imwrite('en_flag.png', arnold_image, [int(cv2.IMWRITE_PNG_COMPRESSION), 0])
return arnold_image

img = cv2.imread('coke.png')
arnold_encode(img,6,9,1)

考点:猫脸变换

主要看关键代码

1
arnold_encode(img,6,9,1)

直接使用大佬工具一把梭

最后flag为

1
H&NCTF{haji_coke_you_win}

数据处理

题目描述:

1
我不会出题,应该很简单

下载附件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from Crypto.Util.number import bytes_to_long
import random
flag = b"H&NCTF{}"

btl = str(bytes_to_long(flag))
lowercase = '0123456789'
uppercase = '7***4****5'

table = ''.maketrans(lowercase, uppercase)

new_flag = btl.translate(table)
n = 2 ** 512

m = random.randint(2, n - 1) | 1


c = pow(m, int(new_flag), n)
print('m = ' + str(m))
print('c = ' + str(c))
# m = 5084057673176634704877325918195984684237263100965172410645544705367004138917087081637515846739933954602106965103289595670550636402101057955537123475521383
# c = 2989443482952171039348896269189568991072039347099986172010150242445491605115276953489889364577445582220903996856271544149424805812495293211539024953331399

先根据离散对数求出 new_flag

exp:

1
2
3
4
5
6
7
8
9
from Crypto.Util.number import *
from itertools import *
from tqdm import *

m = 5084057673176634704877325918195984684237263100965172410645544705367004138917087081637515846739933954602106965103289595670550636402101057955537123475521383
c = 2989443482952171039348896269189568991072039347099986172010150242445491605115276953489889364577445582220903996856271544149424805812495293211539024953331399
n = 2 ** 512
new_flag = str(discrete_log(mod(c,n),mod(m,n)))
print(new_flag)

运行得到

爆破变表中未知的7位数

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from Crypto.Util.number import long_to_bytes
import itertools

new_flag = 3282248010524512146638712359816289396373430161050484501341123570760619381019795910712610762203934445754701
num = '0123456789'
lowercase = '0123456789'
# uppercase = '2***7****0'

# 生成所有可能的替换表
for i in itertools.product(num, repeat=3):
for j in itertools.product(num, repeat=4):
uppercase = '7' + ''.join(i) + '4' + ''.join(j) + '5'
table = ''.maketrans(uppercase, lowercase)
m = str(new_flag).translate(table)
flag = long_to_bytes(int(m))
if b'H&NCTF{' in flag and b'}' in flag:
print(f'uppercase = {uppercase}, flag = {flag}')

运行得到

最后flag为

1
H&NCTF{cut_cut_rrioajtfijrwegeriogjiireigji}

为什么出题人的rsa总是ez

题目描述:

1
复习一下。。。大佬出题全是ezrsa,害苦我了,提交记得加上H&NCTF{}。

下载附件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#part 1

def pad(flag, bits=1024):
pad = os.urandom(bits//8 - len(flag))
return int.from_bytes(flag + pad, "big")

p = random_prime(2**1024)
q = random_prime(2**1024)
a = randint(0, 2**1024)
b = randint(0, 2**1024)
n = p * q
e = 0x10001
flag = b''
m = pad(flag)
assert m < n

c = pow(m, e, n)

print(f"c={c}")
print(f"n={n}")
print(f"h1={p + b * q}")
print(f"h2={a * p + q}")
# c=13148687178480196374316468746303529314940770955906554155276099558796308164996908275540972246587924459788286109602343699872884525600948529446071271042497049233796074202353913271513295267105242313572798635502497823862563815696165512523074252855130556615141836416629657088666030382516860597286299687178449351241568084947058615139183249169425517358363928345728230233160550711153414555500038906881581637368920188681358625561539325485686180307359210958952213244628802673969397681634295345372096628997329630862000359069425551673474533426265702926675667531063902318865506356674927615264099404032793467912541801255735763704043
# n=13718277507497477508850292481640653320398820265455820215511251843542886373380880887850571647060788265498378060163112689840208264538965960596605641194331300743676780910818492860412739541418029075802834265712602393103809065720527365081016381358333378953245379751008531500896923727040455566953960991908174586311899809864209624888469263612475732913062035036254077225370843701146080145441104733074178115602425412116325647598625157922655504918118208783230138448694045386019901732846478340735331718476554208157393418221315041837392020742062275999319586357229583509788489495876723122993592623230858393165458733055504467513549
# h1=6992022576367328281523272055384380182550712894467837916200781058620282657859189270338635886912232754034211897894637971546032107000253692739473463119025570291091085702056938901846349325941043398928197991115231668917435951127329817379935880511925882734157491821315858319170121031835598580384038723788681860763814776365440362143661999054338470989558459179388468943933975861549233231199667742564080001256192881732567616103760815633265325456143601649393547666835326272408622540044065067528568675569233240785553062685974593620235466519632833169291153478793523397788719000334929715524989845012633742964209311952378479134661
# h2=16731800146050995761642066586565348732313856101572403535951688869814016691871958158137790504490910445304384109605408840493227057830017039824412834989258703833576252634055087138315434304691218949240382395879124201923060510497916818961571111218224960267593032380037212325935576750663442553781924370849537501656957488833521657563900462052017695599020610911371304659875887924695896434699048696392210066253577839887826292569913713802634067508141124685789817330268562127695548527522031774601654778934513355315628270319037043809972087930951609429846675450469414212384044849089372435124609387061864545559812994515828333828939

#part 2

from Crypto.Util.number import *
from gmpy2 import *
a = random_prime()
b = random_prime()
g = random_prime()
h = 2*g*a*b+a+b
while not is_prime(h):
a = random_prime()
b = random_prime()
g = random_prime()
h = 2*g*a*b+a+b
N = 2*h*g+1
e from part1's flag
flag=b''
c=pow(bytes_to_long(flag),e,N)
print(N)
print(g)
print(c)
#N=10244621233521168199001177069337072125430662416754674144307553476569744623474797179990380824494968546110022341144527766891662229403969035901337876527595841503498459533492730326942662450786522178313517616168650624224723066308178042783540825899502172432884573844850572330970359712379107318586435848029783774998269247992706770665069866338710349292941829996807892349030660021792813986069535854445874069535737849684959397062724387110903918355074327499675776518032266136930264621047345474782910332154803497103199598761422179303240476950271702406633802957400888398042773978322395227920699611001956973796492459398737390290487
#g=2296316201623391483093360819129167852633963112610999269673854449302228853625418585609211427788830598219647604923279054340009043347798635222302374950707
#c=7522161394702437062976246147354737122573350166270857493289161875402286558096915490526439656281083416286224205494418845652940140144292045338308479237214749282932144020368779474518032067934302376430305635297260147830918089492765917640581392606559936829974748692299762475615766076425088306609448483657623795178727831373194757182797030376302086360751637238867384469269953187938304369668436238848537646544257504724753333177938997524154486602644412199535102323238852958634746165559537630341890450666170836721803871120344373143081664567068672230842855208267929484000179260292518351155693154372172449820053764896414799137097

可以看出分了两部分

part1部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def pad(flag, bits=1024):
pad = os.urandom(bits//8 - len(flag))
return int.from_bytes(flag + pad, "big")

p = random_prime(2**1024)
q = random_prime(2**1024)
a = randint(0, 2**1024)
b = randint(0, 2**1024)
n = p * q
e = 0x10001
flag = b''
m = pad(flag)
assert m < n

c = pow(m, e, n)

print(f"c={c}")
print(f"n={n}")
print(f"h1={p + b * q}")
print(f"h2={a * p + q}")
# c=13148687178480196374316468746303529314940770955906554155276099558796308164996908275540972246587924459788286109602343699872884525600948529446071271042497049233796074202353913271513295267105242313572798635502497823862563815696165512523074252855130556615141836416629657088666030382516860597286299687178449351241568084947058615139183249169425517358363928345728230233160550711153414555500038906881581637368920188681358625561539325485686180307359210958952213244628802673969397681634295345372096628997329630862000359069425551673474533426265702926675667531063902318865506356674927615264099404032793467912541801255735763704043
# n=13718277507497477508850292481640653320398820265455820215511251843542886373380880887850571647060788265498378060163112689840208264538965960596605641194331300743676780910818492860412739541418029075802834265712602393103809065720527365081016381358333378953245379751008531500896923727040455566953960991908174586311899809864209624888469263612475732913062035036254077225370843701146080145441104733074178115602425412116325647598625157922655504918118208783230138448694045386019901732846478340735331718476554208157393418221315041837392020742062275999319586357229583509788489495876723122993592623230858393165458733055504467513549
# h1=6992022576367328281523272055384380182550712894467837916200781058620282657859189270338635886912232754034211897894637971546032107000253692739473463119025570291091085702056938901846349325941043398928197991115231668917435951127329817379935880511925882734157491821315858319170121031835598580384038723788681860763814776365440362143661999054338470989558459179388468943933975861549233231199667742564080001256192881732567616103760815633265325456143601649393547666835326272408622540044065067528568675569233240785553062685974593620235466519632833169291153478793523397788719000334929715524989845012633742964209311952378479134661
# h2=16731800146050995761642066586565348732313856101572403535951688869814016691871958158137790504490910445304384109605408840493227057830017039824412834989258703833576252634055087138315434304691218949240382395879124201923060510497916818961571111218224960267593032380037212325935576750663442553781924370849537501656957488833521657563900462052017695599020610911371304659875887924695896434699048696392210066253577839887826292569913713802634067508141124685789817330268562127695548527522031774601654778934513355315628270319037043809972087930951609429846675450469414212384044849089372435124609387061864545559812994515828333828939

参考

2024-强网杯-wp-crypto | 糖醋小鸡块的blog

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from Crypto.Util.number import *

c = 13148687178480196374316468746303529314940770955906554155276099558796308164996908275540972246587924459788286109602343699872884525600948529446071271042497049233796074202353913271513295267105242313572798635502497823862563815696165512523074252855130556615141836416629657088666030382516860597286299687178449351241568084947058615139183249169425517358363928345728230233160550711153414555500038906881581637368920188681358625561539325485686180307359210958952213244628802673969397681634295345372096628997329630862000359069425551673474533426265702926675667531063902318865506356674927615264099404032793467912541801255735763704043
n = 13718277507497477508850292481640653320398820265455820215511251843542886373380880887850571647060788265498378060163112689840208264538965960596605641194331300743676780910818492860412739541418029075802834265712602393103809065720527365081016381358333378953245379751008531500896923727040455566953960991908174586311899809864209624888469263612475732913062035036254077225370843701146080145441104733074178115602425412116325647598625157922655504918118208783230138448694045386019901732846478340735331718476554208157393418221315041837392020742062275999319586357229583509788489495876723122993592623230858393165458733055504467513549
h2 = 6992022576367328281523272055384380182550712894467837916200781058620282657859189270338635886912232754034211897894637971546032107000253692739473463119025570291091085702056938901846349325941043398928197991115231668917435951127329817379935880511925882734157491821315858319170121031835598580384038723788681860763814776365440362143661999054338470989558459179388468943933975861549233231199667742564080001256192881732567616103760815633265325456143601649393547666835326272408622540044065067528568675569233240785553062685974593620235466519632833169291153478793523397788719000334929715524989845012633742964209311952378479134661
h1 = 16731800146050995761642066586565348732313856101572403535951688869814016691871958158137790504490910445304384109605408840493227057830017039824412834989258703833576252634055087138315434304691218949240382395879124201923060510497916818961571111218224960267593032380037212325935576750663442553781924370849537501656957488833521657563900462052017695599020610911371304659875887924695896434699048696392210066253577839887826292569913713802634067508141124685789817330268562127695548527522031774601654778934513355315628270319037043809972087930951609429846675450469414212384044849089372435124609387061864545559812994515828333828939
e = 0x10001

brute = 2
for i in range(2^brute):
for j in range(2^brute):
L = Matrix(ZZ, [
[1,0,0,2^brute*h1],
[0,1,0,2^brute*h2],
[0,0,2^(1024-brute),h1*i+h2*j-h1*h2],
[0,0,0,n]
])
L[:,-1:] *= n
res = L.LLL()[0]

p = 2^brute*abs(res[0])+i
if(n % p == 0):
print(p)
q = n//p
phi = (p-1)*(q-1)
d = inverse_mod(e, phi)
print(long_to_bytes(pow(c, d, n)))
print(pow(c, d, n))
#flag{e_is_xevaf-cityf-fisof-ketaf-metaf-disef-nuvaf-cysuf-dosuf-getuf-cysuf-dasix,bubbleBabble}

bubbleBabble解密得到e值

part2部分

Common Prime RSA

参考

hasegawaazusa.github.io/common-prime-rsa.html#common-prime-rsa

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from sage.groups.generic import bsgs

N=10244621233521168199001177069337072125430662416754674144307553476569744623474797179990380824494968546110022341144527766891662229403969035901337876527595841503498459533492730326942662450786522178313517616168650624224723066308178042783540825899502172432884573844850572330970359712379107318586435848029783774998269247992706770665069866338710349292941829996807892349030660021792813986069535854445874069535737849684959397062724387110903918355074327499675776518032266136930264621047345474782910332154803497103199598761422179303240476950271702406633802957400888398042773978322395227920699611001956973796492459398737390290487
g=2296316201623391483093360819129167852633963112610999269673854449302228853625418585609211427788830598219647604923279054340009043347798635222302374950707
c=7522161394702437062976246147354737122573350166270857493289161875402286558096915490526439656281083416286224205494418845652940140144292045338308479237214749282932144020368779474518032067934302376430305635297260147830918089492765917640581392606559936829974748692299762475615766076425088306609448483657623795178727831373194757182797030376302086360751637238867384469269953187938304369668436238848537646544257504724753333177938997524154486602644412199535102323238852958634746165559537630341890450666170836721803871120344373143081664567068672230842855208267929484000179260292518351155693154372172449820053764896414799137097

nbits = int(N).bit_length()
gamma = 500/nbits #这边的500对应g的比特位数
cbits = ceil(nbits * (0.5 - 2 * gamma))

M = (N - 1) // (2 * g)
u = M // (2 * g)
v = M - 2 * g * u
GF = Zmod(N)
x = GF.random_element()
y = x ^ (2 * g)
# c的范围大概与N^(0.5-2*gamma)很接近
c = bsgs(y, y ^ u, (2**(cbits-1), 2**(cbits+1)), operation='*')
#(a, b, bounds, operation='*', identity=None, inverse=None, op=None)
ab = u - c
apb = v + 2 * g * c
P.<x> = ZZ[]
f = x ^ 2 - apb * x + ab
a = f.roots()
if a:
a, b = a[0][0], a[1][0]
p = 2 * g * a + 1
q = 2 * g * b + 1
print("p=",p)
print("q=",q)

运行得到

然后简单rsa解密即可

exp:

1
2
3
4
5
6
7
8
9
10
11
12
from Crypto.Util.number import long_to_bytes, isPrime
import gmpy2

p=114223230692329221233593176873809300402703143063931397822580003361438712054166147412606967205124955861521969519047697209787311806459638088623102779532442176190528211946769436968799761724667716082655997119572158947882963880778970164432326393480858337150525471346874196183962785321409039116916910681846888186947
q=89689471847596377741222144429998037990667180177357564376140367776414308387012923411995322262858328353318533567758158657166891766790825298883408932478365300323143798943782413227199460096726803837011408747331311614322911225425264615177532865042145570988661750629687056545931523546752474174278821175282246381821
c=7522161394702437062976246147354737122573350166270857493289161875402286558096915490526439656281083416286224205494418845652940140144292045338308479237214749282932144020368779474518032067934302376430305635297260147830918089492765917640581392606559936829974748692299762475615766076425088306609448483657623795178727831373194757182797030376302086360751637238867384469269953187938304369668436238848537646544257504724753333177938997524154486602644412199535102323238852958634746165559537630341890450666170836721803871120344373143081664567068672230842855208267929484000179260292518351155693154372172449820053764896414799137097
n=p*q
e=81733668723981020451323
phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))

运行得到

最后flag为

1
flag{I wish you success in your cryptography career}

文章作者: yiqing
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 yiqing !
  目录