← Back to Writeups
HTBMediumForensics

Не пойман — не медоед

D3v0o0Nu119/10/20265 min read
#forensics#htb#medium#log_anomaly_analysis#base64_command_decoding#timezone_correlation#file_magic_validation#password_recovery

Не пойман — не медоед

Platform: Avitoctf | Category: Forensics | Type: Challenge | Difficulty: Medium | OS: NA | Author: D3v0o0Nu11 | Date: 2026-07-22 | Status: Solved Techniques: log_anomaly_analysis, base64_command_decoding, timezone_correlation, file_magic_validation, password_recovery

Summary

Task: An Apache access log records a noisy intrusion and the theft of a corporate accounting export. Solution: Isolate Base64 webshell commands, correlate UTC timestamps with an exfiltration index, verify ZIP magic, and extract the SQL file.

Recon

Port scan

bash
nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
PortServiceVersionNotes
<PORT><SVC><VER><notes>

Enumeration highlights

  • Event: avitoctf | ID: 20260722_avitoctf_ne_poyman_ne_medoyed
  • Tags: webshell, data_exfiltration, powershell, encrypted_zip, apache_access_log
  • Indicators: only 22 requests contain query strings, four successful cmd requests share a unique legacy MSIE user-agent, exfiltration index timestamps differ from HTTP Last-Modified by three hours, a misleading extension contains ZIP magic
  • Source: 20260722_avitoctf_ne_poyman_ne_medoyed.md

Foothold

Vulnerability / Misconfiguration

  1. log_anomaly_analysis
  2. base64_command_decoding
  3. timezone_correlation
  4. file_magic_validation
  5. password_recovery
bash
<command>

Exploitation

  • See original writeup content for detailed exploitation.

Privilege Escalation

Enumeration

bash
sudo -l
find / -perm -4000 2>/dev/null
getcap -r / 2>/dev/null
cat /etc/crontab
ps aux

Exploitation

  1. N/A for challenge-type writeup; see exploitation above.
  2. Flag obtained via challenge solve.
bash
<command>

Flags

FlagLocationValue
flagREDACTED

Key Takeaways / Lessons

  • log_anomaly_analysis
  • base64_command_decoding
  • timezone_correlation
  • file_magic_validation
  • password_recovery
  • Tags: webshell, data_exfiltration, powershell, encrypted_zip, apache_access_log

Original Writeup

<details><summary>Click to expand original content</summary>

Description

At dawn the hive server's bee-accounting database disappeared. Honey badgers were blamed, but were asleep. The med-team preserved access.log. Analyze ordinary traffic, reconstruct the real intruder's actions, recover the stolen database, and identify the secret in corporate accounting.

The supplied Apache access log contains ordinary browsing, monitoring, and scanner noise. The objective is to reconstruct the real compromise, recover the exfiltrated accounting data, and locate its secret.

Analysis

Finding the anomalous requests

The log has SHA-256 fb09545f74edb3605aed3854f5cc1104911b7b14b4f18bf4d0e4479850ae3af0. All 56,873 lines parse as Apache Combined Log Format records, and their timestamps are UTC.

Instead of following the numerous scanner-like paths, I grouped requests by method, status, path, source, user-agent, and query key. Only 22 requests had query strings. Four stood out:

Log lineSourcePathStatus
26016185.193.88.77/aspnet_client/system_web/healthcheck.aspx?cmd=...200
26118185.193.88.77/aspnet_client/system_web/healthcheck.aspx?cmd=...200
26262185.193.88.77/aspnet_client/system_web/healthcheck.aspx?cmd=...200
26313185.193.88.77/aspnet_client/system_web/healthcheck.aspx?cmd=...200

These were also the only four requests using the legacy user-agent Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0). Their successful responses and Base64-looking cmd values made them much stronger evidence than the bulk scanning traffic.

The following script reproduces the parsing and command extraction:

python
#!/usr/bin/env python3
import base64
import collections
import re
from pathlib import Path
from urllib.parse import parse_qs, urlsplit

log_path = Path("honeyleak_access.log")
pattern = re.compile(
    r'^(\S+) \S+ \S+ \[([^]]+)] "(\S+) (.*?) (HTTP/[^\"]+)" '
    r'(\d{3}) (\S+) "([^\"]*)" "([^\"]*)"$'
)

