雑記

2000|01|
2003|05|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|
2007|01|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|09|11|
2009|02|03|05|06|07|08|10|11|12|
2010|01|03|04|05|06|07|08|09|10|
2011|05|06|09|10|
2012|03|07|09|12|
2013|01|02|04|05|07|08|10|11|
2014|04|05|08|10|12|
2015|01|05|
2016|09|

2013-08-10 [長年日記]

SuperMicro社のBMC/IPMI搭載製品における初期設定の問題について

[概要]

SuperMicro社のBMC/IPMI搭載製品では、その初期設定の状態に問題があるため、特定の条件下で外部からコンソール等にアクセス可能となる可能性があります。

本問題については、該当製品で稼働しているOSのroot権限を取得できる可能性があるため、発見後すぐにIPAに脆弱性関連情報の届出を行いましたが、1年以上に渡り返信が無い状態が継続しているという事であり、また適切に設定する事により回避することができるため、広く公開して注意喚起したほうが公益に資すると判断し、公開するものです。

[公開までの経緯]

[flat] ;2012/03/19;:IPAに届け出 ;2012/04/04;:IPAより届け出受理の連絡 ;2013/07/17;:IPAより2012/05/16(起算日)以降、製品開発者へ連絡をとっているが、返信がない旨の連絡 ;2013/07/18;:IPAに情報非開示依頼の取下げを依頼 ;2013/08/02;:IPAより情報非開示依頼の取下げの連絡 ;2013/08/10;:本エントリ公開

[対象となる製品]

本問題の対象となる製品は以下の通りです。

IPMI Manual (AMI)より

[border]

Intel UP Motherboards supportedIntel DP Motherboards supportedAMD Motherboards supported
X7SB3-FX7DCT-3FH8DMT-F
X8ST3-FX7DCT-3IBXFH8DMT-IBXF
X8STi-FX7DCT-LF
X8STi-3FX8DAH+-F
X8DT3-F
X8DT3-LN4F
X8DTH-6F
X8DTH-iF
X8DTi-F
X8DTi-LN4F
X8DTT-F
X8DTT-IBQF
X8DTT-IBXF
X8DTU-F

IPMI Manual (SMT)より

[border]

Intel Dual-Processor Motherboards supported (-F models only)Intel Single-Processor Motherboards supported (-F models only)AMD Motherboards supported (for -F models only)
X8DTL-3F/-6F/iFX7SPA/E-HF/-D525H8DGG-QF
X8DTN+-FX7SPT-DF-D525H8DGT-HF/-HIBQF/-HLF/-HLIBQF
X8DTU-6F+/6TF+/LN4F+/TFX8SI6-FH8DGU-F/-LN4F+
X9DBU-6F/iFX8SIA-FH8SGL-F
X9DR6/i-FX8SIE-F/LN4FH8SCM-F
X9DRT-H6FX8SIL-FH8DCL-6F/-iF
X9DRG-QF+X8SIT-F/-HFH8DCT-F/-HIBQF/-HLN4F/-IBQF
X8SIU-FH8DG6-F
X9SCA-FH8DGi-F
X9SCD-F
X9SCi-LN4F
X9SCL-F
X9SCM-F
X9SRE-F
X9SRW-F

[問題の詳細]

上記のマザーボードには、Nuvoton WPCM450というBaseboard Management Controller(BMC)が搭載されています。このコントローラにより、専用ポートまたはオンボードのLAN1ポート経由で遠隔地からのコンソールの操作やCDイメージのマウント、電源の制御などが行えます。

このコントローラの標準の設定は以下のような組み合わせになっています。

[flat] ;LANポート:;:Failover ;IPアドレス:;:DHCPで取得

LANポートの"Failover"という設定では、BMCの専用ポートがネットワークに接続されていなければ、オンボードのLAN1ポートで接続を試みます。このため、初期設定の状態で、

  • OSで利用するためLAN1ポートをグローバルなネットワークに接続した
  • LAN1ポートに接続したネットワーク上でDHCPサーバが稼働していた
  • DHCPサーバではMACアドレスによるフィルタリング等は行わずに接続された任意の機材にIPアドレスを割り当てるよう設定していた
  • BMC機能は使わないつもりでBMC専用ポートにはなにも接続しなかった

といった条件を満たしていると、OSで利用している通信とLAN1ポートをシェアする形でBMCにも独立したIPアドレスが割り当てられ、BMCが提供する各機能にアクセスできるようになります。この時さらに、

  • DHCPサーバでグローバルIPを割り当てていた
  • 割り当てられるグローバルIPに対して、ファイアウォール等でパケットフィルタリングを設定していなかった

