[FreeBSD-users-jp 95813] Re: nc(1)を使ってデータを送信しても完了にならない

IIJIMA Hiromitsu delmonta @ dennougedougakkai-ndd.org
2016年 5月 18日 (水) 04:00:40 UTC


いいじまです。お返事が遅くなりました。

>> それから、これは釈迦に説法ですが、nc -N が使えるかどうかの判定に
>>     % nc -h |& egrep '[-]N[^[:alnum:]] >& /dev/null
>> を実行して終了コード $? で判別しようとすると罠にはまります。
>> 
>> FreeBSDの場合、nc -h は1を返し、egrepは0を返します。
>> で、このパイプをbashで実行すると $? は0になります。
>> ところが、同じコマンドをtcshで実行すると $? は1になります。
>> 同じことをUbuntuでもやってみたのですが、こちらの場合、nc -h は
>> 0を返し、egrepは1を返すので、$? はbashでもtcshでも1になります。
> 
> えーと,全てのソースは見てないので憶測に過ぎませんが,基本的
> に *BSD* ではもともと -h や --help なんて洒落たオプションは
> なく,間違ったのを指定すると常に usage を返す仕様になってい
> るのでは? nc は -h がありましたが,でも基本 1 を返している
> のでは?sh で見ると,

FreeBSDでは確かにそうですね。
こちらでも下記のように確認しました。

$ sh
$ uname -a
FreeBSD sodans3.funini.com 9.3-RELEASE-p24 FreeBSD 9.3-RELEASE-p24 #0:
Sat Aug 22 01:54:44 UTC 2015
root @ amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC amd64
$ nc -h 1>/dev/null 2>&1 ; echo $?
1

でも、Ubuntuでは nc -h は0を返すんです。

$ sh
$ uname -a
Linux ubuntu.delmonta.orz 4.2.0-36-generic #41-Ubuntu SMP Mon Apr 18
15:47:56 UTC 2016 i686 i686 i686 GNU/Linux
$ ls -li `which sh` `which bash`
263917 -rwxr-xr-x 1 root root 1109520 Sep  1  2015 /bin/bash
262845 lrwxrwxrwx 1 root root       4 Feb 18 05:26 /bin/sh -> dash
$ ls -li /bin/dash
262839 -rwxr-xr-x 1 root root 173644 Feb 18 05:26 /bin/dash
$ nc -h 1>/dev/null 2>&1 ; echo $?
0

#shがbashへのハードリンクになっていないというのは、
#Linux系では珍しいかも。

>> で、このパイプをbashで実行すると $? は0になります。
>> ところが、同じコマンドをtcshで実行すると $? は1になります。

これも釈迦に説法ですが、bashの挙動をtcsh風にすることも、
逆にtcshの挙動をbash風にすることも可能です。

$ tcsh -c 'unset anyerror ; perl -e exit\ 23 | perl -e exit\ 13 | perl -e exit\ 0 ; echo $?'
0
$ bash -o pipefail -c 'perl -e exit\ 23 | perl -e exit\ 13 | perl -e exit\ 0 ; echo $?'
13

>> 結局のところ、nc -N が使えるかどうかの判定には
>>     % test -n "`nc -h |& egrep '[-]N[^[:alnum:]]'`"
>> あたりを使う必要があります。
> 
> sh ですが,直接,
> if nc -N foo 1234 < bar; then
> とかすれば良いような...

今回の場合、この nc コマンドは「既知のポートからデータを取ってくる」
のが目的ではなく、「既に nc -l で立ち上がっているサーバプロセスを
落とす」のが目的なんです。
具体的には、ncを使っているのは某アプリの脆弱性検証スクリプト
(ここで具体的な手口まで公開していいのかどうか迷うので、
名前は伏せておきます)でして、こんな書き方がしてあります。

| #!/usr/bin/env bash
...
| #random port above 16K
| PORT=$(($RANDOM + 16384))
| echo "testing http with local port: ${PORT}"
| # silence job control messages
| set -b
| # setup a dummy http server
| printf "HTTP/1.0 200 OK\n\n" | nc -l ${PORT} > requestheaders 2>/dev/null &
| if test $? -ne 0; then
|     echo >&2 "failed to listen on localhost:${PORT}"
|     exit 1
| fi
| ### 脆弱なら http://localhost:${PORT}/ にアクセスしてしまうコマンド ###
| if test -s requestheaders; then
|     echo "UNSAFE"
| else
|     echo "SAFE"
|     # terminate the dummy server
|     echo | nc localhost ${PORT} 2>/dev/null 1>/dev/null
| fi
| rm requestheaders
| set +b

この最後の
    echo | nc localhopst ${PORT} 
がFreeBSDではいつまでたっても終わらなくて(ncはデフォルトで
タイムアウト無期限です)、それを
    nc -z localhost ${PORT} 2>/dev/null 1>/dev/null
に変えたらうまくいった、というわけで。

なので、nc -L をいちど実行してみて動作が確認できたら2回目を実行する
意味はないし、逆に invalid option と言われたら -N なしで再度実行する
必要があるし、というわけなんです。

とりあえず nc -z で解決するので、その方向で脆弱性検証チームに
パッチを送りました。どうも無視されているようではありますが。

========================================================================
(Mr.) IIJIMA Hiromitsu aka Delmonta <delmonta @ dennougedougakkai-ndd.org>
飯嶋 浩光 / でるもんた・いいじま ; (任同)電脳外道学会 代表取締役椅子人
------------------------------------------------------------------------
Web (Japanese): http://www.dennougedougakkai-ndd.org/
      Twitter: @delmonta_iijima, @kabu_agare, #放送大学, #OUJ
  Yahoo! Japan: delmonta_iijima
------------------------------------------------------------------------
マニアツクで綾しいクイヅbot、運用開始!現在、購読者・出題者とも募集中。
    ※購読はこちらから → https://twitter.com/AyaC_KaltQ
    ※出題希望のかたは → http://kaltq.wicurio.com/
========================================================================



freebsd-users-jp メーリングリストの案内