2024 红岩杯 CTF WP
开学前忘记迁移 hexo 数据了,几个月都没更新,现在回家不知道发什么,就把之前写的 wp 拉过来凑个数了
Misc
Are you a JPG master?
step 1
根据提示使用 Java 盲水印来获得 level2.zip
的密码
step 2
有一个 level2.jpg
和 dic.txt
猜测要跑字典,可能是图种或用某种隐写方式隐写了flag
使用 binwalk
未检测出压缩包
使用 stegdetect
检测隐写类型:
未检测出有效隐写类型,猜测使用了 steghide
,尝试使用 stegbrute
跑字典,得到flag
HardZip
step 1
给了一个 dic.txt
,所以使用 ARCHPR 跑字典
step 2
得到密码,解压得到 第二关.zip
和 hint.txt
,根据 hint.txt
,了解到要用掩码攻击
step 3
得到密码,继续解压得到一个 flag.zip
文件
使用 010editor
查看其十六进制,得知此文件并非伪加密
查看压缩包目录,发现有 flag.txt
和 What's_this.png
两个文件,可以知道要使用明文攻击,因为已知文件中12字节数据,且其中至少8字节连续,即可进行明文攻击
因为 png
头都是一样的,所以我构造了一个 png
头,然后使用 bkcrack
进行明文攻击,得到3个密钥并解密,得到 flag
刚做题时的情形:“我真傻,真的,”蒟蒻抬起他没有神采的眼睛来,接着说。“我单知道明文攻击时候需要一个已知文件;我不知道只要前12字节就能攻击了。我一清早起来就开了电脑,计算flag.txt的crc32值,叫我们的Python脚本开始工作。到了下午,终于给出了12个crc32值相同的字符串,我便开了12个ARPHCR来攻击,过了一阵子没出结果。我急了,CPU内核们都说找不到了,再一看,8个密钥未找到,还有几个还在算呢。。。。”他接着但是呜咽,说不出成句的话来。。
对此,我们伟大的Beta猫学长回复道:成长需要时间
YourCraft
666,这个入开桂了
点击即送flag
点击即送 flag:
290的小秘密
根据题目提示,该图片使用了lsb隐写
使用 stegsolve
打开,这题的信息隐藏在 RGB 三个通道的最低位中,通过 Analyse -> Data Extract
得到flag
5525
根据题目提示采用了 SilentEye
隐写,从压缩包中的 hint.txt
得到密钥为 “Mayday” ,使用 SilentEye
解密,得到flag
EasyZip
根据题目描述得知要暴力破解,使用 ARCHPR
暴力破解得到密码:
WirrreShark
step 1
使用 WirrreShark
打开题目文件
step 2
依次查看各个条目,在第五个条目中发现flag
我图图呢
step 1
题目文件是一个图片,无法打开
使用 010editor
查看
发现文件标头被修改,将其改正
修正后得到图片
step 2
图片宽高不对,需要使用脚本爆破CRC得到宽高
脚本源码:
import zlib
import struct
import argparse
import itertools
parser = argparse.ArgumentParser()
parser.add_argument("-f", type=str, default=None, required=True,
help="crc.png")
args = parser.parse_args()
bin_data = open(args.f, 'rb').read()
crc32key = zlib.crc32(bin_data[12:29]) # 计算crc
original_crc32 = int(bin_data[29:33].hex(), 16) # 原始crc
if crc32key == original_crc32: # 计算crc对比原始crc
print('宽高没有问题!')
else:
input_ = input("宽高被改了, 是否CRC爆破宽高? (Y/n):")
if input_ not in ["Y", "y", ""]:
exit()
else:
for i, j in itertools.product(range(4095), range(4095)): # 理论上0x FF FF FF FF,但考虑到屏幕实际和cpu,0x 0F FF就差不多了,也就是4095宽度和高度
data = bin_data[12:16] + struct.pack('>i', i) + struct.pack('>i', j) + bin_data[24:29]
crc32 = zlib.crc32(data)
if(crc32 == original_crc32): # 计算当图片大小为i:j时的CRC校验值,与图片中的CRC比较,若相同,则图片大小已经确定
print(f"\nCRC32: {hex(original_crc32)}")
print(f"宽度: {i}, hex: {hex(i)}")
print(f"高度: {j}, hex: {hex(j)}")
exit(0)
最后得到宽高为:
使用 010editor
编辑宽高,得到完整图片
step 3
在文件尾找到后半部分 flag
Crypto
Classic_AES
由题目可知采用了AES_ECB加密,并且种子是一个小整数,编写脚本爆破:
import random
from Crypto.Cipher import AES
import base64
import os
def generate_key(seed):
random.seed(seed)
key = bytes([random.randint(0, 255) for _ in range(16)])
return key
def decrypt(ciphertext, key):
cipher = AES.new(key, AES.MODE_ECB)
plaintext = cipher.decrypt(base64.b64decode(ciphertext))
pad_len = plaintext[-1] # 去除 PKCS#7 填充
return plaintext[:-pad_len].decode()
if __name__ == "__main__":
flag = "x/xvgy+sXb6I8j96FTT5fgEGT9lMR4XC/zKTvdY77a3Yntdvn1GScfkf/MHziWzI"
for seed in range(100000): # 暴力破解种子
try: # 使用try...except...避免无法解码错误退出
key = generate_key(seed)
decrypted_flag = decrypt(flag, key)
if "Redrock" in decrypted_flag: # 筛选出包含"Redrock"的结果
print(decrypted_flag)
break
except:
pass
得到 flag :
Redrock{6b16bf86-6749-4112-b438-319e4ce7a5c1}
Morse_Code
密文:
解密得:
What is RSA
文件中有p,q,e,c四个值
From ChatGPT:
在RSA加密算法中,以下是每个符号的含义:
-
p 和 q:
这两个是大素数,用于生成密钥。- 选择两个大素数 p 和 q,它们应尽可能随机且保密。
- 计算 n=p×q,n 是密钥的一部分。
-
e:
公钥指数(加密指数)。- e 是一个与 ϕ(n)=(p−1)(q−1) 互素的整数,满足 1<e<ϕ(n)。
- 常见的 e 值是 65537,因为它计算效率高,且足够安全。
-
c:
密文(ciphertext)。- 明文 m 加密后生成的结果 c,计算公式是: c=m^e mod n
补充说明
- 私钥指数 d:解密指数,用于解密密文。它满足: d×e≡1mod ϕ(n)
- 解密公式: m=c^d mod n
RSA 的核心在于大数分解的困难性。
根据以上内容写出解密脚本代码:
from sympy import mod_inverse
p = 107838628855654812471413655393398150378995246065154350033910452648032730414023
q = 63326381933899241811507370594269184413864749996932931556519044275437019848179
e = 65537
c = 2614337245710053040032169192794377666429639491165446083830186166080709603975820326607483164927365452151697893098970942225623463372515924991756039075659888
phi_n = (p - 1) * (q - 1) # 计算 n 和 φ(n)
n = p * q
d = mod_inverse(e, phi_n) # 计算 d
m = pow(c, d, n) # 得到明文
# 将得到的明文转为字符串
def int_to_string(m):
hex_string = hex(m)[2:] # 转成16进制并去掉 "0x" 前缀
if len(hex_string) % 2: # 确保长度为偶数
hex_string = "0" + hex_string
return bytes.fromhex(hex_string).decode('utf-8') # 按照字节解码
# 转换并输出字符串
try:
plaintext = int_to_string(m)
print(plaintext)
except UnicodeDecodeError:
print("无法解码")
得到 flag :
Redrock{0b46cdfc-4b31-4023-a33d-b8defada9457}
real1ty的小秘密
由题目可知是凯撒密码,因为不知道偏移量,所以需要枚举26次得到明文
我解md5真的假的
part1-3和5可通过 [[https://www.somd5.com/]] 查到,part4根据提示,可通过穷举得到原文,穷举代码如下:
import hashlib
# MD5目标值
target_md5 = "ad5da884551e8e48886ce42b926d7fe8"
# 字符来源
special_chars = "!@#$%^&-()"
numbers = "0123456789"
letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
# 所有可能的组合
for special_pair1 in special_chars:
for special_pair2 in special_chars: # 从特殊字符中选2个
for number in numbers: # 从数字中选1个
for letter in letters: # 从字母中选1个
# 拼接成字符串
candidate = '' + special_pair1 + special_pair2 + number + letter
# 计算MD5
md5_hash = hashlib.md5(candidate.encode()).hexdigest()
# 判断是否匹配
if md5_hash == target_md5:
print(f"找到匹配字符串: {candidate}")
break
最终得到flag:
youknowmd5isnotsafe%@7D8545
Pwn
login
step 1
分析程序逻辑,发现输入-1即可得到shell
step 2
nc连接输入-1,得到shell
real_login
按照提示操作即可
计算猫
手动计算得到 shell
Web
这是真签到
F12
大法好
Ping
注入题,输入 1|ls /
查看根目录
发现有flag,尝试查看文件,输入 1|cat /flag
可能是对 flag
关键字做了特殊处理,用模糊匹配就行了
输入 1|cat /fla*
即可
贪吃蛇
打开控制台,给score赋值10000即可
Reverse
srand%s
Linux远程调试后,得到对应的v4值,并将其输出
#include <stdio.h>
int main()
{
int v3[41];
v3[0] = 53;
v3[1] = 163;
v3[2] = 13;
v3[3] = 1;
v3[4] = 62;
v3[5] = 156;
v3[6] = 33;
v3[7] = 151;
v3[8] = 72;
v3[9] = 190;
v3[10] = 222;
v3[11] = 221;
v3[12] = 194;
v3[13] = 195;
v3[14] = 208;
v3[15] = 46;
v3[16] = 26;
v3[17] = 168;
v3[18] = 49;
v3[19] = 150;
v3[20] = 113;
v3[21] = 219;
v3[22] = 223;
v3[23] = 184;
v3[24] = 78;
v3[25] = 99;
v3[26] = 29;
v3[27] = 11;
v3[28] = 91;
v3[29] = 249;
v3[30] = 163;
v3[31] = 185;
v3[32] = 38;
v3[33] = 20;
v3[34] = 101;
v3[35] = 196;
v3[36] = 91;
v3[37] = 96;
v3[38] = 154;
v3[39] = 39;
printf("Redrock{");
printf("%c",0x29u^v3[8]);
printf("%c",0xCDu^v3[9]);
printf("%c",0xBAu^v3[10]);
printf("%c",0xABu^v3[11]);
printf("%c",0xF2u^v3[12]);
printf("%c",0xFBu^v3[13]);
printf("%c",0xE3u^v3[14]);
printf("%c",0x46u^v3[15]);
printf("%c",0x7Cu^v3[16]);
printf("%c",0xC2u^v3[17]);
printf("%c",0x54u^v3[18]);
printf("%c",0xF8u^v3[19]);
printf("%c",0x1Bu^v3[20]);
printf("%c",0xE8u^v3[21]);
printf("%c",0xE7u^v3[22]);
printf("%c",0x8Du^v3[23]);
printf("%c",0x76u^v3[24]);
printf("%c",0x5Au^v3[25]);
printf("%c",0x2Eu^v3[26]);
printf("%c",0x63u^v3[27]);
printf("%c",0x33u^v3[28]);
printf("%c",0x9Fu^v3[29]);
printf("%c",0xC9u^v3[30]);
printf("%c",0x9Au^v3[31]);
printf("%c",0x66u^v3[32]);
printf("%c",0x32u^v3[33]);
printf("%c",0xDu^v3[34]);
printf("%c",0xB7u^v3[35]);
printf("%c",0x31u^v3[36]);
printf("%c",0x58u^v3[37]);
printf("%c",0xA3u^v3[38]);
printf("%c",0x5Au^v3[39]);
}
通过对应的值输出对应的字符
easy
在 IDA 中按下 Shift + F12
查看字符串,即可找到flag
花花的世界
先查壳,但查不到,根据题目描述猜测使用 UPX
壳
无法使用 UPX
直接去壳,使用 010editor
打开发现识别 UPX
的部分被改成了 SRE
,改回去壳即可
反编译使用 NoMoreFlower 去花
再对关键函数按下 P
重构函数,按 F5
得到伪代码
分析代码逻辑,程序将输入进行 RC4
加密,密钥为 flower
,后将其与随机数进异或位运算,最后与预存数组比较
srand种子是取了高位,所以随机数种子短时间不变
最后根据逻辑编写程序算出原RC4密文,再进行解密,得到flag
Rc4_py
使用 pyinstxtractor
解包,然后在 ereee
文件发现base64字符串后,又根据题目描述使用rc4解密,密钥为 flag{123321321123badbeef012}
,密文即发现的base64字符串
baby_reverse
走迷宫,程序似乎会对行顺序进行调整
调整后即可得到路径
原文wp:[[https://singularityctf.blogspot.com/2014/03/volgactf-quals-2014-writeup-reverse-100.html]]
这是什么语言
下述操作需要先找到入口
这是仓颉语言,分析貌似使用了RSA或AES,但无法找到对应公私钥和密文,所以使用动态调试,在栈中找到flag
设置断点在解密结束后,在寄存器中找到了flag