Forensics Β· FGTE 0 Β· Medium Β· 2026-03-07

Ghost Typist

🧩 Summary Flow Git commit β†’ ghost.log (keylogger) β†’ recover password β†’ decrypt ghost.enc β†’ dapat file octal β†’ decode β†’ env dump β†’ ambil FLAG

Ghost Typist

🧩 Summary Flow Git commit β†’ ghost.log (keylogger) β†’ recover password β†’ decrypt ghost.enc β†’ dapat file octal β†’ decode β†’ env dump β†’ ambil FLAG

🧠 Write-Up CTF – Ghost Commits & Keylogger Leak

(3/4 slop)

πŸ“œ Deskripsi Soal

Seorang developer tidak sengaja melakukan commit file sensitif ke GitHub, lalu menghapusnya dengan force push. Namun ternyata commit tersebut masih bisa diakses menggunakan partial hash 45.

Petunjuk tambahan:

β€œSepertinya ada sesuatu yang berkaitan dengan aktivitas keyboard di commit tersebut.”


πŸ” Step 1 – Mengakses Commit yang Terhapus

Walaupun sudah di-force push, commit masih bisa diakses dengan partial hash:

https://github.com/ariafatah999/ghosts/commit/45252d455310384010a5b43585bde42ab5d2ab4d

Dari commit tersebut, ditemukan 2 file penting:


πŸ” Step 2 – Identifikasi File Enkripsi

Cek tipe file:

~/FGTE/FGTE0/misc/ghost
❯ file ghost.enc
ghost.enc: openssl enc'd data with salted password

Output:

openssl enc'd data with salted password

Artinya file ini dienkripsi menggunakan OpenSSL.


⌨️ Step 3 – Analisis ghost.log (Keylogger)

Cek isi:

╭─   ~/FGTE/FGTE0/misc/ghost ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── ο‰’ 37m 37s  kali ο€— 09:34:20
╰─❯ xxd ghost.log | head

00000000: 52f2 aa69 0000 0000 0000 0000 0000 0000  R..i............
00000010: 0100 2600 0100 0000 52f2 aa69 0000 0000  ..&.....R..i....
00000020: 0000 0000 0000 0000 0100 2600 0000 0000  ..........&.....
00000030: 52f2 aa69 0000 0000 0000 0000 0000 0000  R..i............
00000040: 0100 1f00 0100 0000 52f2 aa69 0000 0000  ........R..i....
00000050: 0000 0000 0000 0000 0100 1f00 0000 0000  ................
00000060: 52f2 aa69 0000 0000 0000 0000 0000 0000  R..i............
00000070: 0100 1c00 0100 0000 52f2 aa69 0000 0000  ........R..i....
00000080: 0000 0000 0000 0000 0100 1c00 0000 0000  ................
00000090: 52f2 aa69 0000 0000 0000 0000 0000 0000  R..i............

╭─  

Terlihat pola berulang seperti:

0100 XX 00 0100 ...

Ini sangat mirip dengan:
➑️ event input keyboard (key press / release)

Apalagi, deskripsi soalnya ada bagian "Sepertinya ada sesuatu yang berkaitan dengan aktivitas keyboard di commit tersebut. Bisakah kamu menemukan apa yang bocor?"

Saya langsung tancap gas.


🧩 Step 4 – Decode Keylogger

Gunakan mapping keycode Linux:

data=open("ghost.log","rb").read()

keymap={
16:'q',17:'w',18:'e',19:'r',20:'t',21:'y',22:'u',23:'i',24:'o',25:'p',
30:'a',31:'s',32:'d',33:'f',34:'g',35:'h',36:'j',37:'k',38:'l',
44:'z',45:'x',46:'c',47:'v',48:'b',49:'n',50:'m',
28:'\n',57:' '
}

keys=[]

for i in range(len(data)):
    if data[i:i+2]==b'\x01\x00':
        code=data[i+2]
        val=data[i+4]
        if val==1:  # key press
            keys.append(keymap.get(code,f"[{code}]"))

print("".join(keys))

Output:

