31. 听首音乐

用Audacity看频谱图得到摩斯密码..... -... -.-. ----. ..--- ..... -.... ....- ----. -.-. -... ----- .---- ---.. ---.. ..-. ..... ..--- . -.... .---- --... -.. --... ----- ----. ..--- ----. .---- ----. .---- -.-.

解码得到5BC925649CB0188F52E617D70929191C

{% folding cyan, flag %}

flag
flag{5BC925649CB0188F52E617D70929191C}

{% endfolding %}

32. 好多数值

打开1.txt后发现全部都是*,*,*这种形式的数据,且每个数最大为255,很明显是RGB值,那么这题就很明显是需要将这些RGB像素点还原成一张图片了

再看文件的行数,除去空行以外共有61366行,分解质因数得到2*61*503

排列组合一下得到下面几种组合方式:122*50361*10062*30683

最后两种显然不合适,那么就先尝试122*503这个长宽组合

附上源码

python
from PIL import Image def create_image_from_rgb_file(file_path, width, height):    with open(file_path, 'r') as file:        lines = file.readlines()     rgb_values = [tuple(map(int, line.strip().split(','))) for line in lines]     image = Image.new('RGB', (width, height))     pixels = []    for i in range(height):        for j in range(width):            index = i * width + j            if index < len(rgb_values):                pixels.append(rgb_values[index])            else:                pixels.append((0, 0, 0))     image.putdata(pixels)     image.save('output.png')    print("图像已保存为 output.png") if __name__ == "__main__":    width = int(input("请输入图像边长1: "))    height = int(input("请输入图像边长2: "))     with open('1.txt', 'r') as file:        line_count = sum(1 for _ in file)     create_image_from_rgb_file('1.txt', width, height)

解出来的图片向右旋转90度,水平翻转就得到flag了

{% folding cyan, flag %}

flag
flag{youc@n'tseeme}

{% endfolding %}

33. 很普通的数独(ISCCCTF)

刚解压看缩略图能隐约看出1.png有点像二维码定位角,再看图片数量不但猜到这是一张二维码,有数字的地方涂黑就好了

先按5×5把图片拼起来,发现1.png5.png21.png都很像二维码定位角,更加确定这就是一张二维码了,然而它们的位置明显不对

21.png放在原来1.png的位置,5.png放在原来21.png的位置,21.png放在原来5.png的位置就搞定了

总之前面大致的思路就是这样,但是由于这个工作量太大了我懒得画,于是我就用了网友们的数据(心虚),附上还原出来的二维码

33.png

扫码得到Vm0xd1NtUXlWa1pPVldoVFlUSlNjRlJVVGtOamJGWnlWMjFHVlUxV1ZqTldNakZIWVcxS1IxTnNhRmhoTVZweVdWUkdXbVZHWkhOWGJGcHBWa1paZWxaclpEUmhNVXBYVW14V2FHVnFRVGs9,base64解码8次就能得到flag了

{% folding cyan, flag %}

flag
flag{y0ud1any1s1}

{% endfolding %}

34. PEN_AND_APPLE

没做出来

网上搜了下原题,是NTFS数据流隐藏,按理来说用NtfsStreamsEditor就可以解出来了

然而似乎是题目出问题了,无法复现

下面贴上网上找到的flag

{% folding cyan, flag %}

flag
SYC{Hei_hei_hei}

{% endfolding %}

35. color

每张图片都拖进随波逐流修复高宽,发现下面多了一行黑白块

按照黑白分别对应1和0的逻辑并按图片名字顺序排列可以得到这些数:11111111010111101111111110111111101111110000110010101011000101001010010000001101110100110111010101111001101101101011011000111001101101111101

直接二进制转ascii发现是乱码的,于是转换思路看是不是要竖着看,写个python脚本看看

python
flags = ['11111111010111101111', '11111011111110111111', '00001100101010110001', '01001010010000001101', '11010011011101010111', '10011011011010110110', '00111001101101111101'] # 按顺序存到列表里 for i in range(0, 20):    flag = ''    for j in range(0, 7):        flag += flags[j][i] # 提取每一列的二进制位,将其组合成一个新的二进制字符串    print(chr(int(flag, 2)), end='') # 将该二进制字符串转换为对应的 ASCII 字符并输出

{% folding cyan, flag %}

flag
flag{Png1n7erEs7iof}

{% endfolding %}

36. 怀疑人生

ctf3.jpg扫码的结果是12580}

ctf2.jpgbinwalk一下发现一个压缩包,解压得到一个文本,内容是

text
..... ..... ....! ?!!.? ..... ..... ....? .?!.? ....! .?... ..... .......!?! !.?.. ..... ..... ..?.? !.?.. ..... ..... ..... ..... !.?.. .......... .!?!! .?!!! !!!!! !!!!? .?!.? !!!!! !!!!! !!!!! .?... ....! ?!!.?!!!!! !?.?! .?!!! !!!!! !!!!! .!!!. ?.... ..... ..... .!?!! .?... .......... .?.?! .?!.? .

