Bruteforce

Scenario

Can you analyze logs from an attempted RDP brute-force attack?

A system administrator identified a high volume of Audit Failure events in Windows Security logs. The goal is to validate attack scale, identify the targeted account, extract source infrastructure indicators, and summarize attacker behavior.

Investigation

Step 1: Convert CSV evidence to JSON for structured parsing

import pandas as pd

df = pd.read_csv("BTLO_Bruteforce_Challenge.csv")
df.to_json("challenge.json", orient="records", indent=4)

Purpose: prepare evidence for deterministic field extraction.
Logic: jq works reliably on JSON; converting once avoids repeated manual parsing.
What this proves: source dataset is now queryable for repeatable forensic pivots.
Next: profile event IDs.

Step 2: Count event IDs in the dataset

jq -r '.[] | .Source' challenge.json | sort -n | uniq -c
      4 4624
   3103 4625
      4 4672
     18 5379

Purpose: identify dominant authentication outcome in logs.
Logic: Event ID distribution shows where attacker activity is concentrated.
What this proves: 4625 (failed logon) dominates with 3103 events.
Next: extract which account is being targeted.

Step 3: Identify targeted local account

jq -r '.[]
  | select(.Source==4625)
  | ."Task Category"
  | capture("Account For Which Logon Failed:\\r\\n\\tSecurity ID:\\t\\tNULL SID\\r\\n\\tAccount Name:\\t\\t(?<u>[^\\r\\n]+)")
  | .u' challenge.json | sort | uniq -c | sort -nr | head -1
   3103 administrator

Purpose: determine which account is under brute-force pressure.
Logic: parse 4625 message body and count failed-account occurrences.
What this proves: the targeted local username is administrator.
Next: confirm the failure reason text.

Step 4: Extract failure reason

jq -r '.[] | select(.Source==4625) | ."Task Category"
  | capture("Failure Reason:\\t\\t(?<r>[^\\r\\n]+)") | .r' challenge.json \
| sort | uniq -c | sort -nr | head -1
   3103 Unknown user name or bad password.

Purpose: capture authentication failure semantics from event body.
Logic: exact reason text validates this is password/credential brute-force behavior.
What this proves: primary failure reason is Unknown user name or bad password.
Next: isolate source IP driving these failures.

Step 5: Identify attacker source IP

jq -r '.[] | select(.Source==4625) | ."Task Category"
  | capture("Source Network Address:\\t(?<ip>[0-9.]+)") | .ip' challenge.json \
| sort | uniq -c | sort -nr | head -1
   3103 113.161.192.227

Purpose: attribute brute-force activity to an originating host.
Logic: parse network address field from failed-logon records and rank by count.
What this proves: attack source IP is 113.161.192.227.
Next: enrich IP with geo attribution.

Step 6: Geo-attribute source IP

curl ipinfo.io/113.161.192.227
{
  "ip": "113.161.192.227",
  "hostname": "static.vnpt.vn",
  "city": "Phan Thiết",
  "region": "Lam Dong",
  "country": "VN",
  "loc": "10.9289,108.1021",
  "org": "AS45899 VNPT Corp"
}

Purpose: enrich network IOC for reporting context.
Logic: external enrichment maps IP to country and provider.
What this proves: source country is VN (Vietnam).
Next: determine attacker source-port behavior.

Step 7: Compute attacker source-port range

jq -r '.[]
  | select(.Source==4625)
  | ."Task Category"
  | capture("Source Port:\\t\\t(?<p>[0-9]+)")
  | .p' challenge.json \
| sort -n | awk 'NR==1{min=$1} {max=$1} END{print min "-" max}'
49162-65534

Purpose: characterize source-port spread for brute-force traffic profile.
Logic: minimum and maximum observed ports summarize attacker connection behavior.
What this proves: source port range is 49162-65534.

Timeline

Final Answers (for submission)

  1. 3103
  2. administrator
  3. Unknown user name or bad password.
  4. 4625
  5. 113.161.192.227
  6. Vietnam
  7. 49162-65534

Tool Significance