アーカイブ

Archive for 2015年2月

qemu用iPXEが古すぎたのでごり押しでworkaround

FedoraやDebianでKVMを使いネットワークブートするとipxe-roms-qemuのiPXEが起動しますが、
そのバージョンが古すぎてcpairがなくてエラーが出たり(Fedora)、menuがなくてエラーが出たり(debian)してしまうようです。
ということで、chainloadで自前のiPXEを起動することにしたのですが、qemu由来のiPXEとtftpでダウンロードしたiPXEをdhcpサーバが区別できません。

tftpで配布するiPXEはuser-classを適当に書き換え、user-classで判別できるようにしました。完全にごり押し解法。

src/net/udp/dhcp.c
- DHCP_USER_CLASS_ID, DHCP_STRING ( 'i', 'P', 'X', 'E' )
+ DHCP_USER_CLASS_ID, DHCP_STRING ( 'r', 'P', 'X', 'E' )


if exists user-class and option user-class = "rPXE" {
filename "tftp://tftpsvr/menu.ipxe";
option ipxe.keep-san 1;
option ipxe.no-pxedhcp 1;
}else{
next-server tftpsvr;
filename "/undionly2.kpxe";
}

こうすると、通常のPXEromの場合でもiPXEの場合でも一度ロードさせることができます。

ちなみに、ipxe-roms-qemu自体のtarballを差し替えてrpmbuildは試しましたがうまく動いてくれませんでした。こっちの原因はまったく不明。

広告
カテゴリー:GNU/Linux

hardcoded user-class “iPXE”

config/general.hを書き換えても変わらないのでソースレベルで追いかけてみた。
本体はnet/udp/dhcp.cのline83、バイト配列 dhcp_request_options_dataのなかに隠されている。

DHCP_USER_CLASS_ID, DHCP_STRING ( 'i', 'P', 'X', 'E' ),

こりゃ文字列”iPXE”で検索しても出ないわけだ。

カテゴリー:未分類

Fedora21のLive DiskをPXEbootする

緊急時用にFedora21の環境をネットワークブートできるようにしようとしたところ、30時間ほどはまり続けました。
1. とりあえず適当に書いた
「なーに、Live DVDダウンロードしてきてvmlinuzとinitrdとsquashfs投げ込めば動くだろー」と甘い考えでとりあえずやってみる。

kernel fedora21/vmlinuz0 rootflags=loop root=live:ht tp://httpserver/bootimg/squashfs.img ro rd.live.image quiet rhgb rd.luks=0 rd.md=0 rd.dm=0
initrd fedora21/initrd0.img
boot

→ dracut: Fatal: Don’t know how to handle root=live:ht tp://httpserver/bootimg/squashfs.img とか言われて失敗します。

2. iPXEのmemdiskでやってみる
→ dracutがルートファイルシステムを見失ってコンソールに落ちる。

3. 【initrdをftpのpxebootディレクトリからもってくる】
Live DVDのdracutがroot=liveを認識できないのが問題なので、じゃあroot=liveを認識できるdracutが入ってるinitrd持ってくれば良いんじゃね?
vmlinuz ( from LiveDVD ) + initrd ( from releases/21/Server/x86_64/os/images/pxeboot/initrd.img ) + squashfs ( from Live DVD) の混成により成功。
kernel optionは1と同様。

カテゴリー:GNU/Linux

windowsインストールディスクのboot.wimに入れたはずのファイルが見えない

WindowsのインストーラをiSCSI bootした時に発生したこと。
蟹NICのドライバが入っていなかったためWindowsに制御が移るとディスクを見失ってしまうため、
boot.wimに蟹のドライバを突っ込むことにしました。

ところが、

dism /mount-image /imagefile:e:\sources\boot.wim /index:1 /mountdir:c:\wimtemp

とやってc:\wimtemp\driversにドライバデータを突っ込んだものの、インストーラを起動してドライバを追加しようとするとdriversディレクトリが見えません。
どうしたことかと戦うこと数時間、「wimは内部に複数イメージを持つことができる」という情報を見たため、もしやと思い