rows = []
for line_no, line in enumerate(log_path.read_text(encoding="ascii").splitlines(), 1):
    match = pattern.match(line)
    if not match:
        raise ValueError(f"Malformed line {line_no}")
    ip, timestamp, method, target, protocol, status, size, referer, agent = match.groups()
    url = urlsplit(target)
    rows.append((line_no, ip, timestamp, method, url, int(status), agent))

print("records:", len(rows))
print("query requests:", sum(bool(row[4].query) for row in rows))
print("query keys:", collections.Counter(
    key for row in rows for key in parse_qs(row[4].query)
))

for line_no, ip, timestamp, method, url, status, agent in rows:
    params = parse_qs(url.query)
    if url.path.endswith("/healthcheck.aspx") and "cmd" in params:
        command = base64.b64decode(params["cmd"][0]).decode()
        print(line_no, timestamp, ip, status, agent)
        print(command)

Reconstructing the attack

Decoded in chronological order, the four commands did the following:

  1. Ran whoami, hostname, and an IPv4 address check.
  2. Used 7z.exe to create a password-protected ZIP archive in C:\Windows\Temp. The source was C:\inetpub\wwwroot\App_Data\corp_finance_2026_07_03.sql, and the command exposed the password S7m!vQ2@rK9Lp4X_2026.
  3. Uploaded the timestamped archive with curl.exe -F to http://178.154.230.44/upload.php.
  4. Requested the exfiltration host's index and searched it for blob_.

This proves command execution through a Base64-command webshell. It also disproves SQL injection and the hypothesis that the database itself was split across query parameters.

Solution

Correlating the uploaded object

The upload occurred at approximately 18:42 UTC. The authorized exfiltration index held more than 1,340 decoy objects, so choosing a file by extension or a visually similar time was unreliable.

The important discrepancy was timezone presentation: index timestamps were UTC+3, whereas the access log was UTC. HTTP Last-Modified headers remained GMT. For example, a tempting object displayed at 18:42 had Last-Modified: 15:42 GMT and contained random bytes. Therefore, the 18:42 UTC upload had to appear near 21:42 in the index.

That correction identified blob_3po654ppbr.log. Its .log extension was intentionally misleading. Before downloading the 12 MB object, I checked only its first 16 bytes:

bash
curl --range 0-15 --output prefix.bin http://178.154.230.44/blob_3po654ppbr.log
xxd prefix.bin

The response began with PK 03 04, the local-file-header signature of a ZIP archive. This cheap magic check rejected decoys without trusting filenames.

Extracting the accounting export

After the magic check, I downloaded and verified the complete object:

bash
curl --output blob_3po654ppbr.log http://178.154.230.44/blob_3po654ppbr.log
shasum -a 256 blob_3po654ppbr.log
7z x -p'S7m!vQ2@rK9Lp4X_2026' -orecovered blob_3po654ppbr.log
shasum -a 256 recovered/corp_finance_2026_07_03.sql recovered/encrypted_database.dat

The archive hash was 1fa6077f2976b0398b0bae70ee89e06fba5748a5f2c87735bcb65b16759fd070. Extraction produced:

  • corp_finance_2026_07_03.sql — SHA-256 7e6ec7d07ffe976889aecfa8dff4d286a4b7fbde65ed5ba20509af10379f6175
  • encrypted_database.dat — SHA-256 de4c8b0ec8c601743fa53b34549e16acab2439fdc7c36aba6c50fd9df2122408

Searching the SQL export was sufficient:

bash
rg -n "secrets|incident_flag" recovered/corp_finance_2026_07_03.sql

Line 19 inserted the incident_flag value into the secrets table. The second encrypted file did not need to be decrypted because the required value was already present in the recovered export.

Pitfalls

  • SQL injection tooling in the background traffic was noise; the successful path was a command webshell.
  • The query parameters held commands, not chunks of database content.
  • Guessed organizer mirror names returned 404 and did not reproduce the actual randomized upload name.
  • Selecting the displayed 18:42 entry without correcting UTC to UTC+3 selected random data.
  • A nearby .tmp entry completed at 21:49 was also a decoy; both timestamp correlation and ZIP magic were required.
</details>

signed by XESXOR