Post

Python for Cybersecurity - Evaluating Situations with Boolean Expressions

Python for Cybersecurity - Evaluating Situations with Boolean Expressions

As a SOC analyst, one of your primary responsibilities is to detect potential threats to your organization, typically by investigating alerts generated by a SIEM or any other security monitoring tool.

Determining whether an alert represents a genuine threat or a false positive requires careful investigation. This is why before making any move, you first evaluate the situation by analyzing the available evidence and asking yourself the right questions:

  • Has an account exceeded the allowed number of failed logon attempts?
  • Did those failed logon attempts come from an unknown IP address?
  • Is a suspicious process running from an unusual folder, like a temporary directory?
  • Is a process doing something weird, like spawning a CLI unexpectedly?

When it comes to automating these kinds of situations, things work pretty much the same. The difference now is that instead of you being the one asking these questions, it’s the security tool you bring to life that does the work for you, and the programming vocabulary it uses to do that is called Boolean expressions.

You see, a Boolean expression is simply a condition that any programming language evaluates and answers with either true or false. That’s it! Later on, your security tools can use those same answers to make further decisions and determine what’s going to happen next.

Alright, no more spoilers!

Up to this point you’ve learned how to store and represent security information in variables and you also learned how to display that information back to the user in a readable and digestible format. Now it’s time to take it one step further and give your security tools the brains 🧠 needed to evaluate that same information, make decisions on their own, and respond accordingly.

Ready to take your security tools 🤖 to the next level? Let’s get started!

Boolean Expressions

Boolean expressions are the most basic form of intelligence your security tools can have to evaluate a situation. With them, they’ll be able to look at information, question what they’re seeing, and determine if something is either true or false.

To better understand this, walk with me through the following scenario:

Imagine you’re working as a SOC analyst responsible for monitoring authentication activity across your organization’s Windows infrastructure. Your environment includes Windows servers and employee workstations that administrators and remote employees access through Remote Desktop Protocol (RDP).

Recently, your team has noticed an increase in failed remote logon attempts. While in some cases, these failures are caused by legitimate users entering incorrect credentials, in others, repeated attempts against the same account may indicate that an attacker is trying to guess a password or gain access using compromised credentials.

Your task is to write a Python detection rule that processes Windows Security Event logs to identify and flag any potentially suspicious login activity according to the following requirements:

  1. Detect potential brute-force attacks: If an account experiences five or more failed remote logon attempts from an unknown IP address, the activity should be flagged as a potential brute-force attack.
  2. Detect excessive failed remote logons from known IP addresses: If an account has five or more failed remote logon attempts from a known IP address, the activity must be flagged for investigation.
  3. Flag remote failed logons from unknown IP addresses: Any failed remote logon attempt originating from an unknown IP address must be flagged for review.

Here’s an example of the event data you’ll be working with:

1
2
3
4
5
6
7
8
9
10
Event ID                4625
Account Name            jsmith 
Logon Type              10 — RemoteInteractive
Failed Logons           7
IP                      198.51.100.23
Source Port             49832
Failure Reason          Unknown user name or bad password
Account Enabled         true
Source IP Known         false
Timestamp               2026-05-09T14:32:18Z

Alright, let’s get down to business!

The first step is to give Python 🐍 a way to understand the security event. You can do that by representing its information using variables, along the way, you also define a couple of constants to make your detection rule easier to read and maintain in the future:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# --- Detection constants ---
EVENT_ID_LOGON_SUCCESS = 4624
EVENT_ID_LOGON_FAILURE = 4625
LOGON_TYPE_REMOTE_INTERACTIVE= 10
FAILED_LOGON_THRESHOLD = 5

# --- Event data ---
event_id = 4625
account_name = "jsmith" 
logon_type = 10
failed_logons = 7
source_ip_address = "198.51.100.23"
source_port = 49832
failure_reason = "Unknown user name or bad password"
is_account_enabled = True
is_source_ip_known = False
timestamp = "2026-05-09T14:32:18Z"

There you go! Python 🐍 is now ready to answer all kinds of questions your detection rule might throw at it about this security event.

For example, it can ask: “Is this a failed logon event?”

1
2
3
4
# Is this a failed logon event? 
is_logon_failure = event_id == EVENT_ID_LOGON_FAILURE

print(is_failed_logon)

The result is:

1
True

Why?, well, because both event_id and EVENT_ID_LOGON_FAILURE contain the value 4625. Therefore, the statement is true.

Let’s now try a different question: “Is this a successful logon event?”

