I Went Back to KC7 — This Time With a Purpose
Before I became a SOC analyst, I had come across KC7 and played a few games on it. KC7 is a free platform where you investigate simulated…

I Went Back to KC7 — This Time With a Purpose
Before I became a SOC analyst, I had come across KC7 and played a few games on it. KC7 is a free platform where you investigate simulated cyberattacks by querying logs. At the time I was just clicking through it with no real sense of why. Now I am about four months into my role, actively trying to build real foundations in this field, and going back to KC7 made a lot more sense. Reading logs, knowing where to look and what to look for, that is core to SOC work. So this is part of the process.
The Query Language: KQL
KC7 uses KQL (Kusto Query Language) to search through log data. When I came back to it, my brain immediately started comparing it to SQL, which I already have some experience with. That comparison made it a lot less intimidating, so I want to share it here.
The Structure Is Familiar, But Rearranged
In SQL, a basic query looks like this:
SELECT * FROM Employees WHERE department = 'IT';
You start with what you want, then where to get it from, then the conditions.
In KQL, the same logic looks like this:
Employees
| where department == "IT"
The table name comes first, on its own line. Your conditions follow on the next lines, each starting with a pipe |. Start with the thing you are looking at, then filter it down.
One small thing that caught me: no semicolon at the end. In SQL you end with ; out of habit. KQL does not use it.
Wildcards Work Here Too
Just like in SQL where you use % with LIKE to search broadly, KQL supports wildcards. When you are not sure of the exact value you are looking for, you can search loosely. This comes up a lot when you are looking for patterns rather than exact matches.
Some Operators Worth Knowing
take - Get a Feel for the Data
When you open a table and want to understand what you are working with, take pulls a random sample of rows.
Employees
| take 10
Ten random rows from the Employees table. Useful before you start filtering, just to get oriented.
where with datetime - Searching by Time
A lot of investigation work comes down to: what happened, and when? For a specific time range:
SecurityEvents
| where timestamp between (datetime("2026-05-10T00:00:00") .. datetime("2026-05-11T00:00:00"))
That double dot .. means between these two points.
Variables — Carrying Information Between Tables
This clicked for me because of my programming background. In most languages, a variable is a container: you store something in it and call it later. KQL has the same concept using let.
let suspiciousUsers =
SecurityEvents
| where EventID == 4625
| summarize FailedLogins = count() by AccountName
| where FailedLogins > 10
| project AccountName;
Employees
| where name in (suspiciousUsers)
suspiciousUsers holds a list of account names pulled from one table, and then I use it to cross-reference another. Real investigations rarely live in one place, so being able to carry information between tables is something you will use a lot.
I have only played a few games so far. KQL is not second nature yet, but having SQL knowledge as a reference point made it far easier to get started than I expected. The games also push you to read logs with a question in mind rather than just skimming through them.
If you want to try it: kc7cyber.com
메타데이터
- post_id
- f4384ebebc2d
- slug
- i-went-back-to-kc7-this-time-with-a-purpose-f4384ebebc2d
- url
- https://medium.com/@wildthoughtz/i-went-back-to-kc7-this-time-with-a-purpose-f4384ebebc2d
- canonical_url
- https://medium.com/@wildthoughtz/i-went-back-to-kc7-this-time-with-a-purpose-f4384ebebc2d
- author_url
- https://medium.com/@wildthoughtz
- status
- ok
- fetched_at
- 2026-06-11 21:11:36