当前位置: 首页 > news >正文

HNCTF2025 - Misc、Osint、Crypto WriteUp

还是学了非常多的知识的,有待进步与提升

Misc:

芙宁娜的图片

给了文档和图片,图片lsb藏了一个key,随波逐流直接梭出来

文档内容brainfuck得到一个加密后的flag

用key和加密后的flag进行维吉尼亚加密或者一把梭不行

注:为什么知道是维吉尼亚呢,因为看到了又flag{}的雏形了,非常像凯撒密码,但是图片提供了各key,所以很容易想到是维吉尼亚密码辣
好像只能用bugku的维吉尼亚解密

维吉尼亚加密/解密 - Bugku CTF平台
我用千千秀字和其他解密网站不行

星辉骑士

给了一个word文档,一张图片,没有发现什么信息,将其后缀改位zip

解压看到一个flag.zip

解压,发现需要密码

这时就要看看是真加密还是伪加密了

拖入010 editor

是伪加密了

把十个09都改了改为偶数00

 改了之后,保存,解压

解压得到一堆文档,打开可以看到是垃圾邮件隐写

spammimic - decoded

一个一个文档进行解密,还有假flag!

乱成一锅粥了

题目附件是一个流量包

初见端倪

 再往下翻翻

一共有9个zip

 导出字节流都解压

txt文件内容类似base64编码,将其合并一起发现解码出来是乱码,所以想到可能是顺序不对,又注意到,文件命名类似hash值

注:解压发现每个压缩包里都有50个txt文档,而且命名都一样

解密发现是数字,猜测md5解密后的内容在00-50之间,这样就可以按照序号拼接了

用ai帮我们把脚本写出来 

import os
import hashlibdef generate_md5_mapping():"""生成00到50的数字与其MD5值的映射关系"""mapping = {}for i in range(0, 51):  # 包括50,所以是0-50共51个文件# 格式化为两位数字符串:00, 01, ..., 50original_name = f"{i:02d}"# 计算MD5值md5_hash = hashlib.md5(original_name.encode('utf-8')).hexdigest()# 添加到映射表mapping[md5_hash] = original_namereturn mappingdef rename_files(folder_path, mapping):"""根据映射表重命名文件"""for md5_name in os.listdir(folder_path):if md5_name.endswith('.txt'):# 提取MD5部分(不含扩展名)md5_key = os.path.splitext(md5_name)[0]if md5_key in mapping:original_name = mapping[md5_key]new_filename = f"{original_name}.txt"# 构建完整文件路径old_path = os.path.join(folder_path, md5_name)new_path = os.path.join(folder_path, new_filename)# 重命名文件os.rename(old_path, new_path)print(f"成功重命名: {md5_name} -> {new_filename}")else:print(f"警告: 未找到映射 {md5_name} - 可能超出00-50范围")if __name__ == "__main__":# 使用原始字符串避免转义问题folder_path = r"E:\粥\Down"# 生成MD5映射表 (00-50)md5_mapping = generate_md5_mapping()# 执行重命名操作rename_files(folder_path, md5_mapping)print("\n操作完成! 所有文件已恢复为原始数字名称")print(f"共处理文件: {len(md5_mapping)}个 (00-50)")

将文件内容按照01到50合并在一起

import osdef combine_files(folder_path, output_file):"""将01.txt到50.txt的文件内容按顺序合并"""# 确保输出文件路径正确output_path = os.path.join(folder_path, output_file)# 创建01-50的文件名列表file_names = [f"{i:02d}.txt" for i in range(1, 51)]# 按顺序合并文件内容with open(output_path, 'w', encoding='utf-8') as outfile:for filename in file_names:file_path = os.path.join(folder_path, filename)# 检查文件是否存在if not os.path.exists(file_path):print(f"警告: 文件 {filename} 不存在,跳过")continue# 读取并写入内容with open(file_path, 'r', encoding='utf-8') as infile:content = infile.read()outfile.write(content)# 可选:在文件之间添加分隔符# outfile.write("\n\n--- 文件分割线 ---\n\n")print(f"\n合并完成! 所有内容已保存到: {output_path}")print(f"共合并了 {len(file_names)} 个文件 (01.txt - 50.txt)")if __name__ == "__main__":# 配置路径folder_path = r"E:\粥\Down"  # 包含01-50.txt的文件夹output_file = "combined_content.txt"  # 合并后的文件名# 执行合并combine_files(folder_path, output_file)

将其base64解码,发现是一张图片

都转码得到9张图片,将其拼接得到二维码

扫一扫就能得到flag了

谁动了黑线

待定

OSINT

时间图片属性都有

Chasing Freedom 1

