你拿到一个叫Bundle_99的文件,没有扩展名,没任何说明。要做的只有一件事:挖出里面可能藏着的flag。但这东西到底是个什么?直接扔给Linux的file命令,输出却很诚实——它就是个Zip压缩包,MIME类型还贴心地写了“application/x-krita-resourcebundle”。也就是说,这不是普通zip,而是Krita的资源包格式,专门用来打包笔刷预设、图案之类的画材。

既然知道是zip,解压是本能。zipinfo先看一眼:5个文件,共83433字节未压缩大小。目录结构有mimetype、paintoppresets/Brush 99.kpp、preview.png、META-INF/manifest.xml、meta.xml。这个布局跟OpenDocument家族如出一辙,一看就是正经捆绑包。mimetype文件的内容也交了底:“application/x-krita-resourcebundle”,彻底确认身份。

顺着常规思路,先把meta.xml和manifest.xml翻了个遍。meta.xml里只有生成器Krita 5.2.10的版本号、作者“Bundle 99”,以及一段打油诗般的描述:“99 bundles of brushes on the wall...”。manifest.xml里列出了文件清单和MD5,那个Brush 99.kpp的md5是3c3433276c419d607d0a5b60d65fc21d。可flag的影子呢?一丝都没有。随手在整个解压目录里递归grep flag前缀,结果也是空。

这时候就得盯住那个paintoppresets/Brush 99.kpp了。表面看它只是个笔刷预设文件,但它的内部结构才是关键。.kpp文件实质是一张PNG图片,而图片的元数据里嵌入了一个XML Preset块。打开这个XML,你会被几十行看似无害的paintop参数淹没,什么直径、间距、抖动设置之类。但滑到深处,一个kis_text_brush定义跳了出来,它有个text属性,里面写着的正是要找的flag。

藏匿思路其实异常简单粗暴:Krita允许用文字生成笔刷,也就是你可以输入任意文本,保存为自定义笔刷,之后笔刷就能直接把文字“印”到画布上。这个功能本意是方便加签名或做文字纹理,但出题人直接把它当成了容器——把flag当作文字笔刷的text属性值,塞进.kpp里,再打个.zip包,齐活。

所以整个解题链条就是:识别为zip→解压→定位.kpp→解析PNG元数据→找到XML里的kis_text_brush→读出text属性。全程没有任何加密,flag就躺在结构化的文本块里。但这招的隐蔽性在于,大多数人看到.kpp会以为是二进制大杂烩,而XML里又堆满了正常参数,那个text属性很容易被当成空白字段忽略。

真要说有什么技术含量,可能就是得对Krita资源包的结构稍微有点感觉:.bundle是纯zip,.kpp是PNG套XML,而笔刷可以嵌入纯文本。但这也正是CTF里常见的出题逻辑——把秘密放在人人都能看到却不会细看的地方,然后用一层层稀松平常的格式包裹起来。与其说考技术,不如说考的是“你会不会拆这个特定软件的行李箱”。