bunaken

description
Author: vidner
Can you help me to recover the flag?
Attachments
unzip bunaken_bunaken-dist.zip
# Archive: bunaken_bunaken-dist.zip
# inflating: bunaken
# inflating: flag.txt.bunakencrypted
ls
# bunaken bunaken_bunaken-dist.zip flag.txt.bunakencrypted
file *
# bunaken: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=109a021c1b3405d73bd0e95dcad52ec5857f4ed9, not stripped
# bunaken_bunaken-dist.zip: Zip archive data, at least v2.0 to extract, compression method=deflate
# flag.txt.bunakencrypted: ASCII text, with no line terminatorsOverview
Ringkasan singkat
bunakenadalah binary Bun (JavaScript) yang menyembunyikan password di kode yang di‑obfuscate dan menggunakan AES‑CBC + gzip untuk menyimpan flag terenkripsi. Tujuan: ekstrak password → turunkan kunci → dekripsi → dekompresi → baca flag. ✅
Artefak & teknik
- Binary:
bunaken(decompile denganbun-decompile). - Enkripsi: AES‑CBC (IV || ciphertext), key = SHA-256(password)[0:16].
- Obfuscation: string array + RC4‑like decoder → password
sulawesi.
Alur penyelesaian (singkat)
- Decompile
bunaken→ temukan decoder string dan panggilc(373, "rG]G")→ dapatsulawesi. 🔑 - Derive key: SHA256("sulawesi")[0:16].
- Dekripsi
flag.txt.bunakencrypted(ambil IV 16‑byte pertama), hapus padding, lalu decompress (gzip) → flag. 🔓
Kenapa ini bekerja
- Semua secret (password) dan logika dekripsi ada di binary (client side) — reverse engineering cukup untuk memulihkan bahan dekripsi. ⚠️
analisis
./bunaken
# ENOENT: no such file or directory, open 'flag.txt'
# path: "flag.txt",
# syscall: "open",
# errno: -2,
# code: "ENOENT"
# Bun v1.3.6 (Linux x64)dari error di atas, kita bisa lihat bahwa program mencoba membuka file flag.txt yang tidak ada. Namun, kita punya file flag.txt.bunakencrypted yang kemungkinan besar adalah versi terenkripsi dari flag tersebut.
selain itu kita juga mendapatkan informasi penting bahwa binary ini dibuat menggunakan Bun v1.3.6, yang merupakan runtime JavaScript/TypeScript yang relatif baru. Ini menunjukkan bahwa binary ini mungkin menggunakan fitur-fitur modern dari JavaScript, dan kita mungkin perlu menggunakan teknik reverse engineering yang sesuai untuk memahami bagaimana file flag.txt dihasilkan dari flag.txt.bunakencrypted.
saya mencari informasi di google terkait bun decompile

setelah dibuka kita dapat informasi cara melakukan installasi dan penggunaan bun decompile

