/

問題文

以下の図のようなDMZとLOCALの2つの空間が接続されている内部向けDNSサーバと、外部向けのwebサーバがあり、webサーバは8000番で待ち受けている。
LOCALからそのwebサーバの8000番に対しFQDNでアクセスしても表示されないと社内の各所から連絡があった。

そのため、内部からwebサーバにFQDNでアクセスできる様に解決してほしい。
ただし、既に構築してあるこのDNSサーバを使い、FQDNで正常にアクセスできることを証明してほしい。

制約

この問題での制約は問題文で指示されている通り、図にあるdns-serverを必ず使用することです。

スタート地点

  • DNSの問い合わせができない

ゴール地点

  • DNSの問い合わせができる
  • 正常に問い合わせができているかをコマンドを使用して証明する
  • 健全なDNSサーバを構築する

必要情報

  • ドメイン: ictsc.local
  • ホスト:
  • web-server: www.ictsc.local
  • dns-server: dns.ictsc.local

情報

サーバIP アドレスアカウントパスワード
dns192.168.4.70admine4EYoNiTlII4zEE7udxG
web192.168.4.71adminEaa4mXBsgygxag934x3H

トラブルの概要

図のように各サーバは2つのNICをもちそれぞれDMZとLOCALに接続されていました。トラブルの概要としてLOCAL側からdns-serverに対して名前解決の問い合わせをしてもドメインと紐づけられているIPアドレスが帰ってこないというものでした。

解説

このトラブルは/etc/bind/以下にDMZとLOCALの空間から名前解決できるように定義されたzoneファイルが不適切のため発生していました。それがこの4つのファイルです。

  • 0.4.168.192.in-addr.arpa
  • 64.4.168.192.in-addr.arpa
  • ictsc.local-0.zone
  • ictsc.local-64.zone

トラブルの原因としてこの4つのファイル全てに共通して以下の3つがありました。

  • SOAレコードを定義する箇所で最初の@が抜けている
  • SOAレコードのhostmaster-emailの最後に.がついていない
  • SOAレコードを括弧で囲むときに最後が)ではなく}となっている

問題の初期状態は以上の3つが原因でDMZとLOCALから名前解決ができませんでした。なので適切な状態に書き直して名前解決ができることを提示すると基準点となります。満点にするためにはゴール地点に記載した通り健全なDNSサーバを構築するまで行うことです。実はこのdns-serverはDMZからictsc.local以外の名前解決をしてしまいます。つまりオープンリゾルバ状態でした。なので外部からはictsc.local以外は受け付けないように設定を変更する必要があります。それには以下のファイルを書き換える必要があります。

  • named.conf.default-zones

解答例

まず、/etc/bind/以下の0.4.168.192.in-addr.arpaを書き換えます。これはDMZの空間からの逆引きを解決するためのファイルです。

$TTL 3600
IN SOA dns.ictsc.local. root.ictsc.local (
2018022400
3600
900
604800
86400
}

IN NS dns.ictsc.local.
10 IN PTR dns.ictsc.local.
11 IN PTR www.ictsc.local.

これを先ほど指摘した3つの原因を以下のように修正します。

$TTL 3600
@ IN SOA dns.ictsc.local. root.ictsc.local. (
2018022400
3600
900
604800
86400
)

IN NS dns.ictsc.local.
10 IN PTR dns.ictsc.local.
11 IN PTR www.ictsc.local.

これを他のファイルも同様に修正し、サービスの再起動を行うことで名前解決ができるようになります。
次にオープンリゾルバを解決するためにnamed.conf.default-zonesを修正します。このファイルの中にinternalexternalのゾーンによって読み込むファイルを記述している箇所があります。そこにmatch-clientsを追加して適切な空間を記述することでオープンリゾルバを回避することができます。

採点基準

  • 上記のトラブルを指摘
  • 対策後にちゃんと名前解決ができていることを提示
  • オープンリゾルバとして動作してしまっているのでそれを指摘して対処(加点対象)

講評

この問題はウォームアップ問題として作成しましたが実際に解答を送ってくれたチームは半分ぐらいで想定と違う結果となり驚きました。その中でもちゃんと最後まで解けていたのは1チームのみでした。

 /
カテゴリー

問題文

電子通信網局 特殊物理装置課から構築中のトラブルを解決して欲しいと依頼が届いた。
社内IoTシステムの開発のためRaspberryPiにRaspbianをインストールしたが、SSH接続ができず何もセットアップができない状態らしい。
尚、初めからSSHを用いてセットアップを行う予定だったためディスプレイやキーボードは用意されていないようが、なんとかしてセットアップを完了させてほしい。