という条件が重なった場合は、インターネットからBMCへのアクセスが可能となってしまいます。

このBMCはWeb UIも提供しており、その初期アカウント名とパスワードの情報はマニュアルに記載され、SuperMicro社のサポートページからダウンロード可能な状態で公開されているため、誰でも容易に入手可能な状態となっています。前述の通り、このWeb UIからはコンソールの操作が可能となり、また多くのUNIX系のOSではコンソールからの操作に関してはやや楽観的な初期設定が行われているため、

  1. Ctrl+Alt+DeleteでOSを強制的にリブート
  2. シングルユーザモードで起動する

などといった操作で、簡単にroot権限を奪う事ができてしまいます。また、コンソールに表示されているカーネルからのメッセージを確認する事も可能となります。

[回避方法]

BMCポートを外部から遮断されたネットワークに接続することで、ひとまずこの問題は回避できますが、接続先の機器の電源が落ちるなどしてネットワークが不通になると、すぐにオンボードのLAN1ポートに切り替わってしまいます。

さらに悪い事に、いったんBMCがLAN1ポートに切り替わってしまうと、BMC専用ポートの接続が復旧しても自動的に戻らないため、迅速に元に戻すためにはOSをシャットダウンして電源ケーブルを抜き、しばらく待ってから再起動する必要があります。

これらの問題も含めて回避するためのいくつかの方法を説明します。

  1. パスワードを変更する
Web UIにログインしてパスワードを変更します。一番基本的かつ有効な対策です。
  1. BMCは専用ポートのみで使用する
BMC専用ポートを保護されたネットワークに接続してこちらのみ使用するようにします。
    1. Web UIからログイン
    2. [Configuration]->[Network]に進む
    3. [Lan Interface]で"Dedicate"を選択する
    4. [Save]ボタンをクリックして設定を保存する
  1. (((

OS側でCtrl+Alt+Deleteによる再起動を無効にする

直接的な解決方法ではありませんが、インストールしているOS側でCtrl+Alt+Deleteキーによる再起動を無効化することもできます。

;Linux(CentOS)の場合:

(((

/etc/init/control-alt-delete.confを編集して次の行をコメントアウトする

 exec /sbin/shutdown -r now "Control-Alt-Delete pressed"

または/etc/inittabを編集して以下の行をコメントアウトする

 ca::ctrlaltdel:/sbin/shutdown -t3 -r now

))) ;FreeBSDの場合:

(((

以下のコマンドを実行する

sysctl hw.syscons.kbd_reboot=0

さらに以下の行を/etc/sysctl.confに追加して再起動する

hw.syscons.kbd_reboot=0

))) )))

  1. BMCを無効にする
BMCの機能を使うつもりが無いのであれば、マザーボード上のJPBジャンパーの設定を変更してBMCを無効化してしまいましょう。

[免責事項]

  • 本エントリは、該当製品の利用者に安全な運用の方法を提示するために公開するものです。従って、本エントリに記載されている内容を悪用する事は禁止します。
  • 本エントリに記載されている内容をもとに第三者が管理するサーバにアクセスすると、不正アクセス行為の禁止等に関する法律で禁止された不正アクセス行為に該当すると思われます。
  • 本エントリを公開した結果生じたいかなる損害についても、筆者は一切責任を負いません。

以上


2013-08-15 [長年日記]

tDiary-4.0.0に移行

だいぶ手を入れていたせいでなかなか踏ん切りがつかなかったtDiaryの環境を一念発起して最新の4.0.0に上げる事に。ruby18+2.2.3(EUC)からruby19+4.0.0(UTF-8)への移行ということで、なかなか厳しいかなと思っていたのですが、結果的には1日で終わりました。tDiary開発陣の継続性への配慮には感服するばかりです。とはいえ多少手こずったのでメモを残しておきます。

最初に手順をまとめておくと、

  1. まず、ruby18+3.2.2に上げてUTF-8化する
  2. 3.2.2をruby19で動かす
  3. 4.0.0にアップデートする

という順にやるのが確実なようです。

まず試したのは4.0.0のインストール。最初gem版を入れてみたのですが、プラグインやテーマ、BlogKitなどの入れ方がよく分からなかったので、すぐに挫折してダウンロード版を使う事に。ダウンロードページからフルセットとBlogKitをダウンロードして展開、コピー。この辺の手順は2.2.3の頃とほとんど変わりません。

データをコピーしてアクセスしてみると、以下のエラー