dism /get-imageinfo /imagefile:e:\sources\boot.wim

とかやってみたところ、

インデックス 1
名前 Microsoft Windows PE (x64)
説明 Microsoft Windows PE (x64)
サイズ 1,097,225,907 バイト

インデックス 2
名前 Microsoft Windows Setup (x64)
説明 Microsoft Windows Setup (x64)
サイズ 1,193,059,160 バイト

これである。

インストーラが読むのはindex:2の方なので、

dism /mount-image /imagefile:e:\sources\boot.wim /index:2 /mountdir:c:\wimtemp

して、そっちにファイルを突っ込むのが正解でした。

カテゴリー:その他

Raspberry Pi 2が突然再起動する現象を打開した

先日Raspberry Pi 2を購入し、まずは適当に遊んでみようと動かしてみたのですが、どうにも起動から数秒するとリセットがかかったりして不安定です。
また、画面の右上になぜか起動時の虹色のやつが出っぱなしになります。

再起動の原因は例のフラッシュ問題ではなく、
どうやらGUIを使ったり無線LANを使ったりすると再起動がかかりやすい、と気が付き、
ちゃんと原因切り分けを行った結果、USBケーブルが駄目だったようで、高電流対応のケーブルにしたところ安定しました。
これが800mAの力か。

カテゴリー:その他

NFSでnosuidしてないと最悪ディスクデバイスにアクセスできる

昨日の続きです。

sshポートフォワーディングにより、NFSサーバに対してrootを除く任意のユーザ・グループとしてアクセスする道が開けました。
NFSクライアントでマウント時にnosuidが設定されていない場合、そのクライアントマシンのブロックデバイスファイルに対してアクセスが可能となるケースがあります。
重要な点として、NFSのroot squashはuid/gidが0でないと機能しません。

【ddの所有グループをdiskとし、setgidします】

FedoraとRHEL、CentOS、Debian7で確認した限り、ディスクのデバイスファイル/dev/sd?や/dev/sd??はdisk(gid=6)グループの所有となっており、660です。
(FreeBSDではroot:operatorの640だったので読み込みしかできなさそうです)
このgid=6に対してはroot squash機能が働かないため、以下の手順でデバイスファイルにアクセスする道が開けます。

1. 昨日の記事のように、NFSをローカルマシンにマウントする
2. ローカルマシン上の一般ユーザアカウントに対し、diskグループを付与
3. NFS上にddを配置、グループをdiskに変更
4. chmod g+s
5. NFSクライアント側にログイン
6. NFSクライアント側で、egid=6なddを実行可能となり、ディスクデバイスファイルへの無制限アクセスが可能となる。即ちroot獲得と同義である。

対策
nosuidつけましょう。

実は発見の経緯は逆で、nosuid付いてなかったシステムへの攻撃方法を考えているときにポートフォワード案がでてきてしまい、
「NFSサーバに接続できちゃった時点でnosuidとかどうでもいいだろー」と思ってしまったのですが、まさかこれが最後のピースとなってしまうとは。

カテゴリー:GNU/Linux

NFSサーバのIPアドレス制限は割と簡単に回避できる

NFSの仕様を理解していない方が多いようですが、NFSのマウント成功=NFS上にrootを除く任意のユーザとしてアクセス可能(デフォルト設定の場合。nosquashしていればrootでも素通りする)であるということです

kerberos使ってないNFSを特定条件下で外部から割と簡単にマウントできてしまった話です。

NFSのセキュリティ機構といえばkerberosですが、
この設定が難解で運用が難しく、/homeに使うにはsshの公開鍵認証との相性が悪い事もあり、
IPアドレスベースの制限で済ませている環境も多いかと思います。
IPアドレスベースで制限をかけ、ネットワーク的に独立していれば安全、そう思っていた時期が私にもありました・・・

想定するネットワークの構成は
[ファイルサーバS(NFS)] – SAN – [クライアントマシンC(一般ユーザがssh接続可能)] – 外部
という構成です。割とあるんじゃないでしょうか。
変なルーティングやアクセス制限の設定ミス、SANへの物理的接続による攻撃はないものとします。