スタート

RaspberryPiにRaspbianをインストールした直後の状態

ゴール

指定されたIPアドレスがRaspberryPiに振られており、SSHでアクセスできる。

情報

  • 指定されたIPアドレス 192.168.0.88
  • ネットワーク・アドレス 192.168.0.0/24
  • デフォルトゲートウェイ 192.168.0.254
  • DNSサーバー 8.8.8.8
  • ユーザー pi
  • パスワード raspberry
  • イメージ 2017-11-29-raspbian-stretch-lite

トラブルの概要

Raspbian は 2016/11/25 以降のイメージではデフォルトでsshが無効化されていて、有効化するためには何らかの方法を取る必要がある。
Raspbian では、IPアドレスを固定する際に編集するファイルが、 /etc/network/interfaces から /etc/dhcpcd.conf に変更された。

解説

Raspbian では以下のいずれかの方法によって ssh を有効化する必要がある。

  • /boot パーティションに ssh という名前の空のファイルを設置してから電源を入れてブートを始める。
  • Raspbian の Linux ファイルシステムを手元のPCにマウントして、 /etc/rc.d などに起動時にsshを有効化するスクリプトを作成する。
  • UART などの何らかの方法でコンソールにアクセスして raspi-config からsshを有効化する、もしくは $ systemctl start ssh ($ systemctl enable ssh) を実行してsshを有効化する。

また、IPアドレスを固定するために /etd/dhcpcd.conf にIPアドレスの設定を追記する。

解答例

お疲れ様です。運営委員の源波です。「アップルパイが完成しない!」問題の作業報告を提出いたします。

まず、一度 Raspberry Pi の電源を抜いてから、Raspberry Pi に挿入されていたSDカードを手元のノートパソコンにマウントします。dfコマンドの結果、 /boot パーティションは手元PCの /Volumes/boot にマウントされていることがわかったので次のコマンドで空のsshというファイルを作成します。$ touch /Volumes/boot/ssh lsコマンドで正常にファイルが作成されていることを確認してから、SDカードを手元からアンマウントし、Raspberry Pi に挿入し直してから電源ケーブルを再度差し込みます。

これで Raspberry Pi のsshが有効化されたので、次にDHCPによって割り振られているアドレスを特定します。Raspberry Pi と同じLANに属しているインターフェイスを対象として、arp-scanコマンドを実行します。 $ arp-scan --interface en0 -l
Raspberry Pi に割り振られているIPアドレスが 192.168.0.8 であることがわかったので、sshで接続します。 $ ssh pi@192.168.0.8 sshで接続できたら、IPアドレスを固定するために、/etc/dhcpcd.conf に以下の設定を追記しました。

interface eth0
static ip_address=192.168.0.88/24
static routers=192.168.0.254
static domain_name_servers=8.8.8.8

networking を再起動して、変更を完了します。$ sudo systemctl restart networking

これでIPアドレスが固定されます。$ ssh pi@192.168.0.88

以上が作業報告になります。よろしくお願いします。

採点基準

採点の基準として、sshの有効化とIPアドレスの固定で、それぞれ50%を想定していましたが、どちらかしかできていないチームはなかった。IPアドレスの固定については、現在でも /etc/network/interfaces の編集による設定でも変更が可能であるが、/etc/network/interfaces の中には、/etc/dhcpcd.conf を編集しろという旨の記述がコメントアウトされており、そちらのほうが妥当であると考え、/etc/network/interfaces を編集していたチームには満点より10点低い点数をつけた。

 /

問題文

導入

仮想機密伝送路課から同時に2件のトラブルの解決を依頼された。
どうやら社内LANの変更工事を行ったところ、いくつか問題が発生しているようだ。
問題を解決し再発を防止するための作業を行って欲しい。
また、必要であれば上司への相談や提案を行うことが出来る。

トラブル1

仮想機密伝送路課から「帯域幅が不足している為、業務に支障をきたしている」という不満の声があり、「ネットワークで使用可能な帯域幅」を増やすこととなった。
以前この部署では上流回線を他の優先的なサービスと併用していた為、何らかの設定が残った可能性が考えられる。
しかし、先日の社内LAN変更工事により回線には次世代ブロードバンドを導入している為、上流の帯域幅のグッドプットは十分に確保されている。
どうやらネットワーク機器の設定変更を忘れてしまっているようだ。
この問題を解決し再発を防止するよう作業してほしい。

