⏪
CTFs
TwitterGithub
  • 👋Introduction
  • 📚Write Up
    • 2024
      • 📖1337UP LIVE CTF
        • Reverse Engineering
        • Mobile
        • Forensic
        • Misc
      • 📖HKCERT CTF Quals
        • Reverse Engineering
        • Binary Exploitation
      • 📖Flare-On 11
        • Challenge #1 - frog
      • 📖Intechfest
        • Reverse Engineering
        • Forensic
        • Cryptography
        • Mobile
      • 📖Cyber Breaker Competition (1v1)
        • Reverse Engineering
        • Web Exploitation
        • Cryptography
        • Binary Exploitation
      • 📖Cyber Breaker Competition Quals
        • Reverse Engineering
        • Web Exploitation
        • Cryptography
      • 📖BlackHat MEA Quals
        • Reverse Engineering
        • Forensic
      • 📖TFC CTF
        • Reverse Engineering
        • Forensic
        • Misc
      • 📖DeadSec CTF
        • Reverse Engineering
        • Web Exploitation
      • 📖Aptos - Code Collision CTF
        • Reverse Engineering
        • Misc
      • 📖DownUnder CTF
        • Reverse Engineering
      • 📖JustCTF
        • Reverse Engineering
        • Forensic
        • Misc
      • 📖Akasec CTF
        • Reverse Engineering
        • Forensic
      • 📖Codegate CTF Preliminary
        • Reverse Engineering
      • 📖NahamCon CTF
        • Cryptography
        • Reverse Engineering
        • Malware
        • Misc
        • Mobile
        • Scripting
        • Web Exploitation
        • Forensic
      • 📖SAS CTF Quals
        • Reverse Engineering
      • 📖SwampCTF
        • Reverse Engineering
        • Misc
        • Cryptography
      • 📖UNbreakable International
        • Reverse Engineering
        • Network
        • Cryptography
      • 📖ACSC
        • Reverse Engineering
        • Hardware
        • Web Exploitation
      • 📖0xL4ugh
        • Mobile
    • 2023
      • 📖BlackHat MEA Final
        • Reverse Engineering
        • Web Exploitation
      • 📖Flare-On 10
        • Challenge #1 - X
        • Challenge #2 - ItsOnFire
        • Challenge #3 - mypassion
        • Challenge #4 - aimbot
        • Challenge #5 - where_am_i
        • Challenge #6 - FlareSay
        • Challenge #7 - flake
        • Challenge #8 - AmongRust
        • Challenge #9 - mbransom
        • Challenge #10 - kupo
        • Challenge #11 - over_the_rainbow
        • Challenge #12 - HVM
        • Challenge #13 - y0da
      • 📖LakeCTF Quals
        • Reverse Engineering
        • Cryptography
      • 📖TSG CTF
        • Reverse Engineering
        • Cryptography
      • 📖ISITDTU Quals
        • Web Exploitation
        • Misc
        • Reverse Engineering
      • 📖BlackHat MEA Quals
        • Reverse Engineering
      • 📖ASCIS Final
        • Reverse Engineering
        • Web Exploitation
        • Cryptography
      • 📖ASCIS Quals
        • Reverse Engineering
        • Forensic
        • Cryptography
      • 📖IFest
        • Reverse Engineering
        • Cryptography
        • Misc
      • 📖Cyber Jawara International
        • Reverse Engineering
        • Forensic
        • Cryptography
        • Web Exploitation
      • 📖Intechfest
        • Reverse Engineering
        • Forensic
        • Cryptography
        • Mobile
      • 📖CSAW Quals
        • Reverse Engineering
      • 📖SECCON Quals
        • Reverse Engineering
      • 📖CTFZone Quals
        • Reverse Engineering
      • 📖Securinets Quals
        • Reverse Engineering
      • 📖Compfest Final (Attack Defense)
        • Web Exploitation
        • Cryptography
      • 📖Compfest Quals
        • Reverse Engineering
        • Cryptography
        • Forensic
        • Misc
      • 📖Tenable
        • Reverse Engineering
        • Cryptography
        • Steganography
      • 📖ASCWG Quals
        • Reverse Engineering
        • Cryptography
      • 📖Gemastik Quals
        • Reverse Engineering
      • 📖BSides Indore
        • Reverse Engineering
        • Cryptography
      • 📖NahamCon CTF
        • Cryptography
      • 📖HSCTF
        • Reverse Engineering
        • Cryptography
        • Web Exploitation
        • Misc
      • 📖ACSC
        • Reverse Engineering
      • 📖HackTM Quals
        • Reverse Engineering
    • 2022
      • 📖Intechfest
        • Reverse Engineering
        • Mobile
        • Cryptography
      • 📖NCW Final
        • Reverse Engineering
      • 📖NCW Quals
        • Reverse Engineering
        • Misc
        • Cryptography
      • 📖Compfest Final
        • Reverse Engineering
        • Forensic
      • 📖Compfest Quals
        • Reverse Engineering
        • Cryptography
      • 📖IFest
        • Reverse Engineering
        • Cryptography
        • Forensic
    • 2021
      • 📖Cyber Jawara Final
        • Reverse Engineering
      • 📖Cyber Jawara Quals
        • Reverse Engineering
        • Cryptography
      • 📖DarkCon CTF
        • Reverse Engineering
      • 📖Wreck IT Quals
        • Mobile
      • 📖MDT4.0 Final
        • Reverse Engineering
        • Cryptography
        • Forensic
      • 📖MDT4.0 Quals
        • Reverse Engineering
        • Cryptography
      • 📖IFest
        • Reverse Engineering
        • Cryptography
      • 📖Compfest Final
        • Reverse Engineering
      • 📖Compfest Quals
        • Reverse Engineering
        • Cryptography
    • 2020
      • 📖Deep CTF
        • Reverse Engineering
  • 🚩Lifetime CTF
    • 📖Hack The Box
      • Reverse Engineering
        • TBU