1
2
3
4
# Is this a successful logon event?
is_logon_success = event_id == EVENT_ID_LOGON_SUCCESS

print(is_logon_success)

Python answers:

1
False

This time the result is different because event_id and EVENT_ID_LOGON_SUCCESS contain different values, they don’t match!, therefore, the statement is false.

Notice two things happening here:

  • First, you’re using the == equal operator to compare two values. As the name suggests, you can use it to ask if two things are equal. If they are, the result is True, otherwise is False.
  • Second, you’re storing the result of each comparison in its own variable. When storing the result of a Boolean expression, choose variable names that make it clear what you’re evaluating. Prefixes such as is_, has_, can_, should_, contains_, allows_, etc., can help you communicate the meaning and intent.

And that’s the basic idea behind Boolean expressions: they allow your security tools to ask questions about the data they’re analyzing. Simple as that! 🫠

Comparison Operators

Of course, not all questions are built the same.

Depending on what your security tools need to find out about the information they’re analyzing, they’ll need different ways to ask different questions. Fortunately, Python 🐍 has you covered!

Let me introduce you to Python’s well-known comparison operators: ==, !=, >, <, >=, and <=. Don’t overthink them too much. Instead, picture them as different ways of questioning your data:

1
2
3
4
5
6
== Is it the same? 
!= Is it different? 
>  Is it greater? 
<  Is it smaller? 
>= Is it at least this much? 
<= Is it at most this much?

Each one of these little fellas will help you out compare two values and yield a Boolean result.

Let’s see them in action against the same security event:

OperatorMeaningExampleResult
==Equal toaccount_name == "jsmith"True
!=Not equal tosource_ip_address != "198.51.100.23"False
>Greater thanfailed_logons > 5True
<Less thanfailed_logongs < 5False
>=Greater than or equal tofailed_logons >= 4True
<=Less than or equal tofailed_logons <= 10True

As you can see, the same security information can be used to ask different questions. Python 🐍 will simply evaluate each and give you True or False for an answer.

Later on, your security tools can use those same answers to decide what they should do in different situations.

Logical Operators: and / or / not

Just like in a real investigation, a single question rarely tells you the whole story. Understanding the bigger picture requires asking multiple questions and connecting the dots between their answers.

This is where Python’s logical operators and, or, and not can come in handy.

You see, these operators will let you connect several simple questions together to create a more complex one, and the neat part is that Python’s syntax makes it look a lot like the way you would naturally express yourself in plain English.

So, let’s take a look into each logical operator and see how they work in practice.

The and Operator: When Both Questions Must Be True

So far, you already know how to detect a failed a logon event:

1
2
# Is this a failed logon event?
is_logon_failure = event_id == EVENT_ID_LOGON_FAILURE

But according to your organization’s security requirements, identifying a failed logon isn’t enough. You also need to determine whether an attempt involved a remote interactive logon.

That brings you to another simple question: “Is this a remote interactive logon?”. Such inquiry can be easily translated into Python code like this:

1
2
# Is this a remote interactive logon?
is_remote_interactive_logon = logon_type == LOGON_TYPE_REMOTE_INTERACTIVE

Great! These two questions are exactly what you need. However, on their own, each one only gives you a piece of the puzzle, neither tells you the whole story.

But, what if you could connect these two questions into a single expression? That way, Python could evaluate both conditions together and tell you whether the event actually represents a failed remote logon.

Well, that sounds like a job for Captain and logical operator! Let’s see it in action:

1
2
# Is this a failed remote logon?
is_failed_remote_logon = is_logon_failure and is_remote_interactive_logon

Much better! By combining the two Boolean expressions into one, you’re telling Python 🐍 to check if the current event is both a failed logon and a remote interactive logon. Both sides must be True for is_failed_remote_logon to evaluate True.

Here’s the drill: the and operator returns True only when both conditions are True. If either condition is False, the entire expression will be False.

Pretty straightforward, right? 🫠. So, let’s keep going!

As you know, a failed remote logon by itself may not be unusual. A user simply might have mistyped their password while trying to connect remotely.

But what if that failed attempt came from an IP address your organization simply doesn’t recognize? According to your organization’s security requirements, that event must be flagged for review.

You already have a Boolean variable called is_source_ip_known that tells you if a source IP address is known to your organization. You can combine this information with your previous condition to pinpoint failed remote logons coming from unknown sources.

This is what I mean:

1
2
3
4
5
# Is this a failed remote logon coming from an unknown source IP address?
is_logon_failure_from_unknown_source = (
  is_failed_remote_logon and
  is_source_ip_known == False
)

