Arsenal: A Command Injection Framework for Pentesting (That Literally Injects Your Shell)
Hook
Most CLI tools execute commands in subshells. Arsenal does something far more audacious: it literally pretends to be your keyboard, injecting commands character-by-character into your terminal as if you typed them yourself.
Context
If you've done penetration testing, you know the drill. You're in the middle of an Active Directory engagement, you need to dump Kerberos tickets with Impacket, but you can't remember if it's getTGT.py or GetUserSPNs.py, and which flags handle NTLM authentication versus Kerberos. You alt-tab to your notes, grep through scattered text files, or—let's be honest—Google the syntax for the hundredth time.
The offensive security community has tried to solve this with wikis, GitHub repos full of markdown files, and general-purpose cheatsheet tools like tldr or navi. But these solutions fall short for pentesting workflows. You don't just need command reference; you need something that understands your engagement context (target IPs, domain names, usernames) and can populate commands with those values. You need something that integrates with tmux split-pane workflows, preserves your shell history for reporting, and covers the esoteric corners of offensive tooling that general cheatsheet databases ignore. Arsenal emerged from Orange Cyberdefense's internal tooling to solve exactly this problem—a fuzzy-searchable command launcher built by pentesters who got tired of context-switching during engagements.
Technical Insight
Arsenal's most fascinating technical decision is how it gets commands into your shell. Rather than executing commands in a subprocess (which would lose your shell environment, aliases, and history), Arsenal uses the TIOCSTI ioctl to inject characters directly into the terminal's input buffer. This is the same mechanism a hardware keyboard uses—your shell literally cannot tell the difference between you typing a command and Arsenal stuffing it into the TTY.
Here's the core mechanism stripped down:
import fcntl
import termios
import sys
def inject_command(cmd):
# Open the controlling terminal
with open('/dev/tty', 'w') as tty:
# Inject each character into the TTY input buffer
for char in cmd:
fcntl.ioctl(tty, termios.TIOCSTI, char)
# Add a newline to execute
fcntl.ioctl(tty, termios.TIOCSTI, '\n')
This approach has profound implications. Because the command appears in the terminal's input buffer, it gets added to your bash/zsh/fish history automatically. You can see the command before it executes (Arsenal doesn't auto-execute by default). And critically, the command runs in your parent shell environment—it has access to your SSH agent, environment variables, shell functions, and working directory context.
Arsenal layers variable substitution on top of this foundation. You define global variables for your engagement—ip, domain, user—and commands in the cheatsheet reference them:
# SMB Enumeration
## List shares with smbclient
smbclient -L //${ip}/ -U ${domain}/${user}
## Enumerate with crackmapexec
crackmapexec smb ${ip} -u ${user} -p ${password} --shares
When you select a command, Arsenal performs variable expansion before injection. The fuzzy search (powered by fzf) searches both command descriptions and the commands themselves, so you can find things by typing "kerberos ticket" or "getTGT" or "impacket".
The tmux integration is particularly clever for engagement workflows. Arsenal can detect if you're in a tmux session and send the selected command to a specific pane:
# Simplified tmux integration logic
def run_in_tmux_pane(cmd, pane_id=None):
if pane_id:
# Send to specific pane
subprocess.run(['tmux', 'send-keys', '-t', pane_id, cmd, 'Enter'])
else:
# Create split pane and run there
subprocess.run(['tmux', 'split-window', '-h'])
subprocess.run(['tmux', 'send-keys', cmd, 'Enter'])
This means you can keep Arsenal in one pane, select commands, and have them execute in an adjacent pane where you're watching logs or maintaining a reverse shell—a workflow that's clunky with traditional command runners.
The cheatsheet format itself is pragmatic. Arsenal parses Markdown and reStructuredText, extracting commands from code blocks under headers. Headers become searchable categories; code blocks become executable commands. You can maintain cheatsheets in the same documentation format you'd use for team wikis, and Arsenal makes them executable. The project includes extensive cheatsheets covering Active Directory attacks (AS-REP roasting, Kerberoasting, DCSync), web enumeration (wfuzz, ffuf, gobuster), reverse shells across languages, and AWS/Azure cloud pentesting.
The repository also includes mindmaps (in SVG format) for Active Directory and Exchange attack paths—visual references for privilege escalation routes that complement the command database.
Gotcha
The elephant in the room: Linux kernel 6.2 and later disabled TIOCSTI by default because it's a security risk. The ioctl allows any process to inject input into any TTY it can write to, which enables privilege escalation attacks (inject sudo commands into another user's shell). Modern distributions require you to explicitly re-enable it with sysctl -w dev.tty.legacy_tiocsti=1, and many security-conscious users won't want to do that. Arsenal's core functionality relies on what is now considered a deprecated, dangerous kernel feature.
The cheatsheet coverage, while extensive, has significant gaps. The TODO list reveals missing documentation for increasingly important tools: nuclei templates, modern PowerView commands, shadow credentials attacks, ADCS exploitation, and container escape techniques. If your engagements focus on cutting-edge attack vectors, you'll spend time authoring your own cheatsheets—which is supported, but defeats the "quick inventory" promise. The YAML format for custom cheatsheets is documented but examples are sparse, making the learning curve steeper than it should be.
There's also no safety net. Arsenal injects whatever command you select directly into your shell. There's no sandboxing, no confirmation for destructive commands, no parsing to prevent syntax errors. If you accidentally select a dd command targeting the wrong device or an rm -rf with the wrong path variable, Arsenal will happily inject it. The fuzzy search occasionally surfaces commands out of context—you might search "dump" and get a database dump command when you wanted memory dump, and the similarity could lead to dangerous mistakes during high-pressure engagements.
Verdict
Use if: You're a penetration tester on engagements requiring frequent recall of complex command syntax across diverse tooling (Impacket, CrackMapExec, Bloodhound, cloud CLIs), you're willing to enable legacy kernel features or run on older systems, and you work heavily in tmux-based workflows where command injection into split panes saves significant time. Arsenal shines when you've customized it with your team's cheatsheets and engagement-specific variables. Skip if: You're on modern Linux distributions and won't compromise kernel security settings for convenience, you need comprehensive coverage of cutting-edge attack techniques without authoring custom cheatsheets, or you prefer tools that sandbox command execution rather than injecting directly into your shell. Also skip if you're not doing offensive security work—Arsenal's value proposition is entirely tied to pentesting workflows, and general-purpose alternatives like navi or tldr serve broader development needs better.