Powered by GitBook
On this page
  • Staged (1000 pts)
  • Description
  • Solution
  1. Write Up
  2. 2024
  3. Intechfest

Forensic

PreviousReverse EngineeringNextCryptography

Last updated 5 months ago

Challenge
Link

Staged (1000 pts) 🥇

Staged (1000 pts)

Description

-

Solution

Diberikan file pcap dan isinya adalah QUIC protocol, di awal saya mencoba mencari referensi untuk melakukan crack terhadap enkripsinya dengan asumsi menggunakan parameter yang lemah dan berakhir tidak menemukan apa-apa. Karena sudah menyerah, tiba-tiba kepikiran untuk ls -la dan ternyata ada .ssl.log

Lanjut analisis dengan load ssl.log pada preferences>protocols>tls>pms log filename

Selanjutnya adalah melakukan analisis terhadap HTTP3

Pada frame ke 10 bisa dilihat terdapat request stream dan pada header terdapat path dan range, range mengindikasikan bytes range yang didownload, semisal 0-1024 maka 1024 bytes pertama akan didownload.

Pada frame ke 13 bisa dilihat terdapat response yang mengindikasikan pemberian data untuk byte 4608-4655 dari file/data yang direquest. Jadi disini kita mengetahui bahwa terdapat proses download secara partial yang dilakukan oleh client. Idenya adalah melakukan parsing untuk semua yang didownload dan menggabungkannya. Namun ada beberapa masalah dalam melakukannya

  • Ada banyak file yang didownload dan semua dilakukan secara partial

  • Request dan response untuk download tidak berurutan

    • Jadi semisal download file a sebesar 0-1024 pada frame 10, maka pada frame 11 download file b sebesar 2048-2560

  • Besar byte range tidak tetap

    • Misal ada yang 0-563 untuk file a, ada yang 0-572 untuk file b. Tetapi untuk block selanjutnya untuk file a rangenya 512-1234

  • Hasil export dari wireshark ke json bermasalah

    • http3.headers.header (key sama), jadi kalau diload sebagai json akan diambil nilai yang paling terakhir di python

Jadi disini kita tidak bisa dengan mudah melakukan dump terhadap filenya dengan memanfaatkan export json. Disini saya melakukan pendekatan untuk parsingnya sebagai berikut

  • Mencari nilai unik yang bisa dijadikan sebagai key untuk setiap downloadnya

    • Path adalah nilai yang tepat

  • Mencari paket yang memberikan respons berupa n byte dari file dan mencari nama untuk file tersebut

    • Http3.frame_type = 0x0000000000000000 -> untuk tipe response

    • Http3.frame_payload -> untuk data yang diberikan

    • udp.port dan quic.connection.number dapat dijadikan identifier untuk menemukan path dari response yang ditemukan