スタート

  • 参加者PCを2960BのFE0/9もしくはFE0/10に接続し適当なWEBページにアクセスすると通信速度が明らかに遅い

ゴール

  • 通信速度の問題が仕様(必要情報)通りに改善されている

情報1

  • 部署内のルータである892jの設定を確認し、帯域幅を適切に設定してください。
  • enable password : q0bC50xE
  • 帯域幅は、上流回線をベストエフォート100Mbpsとして業務に使用する帯域は約40%程度として調整して下さい。

トラブル2

電子通信網局でBYODを導入し、局内の端末を全てLANに接続することになった。しかし、一部の人から他の人の端末は繋がるのに自分は繋がらないという不満の声が上がっている。
この問題を“適切に”解決し、再発を防止してほしい。

スタート2

  • 自分“一部の端末”からまともに外部疎通ができない

ゴール2

  • 使用可能なIPアドレスを全て社員の端末に自動設定されるように解放されている。
  • 全ての端末が外部疎通ができる状態になっている

情報2

  • 部署内のルータである892jの設定を確認し、適切に設定を施してください。
  • enable password : q0bC50xE
  • 改善が必要だと思った設定は自由に変更してください。(動作に影響が無ければ減点はありません)

  • この問題に関係のあるIP及びvrfは192.168.17.0/26,vrf17です。それを除く他のIP,vrfは当問題とは関係ありません。

回答例

no ip dhcp excluded-address 192.168.17.31 192.168.17.62
ip dhcp excluded-address 192.168.17.62

shape average 40000000

access-list 1 permit 192.168.17.0 0.0.0.63

access-list 100 permit ip 192.168.17.0 0.0.0.63 any
access-list 100 permit ip any 192.168.17.0 0.0.0.63

コアの技術

  • クラスベースの帯域制御/シェーピング
  • NAT・DHCP・ACLの複合

トラブルの内容

  • シェーピングをかけて帯域制限をしようとしたが、意図した速度より通信速度が大幅に遅くなってしまった
  • BYODでスマホ等を導入したらネットワークに端末が増えて過ぎて(DHCPで)繋がらない
  • DHCPのレンジを拡張したらNATのACLとシェーピングのACLから外れたアドレスが不調になる

###スタート地点
通信速度がめっちゃ遅い
“一部の端末”からまともに外部疎通ができない

###ゴール地点
普通にインターネットができる

###採点基準(基準点160点)
– (計120点)原因の説明・理解
– (30点)ホストアドレスが足りないと気づきNWアドレスの拡張を提案する
– (30点)シェーピングのパラメータが適切な値で無いと気づく
– (30点)IPアドレスが足りない事に気づく
– (30点)ACLが不適切であると気付く

  • (計40点)リモートネットワークに快適に接続できる
  • (20点)スループットが改善されている
  • (20点)全員が適切に接続し自動アドレッシングが行われる

  • (計40点)いい感じで設定を直している

  • (10点)シェーピングの設定値を正しい値に修正出来ているか
  • (10点)PATのACLを変更している
  • (10点)DHCPのレンジ(ip dhcp excluded-address)をいい感じに変更しているか
  • (10点)シェーピングのACLを書き換えているか
  • (10点)アイデア(DHCPのリース期間を変更するなど)

問題解説

この問題はクラスベースの帯域制御、シェーピング、PAT・DHCP・ACLのに関する問題です。
ACLのステートメント条件が他の設定コマンドに影響する事が原因です。
また、ネットワーク管理者はシェーピングを定義する為に発行されているコマンドのサブコマンドパラメータの単位に注意する必要があります。
ネットワーク管理者はこのネットワークセグメントのホスト数を調査し、適切なアドレス設計を上長へ提案する必要があります。

 /

問題文

今まで使っていたサーバが老朽化してしまったため、新しくサーバのマイグレーションを行うこととなった。
現在はそのマイグレーション前の移行作業中なのだが、cronで動作させていたスクリプトが実行されない。

そのため、新しいサーバでcronが正しく実行されるように設定の変更を行ってほしい。

スタート

旧サーバで実行されているcronに登録されているスクリプトが新サーバで実行されない

ゴール

新サーバにて、全てのcronに登録されているスクリプトが正常終了するようにする

トラブルの概要

Linuxディストリビューションにおいて一般的に利用されているタスクスケジューラである cron の実行時に発生する、ディストリビューション間での差異を利用したトラブルです。