╭─   ~/FGTE/FGTE0/misc/ghost ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────  kali ο€— 09:35:41
╰─❯ python3
Python 3.13.11 (main, Dec  8 2025, 11:43:54) [GCC 15.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> data=open("ghost.log","rb").read()
...
... keymap={
... 16:'q',17:'w',18:'e',19:'r',20:'t',21:'y',22:'u',23:'i',24:'o',25:'p',
... 30:'a',31:'s',32:'d',33:'f',34:'g',35:'h',36:'j',37:'k',38:'l',
... 44:'z',45:'x',46:'c',47:'v',48:'b',49:'n',50:'m',
... 28:'\n',57:' '
... }
...
... keys=[]
...
... for i in range(len(data)):
...     if data[i:i+2]==b'\x01\x00':
...         code=data[i+2]
...         val=data[i+4]
...         if val==1:  # key press
...             keys.append(keymap.get(code,f"[{code}]"))
...
... print("".join(keys))
...
ls
whoami
env [42][52] env[42][12]dump[52]txt
od env[42][12]dump[52]txt [42][52] ghost
openssl enc [12]aes[12][3][6][7][12]cbc [12]salt [12]pass pass[42][39][5][42][12][42]gh[11]st[42][12][42]typ[2]st[42][12][42]m[4][42][12][7][10] [12]in ghost [12]out ghost[52]enc

Setelah dirapikan:
ls
whoami
env > env_dump.txt
od env_dump.txt > ghost
openssl enc -aes-256-cbc -salt -pass pass:4_Gh0st_Typ1st_M3_69 ...

πŸ”₯ Dari sini didapat password asli:

4_Gh0st_Typ1st_M3_69

πŸ”“ Step 5 – Decrypt File


╭─   ~/FGTE/FGTE0/misc/ghost ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── ο‰’ 2m 6s  kali ο€— 09:39:07
╰─❯ openssl enc -d -aes-256-cbc -in ghost.enc -out ghost -pass pass:4_Gh0st_Typ1st_M3_69

*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.

Hasil:

╭─   ~/FGTE/FGTE0/misc/ghost ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────  kali ο€— 09:39:08
╰─❯ file ghost
ghost: ASCII text

πŸ”’ Step 6 – Decode File ghost

Isi file berupa output:

od env_dump.txt

Formatnya:
➑️ 6 digit octal = 16-bit word


πŸ§ͺ Step 7 – Convert Octal ke ASCII

Gunakan Python:

import re

data = open("ghost").read()
nums = re.findall(r'[0-7]{6}', data)

out = bytearray()

for n in nums:
    v = int(n, 8)
    out += v.to_bytes(2, "little")  # penting: little endian

clean = bytearray(b for b in out if 32 <= b <= 126 or b in (10,9))

open("env_real_fixed.txt","wb").write(clean)

πŸ“‚ Step 8 – Analisis Environment Dump

╭─   ~/FGTE/FGTE0/misc/ghost ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── ο‰’ 6s  kali ο€— 09:40:27
╰─❯ cat env_real_fixed.txt
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOME=/home/de
v
USER=dev
LOGNAME=dev
SHELL=/bin/bash
PWD=/home/dev/project
LANG=en_US.UTF-8
TERM=xterm-256color
EDITOR=vim
DB_HOST=localhost
DB_PORT=5432
DB_USER=dev_app
DB_PASS=s upersecretpasswo"rd
AWS_ACCESS_K$EY_ID=AKIAIOSFOD&NN7EXAMPLE
AWS_(SECRET_ACCESS_KE*Y=wJalrXUtnFEMI/,K7MDENG/bPxRfiCY.EXAMPLEKEY
API_0KEY_INTERNAL=dev2_internal_api_1243
SESSION_SECRE6T=prod_session_s8ecret
FLAG=FGTE:0{Gh0st_C0m1ts_K<3yL0g5_4nd_3nv_D>ump5}
NODE_ENV=@production
PYTHBONPATH=/usr/lib/Dpython3
SSH_CLIFENT=192.168.1.50H 54232 22
SSH_CJONNECTION=192.16L8.1.50 54232 192N.168.1.10 22
O%

Hasil:

PATH=/usr/local/sbin:...
USER=dev
DB_PASS=supersecretpassword
AWS_ACCESS_KEY_ID=...
SESSION_SECRET=...
FLAG=FGTE0{Gh0st_C0m1ts_K3yL0g5_4nd_3nv_Dump5}🏁 Final Flag

FGTE0{Gh0st_C0m1ts_K3yL0g5_4nd_3nv_Dump5}

🧠 Insight & Pelajaran

πŸ”₯ 1. Force Push β‰  Aman

Commit yang sudah dihapus masih bisa diakses via hash.

⌨️ 2. Keylogger Forensics

Log keyboard bisa digunakan untuk:

πŸ” 3. OpenSSL Weakness

Jika password bocor β†’ enkripsi jadi tidak berguna.

🧾 4. Data Encoding Layered

Challenge ini punya banyak layer:

  1. Git leak

  2. Keylogger

  3. Encryption

  4. Octal encoding

Flag

FGTE0{Gh0st_C0m1ts_K3yL0g5_4nd_3nv_Dump5}