Berikut script yang saya gunakan untuk melakukan dump

def find_index(target, data):
	for i in range(len(data)):
		if target in data[i]:
			return i

def find_all_index(target, data):
	list_index = []
	for i in range(len(data)):
		if target in data[i]:
			list_index.append(i)
	return list_index

def find_range(index, data):
	for i in range(min(index + 80,len(data) - 1) , index - 500, -1):
		if '"http3.headers.header.value": "bytes ' in data[i]:
			tmp = data[i].split("bytes ")[-1].split("-")
			return int(tmp[0]), int(tmp[1].split("/")[0])
		if '"http3.stream": {' in data[i]:
			return -1, -1

def find_path(index, data, cn):
	if find_connection_after(index, data) != cn:
		return -1
	for i in range(index, index + 200):
		if '"http3.headers.path": "' in data[i]:
			return data[i].split('": "')[1].split('"')[0][1:]
		if '"_index": "packets-2024-08-22",' in data[i]:
			return -1

def find_udp_port(index, data):
	for i in range(index - 1, index - 1000, -1):
		if '"udp.port": "' in data[i]:
			return int(data[i].split('": "')[1].split('"')[0])
		if '"udp": {' in data[i]:
			return -1

def find_connection(index, data):
	for i in range(index - 1, index - 1000, -1):
		if '"quic.connection.number": "' in data[i]:
			return int(data[i].split('": "')[1].split('"')[0])
		if '"quic": {' in data[i]:
			return -1

def find_connection_after(index, data):
	for i in range(index, index + 50):
		if '"quic.connection.number": "' in data[i]:
			return int(data[i].split('": "')[1].split('"')[0])
		if '"quic.frame": {' in data[i]:
			return -1

import json

f = open("dump.json", "r").read()
list_f = f.split("\n")
data = json.loads(f)
dict = {}
for i in data:
	if "http3" in i["_source"]["layers"]:
		if "http3.stream" in i["_source"]["layers"]["http3"]:
			if "http3.frame" in i["_source"]["layers"]["http3"]["http3.stream"]:
				if i["_source"]["layers"]["http3"]["http3.stream"]["http3.frame"]["http3.frame_type"] == "0x0000000000000000":
					fp = i["_source"]["layers"]["http3"]["http3.stream"]["http3.frame"]["http3.frame_payload"]
					fmt = f'"http3.frame_payload": "{fp}"'
					index = find_index(fmt, list_f)
					cn = find_connection(index, list_f)
					start, end = find_range(index, list_f)
					udp_port = find_udp_port(index, list_f)
					tmp_fmt = f'"udp.port": "{udp_port}"'
					list_index = find_all_index(tmp_fmt, list_f)
					for j in list_index:
						ret = find_path(j, list_f, cn)
						if ret != -1:
							break
					if ret == -1:
						print("what?", list_index, tmp_fmt, index)
						exit()
					path = ret
					if start != -1:
						if path not in dict:
							dict[path] = {}
						
						if f"{start}_{end}" in dict[path]:
							print("duplicate", dict[path][f"{start}_{end}"])
							exit()
						dict[path][f"{start}_{end}"] = bytes.fromhex(''.join(fp.split(":")))
					else:
						continue