可以看到船号是闽平渔65599,而且识图可以知道大概位置

是平潭岛蓝眼泪的位置

搜这个渔船停在那里

点开海坛观潮,搜船号

 再高德地图搜索地址,全都试了一遍,最后试了一遍丁鼻垄就对了......

H&NCTF{0503-丁鼻垄}

Chasing Freedom 2

用小红书登app都行识图

输进去不对加一个灯塔就提交成功了

H&NCTF{0504-东庠岛灯塔}

Chasing Freedom 3

直接搜“岚庠渡 码头”

 

一号不对二号三号枚举一下就可以了

H&NCTF{0504-流水码头-岚庠渡3号}

猜猜我在哪儿?

待定

CRYPTO

哈基coke

猫脸

import numpy as np
import cv2def arnold_decode(image, shuffle_times, a, b):""" Arnold inverse shuffle for rgb image """# 确保图像是numpy数组格式if isinstance(image, str):image = cv2.imread(image)# 创建输出图像数组decoded_image = np.zeros_like(image, dtype=np.uint8)h, w = image.shape[0], image.shape[1]N = hfor time in range(shuffle_times):for new_x in range(h):for new_y in range(w):# 逆变换ori_x = ((a*b + 1) * new_x - b * new_y) % Nori_y = (-a * new_x + 1 * new_y) % Ndecoded_image[ori_x, ori_y, :] = image[new_x, new_y, :]image = decoded_image.copy()# 确保图像数据是8位无符号整数decoded_image = np.clip(decoded_image, 0, 255).astype(np.uint8)cv2.imwrite('decoded_flag.png', decoded_image, [int(cv2.IMWRITE_PNG_COMPRESSION), 0])return decoded_image# 使用示例
if __name__ == "__main__":img_path = 'en_flag.png'  # 替换为加密后的图像路径decoded_img = arnold_decode(img_path, 6, 9, 1)print("解密完成,结果已保存为 decoded_flag.png")

lcgp

