文章目录
一、前言
也是比较有趣的一个比赛哈,附件已全部收集且打包完毕!来之不易~点个赞吧!,那我们话不多说直入主题!
WP仅供参考!!!
附件下载——123网盘
二、MISC
高职组
1、签到
解题思路
附近下载,得到公众号二维码,扫码发送flag即可:
至此
CnHongKe{2024-lhb-welcome-you!}
2、BASE
解题思路
附件下载,得到一个file.txt,打开发现一串编码,既然题目说了是base,那就锁定范围base家族:
仔细观察编码特征
首先怀疑base64,因为编码特征极其相似,但是解码之后无果,那就没办法了,不过还好我们有随波逐流工具,一键解码,但也是没有什么效果:
也是前前后后尝试了很多种方法都是没有出(后来别的师傅告知,这里其实刷题刷多了是可以看出是base62的,但编码类的题我刷的也是很少),最后没办法一个一个编码进行删减并且使用工具-随波逐流进行一键解码,才是碰巧发现了最后是base62编码!
虽然过程很枯燥无味,但好在也是很开心发现了flag的头部,那现在就更加确认是base62编码!继续进行解码!
也是没想到最后只剩下21(别说,如果加上去,死活不出),还是怪好玩的:
也就是说最后被切割成:
Nu2j4uga0JPX
tpgRqKTWZIy0zx9ElzulghqDsgqAEBL26BrOjKBqJfPec84f
21
至此:
CnHongKe{2934d4ff-62d2-43d1-9839-365b87190ed1}
拓展
base64编码特征
Base64 是一种常用的编码方式,主要特点如下:
-
编码内容为 ASCII 字符:Base64 将二进制数据编码成由 64 个可打印的 ASCII 字符组成的文本。这 64 个字符包括大小写字母(A-Z、a-z)、数字(0-9)、以及加号(+)和斜杠(/)。有时在 URL 编码中,可能会使用下划线(_)替代斜杠(/),以及减号(-)替代加号(+)。
-
每 3 字节转为 4 字节:Base64 每 3 字节(24 位)的二进制数据会被转换成 4 个 Base64 字符,每个字符 6 位(2^6=64)。因此,编码后的数据长度约为原始数据的 4/3 倍。
-
补位特性:如果输入的数据长度不是 3 的倍数,Base64 编码会在末尾使用一个或两个等号(
=
)进行填充,以保证编码后的输出长度是 4 的倍数。这些等号并不是实际数据,只是为了保证格式一致。 -
无可读性和加密性:Base64 只是一种编码方式,不具备加密性。它不会对数据进行混淆或保护,因此不能作为安全措施。Base64 编码的主要作用是将二进制数据以文本的形式存储和传输。
-
常见应用场景:Base64 常用于电子邮件(MIME)、URL 编码、将二进制数据(如图片、文件)嵌入到 XML 或 JSON 等格式中。
简单总结,Base64 的编码特征是:使用 64 个可打印的字符,将 3 字节二进制数据转为 4 字节文本,并通过等号填充来保证长度。
base62编码特征
Base62 是一种类似于 Base64 的编码方式,但它使用 62 个字符进行编码,主要特点如下:
-
字符集范围:Base62 由 62 个可打印的字符组成,包括:
- 大写字母:A-Z(26个)
- 小写字母:a-z(26个)
- 数字:0-9(10个)
与 Base64 不同的是,Base62 不使用特殊符号,因此没有 “+”、“/” 这样的符号,这使得 Base62 编码更加适合在 URL、文件名或其他不允许使用特殊符号的场景中使用。
-
无填充字符:Base62 通常不使用填充字符(如 Base64 中的
=
)。它能够根据输入数据的长度调整输出长度,避免了额外的填充字符,因此编码后的数据更加紧凑。 -
每 1 字节对应 1 Base62 字符:Base62 通常用于将大数字或数据流转换成 Base62 字符串。它将二进制数据编码成由 62 个字符构成的文本,能够将二进制数据映射为较短的字符串。
-
常见应用场景:
- 短链接:由于 Base62 只使用字母和数字,没有特殊符号,它非常适合用在 URL 短链接中。例如,一些 URL 短网址服务会使用 Base62 将长 URL 映射为短链接。
- 唯一标识符:Base62 可以用于生成短而唯一的标识符,因为它的字符集范围广,可以有效压缩信息长度。
- 文件名或数据库主键:由于 Base62 编码只包含字母和数字,可以生成适合用作文件名或数据库主键的字符串,不会因为特殊符号引发兼容性问题。
-
编码效率:虽然 Base62 的编码效率稍低于 Base64(每个字符表示 6 位信息),但它依然比纯十进制编码(Base10)更紧凑,每个字符可以表示 62 种可能性。
简单总结,Base62 的编码特征是:使用 62 个字符(A-Z、a-z、0-9),无填充字符,适合短链接、唯一标识符等不允许使用特殊符号的场景,且能够生成紧凑的编码。
base64与base62的区别
Base64 和 Base62 都是常用的编码方式,它们在字符集、编码效率和应用场景上存在一些区别。以下是它们的主要差异:
- 字符集
-
Base64 使用 64 个字符,包括:
- 大写字母 A-Z(26个)
- 小写字母 a-z(26个)
- 数字 0-9(10个)
- 特殊符号:
+
和/
- 还使用
=
作为填充符号,用来填充编码结果使其长度是 4 字节的倍数。
-
Base62 使用 62 个字符,包括:
- 大写字母 A-Z(26个)
- 小写字母 a-z(26个)
- 数字 0-9(10个)
Base62 不使用特殊符号,因此不会包含
+
和/
这类符号,也不使用=
作为填充符号。
- 填充符
- Base64:需要使用
=
作为填充符,以保证编码后的字符串长度是 4 字节的倍数。 - Base62:没有填充符,它会根据输入的实际长度生成相应长度的编码结果。
- 编码效率
-
Base64:Base64 将二进制数据按每 6 位一组进行编码,6 位数据对应一个 Base64 字符,因此 Base64 的编码效率较高,数据压缩得较紧凑。
- 每 3 字节(24 位)的二进制数据会转换为 4 个 Base64 字符。
-
Base62:Base62 将数据按 62 进制进行编码,通常用于将大整数或数据压缩成较短的字符串。它不使用填充符,但编码效率稍低,因为每个 Base62 字符只表示 6 位多一点的信息。
- Base62 更适合用于不能包含特殊符号的场景,虽然编码效率低于 Base64,但它提供了更好的兼容性。
- 应用场景
-
Base64:
- 常用于将二进制数据转换为文本数据,例如在传输图片、文件、加密信息时,使用 Base64 编码可以确保数据在基于文本的协议(如邮件、HTTP)中不丢失。
- 由于包含特殊符号
+
和/
,在某些环境下(如 URL 或文件名)可能需要进一步处理,以避免字符冲突。
-
Base62:
- 更适合短链接、文件名或数据库主键等需要避免特殊符号的场景。由于 Base62 只使用字母和数字,它能保证编码结果在不同环境中具有良好的兼容性,且生成的字符串相对较短。
- 通常用于生成短而唯一的标识符或在不允许使用特殊符号的场景中编码数据。
- 用途差异
- Base64 主要用于处理二进制数据和文本之间的转换,尤其是在需要通过文本协议传输二进制数据时使用(如图像、文件、加密消息等)。
- Base62 更适合生成简洁的、只包含字母和数字的字符串,如 URL 短链接、唯一 ID 等,适用于不支持特殊字符的场景。
总结
- Base64 是一种用于编码二进制数据以便通过文本协议传输的常见方法,字符集包含特殊符号,编码效率高。
- Base62 则是避免使用特殊符号的编码方法,适合生成不包含特殊符号的短字符串,虽然编码效率稍低,但更具兼容性,尤其适用于短链接和标识符生成等场景。
3、PG
解题思路
暂无,后续补上,请多多担待!
思路:
需要链接数据库,可以查看到相关表
使用Wireshark分析流量包可以查看到数据库的备份文件被下载过:tar.gz拓展名
最后将相关文件进行提取即可
本科组
1、签到
扫码得到:436e486f6e674b657b323032345f6c68625f77656c636f6d655f796f75217d
一眼hex,解码得到:
CnHongKe{2024_lhb_welcome_you!}
2、veee
解题思路
附件下载,得到一个sfz.txt及vera,sfz.txt不用多说,里面都是给的身份证信息,vera需要简单说一下,可能第一次接触取证的师傅还不是很了解这个文件
vera文件简介
.vera
文件是 VeraCrypt 加密卷的文件格式之一。VeraCrypt 是一个开源的磁盘加密工具,用于保护数据的安全性和隐私性。.vera
文件通常代表了一个加密的容器或磁盘分区,用户可以将敏感文件保存在其中,确保数据在未解密的情况下无法被访问。
.vera 文件的作用
- 加密容器:
.vera
文件充当了一个虚拟的加密硬盘,所有的数据都被加密存储在其中,外部无法直接读取或修改文件内容。 - 保护敏感数据:通过密码或密钥保护,用户必须使用正确的密码或密钥才能访问加密卷内的文件和数据。
使用 VeraCrypt 来挂载 .vera 文件
为了访问 .vera
文件中的数据,必须使用 VeraCrypt 工具将该加密卷“挂载”到系统上。挂载之后,.vera
文件会被系统识别为一个虚拟磁盘,用户可以像访问普通磁盘一样查看和操作其中的文件。
总结
.vera
文件是 VeraCrypt 生成的加密卷文件,需通过 VeraCrypt 工具进行挂载后才能访问文件内容。
那都解释这样了,那就尝试挂载一下试试呗:
果然和我们想的一样是需要密码的,密码估计就是所给出sfz.txt文件中,那我们打开sfz.txt仔细观察一下:
首先我们要先了解一下身份证的构成原理
身份证号码的结构
中国的身份证号码主要有两种类型:
- 15位身份证号码:用于老版身份证,格式为
XXXXXXYYYYYYZZZ
。 - 18位身份证号码:用于新版身份证,格式为
XXXXXXYYYYYYZZZZZZZZZ
,其中最后一位是校验位。
各部分的含义:
XXXXXX
:前六位表示行政区划码。YYYYYY
:中间的八位表示出生日期(年、月、日)。ZZZZZZZZZ
:后九位为顺序码,最后一位为校验位(可能是数字或字母X)。
校验位的计算原理
18位身份证的校验位是通过前17位数字计算得出的,计算方法如下:
-
加权因子:每一位数字都有一个对应的权重。
- 权重数组为:
[7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
。
- 权重数组为:
-
校验码对应值:校验位的取值是根据模11的结果。
- 对应值数组为:
[1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2]
。 - 如果模值为10,则校验位为
X
(大写字母)。
- 对应值数组为:
-
计算步骤:
- 将前17位数字与对应的权重相乘,然后求和。
- 将和对11取模,得到的结果用于查找校验码。
那既然这样我们百度一个脚本来进行校验:
import re
# 判断身份证号码是否合法的函数
def is_id_card(id_card):
# 正则表达式,用于验证身份证号格式(18位身份证)
reg_id_card = re.compile(r'^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])(\d{3}(\d|X|x))$')
# 使用正则表达式进行初步验证
if reg_id_card.match(id_card):
# 如果是18位身份证,进行校验码计算
if len(id_card) == 18:
# 加权因子,用于计算校验码
id_card_wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
# 校验码对应的值
id_card_y = [1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2]
# 用于存储加权和
id_card_wi_sum = 0
# 计算加权和
for i in range(17):
id_card_wi_sum += int(id_card[i]) * id_card_wi[i]
# 计算出校验码的模数
id_card_mod = id_card_wi_sum % 11
# 获取身份证的最后一位(校验位)
id_card_last = id_card[17]
# 如果模数是2,校验位可以是"X"或"x"
if id_card_mod == 2:
if id_card_last.upper() == "X":
return True # 校验成功
else:
return False # 校验位错误
else:
# 否则,校验位应与id_card_y数组中对应的值相等
if id_card_last == str(id_card_y[id_card_mod]):
return True # 校验成功
else:
return False # 校验位错误
else:
# 正则表达式验证不通过
return False
# 读取文件中的身份证号码列表
try:
with open('./sfz.txt', 'r', encoding='utf-8') as file:
id_card_numbers = file.readlines()
# 去除每一行的多余空格,并验证身份证号是否合法
invalid_ids = [] # 存储不合法身份证号的最后一位
for id_card_number in id_card_numbers:
id_card_number = id_card_number.strip() # 去掉首尾空白字符
if id_card_number:
# 调用 is_id_card 函数进行验证
if not is_id_card(id_card_number): # 如果身份证号不合法
invalid_ids.append(id_card_number[-1]) # 保存不合法身份证号的最后一位
# 输出不合法身份证号的最后一位,不带空格
print("".join(invalid_ids)) # 输出为一行,不带空格
except FileNotFoundError:
print("文件未找到,请检查文件路径是否正确。")
except Exception as e:
print("出现错误:", e)
脚本简单分析:
1、正则表达式:
reg_id_card = r'^[1-9]\d{5}(?:\d{2}(?:0[1-9]|1[0-2])(?:[0|1|2]\d|3[0-1])\d{3}(\d|X))?$'
- 用于验证身份证号码的格式是否符合标准。
- 正则表达式的解释:
^[1-9]\d{5}
:前六位为地区代码,第一位不能为0。(?:\d{2}(?:0[1-9]|1[0-2])(?:[0|1|2]\d|3[0-1])\d{3}
:后面的部分用于匹配出生日期。(\d|X)
:最后一位为数字或字母X。
2、校验位的计算:
通过加权因子计算校验位。
id_card_wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
id_card_y = [1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2]
遍历前17位数字与加权因子相乘,并求和。
3、验证校验位:
使用模11计算最后一位,并进行比较。
if id_card_last == 'X':
4、文件读取与验证:
读取身份证号码文件,将每行数据进行验证。
with open('./sfz.txt', 'r', encoding='utf-8') as f:
总结
通过上述逻辑,脚本能够有效地验证输入的身份证号码是否符合国家标准。关键在于校验位的计算和格式验证。最终,输出的不合法身份证号码的最后一位可以帮助我们快速识别并处理问题。
运行:
得出:746869735f69735f7077645f6a37316e617332
一眼hex,解码得出:
得出:this_is_pwd_j71nas2
接着输入密码,也是成功挂载:
选中双击打开:
至此:
CnHongKe{fake_flag}
3、seeme
解题思路
附件下载,得到一个file.txt,打开一眼rgb转换,尝试写一个脚本爆破,在120与511发现有文字存在:
脚本如下:
from PIL import Image, ImageEnhance
import numpy as np
# 读取像素值
def read_pixel_values_from_file(filename):
try:
with open(filename, 'r') as file:
pixel_values = []
for line in file:
values = line.strip().split(',')
if len(values) != 3:
raise ValueError(f"每行必须包含 3 个值。错误行: {line}")
pixel_values.extend(map(int, values))
if not pixel_values:
raise ValueError("文件内容为空或不符合要求。")
except FileNotFoundError:
raise FileNotFoundError(f"文件 {filename} 未找到。")
except ValueError as e:
raise ValueError(f"读取文件时出错: {e}")
return pixel_values
# 创建图像
def create_image_from_pixels(pixel_values, width, height):
expected_pixel_count = width * height * 3
actual_pixel_count = len(pixel_values)
if actual_pixel_count > expected_pixel_count:
print(f"像素值数量多于要求,截取前 {expected_pixel_count} 个像素值...")
pixel_values = pixel_values[:expected_pixel_count]
elif actual_pixel_count < expected_pixel_count:
print(f"像素值数量少于要求,填充黑色像素...")
pixel_values.extend([0] * (expected_pixel_count - actual_pixel_count))
pixels = np.array(pixel_values, dtype=np.uint8).reshape((height, width, 3))
image = Image.fromarray(pixels, 'RGB')
return image
# 图像增强
def enhance_image(image, brightness=1.5, contrast=1.5, color=1.2):
def apply_enhancement(image, enhancement_type, factor):
enhancer = enhancement_type(image)
return enhancer.enhance(factor)
image = apply_enhancement(image, ImageEnhance.Brightness, brightness)
image = apply_enhancement(image, ImageEnhance.Contrast, contrast)
image = apply_enhancement(image, ImageEnhance.Color, color)
return image
# 主函数
def main():
print("欢迎使用像素到图像生成器!")
input_file = "./file.txt"
print(f"从 {input_file} 读取像素值...")
try:
pixel_values = read_pixel_values_from_file(input_file)
total_pixels = len(pixel_values) // 3
print(f"总像素数: {total_pixels}")
# 细化爆破 120 附近和 511 附近的宽度
refined_resolutions = list(range(115, 126)) + list(range(505, 516)) # 细化爆破
for width in refined_resolutions:
height = total_pixels // width
if width * height > total_pixels:
print(f"跳过 {width}x{height},像素数据不足。")
continue
print(f"生成尺寸为 {width}x{height} 的图像...")
# 创建原始图像
image = create_image_from_pixels(pixel_values, width, height)
# 微调图像
enhanced_image = enhance_image(image)
# 保存增强后的图像
output_filename = f"output_image_{width}x{height}.png"
enhanced_image.save(output_filename)
print(f"增强后的图像已保存为 {output_filename}")
except Exception as e:
print(f"发生错误: {e}")
if __name__ == "__main__":
main()
脚本简单分析:
-
功能: 脚本的主要功能是将存储在文本文件中的 RGB 像素值转化为图像,并对生成的图像进行增强处理,包括亮度、对比度和颜色饱和度的调整。最终生成的图像会保存为 PNG 格式文件。
-
关键逻辑:
- 读取像素数据:从文件中逐行读取像素数据,每行期望包含 3 个整数,分别代表 RGB 颜色值。如果某行数据不符合格式要求,程序会抛出异常并终止。
- 像素转图像:读取的像素值会被重新排列为指定宽度和高度的 RGB 格式图像,如果像素数量不足,则自动补充黑色像素;如果过多,则进行截断。
- 图像增强:生成的图像通过
ImageEnhance
进行增强操作,调整亮度、对比度和饱和度,提升图像视觉效果。 - 尺寸爆破:尝试多个可能的图像宽度,计算相应高度,动态调整分辨率,生成不同尺寸的图像并保存。
通俗来说,它做了以下几件事情:
-
读取像素数据:从一个文件里读取每个像素的颜色信息,像素的颜色是用 RGB(红、绿、蓝)三个数值来表示的。
-
生成图片:把这些颜色信息拼成一张图片。程序会尝试不同的图片宽度和高度组合,直到找到合适的尺寸。
-
增强图片效果:对生成的图片做一些简单的美化,比如提高亮度、对比度和颜色饱和度,让图片看起来更清晰、色彩更丰富。
-
保存图片:最终,把调整好的图片保存成一个
.png
文件,文件名里会标注图片的宽度和高度。
总结
简单来说,这个脚本就是从数字还原出一张图片,并且稍微美化一下,最后保存到电脑里。
运行:
爆破出的图片不是很多,随便翻一下就发现了:
简单翻转一下得到:
至此:
CnHongKe{youc@n’tseeme}
三、WEB
高职组
1、aio
解题思路
暂无!后续可能会复现!
2、robots
解题思路
打开靶机,根据题目提示robots,所以直接访问robots.txt:
进入主页面(旁边会议无需理会,因为lhb比赛是需要全程露脸并进入会议的):
访问robots.txt:
根据提示得到:F1aG_gfhsodghoshgish.php
那我们继续访问:F1aG_gfhsodghoshgish.php
简单分析一下:
PHP 代码存在 代码注入漏洞,主要问题在于 eval()
函数的使用。由于代码允许对传入的 $haha
参数进行 eval()
执行,而代码仅过滤了 "system"
关键字:
绕过思路:
-
绕过
system
的过滤:- 代码只会过滤掉
"system"
,但我们可以通过变换字符的方法进行绕过。 - 使用字符串拼接、函数别名、或变量函数(
passthru()
)来绕过过滤。
- 代码只会过滤掉
说说passthru()
这个函数:
passthru()
:这是 PHP 中一个执行系统命令的函数,跟system()
类似,只不过它不会返回命令的输出,而是直接输出到页面上。
那既然知道了这个函数,我们可以开始构造payload:
/?haha=passthru('ls');
直接f12使用插件HackBar来进行传参发现了:/flag_dasodhaodsada,那我们直接查看文件,构造payload
/?haha=passthru('cat /flag_dasodhaodsada');
得到:
至此:
CnHongKe{b5ff7ff5c6862b987f5688d79f60993b}
3、web_sql_xxe
解题思路
打开靶机,不出意外确实和题目描述的一样,是SQL注入:
尝试sqlmap跑一下,无果,直接万能尝试万能账号密码登录试试看,这里我使用HackBar来进行传参登录:
登录成功,得到提示让我们上传xml,是一个xxe读文件:
接着我们又“Ctrl+u”进行查看源码,发现flag就在flag.php里面,那这里我们直接使用filter读,接着base64解码就是flag:
使用bp直接抓admin.php:
base64解码得到:
至此:
CnHongKe{6e5786ca59eb340274632279c45bee7d}
本科组
1、web_sql_xxe
与高职组中的web_sql_xxe相似,这里不再多进行强调
2、提权
解题思路
打开靶机,进去之后是一个web管理界面,简单用dirsearch一下,很快就发现了/admin这个目录:
接着又在源码中发现了账号密码:
提示权限不够:
最后也是在cookie中发现有个power:
解码之后得到:
这里解码可能有点问题,但是不影响我们看出这是guest,那这里我们就有思路了,只要将guest用户替换成admin试试能不能登录(毕竟不是提示权限不够嘛)
改为admin并加密:
得到:YWRtaW4=,这里不需要等于号直接删除(这里不受不影响,同样是可以识别出是admin的),加上%3D,最后:
成功获取flag:
至此:
CnHongKe{96149636340109b610f9dcad2800b15b}
3、acxi
!
解题思路
打开靶机,我们可以随便注册一个账号,然后可以使用注册的账号进行登录:
注册:
注册成功弹出提示:
登录成功,提示我们只有admin才能获得flag:
暂时没啥思路,bp抓包进入change password
,发现了:
得到:HIDDEN_STATE=18&HIDDEN_HIX=463856599638&HIDDEN_LANG=0&new_password=
接着我们将:463856599638,进行hex转换,得到:6C 0002 0256
接着将hex转换得到的,将其改为:6C00020256,在转换成十进制,得到:463856534102
最后放入,然后随机几个密码,注意!这里我输入的是:admin
接着返回登录入口,正常登录即可获取flag:
至此:
CnHongKe{27f8edbf5f68cd474e25f897255b4e02}
拓展
正常的思路是这样的:随便注册一堆账号,看他的 hiddenhix(源码),接着使用Hex 解码这一堆 hix,会发现我们注册的这些账号都有一个特点,其他都是随机的,中间四位是不变的,应该是UID,那我们就推测 admin 的 UID 是 0001,所以伪造 HIX 的十六进制为 00 0001 0000 就好了 修改 admin 密码为 1,最后登录admin获得flag。(这里仅供参考!)
参考别的师傅脚本,这里直接放图:
四、CRYPTO
高职组
1、兔兔
解题思路
附件下载,得到一张图片,选中图片右键查看其属性发现:
要按我来说,这题应该放misc,也是好久没遇到兔子编码,在图片属性中的密码题了,一开始谁也没想到,那既然都这样了,直接找一个在线解兔子编码的即可
备注中也有提示:这首诗好熟悉,叫什么诗来着?(名字全拼),那肯定就是木兰诗了呗!
既然说名字全拼所以key:mulanshi
至此:
CnHongKe{Rabbit_I5_Cut3_1}
2、1zRSA
解题思路
附件下载,打开.py文件,不用说这题就是RSA了:
得到:
from Crypto.Util.number import *
from gmpy2 import *
from secret import flag
assert(flag.startswith("CnHongke{"))
p = getPrime(1024)
q = next_prime(p)
n = p * q
e = 33
m = bytes_to_long(flag)
c = pow(m, e, n)
print(f'n = {n}')
print(f'c = {c}')
"""
n = 20157817216833049974118616679190322575901864730668507144482957326182327740713453136333068539106100083027097757551546799575541531293312944887561483280916726369016319612934944450526019975934692298293195561411060477885773405036861008621958822147021639661752191557841624683504007344816984603147270693016174228339440038288427589158890266471648249125569765932533982185987755634089743765749564333612512194933232263756745378109393583291224010700913573540529420652068898993898479078127254056483844853346390136211506294067721897916177680505768950977554254296490057308239156157838713269319343550186321669135205346102566222209669
c = 5550850995648431308122724561862321298330352966504532253941573060435227523644220681378247173522846277972751332156705955942551071366281109518855989368023554577347696287379088984498887267023431403241260985825192081189555696375201465274976430133175304403838370385321814599530029586724109782046451141042893149621734986470429809900193355827277275722227551304063436655735688781909919640024815423934941154264458525685654968501198690422227441772911516150511832369493008699728485535931462629750837466741030971574567414557223186771992335515743296998159321297009298268426970949419821980177125657422472184449785482615837014554125
"""
简单分析一下
我们可以看到,通过以下步骤生成了 RSA 密钥并加密了明文(flag):
-
生成两个相邻的大素数:
p = getPrime(1024)
:生成一个 1024 位的大素数p
。q = next_prime(p)
:找到p
的下一个素数q
。这意味着p
和q
是非常接近的两个大素数。
-
计算模数 nnn:
n = p * q
:RSA 加密算法的模数n
是两个大素数p
和q
的乘积。
-
加密指数 eee:
e = 33
:加密时使用的公钥指数e
,这是一个相对较小的整数,表明加密时使用较小的指数。
-
将明文(flag)转换为整数:
m = bytes_to_long(flag)
:将 flag 的字节序列转换为一个大整数m
,用于加密。
-
加密:
c = pow(m, e, n)
:使用公钥 (e,n)(e, n)(e,n) 对明文m
进行加密,得到密文c
。这是一个典型的 RSA 加密公式:c=memod nc = m^e \mod nc=memodn。
-
输出:
- 打印了
n
和c
的值,以便进行后续的解密挑战。
- 打印了
给出的数值是:
- n=20157817216833049974118616679190322575901864730668507144482957326182327740713453136333068539106100083027097757551546799575541531293312944887561483280916726369016319612934944450526019975934692298293195561411060477885773405036861008621958822147021639661752191557841624683504007344816984603147270693016174228339440038288427589158890266471648249125569765932533982185987755634089743765749564333612512194933232263756745378109393583291224010700913573540529420652068898993898479078127254056483844853346390136211506294067721897916177680505768950977554254296490057308239156157838713269319343550186321669135205346102566222209669 n = 20157817216833049974118616679190322575901864730668507144482957326182327740713453136333068539106100083027097757551546799575541531293312944887561483280916726369016319612934944450526019975934692298293195561411060477885773405036861008621958822147021639661752191557841624683504007344816984603147270693016174228339440038288427589158890266471648249125569765932533982185987755634089743765749564333612512194933232263756745378109393583291224010700913573540529420652068898993898479078127254056483844853346390136211506294067721897916177680505768950977554254296490057308239156157838713269319343550186321669135205346102566222209669n=20157817216833049974118616679190322575901864730668507144482957326182327740713453136333068539106100083027097757551546799575541531293312944887561483280916726369016319612934944450526019975934692298293195561411060477885773405036861008621958822147021639661752191557841624683504007344816984603147270693016174228339440038288427589158890266471648249125569765932533982185987755634089743765749564333612512194933232263756745378109393583291224010700913573540529420652068898993898479078127254056483844853346390136211506294067721897916177680505768950977554254296490057308239156157838713269319343550186321669135205346102566222209669
- c=5550850995648431308122724561862321298330352966504532253941573060435227523644220681378247173522846277972751332156705955942551071366281109518855989368023554577347696287379088984498887267023431403241260985825192081189555696375201465274976430133175304403838370385321814599530029586724109782046451141042893149621734986470429809900193355827277275722227551304063436655735688781909919640024815423934941154264458525685654968501198690422227441772911516150511832369493008699728485535931462629750837466741030971574567414557223186771992335515743296998159321297009298268426970949419821980177125657422472184449785482615837014554125 c = 5550850995648431308122724561862321298330352966504532253941573060435227523644220681378247173522846277972751332156705955942551071366281109518855989368023554577347696287379088984498887267023431403241260985825192081189555696375201465274976430133175304403838370385321814599530029586724109782046451141042893149621734986470429809900193355827277275722227551304063436655735688781909919640024815423934941154264458525685654968501198690422227441772911516150511832369493008699728485535931462629750837466741030971574567414557223186771992335515743296998159321297009298268426970949419821980177125657422472184449785482615837014554125c=5550850995648431308122724561862321298330352966504532253941573060435227523644220681378247173522846277972751332156705955942551071366281109518855989368023554577347696287379088984498887267023431403241260985825192081189555696375201465274976430133175304403838370385321814599530029586724109782046451141042893149621734986470429809900193355827277275722227551304063436655735688781909919640024815423934941154264458525685654968501198690422227441772911516150511832369493008699728485535931462629750837466741030971574567414557223186771992335515743296998159321297009298268426970949419821980177125657422472184449785482615837014554125
特点分析:
-
相邻素数特性:
- 由于
p
和q
是相邻素数,且都是 1024 位的,因此可以利用相邻素数的性质,通过近似开平方快速找到p
。 - 这个特性使得我们不需要对 nnn 进行困难的素因数分解,转而通过估算平方根来找到
p
。
- 由于
-
加密指数 e=33e = 33e=33:
- 通常 RSA 使用的小公钥指数(例如 e=3e = 3e=3 或 e=65537e = 65537e=65537),但这里使用了 e=33e = 33e=33,这在破解上可以带来一些不同的考虑。加密指数越小,解密可能越容易,但这里使用 33 仍然需要特定的方法进行破解。
-
解密思路:
- 利用 中国剩余定理(CRT) 将模 ppp 和模 qqq 下的开方结果合并,快速恢复出明文。
- 可以通过
p
和q
的关系直接使用Zmod(p)
和Zmod(q)
来解密,而不需要对密文进行完全的分解。 - 在模 ppp 和模 qqq 上分别开 eee-次方根,通过中国剩余定理合并结果,恢复出明文。
破解过程:
破解这道题的主要步骤是:
- 通过
iroot(n, 2)
估算出 nnn 的平方根,然后利用next_prime()
找到p
和q
,因为它们是相邻素数。 - 使用
Zmod(p)
和Zmod(q)
计算密文 ccc 的 eee-次方根,找到在模 ppp 和模 qqq 下的明文部分。 - 使用中国剩余定理将模 ppp 和模 qqq 下的明文合并,恢复完整的明文
flag
。
总的来说
这种解法极大地简化了传统 RSA 的破解步骤,不需要直接对 nnn 进行因数分解,利用了密钥生成时的特殊性质——即 p
和 q
是相邻的素数。
直接上脚本:
from Crypto.Util.number import inverse, long_to_bytes # 导入必要的库用于计算和转换
from gmpy2 import gcd, iroot, next_prime, Zmod, crt # 导入 gmpy2 库,用于数学运算
# 公钥参数
e = 33 # 加密指数
n = 20157817216833049974118616679190322575901864730668507144482957326182327740713453136333068539106100083027097757551546799575541531293312944887561483280916726369016319612934944450526019975934692298293195561411060477885773405036861008621958822147021639661752191557841624683504007344816984603147270693016174228339440038288427589158890266471648249125569765932533982185987755634089743765749564333612512194933232263756745378109393583291224010700913573540529420652068898993898479078127254056483844853346390136211506294067721897916177680505768950977554254296490057308239156157838713269319343550186321669135205346102566222209669
c = 5550850995648431308122724561862321298330352966504532253941573060435227523644220681378247173522846277972751332156705955942551071366281109518855989368023554577347696287379088984498887267023431403241260985825192081189555696375201465274976430133175304403838370385321814599530029586724109782046451141042893149621734986470429809900193355827277275722227551304063436655735688781909919640024815423934941154264458525685654968501198690422227441772911516150511832369493008699728485535931462629750837466741030971574567414557223186771992335515743296998159321297009298268426970949419821980177125657422472184449785482615837014554125
# 估算 n 的平方根来找到 p 的近似值
t = iroot(n, 2)[0] # 使用开平方方法得到 n 的平方根
p = next_prime(t) # 找到比 t 大的下一个素数作为 p
# 计算 q,因为 q 是 n // p
q = n // p
# 计算 φ(n),用来检查 e 和 φ(n) 是否互质
phi = (p - 1) * (q - 1)
assert gcd(e, phi) == 1 # 确保 e 和 φ(n) 是互质的
# 分别在模 p 和模 q 上求 c 的 33 次方根
res1 = Zmod(p)(c).nth_root(e, all=True) # 在模 p 的情况下求 e 次方根
res2 = Zmod(q)(c).nth_root(e, all=True) # 在模 q 的情况下求 e 次方根
# 使用中国剩余定理 (CRT) 将模 p 和模 q 的解合并,恢复明文
for mp in res1:
for mq in res2:
# 使用 CRT 合并模 p 和模 q 的解,得到 m
m = crt([int(mp), int(mq)], [p, q])
# 将 m 转换为字节,再转换为字符串
flag = long_to_bytes(int(m))
# 如果解出的明文包含 "CnHongke",说明找到正确的解
if b"CnHongke" in flag:
print(flag) # 输出正确的 flag
break # 退出循环,避免多余的计算
脚本简单分析:
-
估算
p
的值:- 使用
iroot(n, 2)
得到n
的平方根,之后找到比其大的下一个素数p
,这大大简化了n
分解的过程。
- 使用
-
模
p
和模q
上的开方:- 分别在模
p
和模q
上使用Zmod(p)
和Zmod(q)
来计算c
的 eee-次方根。
- 分别在模
-
中国剩余定理 (CRT):
- 使用
crt()
函数将模p
和模q
的解合并,恢复出明文。CRT 是解 RSA 问题时常用的优化技术,能够减少计算复杂度。
- 使用
-
检查公钥指数
e
和 φ(n) 的互质性:- 通过
gcd(e, phi)
确保e
和 φ(n) 是互质的,这是 RSA 正常工作所必须的条件。
- 通过
-
输出优化:
- 在找到包含 “CnHongke” 的明文后,立即输出并停止循环,避免不必要的额外计算。
这里推荐使用SageMath来跑。
至此:
CnHongke{a5c3895e-cb83-47aa-9674-03f8644b24c0}
本科组
1、兔兔
与高职组密码——兔兔一样,这里不再多述
2、Evaluate
解题思路
暂无!后续补充!!!
附件如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from Crypto.Util.number import bytes_to_long
from secret import flag
import random
import gmpy2
def genPrime():
while True:
p = random.getrandbits(512)
tp = random.getrandbits(20)
if gmpy2.is_prime(p**4 + tp):
return p**4 + tp, tp
p, tp = genPrime()
q, tq = genPrime()
m = bytes_to_long(flag)
e = 0x10001
n = p*q
c = pow(m, e, n)
print("n = %s" % n)
print("e = %s" % e)
print("c = %s" % c)
print("tp = %s" % tp)
print("tq = %s" % tq)
# n = 348633861268974800987621543594391794050602576251154974984659464183689670557042154278476974697016453490819201785300358784253012923228243097332134404026242910925604588584038259315315228893889444939843669749257486949708860998561814051925074671606923444410295823305005631529086726536147080895602477663228560616676262170405451819508135377950748303706440414601010930562462659426049400683721959339610715750999514705160092064778069808917777152514518960915921397885010454299837700178137473176559506632775878504970727133195589627719000777342134690163930795976672849558173904352382711840948912634106992816013078110687913395982200522940389367833394880385914293130497753278649559529676510017019182246185738847006734386951590377969081341642471461851623729419475374687711926818016925130183445353022168148152613275378217305521229419905775407833666184116147956331221347245953176211884420812539281755782597765958348682860931540219177981167631729560430872329478453669808198420220568111802596917628247419801000380051883682016016893011257266195403820466085438260532078126518195549771986252677929871971069350126010168872556301769401538273100167581309470241064559591540046250697280422023839907314367021570351907528865821217382408249845415366037174707949
# e = 65537
# c = 202965658123729301695290823588005720680664417383271993570464094584890156176108923486110171972972401993113712822375619016514191441705557143301731949025997401120652546526334614651700016909257418389562926225046685258219156739609850845736987332118823900545391294861832234610386403331298302317366368346605088228069795089494937055846995868026763654573160917953950219591680588269621708080375680780622173346321372110714193312428798405513095371123064765822911565668751796906670123755481337516315497209404923447908266048920718971446657572773797994824745300369090756972491298883731535351041843493328332121172626485278531188064327174024580996047299403489737947793582635512754294875130563654073805276975301166999928500988213734889107309101743396695392326585224102418089278220663084936941723320602981332095079433983160843105352642856944067290949622842028688640092196424806483741754010182163535577066285500692095904007376189028631599131998117956682152954904738302696106875498821802348285350766676272217956731370990824312151723725994330797852456849294398594048551068472030487686422669190551340406651929845542303823281151104196845826324513363030355866270418198112439142751608756191955103910670125155154217957588507823217402729485000911690196720106
# tp = 954221
# tq = 875057
五、REVERSE
高职组
1、easyre
解题思路
暂无!后续补充!!!
附件已打包!
2、16queen
解题思路
暂无!后续补充!!!
附件已打包!
本科组
3、easystd
解题思路
暂无!后续补充!!!
附件已打包!
标签:编码,WriteUp,Base64,flag,Base62,2024,CTF,id,card From: https://blog.csdn.net/administratorlws/article/details/142919321