丢到随波逐流BrainFuck解码得到3oD54e,再用base58解码得到misc

ctf1.jpg试了发现不是伪加密,题目也没别的线索,那就爆破,解除密码是password,文本内容是XHU2Nlx1NmNcdTYxXHU2N1x1N2JcdTY4XHU2MVx1NjNcdTZiXHU2NVx1NzI=,经过两次base64解码和一次十六进制转字符得到flag{hacker

连起来就是flag了

{% folding cyan, flag %}

flag
flag{hackermisc12580}

{% endfolding %}

37. 红绿灯

丢到随波逐流用gif动图分解帧给拆出来(怎么会有1168张那么多🫠)

扫了一眼发现除了红绿黄灯以外还有很多不知道是什么玩意儿的灰灯

写个脚本把这些灰灯删一下看看先

删了灰灯在文件夹看到每隔8盏灯就有1盏黄灯,猜测是二进制转ascii,每个数长度为8且每个数之间隔1盏黄灯,于是把脚本改改标注出这三盏灯,红绿黄分别对应10/

在脚本输出的结果前面补上漏掉的1(因为第一张图片和其他的格格不入)得到了01100110/01101100/01100001/01100111/01111011/01010000/01101100/00110011/00110100/01110011/00110011/01011111/01110000/00110100/01111001/01011111/00110100/01110100/01110100/00110011/01101110/01110100/00110001/00110000/01101110/01011111/01110100/00110000/01011111/01110100/01110010/00110100/01100110/01100110/00110001/01100011/01011111/01110011/00110100/01100110/00110011/01110100/01111001/01011111/01110111/01101000/00110011/01101110/01011111/01111001/00110000/01110101/01011111/00110100/01110010/00110011/01011111/00110000/01110101/01110100/01110011/00110001/01100100/00110011/01111101

下面附上检测、删除和分类的代码:

python
import osfrom PIL import Image def find_duplicate_images(template_image_name, directory):    duplicates = []    template_path = os.path.join(directory, f'{template_image_name}.png')    with Image.open(template_path) as template_img:        template_hash = hash(template_img.tobytes())                for filename in sorted(os.listdir(directory)):            if filename.endswith('.png'):                try:                    file_num = int(filename.rsplit('.', 1)[0])                    if 0 <= file_num < 1168: # 有1168张图片                        file_path = os.path.join(directory, filename)                        with Image.open(file_path) as img:                            if hash(img.tobytes()) == template_hash:                                duplicates.append(file_num)                except ValueError:                    continue    return duplicates def delete_images(image_numbers, directory):    for image_num in image_numbers:        image_name = f"{image_num}.png"        image_path = os.path.join(directory, image_name)        try:            os.remove(image_path)        except Exception as e:            print(f"Failed to delete {image_name}: {e}") def create_traffic_light_string(red_lights, yellow_lights, green_lights):    traffic_dict = {}    for num in red_lights:        traffic_dict[num] = '1'    for num in yellow_lights:        traffic_dict[num] = '/'    for num in green_lights:        traffic_dict[num] = '0'     result = ''.join([traffic_dict.get(num, '') for num in sorted(traffic_dict)])    return result if __name__ == "__main__":    gif_frame_directory = '/path/gifframe' # 图片所在文件夹路径     # # 删除灰色的图片    # delete_images(find_duplicate_images('1', gif_frame_directory), gif_frame_directory)    # delete_images(find_duplicate_images('3', gif_frame_directory), gif_frame_directory)    # delete_images(find_duplicate_images('17', gif_frame_directory), gif_frame_directory)     # 检测红灯    red_lights = find_duplicate_images('2', gif_frame_directory)    red_lights.sort()     # 检测黄灯    yellow_lights = find_duplicate_images('16', gif_frame_directory)    yellow_lights.sort()     # 检测绿灯    green_lights = find_duplicate_images('18', gif_frame_directory)    green_lights.sort()     # 创建并打印交通灯字符串    traffic_light_str = create_traffic_light_string(red_lights, yellow_lights, green_lights)    print(traffic_light_str)

接下来只需要把那一堆二进制的数转成ascii就搞定了,附上源码:

python
flag = '01100110/01101100/01100001/01100111/01111011/01010000/01101100/00110011/00110100/01110011/00110011/01011111/01110000/00110100/01111001/01011111/00110100/01110100/01110100/00110011/01101110/01110100/00110001/00110000/01101110/01011111/01110100/00110000/01011111/01110100/01110010/00110100/01100110/01100110/00110001/01100011/01011111/01110011/00110100/01100110/00110011/01110100/01111001/01011111/01110111/01101000/00110011/01101110/01011111/01111001/00110000/01110101/01011111/00110100/01110010/00110011/01011111/00110000/01110101/01110100/01110011/00110001/01100100/00110011/01111101'print(''.join([chr(int(i, 2)) for i in flag.split('/')]))

输出的结果就是flag

{% folding cyan, flag %}

flag
flag{Pl34s3_p4y_4tt3nt10n_t0_tr4ff1c_s4f3ty_wh3n_y0u_4r3_0uts1d3}

{% endfolding %}

38. 不简单的压缩包

binwalk发现隐藏了两个压缩包,先提取出来

尝试伪加密修复失败,于是开始字典爆破

爆破得到tingshuo.txt的密码是0,文本内容是パスワードは50桁だそうです,翻译一下得到听说密码是 50 位数

穷举所有可能不切实际,于是猜测它们是重复的,先写个字典先

python
passwords = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z','A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] with open('dict.txt', 'w') as dictionary:    for i in range(len(passwords)):        dictionary.write(f"{passwords[i]*50}\n")