Installasi bun decompile
install bun terlebih dahulu jika belum ada
curl -fsSL https://bun.com/install | bash
exec /usr/bin/zsh
bun --versionsetelah itu lakukan installasi library bun-decompile
bun add -g @shepherdjerred/bun-decompile
langkah penyelesaian
1, decompile binary bunaken
kita lakukan decompile terhadap binary bunaken untuk mendapatkan source code JavaScript/TypeScript yang digunakan untuk membuat binary tersebut. dengan perintah berikut:
bun-decompile ./bunaken -o ./extracted
2. analisis source code hasil decompile
setelah proses decompile selesai, kita akan mendapatkan folder extracted yang berisi file-file JavaScript/TypeScript hasil decompile. kita buka file utama yang kemungkinan besar berisi logika untuk membuka file flag.txt dan menghasilkan flag tersebut. kita cari di dalam source code untuk menemukan bagian yang mencoba membuka flag.txt dan melihat bagaimana file flag.txt.bunakencrypted digunakan dalam proses tersebut.
bunaken.js
// @bun
function w(){let n=["WR0tF8oezmkl","toString","W603xSol","1tlHJnY","1209923ghGtmw","text","13820KCwBPf","byteOffset","40xRjnfn","Cfa9","bNaXh8oEW6OiW5FcIq","alues","lXNdTmoAgqS0pG","D18RtemLWQhcLConW5a","nCknW4vfbtX+","WOZcIKj+WONdMq","FCk1cCk2W7FcM8kdW4y","a8oNWOjkW551fSk2sZVcNa","yqlcTSo9xXNcIY9vW7dcS8ky","from","iSoTxCoMW6/dMSkXW7PSW4xdHaC","c0ZcS2NdK37cM8o+mW","377886jVoqYx","417805ESwrVS","7197AxJyfv","cu7cTX/cMGtdJSowmSk4W5NdVCkl","W7uTCqXDf0ddI8kEFW","write","encrypt","ted","xHxdQ0m","byteLength","6CCilXQ","304OpHfOi","set","263564pSWjjv","subtle","945765JHdYMe","SHA-256","Bu7dQfxcU3K","getRandomV"];return w=function(){return n},w()}function l(n,r){return n=n-367,w()[n]}var y=l,s=c;function c(n,r){n=n-367;let t=w(),x=t[n];if(c.uRqEit===void 0){var b=function(i){let f="",a="";for(let d=0,o,e,p=0;e=i.charAt(p++);~e&&(o=d%4?o*64+e:e,d++%4)?f+=String.fromCharCode(255&o>>(-2*d&6)):0)e="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=".indexOf(e);for(let d=0,o=f.length;d<o;d++)a+="%"+("00"+f.charCodeAt(d).toString(16)).slice(-2);return decodeURIComponent(a)};let U=function(i,B){let f=[],a=0,d,o="";i=b(i);let e;for(e=0;e<256;e++)f[e]=e;for(e=0;e<256;e++)a=(a+f[e]+B.charCodeAt(e%B.length))%256,d=f[e],f[e]=f[a],f[a]=d;e=0,a=0;for(let p=0;p<i.length;p++)e=(e+1)%256,a=(a+f[e])%256,d=f[e],f[e]=f[a],f[a]=d,o+=String.fromCharCode(i.charCodeAt(p)^f[(f[e]+f[a])%256]);return o};c.yUvSwA=U,c.MmZTqk={},c.uRqEit=!0}let u=t[0],I=n+u,A=c.MmZTqk[I];return!A?(c.ftPoNg===void 0&&(c.ftPoNg=!0),x=c.yUvSwA(x,r),c.MmZTqk[I]=x):x=A,x}(function(n,r){let t=c,x=l,b=n();while(!0)try{if(parseInt(x(405))/1*(parseInt(x(383))/2)+-parseInt(x(385))/3*(parseInt(t(382,"9Dnx"))/4)+parseInt(x(384))/5*(-parseInt(x(393))/6)+parseInt(x(396))/7*(parseInt(x(369))/8)+parseInt(t(381,"R69F"))/9+-parseInt(x(367))/10+-parseInt(x(406))/11===r)break;else b.push(b.shift())}catch(u){b.push(b.shift())}})(w,105028);var h=async(n)=>{let r=l,t=c,x=n instanceof ArrayBuffer?new Uint8Array(n):new Uint8Array(n[t(400,"I2yl")],n[r(368)],n.byteLength);if(x.byteLength===16||x.byteLength===24||x.byteLength===32)return x;let b=await crypto.subtle[t(402,"Fw]1")](r(399),x);return new Uint8Array(b).subarray(0,16)},g=(n,r)=>{let t=l,x=new Uint8Array(n.byteLength+r.byteLength);return x.set(n,0),x[t(395)](r,n[t(392)]),x},m=async(n,r)=>{let t=c,x=l,b=crypto[x(401)+x(372)](new Uint8Array(16)),u=await h(n),I=await crypto[x(397)][t(371,"kAmA")](t(370,"CYgn"),u,{name:"AES-CBC"},!1,[x(389)]),A=await crypto.subtle[x(389)]({name:t(375,"dHTh"),iv:b},I,r);return g(b,new Uint8Array(A))},S=Bun[s(391,"9Dnx")](s(377,"R69F")),k=await S[y(407)](),v=await Bun[s(387,"f]pG")+"ss"](k),z=await m(Buffer[y(380)](s(373,"rG]G")),v);Bun[y(388)]("flag.txt.b"+s(374,"CYgn")+y(390),Buffer[s(404,"(Y*]")](z)[y(403)](s(376,"$lpa")));
//# debugId=89BBB7E67C06C2CD64756E2164756E213. decrypt password
Penjelasan singkat:
- Fungsi
c(index, key)pada hasil decompile adalah string-obfuscation/decoder — ia pertama‑tama base64‑decode data internal, lalu menjalankan RC4‑like XOR dengankey(argumen kedua). Untuk mendapatkan password kita cukup mengeksekusic(373, "rG]G").
Langkah teknis (cara cepat): buat file decrypt_password.js berisi fungsi yang di‑decompile (fungsi w + c) dan jalankan dengan Node.
decrypt_password.js
// 1. Array String & Accessor 'w'
function w() {
let n = [
"WR0tF8oezmkl",
"toString",
"W603xSol",
"1tlHJnY",
"1209923ghGtmw",
"text",
"13820KCwBPf",
"byteOffset",
"40xRjnfn",
"Cfa9",
"bNaXh8oEW6OiW5FcIq",
"alues",
"lXNdTmoAgqS0pG",
"D18RtemLWQhcLConW5a",
"nCknW4vfbtX+",
"WOZcIKj+WONdMq",
"FCk1cCk2W7FcM8kdW4y",
"a8oNWOjkW551fSk2sZVcNa",
"yqlcTSo9xXNcIY9vW7dcS8ky",
"from",
"iSoTxCoMW6/dMSkXW7PSW4xdHaC",
"c0ZcS2NdK37cM8o+mW",
"377886jVoqYx",
"417805ESwrVS",
"7197AxJyfv",
"cu7cTX/cMGtdJSowmSk4W5NdVCkl",
"W7uTCqXDf0ddI8kEFW",
"write",
"encrypt",
"ted",
"xHxdQ0m",
"byteLength",
"6CCilXQ",
"304OpHfOi",
"set",
"263564pSWjjv",
"subtle",
"945765JHdYMe",
"SHA-256",
"Bu7dQfxcU3K",
"getRandomV",
];
return (
(w = function () {
return n;
}),
w()
);
}
// 2. Simple Accessor 'l' (digunakan saat shuffle untuk baca angka)
function l(n, r) {
return ((n = n - 367), w()[n]);
}
// 3. Complex Decryptor 'c'
var c = function (n, r) {
n = n - 367;
let t = w(),
x = t[n];
if (c.uRqEit === void 0) {
var b = function (i) {
let f = "",
a = "";
for (
let d = 0, o, e, p = 0;
(e = i.charAt(p++));
~e && ((o = d % 4 ? o * 64 + e : e), d++ % 4) ? (f += String.fromCharCode(255 & (o >> ((-2 * d) & 6)))) : 0
)
e = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=".indexOf(e);
for (let d = 0, o = f.length; d < o; d++) a += "%" + ("00" + f.charCodeAt(d).toString(16)).slice(-2);
return decodeURIComponent(a);
};
let U = function (i, B) {
let f = [],
a = 0,
d,
o = "";
i = b(i);
let e;
for (e = 0; e < 256; e++) f[e] = e;
for (e = 0; e < 256; e++) ((a = (a + f[e] + B.charCodeAt(e % B.length)) % 256), (d = f[e]), (f[e] = f[a]), (f[a] = d));
((e = 0), (a = 0));
for (let p = 0; p < i.length; p++)
((e = (e + 1) % 256),
(a = (a + f[e]) % 256),
(d = f[e]),
(f[e] = f[a]),
(f[a] = d),
(o += String.fromCharCode(i.charCodeAt(p) ^ f[(f[e] + f[a]) % 256])));
return o;
};
((c.yUvSwA = U), (c.MmZTqk = {}), (c.uRqEit = !0));
}
let u = t[0],
I = n + u,
A = c.MmZTqk[I];
return (!A ? (c.ftPoNg === void 0 && (c.ftPoNg = !0), (x = c.yUvSwA(x, r)), (c.MmZTqk[I] = x)) : (x = A), x);
};
// 4. Shuffle Logic (Bagian IIFE dari bunaken.js)
(function (n, r) {
let t = c,
x = l,
b = n();
while (true) {
try {
if (
(parseInt(x(405)) / 1) * (parseInt(x(383)) / 2) +
(-parseInt(x(385)) / 3) * (parseInt(t(382, "9Dnx")) / 4) +
(parseInt(x(384)) / 5) * (-parseInt(x(393)) / 6) +
(parseInt(x(396)) / 7) * (parseInt(x(369)) / 8) +
parseInt(t(381, "R69F")) / 9 +
-parseInt(x(367)) / 10 +
-parseInt(x(406)) / 11 ===
r
)
break;
else b.push(b.shift());
} catch (u) {
b.push(b.shift());
}
}
})(w, 105028);
// 5. Success! Get the password.
try {
const password = c(373, "rG]G");
console.log("Decrypted Password:", password);
} catch (e) {
console.error(e);
}Jalankan:
node decrypt_password.jsOutput:
Decrypted Password: sulawesi
4. decrypt file terenkripsi (flag.txt.bunakencrypted)
Observasi dari source decompiled:
- Binary menggunakan AES‑CBC.
- Kunci AES = SHA‑256(password) lalu truncate ke 16 byte (AES‑128 key).
- File terenkripsi disimpan sebagai IV || ciphertext (IV 16 byte di depan).
decrypt_flag.py
import base64
import hashlib
import gzip
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
def decrypt_flag_from_file(filename, password):
enc = open(filename, "rb").read().strip()
# decode base64
data = base64.b64decode(enc)
iv = data[:16]
ct = data[16:]
key = hashlib.sha256(password.encode()).digest()[:16]
print("[*] Key:", key.hex())
print("[*] IV :", iv.hex())
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(ct)
try:
decrypted = unpad(decrypted, 16)
except:
print("[!] No padding or bad padding")
print("[*] Raw decrypted:", decrypted)
print("[*] Hex:", decrypted.hex())
# cek apakah gzip
if decrypted[:2] == b'\x1f\x8b':
print("[*] GZIP detected, decompressing...")
decrypted = gzip.decompress(decrypted)
print("\n[+] FLAG:", decrypted.decode(errors="ignore"))
decrypt_flag_from_file("flag.txt.bunakencrypted", "sulawesi")Install dependency (jika belum):
pip install pycryptodomesetelah itu jalankan file decrypt nya.
python decrypt_flag.py
flag
C2C{BUN_AwKward_ENcryption_compression_obfuscation}