一部のLinuxディストリビューションでは、/etc/cron.hourly/, /etc/cron.monthly/, /etc/cron.weekly/のように、ディレクトリ以下にスクリプトを設置するだけで一定の時間間隔でスクリプト群を実行するディレクトリが用意されています。
このディレクトリを実行している実態は /etc/cron.d に設置されていることが多いです。

[vagrant@node1 ~]$ cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core)

[vagrant@node1 ~]$ ls -l /etc/cron.d
合計 8
-rw-r--r--. 1 root root 128  8月  3  2017 0hourly
-rw-------. 1 root root 235  8月  3  2017 sysstat

[vagrant@node1 ~]$ cat /etc/cron.d/0hourly
# Run the hourly jobs
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
01 * * * * root run-parts /etc/cron.hourly

/etc/cron.d/0hourly に、run-parts /etc/cron.hourly というコマンドを実行しています。
この際に実行されている run-parts というコマンドの実装が異なることが、今回の問題におけるキモとなります。

今回の大会の競技時間を考慮した場合、1時間に1回実行されるというシナリオは無用な時間の損失を産んでしまう可能性があったため、疑似的に /etc/cron.d/0minutely というファイルを生成し1分に1回実行されるようにしていました。

run-partsについて

実際に確認してみると、 run-parts というコマンドはディストリビューションによってそもそもファイル形式すら違う事が分かります。

[vagrant@node1 ~]$ cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)

[vagrant@node1 ~]$ which run-parts
/usr/bin/run-parts

[vagrant@node1 ~]$ file /usr/bin/run-parts
/usr/bin/run-parts: Bourne-Again shell script, ASCII text executable



vagrant@node2:~$ cat /etc/debian_version
stretch/sid

vagrant@node2:~$ which run-parts
/bin/run-parts

vagrant@node2:~$ file /bin/run-parts
/bin/run-parts: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=53e52d241c66c42300698ceec057edd3417be4b6, stripped

CentOS においてはBash ベースなシェルスクリプトとして実装されており、Debian においては実行可能なバイナリとして実装されていることが分かります。

CentOS におけるシェルスクリプトでは、以下のような記述がありました。

[vagrant@node1 ~]$ head -n 5 /usr/bin/run-parts
#!/bin/bash
# run-parts - concept taken from Debian

# keep going when something fails
set +e

つまり、元々debianutilsに実装されていたrun-partsをシェルスクリプトで実装したものを、CentOSは利用していると考えられます。

この実装時に差異が発生したのが今回のトラブルの原因となります。

今回の問題におけるトラブル

実際には、以下の差異を利用してトラブルを発生させました。

  • スクリプト名に . を含める (例: crawler.sh)
    • Debianでは . が含まれていても実行されますが、CentOSでは実行されません
  • Shebangがスクリプトに存在しない
    • DebianではShebangが存在しなくても拡張子で判別されますが、CentOSでは拡張子を削除するため記載が必要になります

また、今回は移行時に発生するトラブルとして、以下のトラブルも発生させました。

  • 移行先のディストリビューションにコマンドがあっていない
    • 移行先はDebianだったのですが、 yum update というコマンドを実行させていました
  • cronに登録されているスクリプトが移行先サーバに存在しない
    • WebAPIに対してリクエストを送信するスクリプトが移行元にはあるが移行先には配置していませんでした

採点基準

日本語でこの事象を説明しているブログも多く存在しており、cronという比較的利用者も多いプロダクトであることから、入門編と位置づけて出題しました。
そのため、「どこまで気づいているのか」を採点基準に採点を行いました。

まとめ

トラブルシューティングの基本として、「事象の切り分けを行う」という事があります。
実際にトラブルが発生している事象はどのように実行されていて、どのような箇所で実行されているのかを確かめるのがベターと言われています。

今回の回答を見てみると、「実行権限がなかったので付与しました」「内容が誤っていたため修正しました」などの回答が来ていたのですが、今回で言うなればファイル名を変更しない限り実行されていないため、cronを経由したファイルの実行を確認出来ていなかったのではないかと予測します。
実際にはどのような環境で、どのような方法で目の前のコマンドが実行されているのかを確かめるようにするようにしてみるのが重要だと改めて感じました。

なお、今回の記事中で検証のために利用したVagrantfileはこちらとなります。是非検証してみてください。

 /

問題文

障害対策調査課から依頼があった。
我社で運用しているサービスに初歩的なディレクトリトラバーサルの脆弱性が見つかってしまったらしい。