然后把压缩文件和字典一起丢到ARCHPR跑一下,结果发现密码就是50个小写a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,解压拿到flag.swf

这个后缀好眼熟但是又不知道是什么,一查才知道是flash动画(😂好老的东西)

整了个浏览器插件Ruffle来打开,发现是按键盘左右键控制人物赛跑的游戏,而且必须交替按,否则人物还会摔跤

实在跑不过那群人机,于是去下了个swf的逆向工具JPEXS Decompiler

上面都是一些游戏资源,直接略过来看scripts目录,一个个翻

功夫不负有心人🥲我在scripts-Define Sprite(142)-frame 1-DoAction下面发现了这样的代码:

text
user_spd_min = 7;user_spd_max = 17;

凭借我敏锐的直觉,我判断出这俩大概率是玩家的跑步速度😎把这两个数值都改成了9999回去再跑一遍,随便敲几下就轻松通关了

然而,通关了之后flag没出来🙃这是一道逆向题实锤了

我又回去吭哧吭哧地找,终于在scripts-Define Sprite(171)-frame 1-DoAction下面发现了这串神秘代码3F3F666C61677B6A7065787337726565666C6173687D2121

丢到随波逐流看看是怎么个事儿,然后发现flag就这么出来了,base16解码就好了

{% folding cyan, flag %}

flag
flag{jpexs7reeflash}

{% endfolding %}

39. 一枝独秀

binwalk发现藏了压缩包,用foremost解出来发现有密码

尝试伪加密修复,失败了

丢到ARCHPR暴力破解,找到密码12345678

解压出来123张图片,发现flower (81).jpg大小和修改时间和其他的图片都不一样(还真是一枝独秀呢)

考虑到是jpg文件,于是又用stegdetect扫了一下,结果却输出了error: Quantization table 0x00 was not defined

实在没想法了,于是去看了网上大佬的wp,才知道要用到一个jpg的隐写工具JPHS(真是奇怪,按理来说jphide用stegdetect应该是能扫出来的才对啊,想不明白为什么扫不出来)

这个工具我找了半天,最后在德国数据处理服务中心GWDG给我找到了, 下载链接

用工具seek需要密码,经过多次尝试发现密码就是图片属性里的主题flowers

提出来的文件丢到随波逐流发现是zip文件,改一下后缀然后解压,发现了一个名为参悟佛法.txt的文本

text
从一朵花中看到一个世界,那从一段佛文中能看到什么呢?你站在4楼的栏杆上眺望远方,如果参悟不出来就打算跳下去佛曰:阿罰豆缽娑提諳竟諳迦亦侄栗侄大梵尼朋梵彌哆耨除怛奢般是諳爍悉哆爍冥參特參怯涅皤吉缽阿藝耶諳勝侄竟離諳諸尼缽曰。梵究呐耨盧他姪明漫究呐得哆藐集能冥盡滅知俱朋怯室神奢羅姪豆罰帝遠蘇明梵苦奢密侄曰缽者特哆呼勝蘇不冥死等那阿冥悉奢薩豆涅缽波罰。罰摩侄故罰夢缽恐皤寫諳闍舍哆得波苦奢即罰恐冥道一哆究梵呼冥闍哆上罰南訶諳寫冥依皤者哆諦故死哆夷菩侄曰呐逝至皤佛諳耶

一眼看出是佛曰加密,再丢到随波逐流,解开得到H-hDs10OZL3lhIZZbeRSbbbVRZNm32W2X33mGm3Txt999RdV9hx0

做到这里好像又没什么思路了,突然想起题目的提示翻过四个栅栏即可得到flag,不就是栅栏加密吗,于是又丢回随波逐流,分为4栏时,解密结果为:HINT-ZmxhZ3tDb29seW91R290SXROb3dZb3VLbm93VGhlRmxhZ30,把ZmxhZ3tDb29seW91R290SXROb3dZb3VLbm93VGhlRmxhZ30用base64解码就能拿到flag了

{% folding cyan, flag %}

flag
flag{CoolyouGotItNowYouKnowTheFlag}

{% endfolding %}

40. 小猪佩奇

