// build

16 CVEs on a Refurbished Dell

5 min read

The Kali box

I already had Proxmox running on a refurbished Dell Optiplex for various homelab projects. Core i5-6500, 16 gigs of RAM, 512 GB hard drive. $200 off the refurb market. When I decided to try AI-assisted vulnerability research as a personal project in late-March, I spun up a Kali VM on it. Gave it 2 cores and 3.8 gigs of RAM.

Kali provides the standard set of red team tools needed for the job: radare2, strace, ltrace, GDB, Python with all the security libraries. I access it over SSH from my laptop. An MCP server on the Kali box lets my AI workflows (Shrike) run commands on it directly, so the scanning and analysis phases don’t need me to manually SSH in and type commands.

That’s it for the “server.” Two cores. Under 4 gigs of RAM. It handles recon, source code scanning, binary analysis, and PoC validation. A few weeks after setting it up, I’d submitted my first batch of vulnerability reports: 14 findings in 389-ds-base, reported on April 22.

graph LR
    subgraph Laptop["MacBook Pro"]
        Shrike["Shrike<br/>(AI workflows)"]
    end

    subgraph Dell["Dell Optiplex — i5-6500 / 16 GB / $200"]
        subgraph Proxmox["Proxmox VE"]
            subgraph Kali["Kali VM — 2 cores / 3.8 GB"]
                MCP["MCP Server"]
                Tools["radare2, GDB,<br/>strace, ltrace"]
                subgraph Containers["Validation Containers"]
                    C8["CentOS 8"]
                    C9["CentOS 9"]
                    CS10["Stream 10"]
                    CS11["Stream 11"]
                    F42["Fedora 42"]
                end
            end
        end
    end

    Shrike -- "MCP" --> MCP
    Laptop -- "SSH" --> Kali
    Tools -- "PoC" --> Containers

Five containers and a reset button

This is one of the most important pieces of the infrastructure, and I didn’t implement it until I had a close call with catastrophe during an early campaign.

On the Kali box I run 5 containers, each a different downstream Linux distribution: CentOS 8, CentOS 9, CentOS Stream 10, CentOS Stream 11, and Fedora 42. Every finding gets validated against all five. If a bug only reproduces on one version, I want to know that before I write it up, not after.

The containers are resettable. One command destroys them all and rebuilds from clean base images. No leftover files, no stale binaries, no contamination from a previous assessment.

Contamination

Early in my experiment, I was assessing cyrus-sasl and the tool found a SQL injection bug in the SQLite escaping code. The escape function used MySQL-style backslash quoting, but SQLite ignores backslashes.

I was able to prove that it was broken, I ran the script myself against the environment to validate it. I excitedly instructed Claude to write this up as a finding so I could submit my first vulnerability report.

I had the email drafted and ready to send, when I thought, “maybe I should just double-check this again”. I didn’t want to waste someone’s time or embarrass myself by submitting a bogus report.

That’s when I realized that previous experiment had not been fully cleaned up, and that there was a binary with SQLite enabled in the test container. The tool confirmed the exploit was real from 2005, but SQLite was not part of the default distribution for any version of cyrus-sasl.

I was about 5 minutes from submitting my first ever vulnerability report, and it would have been wrong.

Three things changed in the lab after that:

  1. Resettable containers. I built /cleanup, a one-command lab reset that destroys and recreates all five containers from clean images. Takes seconds. No excuse to skip it between assessments.
  2. Never test on the workstation. I built /poc, a structured PoC construction workflow with one non-negotiable rule: always test against the production binary in a downstream container. Never on the assessment machine where source builds might be sitting around.
  3. Adversarial environment checks. The adversarial review pass now independently verifies that the binary under test is the one the distro actually ships, not something I compiled.

Stratification

For each finding, I test against all 5 containers with default configurations. The output looks like this:

PlatformBinaryReproducesNotes
CentOS 8sssd-2.9.4-5.el8_10.4ROOT SHELLDefault config
CentOS 9sssd-2.9.8-2.el9ROOT SHELLDefault config
CentOS Stream 10sssd-2.12.0-3.el10ROOT SHELLDefault config
CentOS Stream 11sssd-2.x.xROOT SHELLDefault config
Fedora 42sssd-2.11.1-2.fc42ROOT SHELLDefault config

For each finding, I produce a table that looks something like this. With an LLM to do the engineering work, the incremental cost to test across 5 containers is relatively trivial once you have a valid reproducer. In addition, I provide the steps to reproduce, a reproducer, and a suggested patch for each finding.

The one thing the Kali box can’t handle is sustained fuzzing. Two cores and under 4 gigs of RAM means AFL++ runs at a crawl. I moved the heavy fuzzing to my MacBook Pro, but that’s a separate post.

What’s it all cost

The total hardware investment is $200 for the Dell, plus a laptop I already had. The 14 CVEs I found in 389-ds-base came out of 9 days of research on this rig. The 2 SSSD CVEs took 2 days.

The AI models are not free. My best estimate is roughly $500 in API tokens for the 389-ds-base campaign alone. I’m still calibrating costs as I iterate on the tooling, but that campaign produced 20 findings: 14 received CVEs, 2 were rejected, and 4 were classified as code quality issues.

Hardware$200 (refurbished Dell Optiplex)
API tokens~$500 (389-ds-base campaign)
Total~$700
CVEs16 (14 in 389-ds-base, 2 in SSSD)
Research time11 days (9 + 2)
Cost per CVE~$44

What I’d do differently

If I were setting this up from scratch today, two things would change.

Start with resettable containers from day one. I got lucky that the cyrus-sasl contamination happened before I submitted my first report, not after. The /cleanup command and the rule about never testing on the workstation should have been in place before the first scan ran, not retrofitted after a near-miss.

Separate fuzzing from analysis sooner. I ran early fuzzing campaigns on the Kali box because it was there and it worked. It worked slowly. Moving the sustained fuzzing to the MacBook with dedicated cores and proper campaign isolation made a measurable difference in throughput. If you’re planning a lab, decide up front which machine handles analysis (can be small) and which handles fuzzing (needs cores).

$200 in hardware. Roughly $500 in API costs. 16 CVEs. That’s about $44 per CVE.