しかし、不幸なことに担当者がバカンス中のため連絡を取ることが出来ない。
このサービスは担当者にバカンス直前に無理やり開発させたため、ソースコードは彼のPCの中のようだ。
ソースコードが無いのでプログラムの修正が出来ない。
だが、担当者が戻るまでサービスを落としたままにするわけにはいかない。

どうにかしてプログラムを修正せずに安全にサービスを動かしてほしい。

制約

  • サービスは80番ポートで動かす
  • 対外疎通無し
  • 新たにパッケージをインストールする等はできない

スタート

ファイルアップローダーがディレクトリトラバーサルの脆弱性を受けてしまう状態

ゴール

ファイルアップローダーがディレクトリトラバーサルの影響を受けずにサービスが動く状態

情報

  • 192.168.1.10:80 でサービスが動く
  • ユーザ: admin
  • パスワード: yasumikure
  • ファイルアップローダのバイナリ: /home/admin/uploader

Webサービスのパス

メソッドパス動作
GET/アップロードされた画像一覧
GET/upload画像をアップロードするページ
POST/upload画像をアップロード

使用するディレクトリ

パス用途
/var/www/templates/レンダリングするテンプレート
/var/www/assets/jsやcssなど
/var/www/images/アップロードしたイメージの保存場所

サーバ動作確認例

# sshしてサーバを起動
ssh admin@192.168.1.10
sudo /home/admin/uploader

# 手元のブラウザもしくはcurlで 192.168.1.10:80にアクセス

# ディレクトリトラバーサルのサンプル
curl 192.168.1.10:80/upload \
-X POST \
-F "graphic=$(echo 'echo Hacked' | base64)" \
-F "filename=../../hacked.txt"

トラブルの概要

この問題ではディレクトリトラバーサルの脆弱性が発覚したファイルアップローダが用意されています。
これをroot権限で動作させるのはまずいので、どうにかしてある程度安全に動くようにして欲しいというのがこの問題の主旨です。

解説

この問題は「Linux Capability」を知って欲しいという意図で、少々無理やり作りました。
問題を解いていて、思うところがあったかもしれませんがご容赦ください。

さて解説に入ります。まず前提を以下に示します。

  • このファイルアップローダはLinuxで動くELFバイナリとして用意されてる。
  • サービスを動かすポートは80番で固定されているため変更はできない。
  • 80番ポートは、通常は一般ユーザではバインドできず、root権限が必要。
  • ディレクトリトラバーサルのあるアップローダをroot権限で動かすと意図しないファイルが書き換えられてしまう可能性が有ります(そもそもサービス止めろよって話ですが)。

この問題の想定解の方向性は「一般ユーザで80番ポートをバインドしてサービスを動かす」です。
その際に、一般ユーザで80番ポートをバインド可能にするのが「Linux Capability」です。
詳細は省きますが、簡単に説明するとケーパビリティとは「root権限を細分化し、部分的に適用できるようにしたもの」です。
今回はウェルノウンポートを一般ユーザでバイドできるようにするために、cap_net_bind_serviceをアップローダのバイナリに付与します。
こうすることで、このアップローダは一般ユーザで80番ポートをバインドできるようになります。
ちなみに、ケーパビリティを付与できるのはバイナリのみで、スクリプトには付与できません。

解答例

この問題の突破基準は以下の解答、もしくは以下と同等の効果が得られると判断した解答です。
以下はファイルアップローダにケーパビリティを付与し、一般ユーザ(admin)で実行する例です。

sudo setcap cap_net_bind_service=eip /home/admin/uploader
/home/admin/uploader

この解答だけでは、ディレクトリトラバーサルは完全には防ぎきれていませんが、この問題を出した意図は達成されているので良しとしました。
adminユーザのままで実行すると、/home/adminが書き換えられてしまうため、以下のようにするとなお良いです。

sudo --user=nobody /home/admin/uploader

お気づきの方もいると思いますが、この問題はケーパビリティを使わなくても、chrootAppArmorを使うことで解決できます(そのほうが良いケースが…)。
今回はそういった解答で、より堅牢で安全だと判断した解答にはボーナス点を付けさせていただきました。

講評

この問題は15チーム中9チームが基準を突破し、そのうち4チームがケーパビリティを使った解答を送ってくれました。(思ったよりケーパビリティ使ってくれなくてちょっと寂しい…)

先程「ケーパビリティを知ってほしい」なんていいましたが、正直ケーパビリティの実用的な用途ってあまり思いつかないんですよね。
ぱっと思いつくのはcap_dac_overrideを付与した、どこでも覗けるlsとか、なんでも読めるcatぐらいですね。

それでは、問題解説を終わります。