There was a Errno::ENOENT while loading tdiary.gemspec: 
No such file or directory - git ls-files from
/home/socodanet/local/tdiary/core/tdiary.gemspec:16:in ``'
(Bundler::GemspecError)

検索するとgitが必要そうな記述を発見。ここはsandbox上で動かしていて開発用ツールを入れるつもりは無いので、4.0.1あたりで直るだろうということで4.0.0化もあっさり挫折。結果論ですがこの判断は正しかったです。

で、3.2.2を入れようとしたのですが、tDiaryのダウンロードページにリンクが無い。ここは慌てず騒がず、4.0.0のパスから類推してフルセットBlogKitを無事ダウンロード。展開してインストール。

日記のデータをコピーして、テスト用のパスで表示すると文字化け。キャッシュを消してみても変わらず。原因が分からずいろいろと情報を探すと、3.0.0のリリースノートに「tDiary 3.0とruby 1.9.2を同時にアップデートしない」とちゃんと書いてありました。今頃アップデートしようとしてるから自業自得です。ということで、ruby18を使うようにindex.cgiのshebangを書き換え、

#!/usr/local/bin/ruby18
require '/usr/local/tdiary-3.2.2/index'

キャッシュをクリアしてからアクセスするとUTF-8に正しく変換されて文字化けは解消しました。すばらしい。

