Technical #ia #activedirectory

We asked an AI to attack an Active Directory lab, but a simple honeypot stopped it

An autonomous AI agent attacks an Active Directory lab. A Trapster honeypot wired to OPNsense blocks its IP on the very first scan, with no human involved.

Florian Schoenhentz
Oct. 5, 2026
0 min
We asked an AI to attack an Active Directory lab, but a simple honeypot stopped it

In the age of AI, detecting and blocking network attacks as quickly as possible has become essential. Implementing a honeypot is a particularly effective solution for this, and the process becomes even more compelling when the blocking is automated, without human intervention. This is what we will explore in this article: how an autonomous AI agent launched an attack on a vulnerable Active Directory lab, and how a honeypot combined with a firewall was sufficient to stop it.

The context

Autonomous AI agents capable of piloting a terminal, executing commands, and iterating on their results are becoming increasingly sophisticated. Tools like Claude Code, initially designed for software development, can just as easily be repurposed to orchestrate an attack sequence: reconnaissance, enumeration, exploitation, lateral movement.

This raises a simple but important question from a defense perspective: Does an AI-driven attack behave differently from a human attack, and can it be detected and blocked more easily?

To answer this, an experiment was set up around four building blocks:

  1. GOAD (Game of Active Directory), a deliberately vulnerable lab that replicates a realistic Active Directory environment with several chainable vulnerabilities.
  2. Claude Code, used as an autonomous agent to lead the attack against this lab.
  3. Trapster Community, a honeypot deployed on the same network, coupled with an OPNsense firewall to automatically block any IP detected interacting with it.
  4. A Python script to retrieve Trapster logs and add the IPs to be blocked in OPNsense.

Configuring OPNsense

Once the lab is ready (GOAD in place, as well as the Trapster machine), the next step is to configure OPNsense: create an alias that will contain the banned IPs, as well as the associated blocking rule.

The idea is then to develop a small script that retrieves Trapster alerts and automatically adds the attacker's IP address to this alias.

Creating the alias

Create a new alias under Firewall > Alias, give it a name, choose the Host(s) type and leave the rest empty: the script will fill it in.

Creating the trapster_blocklist Host(s) alias in OPNsense

Creation of the blocking rule

Next, you need to go to Firewall > Rules > <interface> and create a new rule. The action must be configured in Block (or Reject), and the source must match the alias created previously:

The OPNsense block rule with the trapster_blocklist alias as its source

Remember to place this rule above the others: on OPNsense, the first matching rule wins.

Create an API key

The final step is to create an API key to be able to add malicious IPs to the alias from the script. To do this, go to System -> Access -> Users:

Creating an OPNsense API key from System > Access > Users

Trapster Configuration

For Trapster, you simply need to start with a standard configuration file compatible with Active Directory (SMB, LDAP, MSSQL, etc.). Then tell Trapster to write its logs to a file so the script can read them:

"logger": {
  "output": "file",
  "format": "default",
  "kwargs": {
    "logfile": "/var/log/trapster-community.log",
    "mode": "a"
  }
}

Script creation

To connect everything, a small script is needed that simply reads the previously configured Trapster log file, retrieves the source IP address of each alert, and then adds it to the alias using the OPNsense API:

#!/usr/bin/env python3

import json
import time
import requests

url = "http://<ip_opnsense>/api/firewall/alias_util/add/trapster_blocklist"

def parse_alert(line):
    try:
        data = json.loads(line)
        return data.get("src_ip")
    except json.JSONDecodeError:
        return None

def tail_file(path):
    with open(path, "r") as file:
        file.seek(0, 2)
        while True:
            line = file.readline()
            if not line:
                time.sleep(1)
                continue
            yield line

def block_ip(ip):
    response = requests.post(
        url,
        json={"address": ip},
        auth=("<api_key>", "<secret>"),
        verify=False,  # lab self-signed certificate, drop this in production
    )
    if response.status_code == 200:
        print(f"{ip} added to the ban list")
    else:
        print(response.json())

def main():
    logfile = "/var/log/trapster-community.log"
    for line in tail_file(logfile):
        ip = parse_alert(line)
        if ip:
            block_ip(ip)

if __name__ == "__main__":
    main()

Demonstration

All the building blocks are now in place: all that remains is to verify that everything actually works. First step: place the script on the machine hosting the honeypot, start Trapster, and then run the script.

Trapster Community running, with the blocking script watching the log file

All that remains is to send Claude on a penetration test mission against the GOAD network. It works from a CLAUDE.md file defining the context and scope of the mission:

# Project Context

Educational pentesting lab: GOAD (Game of Active Directory), deployed locally
in an isolated environment for offensive and defensive security training.

## Authorized Scope

- Target network: [e.g., <network>/24]
- Strictly prohibited from going outside this network range

## Objective

Enumerate the Active Directory environment, identify attack paths,
obtain Domain Admin rights on the `sevenkingdoms` domain,
and document every step.

## Tools Available on This Machine

- nmap, NetExec (crackmapexec), Impacket (Python scripts)
- BloodHound / bloodhound-python / SharpHound
- All tools available in Exegol

## Expected Methodology

1. Network reconnaissance
2. AD enumeration (users, groups, ACLs, SPNs)
3. Credential hunting (Kerberoasting, AS-REP roasting, shares)
4. Lateral movement
5. Privilege escalation
6. Documentation of every step in a final report

## Operational Rules

- Document every executed command and its result in a
`logs/session.md` file
- Request confirmation before any destructive action (account
modification, DCSync, etc.)
- Never interact with IP addresses outside the defined scope

Once the mission is launched, Claude begins, as expected, with its reconnaissance phase: it scans the network to identify active machines and exposed services. It is precisely this type of interaction that Trapster is designed to intercept: the mechanism is covered in our article on detecting Nmap scans.

Claude Code starting its network reconnaissance phase against the GOAD lab

And indeed, during this service scan, an alert is raised on the honeypot side, and the Python script retrieves it correctly, extracting the source IP from the log line:

The Python script extracting the source IP from the Trapster alert

A few moments later, the IP address is blocked on OPNsense: the trapster_blocklist alias has been updated through the API, and the blocking rule at the top of the list now applies to this address:

The trapster_blocklist alias now containing the attacker's IP

As a direct consequence, the attack is blocked automatically, with no manual intervention between detection and the traffic being cut. Claude loses access to the target network mid-mission, as the rest of the session shows:

Claude Code losing access to the target network mid-mission

Conclusion

This example highlights the usefulness of a honeypot: simple to set up, it only needs to be coupled with a firewall and a script of a few dozen lines to transform a simple alert into an automated response. In a few seconds, an attack can thus be stopped dead in its tracks, without any human intervention being necessary.