一点思路都没,看了评论区才知道出题人是给了提示的😭(可恶啊怎么不把链接在提示那栏贴出来呢👿出题人的提示

好吧,单看提示只知道和加密有关但还是没什么思路,看了评论区才知道是LSB隐写加密

问了下AI,下面是简易的判断方式:

正常的图像中,像素值的分布应该是比较随机的。如果图像被用来做LSB隐写,那么在最低几位上可能会显示出非随机性,因为这些位被用来存储隐藏信息。
你可以使用专门的工具来分析图像中每个颜色通道的最低有效位的频率分布。如果分布异常(例如某些值过于频繁或不频繁),这可能意味着图像中存在隐写信息。

既然如此,就先把出题人提到的字典先下载下来。

这里使用github上的一个工具处理livz/cloacked-pixel: LSB steganography and detection(注意:该项目不支持Python3,作者疑似放弃了该项目)

上面这个仓库的代码不支持Python3,于是我就把这个问题修复了,顺手还把README加上了中文译文。要是对你有帮助的话欢迎给个star⭐🥰aristorechina/cloacked-pixel: LSB steganography and detection

下载下来之后写个脚本进行爆破,代码参考了大佬的wp

python
import reimport osimport filetype # pip install filetypefrom lsb import extract # 把github上下载的lsb.py放到当前目录下 path = '/path' # 文件存放目录dict_path = f'{path}/darkweb2017-top1000.txt'filename=f'{path}/小猪佩奇.png' # 反转字典with open(dict_path, "r", encoding='utf-8') as file:    lines = file.readlines()lines.reverse()with open(dict_path, "w", encoding='utf-8') as file:    file.writelines(lines) # 读取字典with open(f'{path}/darkweb2017-top1000.txt','r+') as file:    file = file.readlines() # 提取for i in file:    i=i.replace('\n','')    if len(i)==7 and re.search('[0-9!?]',i)==None:        out_file= f'{path}/output/{i}'        extract(filename,out_file,i) # 当前路径下所有子文件def get_files_names(file_dir):    for _, _, files in os.walk(file_dir):        return files files_names = get_files_names(f'{path}/output/') # 判断文件类型并输出for i in range(0, len(files_names)):    try:        kind = filetype.guess(f'{path}/output/{files_names[i]}')        if kind is None:            pass        else:            print(f"File: {files_names[i]}, MIME Type: {kind.mime}")    except Exception as e:        print(f"Error processing file {files_names[i]}: {e}")

输出了File: raiders, MIME Type: image/png

给文件output目录下生成的raiders文件加上.png后缀,打开扫码就得到flag了

{% folding cyan, flag %}

flag
flag{37d9704c-9752-434c-8891-ee15e1800490}

{% endfolding %}

好多压缩包

买了才发现这题要8个币(好贵

解压了发现有好多压缩包(还真是

打开几个发现都是4字节的data.txt,遂打开随波逐流,用多zip文件CRC32爆破

因为是4字节所以位数就是4,开始爆破

等了好久好久,多zip文件crc碰撞结束,结果为:z5BzAAANAAAAAAAAAKo+egCAIwBJAAAAVAAAAAKGNKv+a2MdSR0zAwABAAAAQ01UCRUUy91BT5UkSNPoj5hFEVFBRvefHSBCfG0ruGnKnygsMyj8SBaZHxsYHY84LEZ24cXtZ01y3k1K1YJ0vpK9HwqUzb6u9z8igEr3dCCQLQAdAAAAHQAAAAJi0efVT2MdSR0wCAAgAAAAZmxhZy50eHQAsDRpZmZpeCB0aGUgZmlsZSBhbmQgZ2V0IHRoZSBmbGFnxD17AEAHAA==

CyberChef用base64解码,发现里面夹杂着提示fix the file and get the flag

把它保存之后丢到随波逐流,文件头信息:cf907300,未知文件类型,结合上面的信息大概就知道是要修复文件头了

010Editor打开,看到了RAR的文件尾C43D7B00400700,补上RAR的文件头526172211A0700,改文件后缀为.rar,然后找个解压工具打开,在注释那里就看到了

{% folding cyan, flag %}

flag
flag{nev3r_enc0de_t00_sm4ll_fil3_w1th_zip}

{% endfolding %}

一个普通的压缩包(xp0intCTF)

解压下来发现是rar文件,,用WinRAR再解压发现诊断信息文件头已损坏:secret.png

然而我不知道怎么修复,看了大佬的wp才知道

修复好之后把secret.png丢到随波逐流发现文件类型是gif,分解后发现只有两帧

分别用StegSolve打开,在Red plane 0发现二维码的下半部分和残缺的上半部分

补全上半部分,把它和下半部分拼起来就搞定了

42.jpg

{% folding cyan, flag %}

flag
flag{yanji4n_bu_we1shi}

{% endfolding %}

43. QAQ

解压后丢到随波逐流,文件头是330d0d0a,没看出来是什么

又用记事本打开,看到了一些貌似是代码的东西,还在里面发现了QAQ.py

再在搜索引擎找了下330d0d0a,虽然没找到这个文件头,但是搜出来的清一色都是pyc,那就当作是pyc逆向一下看看吧uncompyle6.exe QAQ.pyc >QAQ.py

得到以下代码:

python
# uncompyle6 version 3.9.2# Python bytecode version base 3.6 (3379)# Decompiled from: Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun  6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)]# Embedded file name: QAQ.py# Compiled at: 2018-08-15 14:38:31# Size of source mod 2**32: 620 bytes  def encryt(key, plain):    cipher = ""    for i in range(len(plain)):        cipher += chr(ord(key[i % len(key)]) ^ ord(plain[i]))     return cipher  def getPlainText():    plain = ""    with open("plain.txt") as f:        while True:            line = f.readline()            if line:                plain += line            else:                break     return plain  def main():    key = "LordCasser"    plain = getPlainText()    cipher = encryt(key, plain)    with open("cipher.txt", "w") as f:        f.write(cipher.encode("base_64"))  if __name__ == "__main__":    main() # okay decompiling QAQ.pyc

根据这个写了个解密的代码,cipher.txt应该就是描述里给的内容

python
import base64def decrypt(key, cipher):    plain = ""    for i in range(len(cipher)):        plain += chr(ord(key[i % len(key)]) ^ ord(cipher[i]))    return plain key = "LordCasser"cipher = base64.b64decode("FSAnRAIzNlMjPQMjNyBJNTs6NlIFPFIqDDVTJy0zGE8rKxZBJDIrJkYoPUQML1M3MDYJZTElFyI7 UzE6DTtSNxckNDw2Mxk9Jzc=").decode()plain = decrypt(key, cipher)with open("plain.txt", "w") as f:    f.write(plain)

结果解出了下面这个(被耍了)

text
YOU ARE FOOLEDTHIS IS NOT THAT YOU WANTGO ON DUDECATCH THAT STEGOSAURUS

根据这个提示用stegosaurus解就行了python stegosaurus.py -x QAQ.pyc(注意这里要用Python 3.6,版本太高会报错)

{% folding cyan, flag %}

flag
flag{fin4lly_z3r0_d34d}

{% endfolding %}

44. 妹子的陌陌

binwalk提取出来一个被加密的rar文件,试出来密码是图片里的字喜欢我吗.

解压得到下面的文本

text
嘟嘟嘟嘟士兵:报告首长!已截获纳粹的加密电报!首长:拿来看看电报内容:..../-/-/.--./---.../-..-./-..-././-./-.-./---/-.././.-.-.-/-.-./..../.-/..../..-/---/.-.-.-/-.-./---/--/-..-.首长:我操你在逗我吗?你确定是他们纳粹发的吗?士兵:难道我弄错了?哦。。。等等是这一条内容:http://c.bugku.com/U2FsdGVkX18tl8Yi7FaGiv6jK1SBxKD30eYb52onYe0=      AES Key:@#@#¥%……¥¥%%……&¥士兵:二维码真的扫不出来吗??肯定可以扫出来

先解开摩斯密码得到HTTP://ENCODE.CHAHUO.COM/,打开了是一个在线加密解密网站

在这个网站进行AES解密(用别的工具也行,既然出题人给了就顺手用了。至于为什么是AES解密那是因为上面说了AES Key。)

密文是U2FsdGVkX18tl8Yi7FaGiv6jK1SBxKD30eYb52onYe0=,密钥是@#@#¥%……¥¥%%……&¥,解密结果是momoj2j.png

到这一步就没思路了,看了大佬的wp才知道这里是要访问http://c.bugku.com/momoj2j.png,但是链接挂了,这里就直接把我找到的图片贴出来了。直接扫码就是flag了

44.png

{% folding cyan, flag %}

flag
KEY{nitmzhen6}

{% endfolding %}

45. 就五层你能解开吗

先看描述:

链接: http://pan.baidu.com/s/1i4TQoz7 密码: w65m 提示:第一层:CRC32 碰撞 第二层:维吉尼亚密码 第三层:sha1 碰撞 第四层:md5 相同文件不同 第五层:RSA

(这题不会Crpyto真的寸步难行😢)

第一层:

下载来的7z压缩包用CRC32 tools爆破

三个txt文档的CRC分别是7C2DF918A58A19264DAD5967

然后在这个工具目录下执行python crc32.py reverse [CRC],这里的CRC例如0x7C2DF918

一条条查看不难得到_CRC32_i5_n0t_s4f3,解压密码到手了

第二层:

写代码解:

python
def letter_to_index(letter):    if 'A' <= letter <= 'Z':        return ord(letter) - ord('A')    elif 'a' <= letter <= 'z':        return ord(letter) - ord('a')    else:        return None def index_to_letter(index, is_upper):    if is_upper:        return chr(index + ord('A'))    else:        return chr(index + ord('a')) def prepare_keyword(keyword, length):    return (keyword * (length // len(keyword) + 1))[:length] def vigenere_decrypt(ciphertext, keyword):    decrypted_text = []    keyword = keyword.upper()    extended_keyword = prepare_keyword(keyword, len(ciphertext))    keyword_index = 0     for char in ciphertext:        if 'A' <= char <= 'Z' or 'a' <= char <= 'z':            is_upper = char.isupper()            char_index = letter_to_index(char)            key_index = letter_to_index(extended_keyword[keyword_index])            dec_idx = (char_index - key_index) % 26            decrypted_text.append(index_to_letter(dec_idx, is_upper))            keyword_index += 1        else:            decrypted_text.append(char)     return ''.join(decrypted_text) def read_file(file_path):    with open(file_path, 'r', encoding='utf-8') as file:        return file.read() def read_keywords(file_path):    with open(file_path, 'r', encoding='utf-8') as file:        return [line.strip() for line in file] def main():    path = "/path" # 密文和密钥所在目录    ciphertext = read_file(f'{path}/ciphertext.txt') # 密文    keywords = read_keywords(f'{path}/keys.txt') # 密钥     for keyword in keywords:        plaintext = vigenere_decrypt(ciphertext, keyword)        if 'password' in plaintext.lower(): # password也可以是别的词,猜出来的            print(plaintext) if __name__ == "__main__":    main()

最后就得到了the vigenere cipher is a method of encrypting alphabetic text by using a series of different caesar ciphers based on the letters of a keyword it is a simple form of polyalphabetic substitution so password is vigenere cipher funny,所以解压密码就是vigenere cipher funny

第三层:

这层不会解,代码来自大佬的wp

python
# 不完整密码: *7*5-*4*3?# 不完整sha-1: 619c20c*a4de755*9be9a8b*b7cbfa5*e8b4365* import stringimport hashlibimport itertools  # 1.先定义几个字符集到时候使用str_digits = string.digitsstr_upper = string.ascii_uppercasestr_lower = string.ascii_lowercasestr_printable = string.printable password = "%s7%s5-%s4%s3?"for chrs in itertools.product(str_printable, repeat=4):    pwd = password % chrs    if (hash_str := hashlib.sha1(pwd.encode()).hexdigest()).startswith("619c20c"):        print(pwd, hash_str)

运行结果是

text
s7v5-T4`3? 619c20c33dbeff190fab0d5498f0789e3ec1519aI7~5-s4F3? 619c20c4a4de75519be9a8b7b7cbfa54e8b4365b

解压密码是I7~5-s4F3?

第四层:

搜索文本内容后

Hello World ;-)
MD5校验真的安全吗?
有没有两个不同的程序MD5却相同呢?
如果有的话另一个程序输出是什么呢?
解压密码为单行输出结果。

Hello World ;-)
MD5 check is really safe?
There are two different procedures MD5 is the same?
If so what is the output of another program?
The decompression password is a single-line output.

发现来源于下面两个程序,这两个程序会在屏幕上打印出不同的字符 ,而它们的md5相同,都为18fcc4334f44fed60718e7dacd82dddf

GoodbyeWorld-colliding.exe
HelloWorld-colliding.exe

因此解压密码是Goodbye World :-(

第五层:

解压得到了flag.encrsa_public_key.pem

然后又不会了(Crypto是真的不会😭😭😭),下面贴上更改后的刚刚引用过的大佬的wp的代码(大佬的代码直接运行报错了,要将 gmpy2.mpz 类型转换为 int 类型才行):

python
import sympyimport libnumfrom Crypto.PublicKey import RSA  # 1.read flag.encwith open("flag.enc", "rb") as f:    flag = f.read()    c = libnum.s2n(flag) # 2.read pub_keywith open("rsa_public_key.pem") as f:    pub_key = RSA.import_key(f.read()) n = pub_key.ne = pub_key.e # 3.使用factordb查询的p = 15991846970993213322072626901560749932686325766403404864023341810735319249066370916090640926219079368845510444031400322229147771682961132420481897362843199q = 28805791771260259486856902729020438686670354441296247148207862836064657849735343618207098163901787287368569768472521344635567334299356760080507454640207003 phi_n = (p - 1) * (q - 1)d = sympy.mod_inverse(e, phi_n) m = pow(c, d, n)m = int(m) # 将 gmpy2.mpz 类型转换为 int 类型print(libnum.n2s(m))

运行得到
b'\x02\xb3\xf3\xc6W8\xb5\x81S/cwr\xe8\xd3\xb5Cf\xe4\xe5w\x81h\t\x82\x8cd\x85D}\xec7\xec!\xe4;\x89\xb3w\xa4Uf\xf5\xd9%\xcb\x96\x85\x10\x11B\x9a<"QS\x05\x84\x80{\xb1.\x82\xcc\x1c\xf6\x87z@\x91\x9e\xf6h\xe7\xa1\x8f\x96\x9d%&\xa4\xcd\xf0\'\x16J\xf4!\x9c\'h8!Y\xa1o(H\xea}\x00flag{W0rld_Of_Crypt0gr@phy}'

{% folding cyan, flag %}

flag
flag{W0rld_Of_Crypt0gr@phy}

{% endfolding %}

46. /.-

..-./.-../.-/—./----.—/-../…—/..-./-.-./-…/..-./.----/—…/..-./----./…—/----./----./…/-----/…-/-----.-

随波逐流秒了,摩斯密码(要转小写)

{% folding cyan, flag %}

flag
flag{d3fcbf17f9399504}

{% endfolding %}

47. 聪明的小羊

一只小羊翻过了2个栅栏 fa{fe13f590lg6d46d0d0}

随波逐流秒了,栅栏密码分两栏

{% folding cyan, flag %}

flag
flag{6fde4163df05d900}

{% endfolding %}

48. ok

Brain Fuck解码

{% folding cyan, flag %}

flag
flag{0a394df55312c51a}

{% endfolding %}

49. [+-<>]

+ + [->+++ +<] >.+ + .<+++ [->— -<]>- -.+++ +.< [ ->+ +<]>+ +.< + +++[- >---- ----< ]>--- ----- ---.< + ++[-> + ++<]> +++.< + +[->- ----- <]>— ----- -.—. ----. —. + +.<++ [ ->+ +<] > +.. <++ [-> ----- -<]>- ----- ----. -.< + [->+++ <]>+. ----. . < +[- >---- ---<] >---- .+.<+ + ++[-> + +++<] >+.<

随波逐流秒了,Brain Fuck解码

{% folding cyan, flag %}

flag
flag{0d86208ac54fbf12}

{% endfolding %}

50. easy_crypto

0010 0100 01 110 1111011 11 11111 010 000 0 001101 1010 111 100 0 001101 01111 000 001101 00 10 1 0 010 0 000 1 01111 10 11110 101011 1111101

随波逐流秒了,摩斯密码(要转小写)

{% folding cyan, flag %}

flag
flag{m0rse_code_1s_interest1n9!}

{% endfolding %}

51. 简单加密

这是基于一个简单的凯撒密码变种,其中每个字符都向后或向前移动了一定数量的位置。每个字符根据固定的ASCII值偏移进行了编码,根据字符串末尾的AA猜测恢复后是一个经过base64编码的字符串,所以AA恢复后是==。由于’A’的ASCII码是65,而’=‘的ASCII码是61,这意味着从’A’到’=‘需要减少4个位置。

python
def decode_string(encoded_str, shift=4):    decoded_str = ""    for char in encoded_str:        # Shift the ASCII value of each character backwards by 'shift'        new_ascii = ord(char) - shift        # Append the shifted character to the result string        decoded_str += chr(new_ascii)    return decoded_str # Given encoded stringencoded_str = "e6Z9i~]8R~U~QHE{RnY{QXg~QnQ{^XVlRXlp^XI5Q6Q6SKY8jUAA"# Decode the stringdecoded_str = decode_string(encoded_str)print("Decoded string:", decoded_str) decoded_provided_string = base64.b64decode(decoded_str).decode('utf-8')print("Decoded Provided String:", decoded_provided_string)

运行代码得到flag

{% folding cyan, flag %}

flag
key{68743000650173230e4a58ee153c68e8}

{% endfolding %}

52. 散乱的密文

lf5{ag024c483549d7fd@@1} 一张纸条上凌乱的写着2 1 6 5 3 4

行置换密码(RowRermutationCipher)解密即可,密钥是216534,解密得到flag{52048c453d794df1}@@

{% folding cyan, flag %}

flag
flag{52048c453d794df1}

{% endfolding %}

53. 一段Base64

Base64解码 -> 八进制转字符 -> 十六进制转字符 -> Unicode转义解码 -> 替换首尾元素 -> 第一次HTML实体解码 -> 第二次HTML实体解码 -> URL解码

python
import base64from html import unescapeimport urllib.parse as urlparse def decode_data(encoded_string):    # Step 1: Base64 decode    base64_decoded = base64.b64decode(encoded_string).decode('utf-8')     # Step 2: Split by backslash and convert octal to characters    octal_parts = base64_decoded.split('\\')    del octal_parts[0]  # Remove the first element if it's empty or not an octal sequence    oct_to_text = ''.join(chr(int(part, 8)) for part in octal_parts if part)  # Convert octal to char     # Step 3: Split by '\x' and convert hex to characters    hex_parts = oct_to_text.split('\\x')    del hex_parts[0]  # Remove the first element if it's empty or not a hex sequence    hex_to_text = ''.join(chr(int(part, 16)) for part in hex_parts if part)  # Convert hex to char     # Step 4: Decode unicode escape sequences    unicode_decoded = hex_to_text.encode().decode('unicode-escape')     # Step 5: Split by comma and replace first and last elements    decimal_parts = unicode_decoded.split(',')    if len(decimal_parts) > 1:  # Ensure there are enough elements to modify        decimal_parts[0] = '38'        decimal_parts[-1] = '59'    dec_to_text = ''.join(chr(int(part)) for part in decimal_parts if part.isdigit())  # Convert decimal to char     # Step 6 & 7: HTML entity decode twice    html_decoded_first_pass = unescape(dec_to_text)    html_decoded_second_pass = unescape(html_decoded_first_pass)     # Step 8: URL decode    url_decoded = urlparse.unquote(html_decoded_second_pass)     return url_decoded encoded_string = "" #这里填入密文print(decode_data(encoded_string))

运行就能得出结果

{% folding cyan, flag %}

flag
flag{ctf_tfc201717qwe}

{% endfolding %}

54. .!?

随波逐流秒了,Brain Fuck解码

{% folding cyan, flag %}

flag
flag{bugku_jiami}

{% endfolding %}

55. 奇怪的密码

突然天上一道雷电 gndk€rlqhmtkwwp}z

随波逐流秒了,凯撒密码mode4 #1 得到flag₧lei_ci_jiami,把删掉,补上括号就好了

{% folding cyan, flag %}

flag
flag{lei_ci_jiami}

{% endfolding %}

56. 托马斯.杰斐逊

Jefferson Disk Cipher(杰斐逊圆盘密码)是一种多表替换加密方法,它使用一组旋转的圆盘来对信息进行加密和解密。每个圆盘都有一个字母表的随机排列,这些圆盘可以独立旋转。加密时,选择一系列圆盘的位置形成密钥,然后将明文中的每一个字母替换成当前选定位置下的相应字母。

python
# 定义圆盘和密钥disks = [    "ZWAXJGDLUBVIQHKYPNTCRMOSFE",    "KPBELNACZDTRXMJQOYHGVSFUWI",    "BDMAIZVRNSJUWFHTEQGYXPLOCK",    "RPLNDVHGFCUKTEBSXQYIZMJWAO",    "IHFRLABEUOTSGJVDKCPMNZQWXY",    "AMKGHIWPNYCJBFZDRUSLOQXVET",    "GWTHSPYBXIZULVKMRAFDCEONJQ",    "NOZUTWDCVRJLXKISEFAPMYGHBQ",    "QWATDSRFHENYVUBMCOIKZGJXPL",    "WABMCXPLTDSRJQZGOIKFHENYVU",    "XPLTDAOIKFZGHENYSRUBMCQWVJ",    "TDSWAYXPLVUBOIKZGJRFHENMCQ",    "BMCSRFHLTDENQWAOXPYVUIKZGJ",    "XPHKZGJTDSENYVUBMLAOIRFCQW"] key = [2, 5, 1, 3, 6, 4, 9, 7, 8, 14, 10, 13, 11, 12]ciphertext = "HCBTSXWCRQGLES" # 根据密钥重新排序圆盘ordered_disks = [disks[i-1] for i in key] # 找到每个密文字符在对应圆盘上的位置,并构建所有可能的解码结果positions = []for i, char in enumerate(ciphertext):    pos = ordered_disks[i].index(char)    positions.append(pos) # 输出所有可能的解码结果(即每一列)for i in range(len(disks[0])):    plaintext = ''    for j, disk in enumerate(ordered_disks):        plaintext += disk[(i + positions[j]) % len(disk)]    print(plaintext)

运行得到

text
HCBTSXWCRQGLESGPVELQAEJWOTNWVMIQOYTOLXIDYASNQGQIDNXPKESYFZHYXZSJKHFNRXUQKXVMRQIKHQUPWWYPEJFGSZEWBLIXPLTWHWEGNAMVKYNOAAETFJYOCUPITCMONHATVXQBBHCKKRYSPDUPWOEFRBGPVPMSWYVILRMDHLUYYEAVJKNLOMINBBGNBUXZAASAWDMXHYMIPGCBFIPVCIBVCKLJZEEZNHOZQUXZTRDUZVYGIUNBPGDFTOWRCFKLOMLJAHRTANJCZVZLTBOEXSXSBUGKUADMIN <- flag在这里MGJJFKJMTOSCKMJJGUZTXRWIRSFCQVDWDEPADRJRZQODLFRBLFCFQFGTYKUHUSQDVCZHHD

在里面找到有意义的字符串

{% folding cyan, flag %}

flag
flag{xsxsbugkuadmin}

{% endfolding %}

57. zip伪加密

zip伪加密,随波逐流修复下就好了

{% folding cyan, flag %}

flag
flag{Adm1N-B2G-kU-SZIP}

{% endfolding %}

58. 告诉你个秘密

636A56355279427363446C4A49454A7154534230526D6843
56445A31614342354E326C4B4946467A5769426961453067

16进制转Base64得到Y2pWNVJ5QnNjRGxKSUVKcVRTQjBSbWhDVkRaMWFDQjVOMmxLSUZGeldpQmlhRTBn

连续两次base64解码得到r5yG lp9I BjM tFhBT6uh y7iJ QsZ bhM

最后键盘密码(Keyboard Cipher)解密(感谢评论区的大佬们,这个真没想到😂)

{% folding cyan, flag %}

flag
flag{TONGYUAN}

{% endfolding %}

59. 这不是md5

随波逐流秒了,16进制转字符

{% folding cyan, flag %}

flag
flag{ae73587ba56baef5}

{% endfolding %}

60. 贝斯家族

随波逐流秒了,base91解码

{% folding cyan, flag %}

flag
flag{554a5058c9021c76}

{% endfolding %}