Sweet! Notice how you’re reusing the Boolean variable is_failed_remote_logon instead of repeating the original comparisons. This makes your code easier to read and helps you build more complex detection rules out of smaller, meaningful conditions.

Alright, see what you got here? You’ve built a detection rule that “identifies remote failed logons coming from unknown IP addresses”. You already satisfied security requirement number three!, so you can cross it off your list.

You’re 1/3 of the way to the finish line. Great start! 😎

Now, bear with me and let’s look at the other side of the scenario.

Your organization surely maintains a list of known IP addresses associated with employee offices, VPN gateways, or other recognized, trusted network locations. However, a known IP address doesn’t automatically mean that the activity coming from it is 100% safe. A compromised account or device can still generate suspicious login activity.

Remember security requirement number two? “If an account experiences five or more failed remote logon attempts from a known IP address, the activity must be flagged for investigation”.

To build this detection rule, you are going break its requirements into two smaller questions (just like you did at the start of this section). Then, you’ll use the and operator to join them back together into a single expression. Let’s see how to do this!

First, you need to identify any failed remote logon coming from a known source IP address. You can do this by simply asking the following: “Is this a failed remote logon coming from a known source IP address?”.

To get Python 🐍 to answer this question, just reuse the is_failed_remote_logon variable you defined in the previous section, this way, you don’t have to repeat the same conditions. Next, use the and operator to join it with the is_source_ip_known variable as shown:

1
2
3
4
5
# Is this a failed remote logon coming from a known source IP address?
is_logon_failure_from_known_source = (
  is_failed_remote_logon and
  is_source_ip_known
)

Awesome! this detection rule can now recognize failed remote logons coming from known sources.

But you’re not done yet!

You now need a way to figure out whether the number of failed logon attempts has reached the predefined threshold established by your organization, which is five or more. To do this, you can simply ask: “Have the number of failed logons reached the predefined threshold?”, then translate such security requirement into code like this:

1
2
# Have failed logon attempts reached the predefined threshold?
has_reached_failed_logon_threshold = failed_logons >= FAILED_LOGON_THRESHOLD

Easy peasy!, right?

Now comes the interesting part! You already have two conditions that answer different questions:

  1. is_logon_failure_from_known_source tells you whether the failed remote logon came from a known IP address.
  2. has_reached_failed_logon_threshold tells you whether the number of failed attempts has reached the required threshold.

So, how can you join these two conditions together to satisfy security requirement number two?

You guessed it! Time to call on the and operator once again🫡:

1
2
3
4
5
# Are there too many failed remote logons coming from a known IP address?
has_too_many_known_ip_logon_failures = (
  is_logon_failure_from_known_source and
  has_reached_failed_logon_threshold
)

The result is a detection rule that “identifies failed remote logons coming from known IP addresses that have reached the predefined threshold”.

That’s security requirement number two checked off! Two down, one to go. You’re getting closer to the finish line! 😎

Finally, let’s tackle the most critical requirement: detecting a potential brute-force attack.

So, your organization’s security requirement number one states that “if an account experiences five or more failed remote logon attempts from an unknown IP address, the activity must be flagged as a potential brute-force attack”.

Sounds like a lot of checks to do, right? Well, here’s the good news: you already have all the pieces you need! 🤯

To build this detection rule you can just reuse the Boolean variables you’ve been defining in the previous sections and join them together using the and operator, like so:

1
2
3
4
5
6
# Is this a potential brute-force attack?
is_brute_force_attack = (
  is_failed_remote_logon and
  has_reached_failed_logon_threshold and
  is_source_ip_known == False
)

Holy moly, that was fast⚡, you solved it in no time! Props to you! 👊

Needless to say, you code speaks for itself: any failed remote logon from an unknown source that reaches the maximum failure threshold will now be flagged as a potential brute-force attack.

Great work! 👏 You’ve successfully cleared all three security requirements set by your organization’s security team.

Alright, let’s take a step back and get a 10,000-foot overview of the detection rules you’ve built so far. Here’s how they look when you put all together:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# --- Detection constants ---
...

# --- Event data ---
...

# --- Detection Rules ---

# Is this a failed logon event?
is_logon_failure = event_id == EVENT_ID_LOGON_FAILURE

# Is this a remote interactive logon?
is_remote_interactive_logon = logon_type == LOGON_TYPE_REMOTE_INTERACTIVE

