academy.security.krd

← Blue Team Operations

Finding the one session that matters in a week of noise

20 min

Searching logs for something suspicious does not work, and it is worth understanding why before you spend a year doing it.

You cannot search for what you have not thought of. A query is a guess about what the attacker did, and the good ones are the guesses you would not have made. So the productive technique is almost the opposite of searching: instead of asking what is bad, ask what is rare, and then ask why.

Count, then read the bottom

Frequency analysis is the whole method, and it is embarrassingly simple. Take a field. Count how often each value appears. Read the bottom of the list.

backup.internal.example1,204repo.internal.example842metrics.internal.example611smtp.internal.example288ntp.internal.example168api.partner.example94hx9q2-cdn.example2connections this weekboth at 02:14
One application server's outbound connections over a week. Six destinations it always talks to, and one it reached twice. Nothing here is flagged and nothing is known-bad — the rare one is at the bottom because the list is sorted by how often, not by how suspicious.

Nearly every host in your estate talks to the same handful of destinations. The one workstation that resolved a domain nobody else has ever asked for is at the bottom of that count, and it took one command to find. The same trick works on user agents, on parent-child process pairs, on which accounts logged into which machines, on JA3 hashes, on outbound ports. Sort ascending. Read the tail.

What that is, on a terminal

Nothing above needs a product. The entire technique is four commands in a pipe, and the last one is the one that matters: sort -n puts the rare values at the top of what you read.

$ awk '{print $3}' conns.log | sort | uniq -c | sort -n
      2 hx9q2-cdn.example
     94 api.partner.example
    168 ntp.internal.example
    288 smtp.internal.example
    611 metrics.internal.example
    842 repo.internal.example
   1204 backup.internal.example

Note what you did not have to know. Not what the attacker's tooling is called, not which domains are malicious, not what the current campaign looks like. You asked one question — how often? — and the answer sorted itself.

Try it

Below is a morning of proxy traffic from a small office. Count by destination and read the bottom of the list. Then count by workstation, and notice that it tells you nothing: most people visit most things, so that field is not where the rarity lives.

44 lines of proxy traffic. Switch the field to destination, and read the bottom.

03:41:09 ws-019  q4t8v-push.example
09:01:59 ws-012  docs.corp.example
09:08:49 ws-011  auth.corp.example
09:17:00 ws-040  cdn.assets.example
09:21:50 ws-023  docs.corp.example
09:26:01 ws-007  cdn.assets.example
09:37:27 ws-031  auth.corp.example
09:55:25 ws-007  print.corp.example
10:46:28 ws-023  docs.corp.example
10:58:36 ws-040  docs.corp.example
11:12:11 ws-011  docs.corp.example
11:20:36 ws-028  auth.corp.example
11:32:20 ws-004  docs.corp.example
11:35:09 ws-019  time.pool.example
11:46:15 ws-012  auth.corp.example
11:54:54 ws-031  cdn.assets.example
12:06:46 ws-023  cdn.assets.example
12:12:50 ws-019  time.pool.example
12:19:24 ws-019  cdn.assets.example
12:39:45 ws-011  time.pool.example
12:49:19 ws-040  print.corp.example
13:17:48 ws-004  docs.corp.example
13:22:06 ws-004  docs.corp.example
13:28:36 ws-023  docs.corp.example
13:30:44 ws-023  docs.corp.example
13:33:41 ws-012  cdn.assets.example
13:37:58 ws-007  auth.corp.example
13:49:48 ws-011  docs.corp.example
13:55:09 ws-012  cdn.assets.example
14:05:51 ws-023  time.pool.example
14:33:07 ws-019  auth.corp.example
14:50:24 ws-028  time.pool.example
15:15:49 ws-011  auth.corp.example
15:16:24 ws-031  auth.corp.example
15:16:31 ws-004  docs.corp.example
15:18:19 ws-023  auth.corp.example
15:25:14 ws-023  docs.corp.example
15:37:12 ws-019  print.corp.example
15:48:26 ws-023  print.corp.example
16:01:40 ws-012  auth.corp.example
16:17:45 ws-012  time.pool.example
16:21:20 ws-012  cdn.assets.example
16:23:37 ws-031  docs.corp.example
16:43:55 ws-023  auth.corp.example
16:57:36 ws-012  cdn.assets.example

Two more techniques

The second technique is stacking two fields that are normally independent. Account and workstation, for example. Most people log into one or two machines. An account that appears on eleven, over a weekend, is not doing anything a filename-based rule would catch, and it is the clearest signature of credential reuse there is.

Third: baseline against time rather than against a threshold. "More than fifty failed logins" is a number someone guessed. "Ten times this account's own weekly average" adapts to a service account that legitimately fails often and to a human who never does.

What goes wrong

Two practical warnings, both learned the hard way.

Absence is evidence. A host that logged steadily for months and went quiet on Tuesday is telling you something, and no search for bad things will surface it — you have to be looking for the gap. Alert on silence from sources that should be talking.

And write down what you ruled out. An investigation that ends "nothing found" is nearly worthless to the next person, who will repeat every query you already ran. An investigation that ends "checked A, B and C, here is why each was normal, did not have data for D" is a real handover, and D is where the next person starts.

Adapted from: Written for this course · CC BY-SA 4.0

Check yourself

2

Sign in to have your answers marked and your progress saved.

1

Why is frequency analysis more productive than searching for suspicious things?

2

A host that logged steadily for months went silent on Tuesday. Why does no search for 'bad things' find this?