[Mobile] Festival Secrets

[Mobile] Festival Secrets

April 22, 2026
1 min read

img1

โจทย์นี้จะได้ File .apk มา โดยจะทำเหมือนโจทย์ Water Blessing เลย

โดยรอบแรกสิ่งที่จะทำเลยคือไปดู MainActivity ของแอพก่อนว่ามีอะไรซ่อนไหม จะไปเจอ Function ตัวหนึ่ง

img2

เห็น Function ตัวหนึ่งที่เขียนว่า generateFlag พร้อมกับมีการแนบอะไรสักอย่างเข้าไปใน Function นั้นก็เลยไปดู Function นั้น

img3

อื้มมม AES-256-CBC นิเอง โห้ไม่ได้เจอกันมาสักพักเลย 5555 มี salt แถมมาด้วย

แต่ก็ด้วยความที่เรารู้แล้วมาด้านในเป็นอะไร แต่สิ่งหนึ่งที่เราขาดไป “เอ๊ะ Secret Key” คืออะไรกันนะ?

สรุปตัว Param festivalCode คือตัวแปร Secret Key นิเอง ก็เลยจำเป็นต้องไปนั่งไล่หาใน Folder res กันว่อนเลย จนไปเจอ

img4

อ่าห้า! อยู่นี่นิเอง แล้ว… ทีนี้จะแกะยังไงล่ะ? เราก็ไม่เซียน Java ด้วยน่ะสิ 555

ก็เลยไปใช้อย่าง AI ช่วยแปลงจาก Java ไปเป็น NodeJS ซึ่งเป็นภาษาที่ถนัด ก็เลยแปลงออกมาได้ดังนี้

const crypto = require('crypto');
/**
* ฟังก์ชันถอดรหัส
* @param {string} festivalCode - รหัสผ่านที่ใช้เป็น Password
*/
function decrypt(festivalCode) {
// 1. กำหนดค่าพื้นฐาน (ตามที่ปรากฏใน Code ต้นฉบับ)
const encryptedData = Buffer.from([109, -41, 124, -88, -36, 90, 24, -19, 73, -59, -21, 55, 73, -50, 107, -28, 0, -41, 116, -6, -79, -113, -112, -66, -70, -43, 37, -80, -18, 97, 8, -44, 111, -31, 50, -56, -39, 56, 82, -80, -6, 111, -56, -105, 113, 1, 3, -24]);
const iv = Buffer.from([57, 74, 54, 15, -76, 41, -70, 20, 112, 122, 106, 62, 59, 48, -39, -11]);
const salt = Buffer.from("songkran_salt_2026", "utf8");
const iterations = 10000;
const keyLen = 32; // 256 bits = 32 bytes
try {
// 2. สร้าง Derived Key โดยใช้ PBKDF2 (เหมือน SecretKeyFactory ใน Java)
// ใช้ 'sha256' ตาม PBKDF2WithHmacSHA256
const key = crypto.pbkdf2Sync(festivalCode, salt, iterations, keyLen, 'sha256');
// 3. ตั้งค่าการถอดรหัส AES-256-CBC
// หมายเหตุ: PKCS5Padding ใน Java เทียบเท่ากับ PKCS7 ใน NodeJS (เป็นมาตรฐานเดียวกันสำหรับ AES)
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
// 4. ทำการถอดรหัส
let decrypted = decipher.update(encryptedData);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString('utf8');
} catch (error) {
console.error(error)
return "ERROR: Invalid festival code or decryption failed";
}
}
// --- วิธีใช้งาน ---
const code = "7h15_15_5up3r_53cr37";
console.log("Decrypted Text:", decrypt(code));

โดยหลักการคือนำ Byte ที่เป็น Content มาใส่ใน Buffer ก่อนรวมถึง iv และ salt มาใช้ในการถอดรหัส

img5

WANLAI{d634e823c1b2f791c8b003de906f0441}