PETIR - Regen 2025 (Rev)

Selamat datang di blog pertama saya yang akan membagikan how to solve Reverse Engineering Challenge by Part of PETIR, dan ngga semua saya tulis ya, karna ada banyak challenge nya jadi saya ambil yang menurutku menarik untuk dibahas. Oiya dan by the way, saya menyumbangkan 1 challenge yang saya buat untuk challenge ctf ini.
PETIR Vault
Category : Reverse Engineering
Points : 500
Difficulty : Hard
breaking classic vaults kinda boring... let's give a shot to our strongest vault the "PETIRVAULT" 😈
Author: gengi
Oke disini diberikan apk dan kita langsung aja coba decompile pakai apktool, mungkin buat beberapa orang lebih enak pakai jadx dan tool lain sebagainya, tapi kalo saya prefer ke apktool.

Setelah di decompile, langsung saja kita lihat file “AndroidManifest.xml”, dan ternyata bisa dilihat bahwa Mainactivity nya ada di “com.gengi.petirvault.MainActivity”
Oke setelah di analisa di dalam file smali_classes3/com/gengi/petirvault/MainActivity.smali kita bisa lihat fungsi utamanya adalah validasi password dengan function checkFlag
.method private final native checkFlag(Ljava/lang/String;)Z
.end method
.line 31
.local v0, "input":Ljava/lang/String;
invoke-direct {p1, v0}, Lcom/gengi/petirvault/MainActivity;->checkFlag(Ljava/lang/String;)Z
Dan di kode ini juga kita tahu bahwa Implementasi JNI dari fungsi checkFlag akan berada dalam file library native (biasanya .so di Android) yang dimuat oleh kode ini.
.line 14
sget-object v0, Lcom/gengi/petirvault/LiveLiterals$MainActivityKt;->INSTANCE:Lcom/gengi/petirvault/LiveLiterals$MainActivityKt;
invoke-virtual {v0}, Lcom/gengi/petirvault/LiveLiterals$MainActivityKt;->String$arg-0$call-loadLibrary$class-Companion$class-MainActivity()Ljava/lang/String;
move-result-object v0
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
karna merujuk pada library .so, maka kita coba check menggunakan disassambler Ida di file lib/x86_64/libpetirvault.so

Kita analisa yang penting penting saja ya, jadi seperti ini
1. memcpy(dest, &unk_131A0, sizeof(dest)); & v9 = xmmword_132A0; //Data hardcoded disalin ke buffer untuk validasi.
2. sub_21B50(v11, &v7, v8); //Process Encrypt.
3. v6 = (sub_21C40(v11, &v9) & 1) != 0; //Pembanding input dengan output yg diharapkan.
4. return v6; //Mengembalikan hasil validasi
Oke, dari informasi penting tersebut kita coba lihat proses enkripsinya gimana.