# Is this a failed remote logon?
is_failed_remote_logon = is_logon_failure and is_remote_interactive_logon

# Have failed logon attempts reached the predefined threshold?
has_reached_failed_logon_threshold = failed_logons >= FAILED_LOGON_THRESHOLD

# Is this a failed remote logon coming from a known source IP address?
is_logon_failure_from_known_source = (
  is_failed_remote_logon and
  is_source_ip_known
)

# Is this a potential brute-force attack?
is_brute_force_attack = (
  is_failed_remote_logon and
  has_reached_failed_logon_threshold and
  is_source_ip_known == False
)

# Are there too many failed remote logons coming from a known IP address?
has_too_many_known_ip_logon_failures = (
  is_logon_failure_from_known_source and
  has_reached_failed_logon_threshold
)

# Is this a failed remote logon coming from an unknown source IP address?
is_logon_failure_from_unknown_source = (
  is_failed_remote_logon and
  is_source_ip_known == False
)

Notice how instead of writing one long, complicated Boolean expression, you’ve created smaller ones that you can reuse to build more specific rules. This is a useful approach because it makes your detection logic easier to read, understand, test, and maintain.

The and logical operator is really straightforward: it returns True only when both conditions are True. If either condition is False, the entire expression evaluates to False. That simple!

The following table shows you all the possible combinations when using the and logical operator with two Boolean conditions:

First conditionSecond conditionResult
TrueTrueTrue
TrueFalseFalse
FalseTrueFalse
FalseFalseFalse

The or Operator: When Either Question Can Be True

Sometimes, you don’t need every question you ask to be True. Sometimes, all you need is for at least one of them to be True.

This is what the or logical operator is all about! It lets you connect several Boolean expressions together and returns True if at least one of them evaluates to True. If all conditions evaluate to False, the entire expression will be False.

Let me show you this with an example.

Throughout your investigation, you’ve built several detection rules to identify different types of suspicious login activity based on your organization’s security requirements. Here’s a quick reminder of what each rule currently does:

  • is_brute_force_attack identifies a potential brute-force attack when a remote logon has failed repeatedly and the source IP address is unknown.
  • has_too_many_known_ip_logon_failures flags failed remote logons from known IP addresses that have reached the predefined threshold.
  • is_logon_failure_from_unknown_source spots remote logons coming from unknown source IP addresses.

Now, what if you could take all those three detection rules and combine them into a single rule to check whether any of them has identified any suspicious login activity in the event?

Well, you can actually do that using the or logical operator. Let’s see:

1
2
3
4
5
6
# Is this suspicious login activity?
is_suspicious_login_activity = (
  is_brute_force_attack or
  has_too_many_known_ip_logon_failures or
  is_logon_failure_from_unknown_source
)

You have now built a broader detection rule that identifies a login event as suspicious if it meets any of the criteria within the is_suspicious_login_activity variable. If even one of those rules evaluates to True, that’d be enough to flag the event for further investigation. If they all evaluate to False, well, looks like we’d be safe for now! 🚦

Dead simple, right? 🫠

Alright, I hope this example has helped you understand how the or logical operator can be used to evaluate different situations. To reinforce this idea, here’s a table that shows you all the possible combinations when using the or logical operator with two Boolean conditions:

First conditionSecond conditionResult
TrueTrueTrue
TrueFalseTrue
FalseTrueTrue
FalseFalseFalse

As you can see, unlike the and logical operator, which returns True only when both conditions are True, the or logical operator returns True if at least one condition is True.

The not Operator: When You Want the Opposite Answer

Finding a needle in a haystack doesn’t start by looking for the needle, it starts by getting rid of the hay.

The same idea applies to Cybersecurity. When analyzing thousands of lines of system logs, you don’t always look for malicious activity directly, instead, you look for everything that is not normal: untrusted IP addresses, unapproved applications, unauthorized users, invalid digital signatures, etc. In situations like these, being able to express the opposite of a condition is essential.

This is where Python’s not logical operator fits like a glove.

You see, unlike and and or, which require two operands to work, the not logical operator only needs one. Its purpose isn’t to connect two things, but simply to reverse a truth value, that is, True becomes False, and False becomes True. That simple!

Let me show you what I mean using our ongoing security investigation.

Remember the Boolean variable is_source_ip_known? You created it to keep track of whether a source IP address is known to your organization. You then used it to identify failed remote logons coming from unknown source IP addresses:

1
2
3
4
5
# Is this a failed remote logon coming from an unknown source IP address?
is_logon_failure_from_unknown_source = (
  is_failed_remote_logon and
  is_source_ip_known == False
)