さて、この環境下でCのユーザが外部からNFSサーバをマウントすることを考えます。
ssh接続可能というあたりで察した方も多いかも知れません。

【NFSをポートフォワーディングします】

NFSv4 over TCPの環境では非常に簡単です。NFSv4は2049/tcpで完結しているため、

ssh -L2049:S:2049 user@C

2049/tcpをポートフォワードすればそのままlocalhostに対してマウントが通るはずです。
通らなければ次に述べるNFSv3の方法を試すと通ると思います。
sshのポートフォワーディングが禁止されている場合にもnetcatを使えば良いのです。
要は、sshでシェルがとれる状況であれば回避できません。

NFSv4 over UDPの環境でも同様に、何らかのフォワーダを自作すれば通るはずです。
あるいは、sshのsocks機能を使うともっと簡単にできるらしいですが、私は未検証です。

NFSv3 over TCPの環境ではmountdのポートがダイナミックに変わるので若干ややこしくなります。
今回実際に攻略したのはこのパターンです。
まず、NFSの2049/tcpとrpc portmapperの111/tcpをローカルにポートフォワードしてきます。
ここで、ループバックインターフェイスに対してwiresharkを仕掛けておきます。
この状態でlocalhostに対してマウントをかけると、portmapperの応答パケットが見えます。
mountdのポートがわかるので、追加でポートフォワードするとmountコマンドからプロンプトが返ってきてマウント成功します。
sshのsocks機能とそれをtun仮想デバイスに変換するソフトがあるからもっと簡単にできるよって@nvsoftsが言ってた。

NFSv3 over UDPはめんどくさすぎるので未調査。socksで簡単にできるよって@nvsoftsが言ってた。
多分自力でフォワーダ書けばなんとでもなると思います。

ということで、NFSのIPアドレス制限は割と簡単に回避できてしまいます。
対策はNFSクライアント側でのみ実施可能です。前述のとおり、sshのポートフォワーディング禁止は役に立ちません。
根本的な対策としてはユーザランドプロセスからのdestport 2049を落っことすことです。
発見当初、そんな都合の良い方法はないだろうと思っていたのですが、ありました。
LinuxのiptablesとFreeBSDのpfには生成元プロセスのuidやgidに基づくフィルタリング機能があります。
ここではiptablesによる制限を紹介します。

iptablesにおいて、NFSのようにカーネルから発生するパケットはuid/gidではいずれの数値にもマッチしません。
また、!でnot演算すると必ずマッチします。

-A OUTPUT -m tcp -p tcp --dport 2049 -m owner --uid-owner 0:65535 #マッチしない
-A OUTPUT -m tcp -p tcp --dport 2049 -m owner ! --uid-owner 0:65535 #マッチする

ということで、こんなことを書けばとりあえず穴は塞がります。

-A OUTPUT -m tcp -p tcp --dport 2049 -m owner --uid-owner 0:65535 -j DROP
-A OUTPUT -m udp -p udp --dport 2049 -m owner --uid-owner 0:65535 -j DROP

もしかすると、NFSv3だと不具合があるかもしれません。
// そんなレガシーなプロトコルは手元の検証環境にないぜ!
redhat系だとrpcuserがそのへんをやっている可能性があるので、ピンポイントで通してやることで解決するんじゃないかと思います。
lockdはカーネル空間。rpc系プロセスはrootで動いてるのとrpcで動いてるのとrpcuserで動いてるのがいてわけがわからない。

ここからの応用で設定の甘いNFSクライアント(C)側を完全掌握する方法については次回。

— 2015/2/4 22:33 —
socks周り勘違いしていたので修正。sshのsocks機能でUDPを通せるか、さらにNFSを通せるかについて検証してくれる方募集。

— 2015/2/15 —
追試の結果、CentOS 6だとデフォルト設定では一般ユーザが開けるポートからのマウントはrefused mount request : illegal port 38058 とか出てきて落とされるようです。
これを解除するにはexportsにinsecureオプションをわざわざ指定する必要がある模様。発見した環境、なんでこんなもん設定されてたんですかね・・・

カテゴリー:GNU/Linux