Kita analisa yang penting penting lagi ya, jadi seperti ini
v5 = *a2; // Mengambil referensi ke data hardcoded
v3 = (unsigned __int8 *)sub_21D10(a3, i); // Mengambil karakter ke-i dari password
v6 = *(_BYTE *)sub_21CF0(v5, *v3); // Memproses karakter dengan data hardcoded
*(_BYTE *)sub_21D40(a1, i) = v6; // Menyimpan hasil di buffer output
memset(a1, 0, 0x25uLL); //37
Oke dari informasi yang kita udah dapetin kita kumpulin jadi seperti ini
1. Var unk 131A0 : Validasi value
2. Var xmmword 132A0 : Perbandingannya
3. Function sub 21B50 : algoritma transformasi
gef➤ x/256 0x131A0
0x131a0: 0xd56a0952 0x38a53630 0x9ea340bf 0xfbd7f381
0x131b0: 0x8239e37c 0x87ff2f9b 0x44438e34 0xcbe9dec4
0x131c0: 0x32947b54 0x3d23c2a6 0xb954cee 0x4ec3fa42
0x131d0: 0x66a12e08 0xb224d928 0x49a25b76 0x25d18b6d
0x131e0: 0x64f6f872 0x16986886 0xcc5ca4d4 0x92b6655d
0x131f0: 0x5048706c 0xdab9edfd 0x5746155e 0x849d8da7
0x13200: 0xabd890 0xad3bc8c 0x558e4f7 0x645b3b8
0x13210: 0x8f1e2cd0 0x20f3fca 0x3bdafc1 0x6b8a1301
0x13220: 0x4111913a 0xeadc674f 0xcecff297 0x73e6b4f0
0x13230: 0x2274ac96 0x8535ade7 0xe837f9e2 0x6edf751c
0x13240: 0x0 0x0 0x0 0x0
0x13250: 0x0 0x0 0x0 0x0
0x13260: 0x0 0x0 0x0 0x0
0x13270: 0x0 0x0 0x0 0x0
0x13280: 0x0 0x0 0x0 0x0
0x13290: 0x0 0x0 0x0 0x0
0x132a0: 0xa4fd686c 0xbcab0348 0x8cb806f7 0xcad84584
0x132b0: 0x84bc0fe4 0x1eabe4b8 0x84af1ed8 0xb8d845d8
0x132c0: 0x8fe48faf 0x13 0x0 0x0
0x132d0: 0x19 0x0 0x14 0x0
0x132e0: 0x61766f63 0x6e616972 0x65722074 0x6e727574
0x132f0: 0x75687420 0x74206b6e 0x3c00206f 0x2b2b00
0x13300: 0x7265706f 0x726f7461 0x6f003d5e 0x61726570
0x13310: 0x3c726f74 0x6f6e003d 0x36387820 0x2034365f
0x13320: 0x616f6c66 0x65722074 0x74736967 0x737265
0x13330: 0x6e6b6e75 0x206e776f 0x6e696f70 0x20726574
0x13340: 0x6f636e65 0x676e6964 0x63656400 0x7079746c
0x13350: 0x3e002865 0x7974003d 0x64696570 0x6f002820
0x13360: 0x61726570 0x3e726f74 0x6f003d3e 0x61726570
0x13370: 0x3c726f74 0x6c003e3d 0x676e6f 0x72616863
0x13380: 0x745f3233 0x62696c00 0x69776e75 0x203a646e
0x13390: 0x666c616d 0x656d726f 0x57442064 0x4146435f
0x133a0: 0x6765725f 0x65747369 0x57442072 0x20465241
0x133b0: 0x69776e75 0x202c646e 0x32676572 0x6f6f7420
0x133c0: 0x67696220 0x696c000a 0x776e7562 0x3a646e69
0x133d0: 0x6c616d20 0x6d726f66 0x44206465 0x46435f57
0x133e0: 0x61765f41 0x666f5f6c 0x74657366 0x2066735f
0x133f0: 0x52415744 0x6e752046 0x646e6977 0x6572202c
0x13400: 0x6f742067 0x6962206f 0x78000a67 0x356d6d
0x13410: 0x316d6d78 0x2e0031 0x6874002f 0x776f72
0x13420: 0x61686377 0x745f72 0x7265706f 0x726f7461
0x13430: 0x7473007e 0x623a3a64 0x63697361 0x7274735f
0x13440: 0x676e69 0x6c636564 0x65707974 0x74756128
0x13450: 0x4400296f 0x74656c65 0x76206465 0x75747269
0x13460: 0x66206c61 0x74636e75 0x206e6f69 0x6c6c6163
0x13470: 0x216465 0x3a647473 0x6378653a 0x69747065
0x13480: 0x78006e6f 0x336d6d 0x6d726574 0x74616e69
0x13490: 0x20676e69 0x68746977 0x20732520 0x65637865
0x134a0: 0x6f697470 0x666f206e 0x70797420 0x73252065
0x134b0: 0x6e6f6300 0x635f7473 0x747361 0x75003e3e
0x134c0: 0x6769736e 0x2064656e 0x6e695f5f 0x38323174
0x134d0: 0x65706f00 0x6f746172 0x65642072 0x6574656c
0x134e0: 0x65706f00 0x6f746172 0x3d3e72 0x69776e75
0x134f0: 0x705f646e 0x65736168 0x696c0032 0x776e7562
0x13500: 0x3a646e69 0x6c616d20 0x6d726f66 0x44206465
0x13510: 0x46435f57 0x65645f41 0x66635f66 0x57442061
0x13520: 0x20465241 0x69776e75 0x202c646e 0x20676572
0x13530: 0x206f6f74 0xa676962 0x74656700 0x42454c53
0x13540: 0x383231 0x53746567 0x64657661 0x69676552
0x13550: 0x72657473 0x31317200 0x70797400 0x666e6965
0x13560: 0x616e206f 0x6620656d 0x20726f 0x7265706f
0x13570: 0x726f7461 0x77656e20 0x64747300 0x756e3a3a
0x13580: 0x74706c6c 0x745f72 0x636a626f 0x6a626f5f
0x13590: 0x746365 0x3a647473 0x6461623a 0x6c6c615f
gef➤ x/37 0x132A0
0x132a0: 0xa4fd686c 0xbcab0348 0x8cb806f7 0xcad84584
0x132b0: 0x84bc0fe4 0x1eabe4b8 0x84af1ed8 0xb8d845d8
0x132c0: 0x8fe48faf 0x13 0x0 0x0
0x132d0: 0x19 0x0 0x14 0x0
0x132e0: 0x61766f63 0x6e616972 0x65722074 0x6e727574
0x132f0: 0x75687420 0x74206b6e 0x3c00206f 0x2b2b00
0x13300: 0x7265706f 0x726f7461 0x6f003d5e 0x61726570
0x13310: 0x3c726f74 0x6f6e003d 0x36387820 0x2034365f
0x13320: 0x616f6c66 0x65722074 0x74736967 0x737265
0x13330: 0x6e6b6e75
Oke, dari ketiga informasi penting tersebut bisa kita buat code untuk mendapatkan flagnya.
def inikahrev():
with open("libpetirvault.so", "rb") as f:
a = f.seek(0x131A0)
table = list(f.read(256)) #_BYTE dest[256];
b = f.seek(0x132A0)
output = list(f.read(37)) #memset(a1, 0, 0x25uLL); decimal : 37
reverse = {v: i for i, v in enumerate(table)}
flag = ''.join(chr(reverse[b]) for b in output)
return flag
print(inikahrev())
PETIR{behold_native_library_analysis}
Shrink
Category : Reverse Engineering
Points : 496
Difficulty : Medium
Recently, I downloaded a malware and try running it. I think it's just sending all files in my computer to the attacker server. Upon reversing it, I found out that before sending, he run a program that shrinks the filesize. I try using a normal unzip command but it doesn't work. Can you help me reverse the following program. Here I also have a sample file that being compressed with the program.
author: Lyo
Oke, di challenge satu ini kita diberikan 2 file, executable(elf) dan output.zip yang dimana secara overview, kita diminta untuk reverse encryption agar dapat membaca isi dalam output.zip nya. Mari kita langsung analisa.
TL;DR
ada beberapa function utama, saya bakalan ambil yang penting penting aja.
1. Function produce zip :
- Magic Bytes 7305548
- Takes dictionary code and an input file, then reads the input byte by byte, looks up each byte's code in the dictionary, and writes the encoded bits to an output file.
2. Function make dictionary :
- Recursively traverses the Huffman tree to build a dictionary mapping each byte value to its Huffman code.
3. Function write out :
- Converts the binary string representation ('0's and '1's) to actual binary data, working 8 bits at a time.
4. Function make tree :
- Shows the Huffman tree structure used
dan ada beberapa function penambahnya.
1. Function print list:
- Only debug
2. Function List and Node :
- These are utility functions for creating data structures, but understanding their implementation details is less critical than understanding how the data structures are used.
3. Function insert :
- While important for building the tree, it's less relevant for the reverse process.
4. Function merge :
- Combines two nodes into a new internal node with the combined frequency.
Oke dari informasi yang kita dapat, kita bisa buat function untuk parse Huffman code dictionary terlebih dahulu
def parse_huffman_dictionary(data, dict_pos):
huffman_dict = {}
pos = dict_pos + 4 # Lewati magic number
while pos + 4 <= len(data):
# Setiap entri dictionary adalah 4 byte
entry = struct.unpack('<I', data[pos:pos+4])[0]
# Ekstrak komponen entri
byte_asli = entry & 0xFF # 8 bit pertama
panjang_kode = (entry >> 8) & 0xFF # 8 bit kedua
kode_huffman = (entry >> 16) & 0xFFFF # 16 bit terakhir
# Hanya proses entri yang valid
if panjang_kode > 0:
# Ambil representasi binary dari Huffman code
kode_biner = format(kode_huffman, '016b')[:panjang_kode]
huffman_dict[kode_biner] = byte_asli
pos += 4
return huffman_dict
setelah itu kita bisa buat function decompress data
def decompress_data(compressed_data, huffman_dict):
hasil = bytearray()
buffer_bit = ""
# Proses setiap byte data terkompresi
for byte in compressed_data:
# Byte dalam file terkompresi di-NOT, jadi kita NOT kembali
byte_terbalik = ~byte & 0xFF
buffer_bit += format(byte_terbalik, '08b')
while True:
ditemukan = False
for kode, nilai in huffman_dict.items():
if buffer_bit.startswith(kode):
# Cocok! Tambahkan byte yang didekompresi
hasil.append(nilai)
# Hapus kode yang cocok dari buffer
buffer_bit = buffer_bit[len(kode):]
ditemukan = True
break
# Jika tidak ada yang cocok, kita butuh lebih banyak bit
if not ditemukan:
break
return hasil
Oke, karna sudah dibuat function untuk parse Huffman dictionary dan udah bikin function buat decompress data, sekarang langsung kita buat untuk decompress filenya pakai huffman dictionary yg sudah kita dapatkan.
def decompress_huffman(input_file='output.zip', output_file='decompressed.bin'):
with open(input_file, 'rb') as f:
data = f.read()
# 2. Cari magic number (pemisah antara data terkompresi dan kamus)
magic_number = bytes([0x4c, 0x79, 0x6f, 0x00]) # "Lyo\0"
dict_pos = data.find(magic_number)
if dict_pos == -1:
print("Error: Format file tidak valid")
return bytearray()
# 3. Pisahkan data terkompresi
compressed_data = data[:dict_pos]
# 4. Buat kamus Huffman dari header
huffman_dict = parse_huffman_dictionary(data, dict_pos)
# 5. Dekompresi data
hasil = decompress_data(compressed_data, huffman_dict)
# 6. Simpan hasil dekompresi
with open(output_file, 'wb') as f:
f.write(hasil)
print(f"Berhasil mendekompresi {len(compressed_data)} byte menjadi {len(hasil)} byte")
print(f"Output disimpan ke {output_file}")
return hasil