Take a closer look at is_source_ip_known == False. This comparison check absolutely works, but there’s a simpler way to express the same idea: the not operator.

Here’s how you can use it:

1
2
3
4
5
# Is this a failed remote logon coming from an unknown source IP address?
is_logon_failure_from_unknown_source = (
  is_failed_remote_logon and
  not is_source_ip_known
)

See the difference?

Instead of checking whether is_source_ip_known is equal to False, you can simply write not is_source_ip_known. The not operator will flip the Boolean value, so if is_source_ip_known is False, not is_source_ip_known will evaluate to True, and vice versa.

The result is the same, but the code reads more naturally.

You can apply the same idea to your brute-force attack detection rule. So instead of having this:

1
2
3
4
5
# Is this a potential brute-force attack?
is_brute_force_attack = (
  ...
  is_source_ip_known == False
)

You can use the not logical operator to express the same condition more cleanly:

1
2
3
4
5
# Is this a potential brute-force attack?
is_brute_force_attack = (
  ...
  not is_source_ip_known
)

Pretty neat, right? 😎

Alright, to reinforce what you’ve learned so far, here’s a quick overview of how the not logical operator works:

ConditionResult of not
TrueFalse
FalseTrue

Remember, this operator is your best ally in situations where you need to handle exclusions or filter out behavior that simply don’t match your expectations.

And that’s it! You’ve got everything you need on these three logical operators:

  1. and requires all conditions to be True.
  2. or requires at least one condition to be True.
  3. not reverses the truth value of a condition.

With this powerful trio in your coding arsenal, you’ll be able to build security tools that recognize different situations and respond accordingly.

Logical Operator Precedence

If you’ve ever solved a mathematical expression like 2 + 3 * 4, you likely remember PEMDAS/BODMAS and know that you must multiply before adding, otherwise, you’d end up with the wrong answer.

Well, Python 🐍 follows a similar idea when it comes to evaluating logical expressions.

You see, when you combine multiple logical operators in a single expression, Python follows a specific order to determine which operator must evaluate first.

Let’s see this with an example. What do you think the value of is_suspicious_activity will be here?

1
2
3
4
is_logon_failure = True
is_source_ip_known = False

is_suspicious_activity = is_logon_failure or is_source_ip_known and False

Not so obvious, eh? 🤔

Well, the answer is True. But let’s break it down piece by piece to see why.

In Python, the and operator takes precedence over or, meaning this part of the code gets evaluated first:

1
... is_source_ip_known and False

Since is_source_ip_known is False, what’s being evaluated here is actually this:

1
... False and False

Which results in False.

With the and expression already resolved, Python moves on to the or operator, plugging the previous result back into the original logical expression:

1
... is_logon_failure or False

Because is_logon_failure is True, the final evaluation becomes:

1
is_suspicious_activity = True or False

Giving is_suspicious_activity the value of True.

There you have it! No magic involved. It’s simply the way Python 🐍 evaluates logical operators.

Here’s a quick reference to help you remember their order of precedence:

PrecedenceOperatorEvaluation order
1notFirst
2andSecond
3orThird

In other words, Python evaluates not before and, and and before or. Easy as that!

Understanding logical operator precedence is important, especially when working with expressions that combine multiple operators. However, as your expressions grow in complexity, it becomes incredibly easy to misunderstand their true intent.

Fortunately, Python gives you a simple way to make your intentions crystal clear: parentheses ().

Parentheses allow you to override default precedence behavior and explicitly control the order in which your conditions are evaluated.

Let’s revisit our earlier example, but this time you’ll group the first two conditions using parentheses, like so:

1
2
3
4
is_logon_failure = True
is_source_ip_known = False

is_suspicious_activity = (is_logon_failure or is_source_ip_known) and False

This time the result is False. But let’s find out why.

The parentheses force Python to evaluate the or expression first:

1
... (is_logon_failure or is_source_ip_known)

Which becomes:

1
... (True or False)

Therefore, the result is True

Next, Python plugs that result back into the rest of the expression and evaluates it:

1
is_suspicious_activity = True and False

Resulting in is_suspicious_activity having a value of False

Notice how the parentheses changed the outcome, even though you used the same variables and logical operators. That’s why using parentheses is recommended whenever an expression starts becoming difficult to read at a glance.

Alright, let’s see if you’ve got all this clear. Take a look at the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# --- Detection constants ---
EVENT_ID_LOGON_FAILURE = 4625
LOGON_TYPE_REMOTE_INTERACTIVE = 10
FAILED_LOGON_THRESHOLD = 5

