只贡献了一个二血的弟弟,见证了协会高光时刻
Ohhhhhhhh~~~!!!
W&MCTF_Dalabengba
Dalabengba
Description
Play game and get flag!
attachment
The flag was divided into three parts, the format is WMCTF{part1+part2=part3}.
https://www.youtube.com/watch?reload=9&v=NYNLq2AIw_s
https://music.163.com/#/song?id=521493845
Try to fix the bug in the gane to start your journey?
About English version:We quickly made the English version of the game, please put this data package where it should be to patch the game. http://cos.wmctf.wetolink.com/data.rar
Analyze
首先开局下载得到一个游戏,然后有图标可得是一个rpgmaker制作的游戏,但是他是打包好的一共36M这么大的游戏,这里使用EnigmaVBUnpacker
可以将其解包得到原始数据文件,但是就算是解包成功了,也还是无法进入游戏,说是找不到某文件的png,然后打开该路径就会发现只有xxx.rpgmvp
的文件在那,看样子是没有解密成功,然后上网查询后是data/system.json
文件中的encryptionKey
来控制解密,但是打开后发现其为···"windowTone":[0,0,0,0],"hasEncryptedImages":true,"hasEncryptedAudio":true,"encryptionKey":""}
,encryptionKey
为空,所以估计是要去找encryptionKey
来解密游戏,但是找是找不到的,于是我找了个rpgmaker mv 1.6.1版本的来对比实验,配合上已有的解密代码,发现其加密核心一句为:
/**
* (Re)-Encrypt a RPG-Make-File-ArrayBuffer
*
* @param {ArrayBuffer} arrayBuffer - Array-Buffer of the File
* @returns {ArrayBuffer} - Encrypted Array-Buffer with the Fake-Header
*/
Decrypter.prototype.encrypt = function(arrayBuffer) {
if(! arrayBuffer)
throw new ErrorException('File is empty or can\'t be read by your Browser...', 1);
// Encrypt the File beginning
arrayBuffer = this.xOrBytes(arrayBuffer);
// Create Header
var fakeHeader = this.buildFakeHeader();
// Add Fake-Header in Front then the File
var tmpInt8Array = new Uint8Array(arrayBuffer.byteLength + this.getHeaderLen());
tmpInt8Array.set(fakeHeader, 0);
tmpInt8Array.set(new Uint8Array(arrayBuffer), this.getHeaderLen());
// Check if header is valid
var header = new Uint8Array(tmpInt8Array.buffer, 0, this.getHeaderLen());
if(! this.verifyFakeHeader(header))
throw new ErrorException(
'Fake-Header don\'t matches the Template-Fake-Header... Please report this Bug',
3
);
return tmpInt8Array.buffer;
};
/**
* XOR x Bytes (x = header-length-bytes)
*
* @param {ArrayBuffer} arrayBuffer - Array-Buffer where bytes should be XORed
* @returns {ArrayBuffer} - Array-Buffer with XORed Bytes
*/
Decrypter.prototype.xOrBytes = function(arrayBuffer) {
var view = new DataView(arrayBuffer);
if(arrayBuffer) {
var byteArray = new Uint8Array(arrayBuffer);
// console.log(this.getHeaderLen());
// console.log(byteArray);
for(var i = 0; i < this.getHeaderLen(); i++) {
console.log(byteArray[i]);
byteArray[i] = byteArray[i] ^ parseInt(this.encryptionCodeArray[i], 16);
console.log(byteArray[i]);
view.setUint8(i, byteArray[i]);
}
}
return arrayBuffer;
}
}
可以看到其加密极度憨批,就是加上自己的头,然后后面bytearray数组与密钥异或得到第二列的加密“校验位”数据,所以我们只需要原图的bytearray和校验位的数据异或一下即可得到密钥,bytearray用js版的RPG-Maker-MV-Decrypter
修改下源码即可获得,校验位就是直接读取16进制后的16~32位数据,python写下脚本得到encryptionKey
:
a = [0x7e,0x15,0xdc,0x75,0x87,0x1c,0x96,0xf2,0x58,0xe7,0x27,0x0d,0x64,0x9c,0xb2,0xf9]
b = [137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82]
res = ''
for i in range(16):
res+=hex(a[i]^b[i])[2:].zfill(2)
print(res)
得到encryptionKey
:f74592328a168cf858e7270078d4f6ab
,进入游戏后迅速开挂过完全剧情,得到3处flag:
Solve
part1:
最后的空中宫殿NPC移动轨迹得Pr1nCe5(S)5(s)
part2:
解密后根目录文件有过part2且宝箱hint为
得知为Java得盲水印隐写,通过https://github.com/ww23/BlindWatermark/releases/tag/v0.0.3项目可以得到水印图像
反色处理+补充识别位得:
再用zxing扫描得到part2:W@rR1or
part3:
文件通过crypto解密,密钥为国王说的那句话的去除大写字母倒叙16进制转换,其密钥为:Y0u_@re_5o_bRaVE
,解密后是一堆不可见字符,分别是tab和空格,换成0和1后得到
100110101111011010101110000001000001011010000110011011101010011000000100011001101111011010101110011101100010011000000100100101100010111010000100100001001000010010000100100001001000010001010000
01010000
01010000
01010000
000011101000011001001110001011101100110001011100111010100001011001001110010010100100111001001110010011100111111001010000
然后再倒叙二进制转字符串再倒叙得到
You have found it!!!!!!
part3:WhrRrrr~
得到part3:WhrRrrr~
(ps:赛后去问(打)出题人得知其实有个工具是s3cr3t
可以直接得到part3的解密
最终fuzz一下part1可以得到flag
flag
WMCTF{Pr1nCe5s+W@rR1or=WhrRrrr~}