常规的 LCG 问题
  • 恢复 LCG 参数 a, b, m(模数、乘数、增量)

  • 反推出初始种子 cc(满足 cc = 2024^flag mod n

  • 求离散对数 flag = log₍₂₀₂₄₎cc mod n

  • 还原原始 flag 字符串

from sage.all import *
from Crypto.Util.number import long_to_bytes, GCD, isPrime# 给定 LCG 输出序列
c = [11250327355112956284720719987943941825496074893551827972877616718074592862130806975889275745497426515405562887727117008818863728803549848574821067056997423443681347885027000632462241968640893471352200125748453396098854283137158609264944692129301617338233670002547470932851350750870478630955328653729176440142198779254117385657086615711880537380965161180532127926250520546846863536247569437, 1289730679860726245234376434590068355673648326448223956572444944595048952808106413165882424967688302988257332835229651422892728384363094065438370663362237241013242843898967355558977974152917458085812489310623200114007728021151551927660975648884448177346441902806386690751359848832912607313329587047853601875294089502467524598036474193845319703759478494109845743765770254308199331552085163360820459311523382612948322756700518669154345145757700392164795583041949318636, 147853940073845086740348793965278392144198492906678575722238097853659884813579087132349845941828785238545905768867483183634111847434793587821166882679621234634787376562998606494582491550592596838027522285263597247798608351871499848571767008878373891341861704004755752362146031951465205665840079918938797056361771851047994530311215961536936283541887169156535180878864233663699607369701462321037824218572445283037132205269900255514050653933970174340553425147148993214797622395988788709572605943994223528210919230924346860415844639247799805670459, 7426988179463569301750073197586782838200202717435911385357661153208197570200804485303362695962843396307030986052311117232622043073376409347836815567322367321085387874196758434280075897513536063432730099103786733447352512984165432175254784494400699821500026196293994318206774720213317148132311223050562359314735977091536842516316149049281012797103790472349557847649282356393682360276814293256129426440381745354969522053841093229320186679875177247919985804406150542514337515002645320320069788390314900121917747534146857716743377658436154645197488134340819076585888700553005062311578963869641978771532330577371974731136, 10389979373355413148376869524987139791217158307590828693700943753512488757973725227850725013905113587408391654379552713436220790487026223039058296951420273907725324214990441639760825661323514381671141482079783647253661594138658677104054180912818864005556386671430082941396497098166887200556959866845325602873713813206312644590812141400536476615405444030140762980665885244721798105034497461675317071497925846844396796854201566038890503298824928152263774446268093725702310124363765630370263370678902342200494544961012407826314577564991676315451785987248633724138137813024481818431889574317602521878974976264742037227074]# 差分构造
t = [c[i] - c[i-1] for i in range(1, len(c))]# 恢复模数 m
m = 0
for i in range(1, len(t)-1):m = GCD(t[i+1] * t[i-1] - t[i]**2, m)print("是否为素数:", isPrime(m))
print("m 位数:", m.bit_length())# 恢复参数 a, b
a = (c[3] - c[2]) * inverse_mod(c[2] - c[1], m) % m
b = (c[2] - a * c[1]) % m# 恢复种子 cc
a_inv = inverse_mod(a, m)
cc = (c[0] - b) * a_inv % m# 离散对数部分
n = 604805773885048132038788501528078428693141138274580426531445179173412328238102786863592612653315029009606622583856638282837864213048342883583286440071990592001905867027978355755042060684149344414810835371740304319571184567860694439564098306766474576403800046937218588251809179787769286393579687694925268985445059
g = Mod(2024, n)
y = Mod(cc, n)flag = discrete_log(y, g)
print("Flag:", long_to_bytes(int(flag)))

数据处理

离散对数 比较喜欢本方法爆破
(sagemath)
from tqdm import tqdm
from itertools import permutations
from Crypto.Util.number import long_to_bytes
from sage.all import *# 1. 模数 Zmod(2^512)
Z = Zmod(2^512)# 2. 目标参数(手动合并换行)
m = Z(5084057673176634704877325918195984684237263100965172410645544705367004138917087081637515846739933954602106965103289595670550636402101057955537123475521383)
c = Z(2989443482952171039348896269189568991072039347099986172010150242445491605115276953489889364577445582220903996856271544149424805812495293211539024953331399)# 3. 恢复出混淆过的 flag
new_flag = str(discrete_log(c, m))# 4. 映射表恢复原始数字
lowercase = '0123456789'  # 正确的数字顺序
uppercase_pattern = '7***4****5'  # 映射前的字符格式# 5. 尝试所有 0123689 的排列来恢复原始 flag
for i in tqdm(permutations("0123689")):up = f"7{''.join(i[:3])}4{''.join(i[3:])}5"table = str.maketrans(up, lowercase)flag = new_flag.translate(table)try:res = long_to_bytes(int(flag)).decode()if res.startswith("H&NCTF"):print("✅ 找到 flag:", res)breakexcept:continue

 

(Python 版本,无需 Sage)

from Crypto.Util.number import *
import sympy
import itertools# 设定大数参数
m = 5084057673176634704877325918195984684237263100965172410645544705367004138917087081637515846739933954602106965103289595670550636402101057955537123475521383
c = 2989443482952171039348896269189568991072039347099986172010150242445491605115276953489889364577445582220903996856271544149424805812495293211539024953331399
n = 2 ** 512# 计算离散对数
flag = sympy.discrete_log(n, c, m)  # 即 c ≡ m^flag mod n
flag_str = str(flag)# 替换映射相关
digits = '0123689'
target_digits = '0123456789'# 枚举可能的密码本并尝试解码
for p in itertools.permutations(digits):up = '7' + ''.join(p[:3]) + '4' + ''.join(p[3:]) + '5'trans_table = str.maketrans(up, target_digits)translated = flag_str.translate(trans_table)try:decoded = long_to_bytes(int(translated))if b'H&NCTF' in decoded:print(f"[+] 找到 flag:{decoded.decode()}")breakexcept Exception:continue

ez-factor

from Crypto.Util.number import long_to_bytes, inverse
from sage.all import PolynomialRing, Zmod, gcd# ===========================
# 已知参数(从题目中整理)
# ===========================N = 155296910351777777627285876776027672037304214686081903889658107735147953235249881743173605221986234177656859035013052546413190754332500394269777193023877978003355429490308124928931570682439681040003000706677272854316717486111569389104048561440718904998206734429111757045421158512642953817797000794436498517023hint = 128897771799394706729823046048701824275008016021807110909858536932196768365642942957519868584739269771824527061163774807292614556912712491005558619713483097387272219068456556103195796986984219731534200739471016634325466080225824620962675943991114643524066815621081841013085256358885072412548162291376467189508ciphertext = 32491252910483344435013657252642812908631157928805388324401451221153787566144288668394161348411375877874802225033713208225889209706188963141818204000519335320453645771183991984871397145401449116355563131852618397832704991151874545202796217273448326885185155844071725702118012339804747838515195046843936285308e = 65537
r_bit_length = 248  # r 是一个 248 位的小素数# ===========================
# Step 1. 使用 Coppersmith’s 方法恢复 r
# ===========================PR.<x> = PolynomialRing(Zmod(N))  # 多项式环 Z_N[x]
f = x - hint                      # f(x) = x - hint# 尝试找到小根 r,使得 f(r) ≡ 0 mod N
roots = f.small_roots(X=2^r_bit_length, beta=0.4, epsilon=0.01)if not roots:print("[-] 未找到满足条件的小根 r,建议调节 beta 或 epsilon 参数后重试")exit()r = int(roots[0])
print("[+] 找到小根 r =", r)# ===========================
# Step 2. 利用 r 分解 N
# ===========================p = gcd(hint - r, N)
if p == 1 or N % p != 0:print("[-] 恢复 p 失败,p 可能不是 N 的因子")exit()q = N // p
phi = (p - 1) * (q - 1)
d = inverse(e, phi)# ===========================
# Step 3. 解密密文
# ===========================m = pow(ciphertext, d, N)
flag = long_to_bytes(int(m))
if b'H&NCTF' in flag:print("[+] 可能的flag:", flag)
else:print("[!] 没有找到明显的flag格式,可能需要进一步处理")

three vertical lines

from Crypto.Util.number import long_to_bytes, inverse
from sage.all import *# 1. 把 n 写成一行:
n = Integer(72063558451087451183203801132459543552092564094711815404066471440396765744526854383117910805713050240067432476705168314622044706081669935956972031037827580519320550326077291392722314265758802332280697884744792689996718961355845963752788234205565249205191648439412084543163083032775054018324646541875754706761793307667356964825613429368358849530455220484128264690354330356861777561511117)# 2. 这里改用整数环,构造多项式环
R = PolynomialRing(Integers(n), 'x')
x = R.gen()# 3. 计算 t 满足 t^5 = 4/3 mod n
# 由于 n 不是素数,GF(n) 不适用,改用mod n的整数环中的多项式求解,或者用扩展欧几里得算法求5次根,这里直接计算t:
# 先计算逆元 3^-1 mod n
inv3 = inverse_mod(3, n)
four_thirds = (4 * inv3) % n# 计算四分之三的5次根 t:这里没有现成函数,需要自定义尝试或者用数论方法。  
# 之前用的 GF(n)(4/3).nth_root(5) 在 n 不是素数时不可用# 假设你有 t,下面直接填上:
# 也可以尝试在 Sage 中用 discrete_log 或者其它算法计算
t = pow(four_thirds, inverse_mod(5, (n-1)), n)  # 这是一个尝试的做法,不保证成功# 4. 构造矩阵 M
M = Matrix(ZZ, [[1, t],[0, n]
])# 5. LLL 找到短向量
q, p = M.LLL()[0]
q, p = abs(q), abs(p)print(3 * p**5 + 4 * q**5 == n)# 6. 密文 c,同样合并成一行:
c = Integer(2864901454060087890623075705953001126417241189889895476561381971868301515757296100356013797346138819690091860054965586977737630238293536281745826901578223)e = Integer(65537)
d = inverse(e, (p - 1)*(q - 1))
m = pow(c, d, p*q)
m_int = int(m)  # 转换成普通整数
flag = long_to_bytes(m_int)
print(flag)

ez-factor-pro

待定

为什么出题人的rsa总是ez

待定

相关文章:

  • 日语学习-日语知识点小记-进阶-JLPT-真题训练-N2阶段(1):单词部分练习
  • Linux操作系统基线检查与安全加固概述
  • 《HarmonyOSNext终极UIAbility手册:从启动模式到页面跳转,一网打尽!》
  • C++之前向声明
  • [学习] Costas环详解:从原理到实战
  • 2025GEO供应商排名深度解析:源易信息构建AI生态优势
  • 一数一源一标准的补充
  • 【C】 USB CDC、Bulk-OUT 端点
  • PostgresSQL日常维护
  • 网页组件强制设置右对齐
  • python下载与开发环境配置
  • 从“字对字“到“意对意“:AI翻译正在重塑人类的语言认知模式
  • 观测云,全球领先的监控观测平台亮相亚马逊云科技中国峰会!
  • SecureRandom.getInstanceStrong() 与虚拟机的爱恨情仇
  • 【更新】中国经济政策不确定性指数数据集(2000.1-2025.5)
  • 2025 年二级造价工程师职业资格考试的报考条件有哪些新变化?
  • 【Java】Arrays.sort:TimSort
  • 560. 和为K的子数组
  • 软件测试之APP测试要点(包含Monkey基础使用)
  • C++实现文本编辑功能
  • 怎么自己设计装修效果图/网站快速优化排名软件
  • 做网站标题头像/石家庄最新消息
  • 网站建设百灵鸟优化/百度网盘搜索神器
  • 芜湖做网站公司/南宁seo关键词排名
  • 网站建设 企泰科技/专业seo公司
  • 典型网站建设实例精讲/百度站长平台如何添加网站