# --- Event data ---
event_id = 4625
logon_type = 10
failed_logons = 7
is_source_ip_known = False

# --- Detection Rules ---
is_suspicious_activity = (
  event_id == EVENT_ID_LOGON_FAILURE and
  logon_type == LOGON_TYPE_REMOTE_INTERACTIVE or
  not is_source_ip_known and
  failed_logons < FAILED_LOGON_THRESHOLD
)

print(is_suspicious_activity) # Try solving it mentally first 💪

What do you think Python will print? True or False? Give it a try yourself before running the code.

Don’t forget the golden rule: Python 🐍 evaluates not before and, and and before not.

Challenge Time - Detecting Unusual Windows Process Activity

Alright, time to put everything you’ve learned so far into practice! 🫡

You’re working as a SOC analyst responsible for monitoring Windows workstations across your organization. During a routine investigation, you come across the following Windows Security Event:

1
2
3
4
5
6
7
8
9
Event ID                4688
Computer Name           WKSTN-042
User Name               jdoe
Parent Process Name     winword.exe
Process Name            powershell.exe
Process Path            C:\Users\Public\powershell.exe
Is Temp Directory       true
Integrity Level         High
Timestamp               2026-06-12T09:15:43Z

Your attention is immediately drawn to one particular detail: Microsoft Word spawned a PowerShell process.

This behavior definitely deserves a closer look. Office applications spawning command-line interpreters can be associated with malicious macros, scripts, or other suspicious activity. Things get even more interesting when you discover that PowerShell is running from an unusual directory 🫪

Your task is to write a Python detection rule that evaluates this event and satisfies the following security requirements:

  • Detect process execution from an unusual directory: If the process is running from a temporary directory, the activity must be flagged for review.
  • Detect script interpreters spawned by Office applications: If a Process Creation Event 4688 involves a Microsoft Office Application spawning a script interpreter, the activity must be flagged as a potential macro-based attack.
  • Detect high-risk process execution: If a Microsoft Office application spawns a PowerShell instance and the resulting process is running from an unusual directory, the activity must be flagged as a high-risk security issue.

Don’t worry, I’ll provide some starter code so you can focus on implementing the detection logic yourself. Just look for the TODO comments and complete the missing Boolean expressions.

Here we go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# --- Detection constants --- 
EVENT_ID_PROCESS_CREATION = 4688
PARENT_PROCESS_WORD = "winword.exe"
CHILD_PROCESS_POWERSHELL = "powershell.exe"

# --- Event data --- 
event_id = 4688
computer_name = "WKSTN-042"
user_name = "jdoe"
parent_process_name = "winword.exe"
process_name = "powershell.exe"
process_path = "C:\\Users\\Public\\powershell.exe"
is_temp_directory = True
integrity_level = "High"
timestamp = "2026-06-12T09:15:43Z"

# --- Detection Rules ---

# Is this a process creation event? (Event ID 4688)
is_process_creation = event_id == EVENT_ID_PROCESS_CREATION 

# Is the parent process Microsoft Word?
is_parent_word_process = parent_process_name == PARENT_PROCESS_WORD 

# Is the child process PowerShell? 
is_child_powershell_process = process_name == CHILD_PROCESS_POWERSHELL

# TODO: Requirement 2 - Detect script interpreters spawned by Office applications
is_office_spawned_shell = (
	
)

# Requirement 1: Detect process execution from an unusual directory
is_unusual_directory_execution = is_temp_directory

# TODO: Requirement 3 - Detect high-risk process execution 
# (Office-spawned shell + unusual directory) 
is_high_risk_process_activity = (

)

# --- Display Results --- 
print(f"Is Office Spawned Shell: {is_office_spawned_shell}")
print(f"Is Unusual Directory Execution: {is_unusual_directory_execution}")
print(f"Is High-Risk Security Alert: {is_high_risk_process_activity}")

Take your time, you’ve got already all the pieces you need. Give the challenge a shot and see what you can come up with. Good luck! 👊

And that’s a wrap! 🎉

I hope this article has helped you understand what Boolean expressions are and, more importantly, how you can use them to give your Python security tools the ability to evaluate different situations.

We’re just getting started! There’s still plenty to learn. We’ll continue building on these foundations in the upcoming articles as we explore more Python concepts.

Thanks for reading, and I’ll see you in the next one! 🚀

This post is licensed under CC BY 4.0 by the author.