ただ、テーマがうまく反映されず、調べているうちに、複数のtDiaryを運用している事を思い出し、[[同一サーバで複数のtDiaryを運営する方法|http://www.tdiary.org/20021205.html]]を参考にpluginsの下にうちの環境に合わせたchange_url.rbを設置して解決。
# change_url.rb
def theme_url
   '/tdiary/theme'
end
 
def js_url
   '/tdiary/js'
end

思い出したついでに他のページでも以下を繰り返して3.2.2にアップデート。

  1. データをバックアップ
  2. index.cgi, update.cgiのshebangを、ruby18を使うように修正
  3. キャッシュを削除
  4. ページにアクセスしてキャッシュを再生成
  5. ruby19を使うようにshebangを再修正
  6. この時点ではキャッシュに"Powered by Ruby 1.8.x"表記が残るのでcache/latest.rbを削除

これでほぼ作業完了ですが、hikidoc.rbとファイルアップロードのプラグインは改造したものを使っているので置き換え。こちらは幸いにもファイルの漢字コードをEUC-JPからUTF-8に変換するだけで問題無く動きました。

当初予定していた4.0.0化は出来なかったけどUTF-8化とruby19対応は出来たので良いかと思い一区切りつけたものの、ちょっともやもやが残っていたのでTwitterで愚痴ったら、30分もしないうちに@machuさんからお返事がきて、インストールしたtDiaryのトップディレクトリにあるGemfileの5行目の"gemspec"という行を削除すれば動くとの助言をいただきました。

source 'https://rubygems.org'

if File.exist?(File.expand_path('../tdiary.gemspec', __FILE__))
        # directly installed (e.g. git clone, archive file)
        # gemspec      <-この行をコメントアウト
else
 :

さっそく試してみると、なぜか手元の環境ではfastimageが見つからないとのエラー

[clear] ダウンロードしてきたtar ballを展開した状態では.bundle/ruby/1.9.1/gems/fastimage-1.5.0に入っていて、このパスが見つけられない模様。rubyは1.9.3p448なのでバージョン番号と思われる"1.9.1"を"1.9.3"に変えてみても駄目。試しに"1.9"にしたところ、こんどはGemfile.lockへの書き込みエラーになったので、Gemfile.lockのownerをwwwにしてapacheに書き込み権限を与えたら無事動きました。

@machuさんに報告すると、先方の環境ではruby 1.9.3でもパスは1.9.1のままで動くとのことなので、rubyやgemのコンパイルやインストール時のオプションが原因かもしれないと思いちょっと調べてみましたが、よく分かりませんでした。rubyもgemもbundlerもFreeBSDのportsを使ってインストールしているので、そんなに変な環境ではないはずなんですが…{{fn '1.8と1.9を共存させるためにちょっといじってはいます'}}

以下、雑感です。

  • 漢字コードの変換や1.9への移行のスムーズさはすばらしい
  • bundlerのパスの謎は環境依存の懸念が残って、かなり気持ち悪い
  • 現在の4.0.0の状態でダウンロードページから3.2.2のリンクが消えてしまっているのはちょっと疑問
  • あえて書いてませんが、"bundle install"で解決する事は確認済みです。いろいろやっている間に、tDiaryの「レンタルサーバーユーザにやさしい」という謳い文句が形骸化してきているように思えてちょっと寂しくなったので。

[green]


本日のツッコミ(全2件) [ツッコミを入れる]

- まちゅ [レンタルサーバでもこれまで通り簡単に動かせるようにしつつ、新しい環境(RackやBundler)にも対応していこうと..]

- hs [まちゅさん せっかくコメントいただいたのにSPAMフィルタの調子が悪かったようで非表示になっていました。 おかげ..]


2013-08-18 [長年日記]

[Ruby]Rubyライブラリのパスの謎に迫る

前回のサーチパスの問題がどうにも気持ち悪いので調べてみました。先に結論を書いておくと、Ruby本体のコンパイル時のオプションによってライブラリのサーチパスが変わり、その影響でbundlerがgemを見つけられなくなるという不具合のようです。

まずは問題のおさらいですが、tDiaryのtarボールを展開するとgemのファイルが".bundle/ruby/1.9.1/"以下に置かれます。ところが、私の環境ではこのパスを見つけられずエラーになってしまいました。調べてみると、

  • bundle installすると動くようになる
  • この時、gemは".bundle/ruby/1.9/"以下にインストールされる
  • 元の".bundle/ruby/1.9.1/"を".bundle/ruby/1.9/"に変更したり、シンボリックリンクを張ればそれらのファイル群でもちゃんと動く

という状況でした。また、@machuさんの環境では1.9.3でもそのままで問題無く動くということでした。とここまでが昨日の時点での話で、ライブラリのサーチパスがかなり怪しいです。

さて昨日も書いたのですが、Ruby関連はFreeBSDのportsを利用しているので、調べてみると、/usr/ports/Mk/bsd.ruby.mk に

  :
RUBY_DEFAULT_VER?=   1.9

RUBY_VER?=     ${RUBY_DEFAULT_VER}
  :
# Directories
RUBY_LIBDIR?=     ${_RUBY_SYSLIBDIR}/ruby/${RUBY_VER}
RUBY_ARCHLIBDIR?= ${RUBY_LIBDIR}/${RUBY_ARCH}
RUBY_SITELIBDIR?= ${_RUBY_SITEDIR}/${RUBY_VER}
RUBY_SITEARCHLIBDIR?=   ${RUBY_SITELIBDIR}/${RUBY_ARCH}
RUBY_VENDORLIBDIR?=  ${_RUBY_VENDORDIR}/${RUBY_VER}
RUBY_VENDORARCHLIBDIR?= ${RUBY_VENDORLIBDIR}/${RUBY_ARCH}
  :
GEMS_BASE_DIR= lib/ruby/gems/${RUBY_VER}
GEMS_DIR=   ${GEMS_BASE_DIR}/gems
DOC_DIR= ${GEMS_BASE_DIR}/doc
CACHE_DIR=  ${GEMS_BASE_DIR}/cache
SPEC_DIR=   ${GEMS_BASE_DIR}/specifications
GEM_NAME?=  ${PORTNAME}-${PORTVERSION}
GEM_LIB_DIR?=  ${GEMS_DIR}/${GEM_NAME}
  :

/usr/ports/lang/ruby19/Makefileに

post-patch:
   @${REINPLACE_CMD} -E \
      -e 's,-l$$pthread_lib,${PTHREAD_LIBS},g' \
      -e '/^RUBY_LIB_PATH/s,\.\$$\{TEENY\},,' \
      -e '/^RUBY_SITE_LIB_PATH2/s,\.\$$\{TEENY\},,' \
      -e '/^RUBY_VENDOR_LIB_PATH2/s,\.\$$\{TEENY\},,' \
      ${WRKSRC}/configure

という記述がありました。ところが、これが原因かと思ってさらに追ってみてもどうにもおかしい。前者はパッケージを作るためのパスの設定でコンパイル時には使用されておらず、後者はTEENYを削除していてそれっぽいのですが、ソースを展開してできるconfigureスクリプトには該当する行が無く、さらに探すと展開されたソースツリーのdoc/ChangeLog-1.9.3に

Thu Feb  5 11:21:35 2009  Nobuyoshi Nakada  <nobu@ruby-lang.org>

   * configure.in (RUBY_LIB_VERSION): added for library version, to split from core version.  [ruby-dev:37748]

   * configure.in (RUBY_LIB_PATH, etc): moved actual version dependent stuff to version.c.

と2009年の2月にはconfigureから消されているようで、今現在は意味の無いコードのようでした。よく分からないのでsandboxを作ってRubyをportsを使わずにソースからインストールしてみると、ちゃんと(?)/usr/local/lib/ruby/1.9.1/以下にインストールされるので、ますます謎です。

ここでいったんRubyの追跡をあきらめ、gemのサーチパスが変わってしまう原因を追ってみますが、こちらのportsはソースには全く手を入れておらずにsetup.rbを実行しているだけでした。いよいよ深みにはまってきたなぁと思いつつgemのソースを追います。ここでかなり時間がかかりましたが、なんとか探し出したところ、gemのサーチパスはdefaults.rbというファイルの中のdefault_dirで定義されているようでした。

  def self.default_dir
    path = if defined? RUBY_FRAMEWORK_VERSION then
             :
           elsif ConfigMap[:rubylibprefix] then
             [
              {~orange:ConfigMap[:rubylibprefix],~}
              {~orange:'gems',~}
              {~orange:ConfigMap[:ruby_version]~}
             ]
           else
             :
           end

    @default_dir ||= File.join(*path)
  end

このConfigMapはrubygems.rbの中で、

  unless defined?(ConfigMap)
    ##
    # Configuration settings from ::RbConfig
    ConfigMap = Hash.new do |cm, key|
      cm[key] = RbConfig::CONFIG[key.to_s]
    end
  else
   :

のように初期化されています。RbConfig::CONFIGってなんぞやとぐぐってみると、「RbConfigというのがあってビルド時の情報とかが取れる」というブログの記事が見つかりました。こちらに習って確認すると、

% ruby19 -rpp -e"pp RbConfig::CONFIG"
{"DESTDIR"=>"",
 "MAJOR"=>"1",
 "MINOR"=>"9",
 "TEENY"=>"1",
   :
 "ruby_version"=>"1.9",
   :
 "rubylibprefix"=>"/usr/local/lib/ruby",

おぉ、ruby_versionが"1.9"だ。同じくソースを直接コンパイルした環境で試すと、

% ruby -rpp -e"pp RbConfig::CONFIG"
   :
 "ruby_version"=>"1.9.1",
   :

と、ちゃんと"1.9.1"になっています。いよいよ核心に迫ってきています。

そうすると、このruby_versionをどこかで変更しているはずだと思ってさがしてみると、/usr/ports/lang/ruby19/Makefileに、

CONFIGURE_ARGS=   ${RUBY_CONFIGURE_ARGS} \
      --enable-shared \
      --enable-pthread \
      {~orange:--with-ruby-version=minor~} \
      --with-sitedir="${PREFIX}/lib/ruby/site_ruby" \
      --with-vendordir="${PREFIX}/lib/ruby/vendor_ruby"

という記述を発見。configure --helpで確認すると、

  --with-ruby-version=STR ruby version string for version specific directories
                          [[full]] (full|minor|STR)

とあったのでビンゴ。FreeBSDのportsではこの"--with-ruby-version=minor"指定でライブラリのインストールパスを"1.9"にしておいて、最初のbsd.ruby.mkでパッケージ化する際のパスを調整しているようでした。

残る疑問は、Rubyのバージョンが"1.9.3"でもライブラリのパスがデフォルトでは"1.9.1"になっている点ですが、こちらは、1.9.2のリリースノートのFAQに答えがありました。

{''標準ライブラリが/usr/local/lib/ruby/1.9.1にインストールされる''}
    このバージョン番号は「ライブラリ互換バージョン」です。Ruby 1.9.2は1.9.1とおおよそ互換なので、ライブラリはこのディレクトリにインストールされます。

まとめると、

  • Rubyには言語のバージョンと独立したライブラリ互換バージョンという概念が存在する
  • デフォルトの状態ではライブラリ互換バージョンの値と同じ名前のディレクトリにライブラリがインストールされる
  • ライブラリのインストール先ディレクトリの名前は、configureスクリプトで"--with-ruby-version"オプションを指定する事により変更可能
  • この"--with-ruby-version"をつかってディレクトリを変更してしまうと、gemのライブラリ検索パスも変わってしまう
  • このため、例え同じバージョンのRubyであっても異なる"--with-ruby-version"オプションで構築された環境間では、{gemやbundlerのパスに関して互換性が無くなってしまう}

ということのようです。たいへん恐縮ながら、

`center large red` ライブラリの互換性を保証するために(も)使われる名前がコンパイルオプションで自由に変更できるようになってちゃ駄目なんじゃないでしょうか?

途中まではFreeBSD固有の問題かなと思っていたんですが…。

`green`