for i in dict:
	tmp = [b"" for _ in range(2012)]
	for j in dict[i]:
		start, end = map(int, j.split("_"))
		assert start % 512 == 0
		tmp[start // 512] = dict[i][j][:512]
	out = open(f"dumps_tmp/{i}", "wb")
	out.write(b''.join(tmp))

Ketika lomba, setelah melakukan dump saya melakukan pengecekan apakah semua path/file sudah berhasil didump atau tidak. Ternyata tidak, terdapat satu file yang tidak ada yaitu KXPrUXBemVsOs0EJ1gi1. Dimana file tersebut adalah file terbesar di pcap, jadi saya sedikit mengubah kode diatas untuk membuatnya bisa melakukan dump terhadap KXPrUXBemVsOs0EJ1gi1

def find_index(target, data):
	for i in range(len(data)):
		if target in data[i]:
			return i

def find_all_index(target, data):
	list_index = []
	for i in range(len(data)):
		if target in data[i]:
			list_index.append(i)
	return list_index

def find_path(index, data, cn):
	if find_connection_after(index, data) != cn:
		return -1, -1, -1
	found_path = -1
	for i in range(index, index + 200):
		if '"http3.headers.path": "' in data[i]:
			found_path = data[i].split('": "')[1].split('"')[0][1:]
			break
		if '"_index": "packets-2024-08-22",' in data[i]:
			found_path = -1
			break
	for i in range(index, index + 200):
		if 'http3.headers.header.value": "bytes=' in data[i]:
			start, end = map(int, data[i].split('bytes=')[1].split('"')[0].split("-"))
			break
		if '"_index": "packets-2024-08-22",' in data[i]:
			start, end = -1, -1
			break
	return found_path, start, end


def find_udp_port(index, data):
	for i in range(index - 1, index - 1000, -1):
		if '"udp.port": "' in data[i]:
			return int(data[i].split('": "')[1].split('"')[0])
		if '"udp": {' in data[i]:
			return -1

def find_connection(index, data):
	for i in range(index - 1, index - 1000, -1):
		if '"quic.connection.number": "' in data[i]:
			return int(data[i].split('": "')[1].split('"')[0])
		if '"quic": {' in data[i]:
			return -1

def find_connection_after(index, data):
	for i in range(index, index + 50):
		if '"quic.connection.number": "' in data[i]:
			return int(data[i].split('": "')[1].split('"')[0])
		if '"quic.frame": {' in data[i]:
			return -1

import json

f = open("dump.json", "r").read()
list_f = f.split("\n")
data = json.loads(f)
dict = {}
for i in data:
	if "http3" in i["_source"]["layers"]:
		if "http3.stream" in i["_source"]["layers"]["http3"]:
			if "http3.frame" in i["_source"]["layers"]["http3"]["http3.stream"]:
				if i["_source"]["layers"]["http3"]["http3.stream"]["http3.frame"]["http3.frame_type"] == "0x0000000000000000":
					fp = i["_source"]["layers"]["http3"]["http3.stream"]["http3.frame"]["http3.frame_payload"]
					fmt = f'"http3.frame_payload": "{fp}"'
					fp_len = len(bytes.fromhex(''.join(fp.split(":"))))
					index = find_index(fmt, list_f)
					cn = find_connection(index, list_f)
					udp_port = find_udp_port(index, list_f)
					tmp_fmt = f'"udp.port": "{udp_port}"'
					list_index = find_all_index(tmp_fmt, list_f)
					for j in list_index:
						ret, start, end = find_path(j, list_f, cn)
						if ret != -1:
							break
					if ret == -1:
						print("what?", list_index, tmp_fmt, index)
						exit()
					if ret == "KXPrUXBemVsOs0EJ1gi1":
						print("found", fp_len, start, end)
					else:
						continue

					path = ret
					if start != -1:
						if path not in dict:
							dict[path] = {}
						
						if f"{start}_{end}" in dict[path]:
							print("duplicate", dict[path][f"{start}_{end}"])
							exit()
						dict[path][f"{start}_{end}"] = bytes.fromhex(''.join(fp.split(":")))
					else:
						continue

for i in d:
	tmp = [b"" for _ in range(503)]
	for j in d[i]:
		start, end = map(int, j.split("_"))
		tmp[start // 2048] = d[i][j][:2048]
	out = open(f"dumps_tmp/{i}", "wb")
	out.write(b''.join(tmp))

Semua file yang didump terlihat sebagai valid ELF file

Lakukan analisis terhadap salah satu file yaitu 0AL893Ky

Dari hasil disasm terlihat bahwa elf tersebut diobfuscate, dari debugging diketahui bahwa elf tersebut akan melakukan xor untuk pada instruksi setelahnya dan kemudian mengubah xor key berdasarkan nilai yang dixor sebelumnya (ditambah). Setelah itu juga step yang sama (diobfuscate 2 kali) dan terakhir akan dijalankan execve dengan syscall. Disini kami melakukan otomasi untuk dump command yang dijalankan melalui execve

#!/usr/bin/python3

import json
import glob

class SolverEquation(gdb.Command):
    def __init__ (self):
        super (SolverEquation, self).__init__ ("solve-equation",gdb.COMMAND_OBSCURE)

    def invoke (self, arg, from_tty):
        d = {}
        for fn in glob.glob("bin/*"):
            gdb.execute(f"file {fn}")
            zz = open("xx.txt", "a")
            zz.write(f"FILENAME_DEBUG: {fn}\n")
            zz.close(   )
            gdb.execute("set print repeats 0")
            gdb.execute("del")
            gdb.execute("start")
            arch = gdb.selected_frame().architecture()
            for i in range(10):
                gdb.execute("si")
                current_pc = addr2num(gdb.selected_frame().read_register("pc"))
                disa = arch.disassemble(current_pc)[0]
                if "loop" in disa["asm"]:
                    gdb.execute("si")
                    gdb.execute(f"b *{hex(disa['addr'] + 2)}")
                    break
            gdb.execute("c")
            gdb.execute("del")
            for i in range(10):
                gdb.execute("si")
                current_pc = addr2num(gdb.selected_frame().read_register("pc"))
                disa = arch.disassemble(current_pc)[0]
                if "loop" in disa["asm"]:
                    gdb.execute("si")
                    gdb.execute(f"b *{hex(disa['addr'] + 2)}")
                    break
            gdb.execute("c")
            for i in range(20):
                gdb.execute("si")
                current_pc = addr2num(gdb.selected_frame().read_register("pc"))
                disa = arch.disassemble(current_pc)[0]
                if "syscall" in disa["asm"]:
                    addr = parse(gdb.execute("x/wx $rsp+0x10", to_string=True))[0]
                    d[fn.split("/")[-1]] = parse_str(gdb.execute(f"x/s {hex(addr)}", to_string=True))[0]
                    break
            gdb.execute("kill")
        print(d)
        with open('out.txt', 'w') as f:
            f.write(json.dumps(d))

def parse(f):
    f = f.split("\n")
    result = []
    for i in f:
        tmp = i.split("\t")
        for j in range(1,len(tmp)):
            result.append(int(tmp[j],16))
    return result

def parse_str(f):
    f = f.split("\n")
    result = []
    for i in f:
        tmp = i.split("\t")
        for j in range(1,len(tmp)):
            result.append(tmp[j])
    return result

def addr2num(addr):
    try:
        return int(addr)
    except:
        return long(addr)

SolverEquation()

Dari xx.txt diketahui terdapat error untuk file QfkAFOiM. Jadi kami menggunakan script untuk KXPrUXBemVsOs0EJ1gi1 pada file QfkAFOiM dengan mengganti string saja dan size saat dump. Sekarang file QfkAFOiM valid dan lanjut otomasi dengan gdb script diatas. Selanjutnya kita mendapatkan command yang dieksekusi dan itu terlihat diobfuscate. Cara paling mudah untuk deobfsucate adalah dengan melakukan echo untuk command yang diexecute, berikut script deobfuscate kami

import zlib
import base64
import os
import json

data = json.loads(open("out.txt", "r").read())

out = {}
for i in data:
	tmp = data[i].split("{base64,-d}<<<")
	ct = []
	for j in tmp[1:]:
		ct.append(j.split("|")[0])
	pt = []
	pt = [base64.b64decode(ct[0]).decode()]
	for j in range(1, len(ct)):
		pt.append(zlib.decompress(base64.b64decode(ct[j])).decode())
	out[i] = pt


list_cmd = []
for i in out:
	cmd = []
	for j in out[i]:
		tmp = j.split("<<<")[-1]
		if "|" in tmp:
			tmp2 = tmp.split("|")
			for tmp_res in tmp2:
				for _ in range(2):
					tmp_res = os.popen(f"echo {tmp_res}").read().strip()
				cmd.append(tmp_res)
		else:
			tmp_res = tmp
			for _ in range(2):
				tmp_res = os.popen(f"echo {tmp_res}").read().strip()
			cmd.append(tmp_res)
	list_cmd.append(cmd)
print(list_cmd)

Dapat dilihat bahwa command yang dijalankan adalah seperti ./KXPrUXBemVsOs0EJ1gi1 JW8ib6vSJzoCJL0Q3zuYIPDRaWEeAqfL92FebTGQAq7TaWDNH60RAqfil2FxvVDGDg8 nF2dfmWkaEKs7D9A8pMqUt6VvJb3uHIliCxgOGzPhZBwy1YNQoLeRXT5r0j4cS OY6kSmMw4poq0xEF7RcLbUVhAeznilTI.ZRCf6nVAF9uWOgt1x3MjkGEYzpalBNKi yang mana KXPrUXBemVsOs0EJ1gi1 merupakan file elf yang kita dump juga. Lakukan decompile untuk KXPrUXBemVsOs0EJ1gi1 dengan IDA

  • Fungsi e

    • Base64 encode dengan custom charset (2nd arg)

  • Fungsi d

    • Base64 decode dengan custom charset (2nd arg)

  • Fungsi r

    • Eksekusi command

  • Fungsi q

    • Query dns ke server

Jadi prosesnya adalah

  • Decode command

  • Query ke server

  • Eksekusi command

  • Encode command 2 kali dengan charset berbeda

  • Query ke server

Dari hasil decode diketahui bahwa terdapat beberapa command yang berbeda tapi untuk exfil flag menggunakan command dd dan base64, berikut script yang kami gunakan untuk mendapatkan flag

import base64
import json
import re

def base64_decode(encoded_str: str, base64_alphabet: str) -> str:
    padding_count = encoded_str.count('=')
    encoded_str = encoded_str.rstrip('=')
    
    base64_reverse_map = {char: index for index, char in enumerate(base64_alphabet)}
    
    output = bytearray()
    for i in range(0, len(encoded_str), 4):
        char1 = base64_reverse_map.get(encoded_str[i], 0)
        char2 = base64_reverse_map.get(encoded_str[i + 1], 0)
        char3 = base64_reverse_map.get(encoded_str[i + 2], 0) if i + 2 < len(encoded_str) else 0
        char4 = base64_reverse_map.get(encoded_str[i + 3], 0) if i + 3 < len(encoded_str) else 0

        combined = (char1 << 18) | (char2 << 12) | (char3 << 6) | char4

        output.append((combined >> 16) & 0xFF)
        if i + 2 < len(encoded_str) or padding_count < 2:
            output.append((combined >> 8) & 0xFF)
        if i + 3 < len(encoded_str) or padding_count < 1:
            output.append(combined & 0xFF)

    return output.decode('utf-8')


def get_val(cmd):
    bs_re = r"bs=(\d+)"
    skip_re = r"skip=(\d+)"
    count_re = r"count=(\d+)"
    bs = re.search(bs_re, cmd).group(1)
    skip = re.search(skip_re, cmd).group(1)
    count = re.search(count_re, cmd).group(1)
    return int(bs), int(skip), int(count)
    


def find_leak(key, data):
    arr = []
    counter = 0
    for i in data:
        for j in i["_source"]["layers"]["dns"]["Queries"]:
            tmp = i["_source"]["layers"]["dns"]["Queries"][j]
            if key in tmp["dns.qry.name"] and key != tmp["dns.qry.name"]:
                tmp2 = tmp["dns.qry.name"].split(".")[-1]
                if tmp2 not in arr:
                    arr.append(tmp2)
        if "Answers" in i["_source"]["layers"]["dns"]:
            for j in i["_source"]["layers"]["dns"]["Answers"]:
                tmp = i["_source"]["layers"]["dns"]["Answers"][j]
                if key in tmp["dns.resp.name"] and "dns.txt" in tmp:
                    charset = tmp["dns.txt"]
                    counter += 1
                    if counter > 2:
                        print("what??")
    return arr, charset


list_cmd = # output from deobfuscated command

f = open("dns.json", "r").read()
data = json.loads(f)
d = {}
flag_arr = [0 for _ in range(29526)]
counter = 0
for i in list_cmd:
    tmp = i[-1].split(" ")
    ct_command = tmp[1]
    charset1 = tmp[2]
    key = tmp[3]
    arr, charset2 = find_leak(key, data)
    pt_cmd = base64_decode(ct_command, charset1)
    ct_val = ''.join(arr)
    val = base64_decode(base64_decode(ct_val, charset1), charset2)
    if "dd if" in pt_cmd:
        bs, skip, count = get_val(pt_cmd)
        result = list(base64.b64decode(val))
        counter += len(result)
        flag_arr[skip*bs:skip*bs + count*bs] = result
    else:
        continue

out = open("niceflag.png.zst", "wb")
out.write(bytes(flag_arr))
  • dns.json export dari traffic dns

  • list_cmd output dari deobfuscate bash commmand

terakhir tinggal unzstd saja

Flag: INTECHFEST{dyn4mic_4nalys1s_with_4_cert4in_twist_huh_368bebc9bb}

📚
📖
Here