← Back to Writeups
CUSTOMMediumForensics

Judgmental Behavior

XESXOR9/2/20265 min read
#forensics#custom#medium#sysmon_event_parsing#chrome_history_forensics#osu_beatmap_analysis#creator_enumeration_osint#decoy_elimination#archive_filename_flag#linux

Judgmental Behavior

Platform: hackerlab | Category: Forensics | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2025-04-01 | Status: Solved Techniques: sysmon_event_parsing, chrome_history_forensics, osu_beatmap_analysis, creator_enumeration_osint, decoy_elimination, archive_filename_flag

Summary

Task: ~165 MB winlogbeat/Sysmon events.json from a slacking developer's workstation; reconstruct his behavior and find the flag. Solution: parse Sysmon events, recover Chrome History showing downloaded osu! beatmaps, ignore the decoy CODEBY{try_it_ok} beatmap, pivot via OSINT to the SAME creator's second beatmap whose audio filename IS the flag.

Judgmental Behavior — hackerlab

Description

Наш коллега — разработчик — совсем отбился от рук, занимается на работе непонятно чем. Разберитесь, что происходит. Прилагаем события с его хоста.

English summary: A developer has been misbehaving at work. We are given the exported events from his workstation (a ~165 MB events.json zip containing Sysmon events shipped via winlogbeat 8.14). Reconstruct what he was doing and recover the flag (format CODEBY{...}).

Challenge

The single artifact is events.json — 68,428 Sysmon events from host w-tst-w-vdi01 in corporate domain test.lab (DCs s-tst-w-dc01/02), user mikkel, all dated 2025-04-01. Each line is a winlogbeat JSON document; the Sysmon event_data fields live under _source.winlog.event_data, NOT at the top level — a common parsing pitfall with winlogbeat exports. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Recon / Artifacts

Event ID distribution:

EIDTypeCount
7ImageLoad63,459
13RegistryEvent1,805
1ProcessCreate1,280
22DNSQuery850
11FileCreate700
5,15,3,2,12,8misc...

Parse the events correctly (data is nested under winlog.event_data):

python
#!/usr/bin/env python3
import json
from collections import Counter

eids = Counter()
procs, dns, files = [], [], []
with open("events.json", encoding="utf-8") as f:
    for line in f:
        line = line.strip()
        if not line:
            continue
        e = json.loads(line)
        src = e.get("_source", {})
        ed  = src.get("winlog", {}).get("event_data", {})
        eid = src.get("winlog", {}).get("event_id")
        eids[eid] += 1
        if eid == 1 and "CommandLine" in ed:
            procs.append(ed["CommandLine"])
        elif eid == 22 and "QueryName" in ed:
            dns.append(ed["QueryName"])
        elif eid == 11 and "TargetFilename" in ed:
            files.append(ed["TargetFilename"])
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

print(eids.most_common())
for c in procs: print("CMD:", c)
for q in sorted(set(dns)): print("DNS:", q)
for t in files: print("FILE:", t)

Reconstructing the developer's behavior

The ProcessCreate command lines, DNS queries and FileCreate paths paint a clear picture of a developer goofing off and then exfiltrating data:

  • Slacking off / gaming: installed and played Tanki Online, Point Blank, osu!; browsed VK, YouTube, 2048, Tetris, Warface, vkplay. The DNS list is full of Russian ad/tracking domains.
  • Data exfiltration: he ran 7-Zip to archive his Chrome profile C:\Users\mikkel\AppData\Local\Google\Chrome\User Data\Default into chrome-profile.7z and everythingisconnected.7z with password -p85VhKyPUKFMhkx, then pushed chrome-profile.7z to the GitHub repos mikkel-shadow/chrome-backup and mikkel-shadow/my-files.
  • Careless: he even Googled the 7z password 85VhKyPUKFMhkx — that search is visible in his Chrome History. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Recover the Chrome profile from the exfiltrated GitHub repo, or read the History SQLite DB directly:

bash
# recover the exfiltrated profile from the dev's own GitHub leak
curl -sL https://github.com/mikkel-shadow/my-files/raw/main/chrome-profile.7z -o chrome-profile.7z
7z x -p85VhKyPUKFMhkx chrome-profile.7z

# Chrome browsing + download history
sqlite3 Default/History "SELECT url FROM urls ORDER BY last_visit_time DESC;"
sqlite3 Default/History "SELECT target_path, tab_url FROM downloads;"

The History urls and downloads tables show he was playing osu! and downloaded custom beatmaps (.osz). ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The decoy (beatmap 2346081)

The osu! account that CREATED the downloaded beatmaps is AnataWaBakada (user id 11449644). The name is Japanese あなたはバカだ = "you are a fool" — a troll hint aimed squarely at anyone who chases the obvious.

The most prominent download is beatmapset 2346081 "Michael - I'm in control". Its osu CDN download filename (recoverable from the Zone.Identifier / download URL in the Sysmon events) is:

2346081 hackerlab.pro - CODEBY{try_it_ok}.osz

CODEBY{try_it_ok} looks like a flag, but it is a DECOY ("try it, ok?"). Its 257 hit-objects (circle vs slider per beat, uniform 600 ms spacing) are a deliberate rabbit hole. We exhausted every reasonable encoding and proved it decodes to nothing: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

  • Morse on/off keying at all thresholds
  • literal slider=dash / circle=dot
  • raw 5/6/7/8-bit ASCII over the object stream
  • A1Z26 on run-lengths
  • Manchester decoding
  • 16x16 bitmap render of the object grid
  • variable-length codes (Fibonacci, Elias)
  • 13-segments-per-character grouping

All produced garbage. The beatmap is purely a trap.

The pivot (creator's second beatmap 2348305)

The hint "everything is connected" (the second exfil archive was literally named everythingisconnected.7z) means: stop fixating on the front-door beatmap and look at the OTHER artifacts connected to it — specifically, the other beatmaps by the SAME creator. Enumerate the creator's maps via an osu! mirror API: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

bash
curl -s "https://catboy.best/api/v2/search?q=AnataWaBakada"
# -> returns TWO sets by AnataWaBakada:
#    2346081  "Michael - I'm in control"   (the decoy)
#    2348305  "The Best - Sun"             (downloaded by the dev at 17:55)

The Chrome downloads table confirms the developer downloaded both sets. The second one, 2348305 "The Best - Sun", holds the real flag. Download and unzip it from a mirror:

bash
curl -sL "https://catboy.best/d/2348305" -o sun.osz
unzip -l sun.osz

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The audio file inside is literally named with the flag, and the .osu [General] section's AudioFilename: field points to it:

CODEBY{REDACTED}.mp3
ini
[General]
AudioFilename: CODEBY{REDACTED}.mp3

REDACTED is leetspeak for "see you next time my dear".

Lessons learned

  • Front-door fixation kills time. The prominent CODEBY{try_it_ok} (from beatmap 2346081's filename and its Zone.Identifier in the events) is a decoy. Three specialist passes proved its 257 hit-objects encode nothing. When a candidate flag resists every reasonable decode, treat it as a trap and pivot.
  • Enumerate the creator, not just the artifact. The real flag came from listing the OTHER beatmaps created by the same osu! user (AnataWaBakada) and inspecting the .osz contents — the flag was the audio filename / .osu AudioFilename field.
  • Read the semantic clues. AnataWaBakada = "you are a fool" (mocking decoy chasers); the archive name everythingisconnected.7z = look at the connected / second artifact.
  • Parse winlogbeat correctly. Sysmon event_data is nested under _source.winlog.event_data; reading the top level yields nothing. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