dan gg bagus btw
PETIR{Pow3r_1snt_d3term1neD_by_y0ur_51ze_but_th3_5iz3_of_your_he4rT_4nd_Dre4ms}
zsaxor’s Machine
Category : Reverse Engineering
Points : 500
Difficulty : Hard
This appears to be a simple image classifier trained on 10 classes. But there's more than meets the eye...
https://huggingface.co/spaces/zsaxor/PETIR_Machine/tree/main
_
author: Yobel
Dann yapp, ini challenge yang saya buat dan saya akan menjelaskan how to solve it sampai dapat flag, btw ini challenge saya buat dan terburu buru juga jadi buat dapet part of flagnya ada yg dukun dikit hehe sorry.
Okee, di link tersebut kita disediakan 2 file penting yaitu App.py dan MachineLearning model nya.
Saya akan meringkas apa yang App.py lakukan.
class FlagHiddenModel(nn.Module):
def __init__(self):
super(FlagHiddenModel, self).__init__()
self.conv1 = nn.Conv2d(3, 16, 3, padding=1)
self.conv2 = nn.Conv2d(16, 32, 3, padding=1)
self.conv3 = nn.Conv2d(32, 64, 3, padding=1)
self.pool = nn.MaxPool2d(2, 2)
self.fc1 = nn.Linear(64 * 4 * 4, 512)
self.fc2 = nn.Linear(512, 10)
self.extra1 = nn.Linear(10, 10)
self.extra2 = nn.Linear(10, 15)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = self.pool(F.relu(self.conv3(x)))
x = x.view(-1, 64 * 4 * 4)
x = F.relu(self.fc1(x))
x = self.fc2(x)
x = self.extra1(x)
x = self.extra2(x)
return x
model = FlagHiddenModel()
model_path = os.path.join(os.path.dirname(__file__), "Petir_model.pth")
model.load_state_dict(torch.load(model_path))
model.eval()
Oke dari file App.py tersebut kita mendapatkan beberapa informasi sebagai berikut :
FlagHiddenModel adalah sebuah Convolutional Neural Network dengan:
- 3 layer konvolusi (16, 32, 64 filter)
- Layer pooling untuk mengurangi dimensi
- Fully connected layer untuk klasifikasi
- 2 layer tambahan (extra1, extra2)
Struktur proses:
- Input gambar RGB (3 channel)
- Diproses melalui konvolusi dan pooling
- Diubah ke bentuk vektor (flattened)
- Diproses melalui fully connected layers
- Output akhir berukuran 15 (kemungkinan 15 kelas)
defined model:
- Memuat bobot pre-trained dari file "Petir model.pth"
- Mengatur model ke mode evaluasi (untuk prediksi, bukan training)
Oke, dari 3 point informasi tersebut kita coba buat extract bias yang ada di dalam model tersebut
import torch
# Defined model (same as app.py)
class FlagHiddenModel(torch.nn.Module):
def __init__(self):
super(FlagHiddenModel, self).__init__()
self.conv1 = torch.nn.Conv2d(3, 16, 3, padding=1)
self.conv2 = torch.nn.Conv2d(16, 32, 3, padding=1)
self.conv3 = torch.nn.Conv2d(32, 64, 3, padding=1)
self.pool = torch.nn.MaxPool2d(2, 2)
self.fc1 = torch.nn.Linear(64 * 4 * 4, 512)
self.fc2 = torch.nn.Linear(512, 10)
self.extra1 = torch.nn.Linear(10, 10)
self.extra2 = torch.nn.Linear(10, 15)
# Load model
model = FlagHiddenModel()
model.load_state_dict(torch.load("Petir_model.pth"))
# Ekstrak layer extra1 dan extra2
extra1_weights = model.extra1.weight.data
extra1_bias = model.extra1.bias.data
extra2_weights = model.extra2.weight.data
extra2_bias = model.extra2.bias.data
print("Extra1 weights:", extra1_weights)
print("Extra2 weights:", extra2_weights)
Ini outputnya
Extra1 weights: tensor([[ 1.5200e+02, 2.3600e+02, 5.0212e-02, 7.8991e-02, -2.5542e-01,
-2.2602e-01, -2.9875e-01, -1.3114e-01, -1.1334e-01, -9.5279e-02],
[ 1.0200e+02, 1.0200e+02, 7.9076e-02, 5.0860e-02, -5.5287e-02,
-9.0633e-02, -1.3254e-01, -1.4084e-01, 1.4269e-01, 7.1517e-02],
[ 1.9400e+02, 2.2800e+02, -7.6083e-02, -9.5965e-02, 1.5007e-02,
2.2705e-01, -1.7065e-01, 3.1315e-01, 2.4081e-01, 2.6580e-01],
[ 2.2800e+02, 2.8283e-01, 3.0254e-01, 2.1410e-02, 2.8588e-01,
4.4408e-02, -2.7380e-01, 1.2713e-01, -2.5916e-01, -9.2629e-02],
[ 2.2000e+02, -1.4661e-01, 1.8783e-01, -2.3814e-01, -2.9129e-01,
-3.0149e-01, 2.1264e-01, -5.5419e-02, 1.8151e-01, -1.0675e-01],
[ 2.2000e+02, 1.3276e-01, 2.0293e-01, -1.2853e-01, 2.8207e-01,
2.6152e-01, -3.1244e-01, -2.3554e-01, 1.6658e-01, 2.2507e-01],
[ 2.2000e+02, 2.9162e-01, -2.1391e-01, 1.9614e-01, 2.7321e-03,
2.0751e-01, 2.5662e-01, -1.7780e-01, -6.1063e-02, -2.6174e-01],
[ 1.9000e+02, -5.2718e-02, -1.7661e-01, 6.7452e-02, -1.3959e-01,
1.7214e-01, 2.8350e-01, -1.4134e-01, -2.3724e-01, 1.1451e-01],
[ 1.6400e+02, 2.5500e-01, -2.9938e-01, 2.4451e-01, 4.4782e-02,
-1.5596e-01, 2.7163e-01, -2.2657e-01, 1.5377e-01, -1.1760e-01],
[ 1.0200e+02, 3.5624e-02, -1.2795e-01, 8.8012e-02, -3.8057e-02,
-6.7770e-02, 2.5786e-01, 1.8688e-01, 3.0476e-01, 3.0181e-02]])
Extra2 weights: tensor([[ 5.3372e-02, -1.2206e-01, -2.0157e-01, -2.9304e-01, 2.6919e-01,
-2.1101e-02, -6.5590e-02, -3.1418e-02, 5.6984e-02, -9.4244e-02],
[ 9.0629e-02, 2.6126e-01, -1.9399e-01, 1.2757e-01, -2.1429e-01,
2.1943e-01, 1.5627e-01, -2.9416e-01, 9.8999e-02, 1.2509e-01],
[-2.1022e-01, 6.5313e-02, -1.3623e-01, -2.9161e-01, -1.8392e-01,
-3.9290e-02, 2.6822e-01, -3.0914e-01, 2.9929e-01, 1.3942e-01],
[ 2.7668e-01, 4.5285e-02, -2.3130e-01, -5.7253e-02, 1.1654e-01,
9.1768e-02, -2.7198e-01, -2.1697e-02, -2.9954e-01, -1.0575e-02],
[ 2.2817e-01, -2.1630e-01, 1.4259e-01, 1.2182e-01, -1.8079e-02,
-1.3866e-01, -2.3029e-01, -1.2908e-01, 2.2787e-01, -4.8569e-03],
[ 2.4511e-01, -1.4637e-01, 1.9247e-01, -1.9916e-01, -1.5090e-01,
2.7718e-02, -1.1462e-01, 2.7909e-01, 1.9089e-01, 2.2465e-01],
[ 2.2524e-01, -7.0634e-02, -2.7436e-01, 1.4859e-01, -1.6495e-01,
-1.7987e-01, -1.3293e-01, 1.3432e-01, 1.8223e-01, 1.3136e-01],
[-5.8470e-02, -1.1194e-01, 2.8960e-01, -1.0045e-01, 2.5031e-05,
1.9365e-01, 2.3421e-01, -2.2163e-01, -2.1082e-02, -8.5013e-02],
[ 2.3026e-01, -2.2223e-01, 4.4447e-02, -2.1648e-01, -1.6877e-01,
-1.1029e-01, -2.2788e-02, 2.7822e-01, -2.6018e-01, -5.6159e-02],
[ 2.1871e-01, 1.2413e-01, 2.5761e-01, 1.5136e-01, 9.7616e-02,
2.1411e-01, -1.2809e-01, 3.8235e-02, -1.4118e-02, 8.8137e-02],
[-3.1106e-01, 1.5345e-01, 2.6579e-01, 1.6218e-01, -2.3825e-01,
-3.1617e-01, -2.2299e-02, 1.8913e-01, -5.7825e-03, -1.7779e-01],
[ 2.2653e-01, 2.0688e-01, -1.9616e-02, 7.6638e-02, -1.4879e-03,
2.7510e-01, -1.7237e-01, 2.9675e-01, 2.9563e-01, 1.4176e-01],
[-3.3684e-02, 5.6850e-02, -1.5909e-01, 1.3998e-02, -1.5619e-01,
2.2956e-01, -1.8440e-01, 2.5275e-01, -2.6133e-01, -2.8207e-01],
[-7.1596e-02, 9.3479e-02, 1.9835e-01, 2.1726e-02, 3.1389e-01,
1.5087e-01, -2.0211e-01, 2.6250e-01, 1.4254e-01, -4.9675e-02],
[ 2.8417e-01, 2.4641e-01, -2.1065e-01, -6.6874e-02, 3.8335e-02,
-2.1096e-01, 2.9706e-01, 3.0813e-01, -2.5225e-01, 3.7253e-02]])
Oke ada yang menarik Di extra1_weights (kolom pertama), nilai-nilainya sangat besar (100-230) dibandingkan nilai parameter neural network biasa yang umumnya kecil (-1 hingga 1). Jadi mari kita coba untuk translate ke ascii karna biasanya flag di simpan menjadi ascii di dalam model.
def extract_flag_part1(model):
flag_chars = []
with torch.no_grad():
for i in range(len(model.fc1.bias)):
val = int(model.fc1.bias[i].item())
if val < 32 or val > 126: # Range karakter ASCII yang dapat dibaca
break
flag_chars.append(chr(val))
return ''.join(flag_chars)
Oke dengan code tersebut, kita dapat flag part 1
Flag Part 1: PETIR{Machine
Biasanya kalo part 1 flagnya ascii, part selanjut selanjutnya kemungkinan besar ngga jauh dari sana, jadi saya baca lagi tapi Sebagian besar nilainya kecil (antara -0.3 dan 0.3), yang merupakan ciri khas neural network weights. Tidak ada pola yang jelas yang menunjukkan ascii code. setelah cukup lama trial n error, saya ngga sengaja ternyata menemukan polanya ternyata hanya dibagi 2, jadi tetap di ascii codenya.
def extract_flag_part2(model):
flag_chars = []
with torch.no_grad():
rows, cols = model.extra1.weight.size(0), model.extra1.weight.size(1)
for i in range(rows * cols):
row = i % rows
col = i // rows
val = int(model.extra1.weight[row][col].item() / 2)
if val < 32 or val > 126: # Range karakter ASCII yang dapat dibaca
break
flag_chars.append(chr(val))
return ''.join(flag_chars)
Oke dengan code tersebut, kita berhasil dapat flag part 2
Flag Part 2: L3arnnn_R3v3r
Okee dan sekarang last part dari flag nya, jujur ini kesalahanku tapi adaa aja yang solve Jagoo jagoo emang PETIR ini, btw harusnya buat dapetin last flag ini ada hint “The Ultimate Question of Life, the Universe, and Everything” di dalam deskripsi challenge, tapi anggap saja tidak ada, kita pakai cara bruteforce aja buat dapat last char yaitu ( } )
def brute_force_part3(model):
results = []
bias_values = model.extra2.bias.data
# Operasi pengurangan (subtraction)
for val in range(1, 1000):
flag = ""
for i in range(len(bias_values)):
float_val = float(bias_values[i])
char_val = int(round(float_val - val))
if 32 <= char_val <= 126: # Range karakter ASCII yang dapat dibaca
flag += chr(char_val)
else:
if len(flag) > 0:
break
if '}' in flag:
print(f"Found: subtract {val} -> {flag}")
results.append(('subtract', val, flag))
# Operasi penambahan (addition)
for val in range(1, 1000):
flag = ""
for i in range(len(bias_values)):
float_val = float(bias_values[i])
char_val = int(round(float_val + val))
if 32 <= char_val <= 126:
flag += chr(char_val)
else:
if len(flag) > 0:
break
if '}' in flag:
print(f"Found: add {val} -> {flag}")
results.append(('add', val, flag))
# Operasi perkalian (multiplication)
for val in range(1, 1000):
flag = ""
for i in range(len(bias_values)):
float_val = float(bias_values[i])
char_val = int(round(float_val * val))
if 32 <= char_val <= 126:
flag += chr(char_val)
else:
if len(flag) > 0:
break
if '}' in flag:
print(f"Found: multiply {val} -> {flag}")
results.append(('multiply', val, flag))
# Operasi pembagian (division)
for val in range(1, 1000): # Skip 0 untuk menghindari division by zero
if val == 0:
continue
flag = ""
try:
for i in range(len(bias_values)):
float_val = float(bias_values[i])
char_val = int(round(float_val / val))
if 32 <= char_val <= 126:
flag += chr(char_val)
else:
if len(flag) > 0:
break
if '}' in flag:
print(f"Found: divide {val} -> {flag}")
results.append(('divide', val, flag))
except ZeroDivisionError:
continue
return results
Dann akhirnya dapat last part flag, tapi dengan cara bruteforce sekali lagi saya minta maaf.
PETIR{MachineL3arnnn_R3s33333_zsaxor}





