自宅ネットワークを見直した話

3月末に今の部屋に引っ越してきてから約3ヶ月が経つ。
それ以来、自宅のネットワーク構成は、ISPから貸与されたモデムルータに全ての機器をぶら下げているという面白みのない状態が続いていた。
このままではいけない、ちゃんとしたネットワークを組まねばとは思いつつも面倒で放置していた。
しかしながらこの間新しくルータを買ったことをきっかけにネットワーク構成を多少見直したので記録として残しておく。

3月末からのネットワーク構成

以下の記事に載せた構成図と同様
自宅ネットワーク内にハニーポット(T-Pot)をVMで構築する - 雑記でザキザキ

f:id:itto-ki:20180702222903p:plain
唯一サーバマシン上に立てたVMだけはDMZに置いている。
その他は全てモデムルータの配下。

新しいネットワーク構成

以下のような構成になった。
f:id:itto-ki:20180704231211p:plain
3つのLANにネットワークを分けている。
1つ目はHG100R-02JGによって提供される192.168.0.0/24のネットワーク。
このネットワークの下に他の2つのLANである192.168.1.0/24と192.168.2.0/24のネットワークがぶら下がっている。
またハニーポットもこのルータによって提供されるDMZにGS105E経由で配置している。
何故スイッチを噛ませてるのかというと、たまに常用マシンの余っているNICと接続してポートミラーリングすることでハニーポットの通信を観測したいため。
よく見ると冗長化を考慮したとしてもHG100R-02JGは無駄なのだが、
何故使用しているのかというと、現在大元は同軸ケーブルで配線されており同軸ケーブルがつながるルータがこれしかないためである。

2つ目はEdge Routerによって提供される192.168.1.0/24のネットワーク。
Edge Routerには無線機能はないため、この下にはWRC-F1167ACFをWi-FI APとして配置している。
今回新しく買ったルータはこのWRC-F1167ACFなんだが、ルータとして使うのではなくAPとして使うことにした。
その他、常用しているマシンとサーバもこの下に配置している。

3つ目はAterm WG1800HP2によって提供される192.168.2.0/24のネットワーク。
このルータにはWi-FIルータとしての機能があるため、無線ネットワークをそのまま提供している。
このネットワークの下にも常用マシンとサーバを192.168.1.0/24に繋いでいるのとは別のNICで繋いでいる。
これはEdge RouterとAtermのどちらかが死んでしまっても常用マシンとサーバがインターネットに接続されるようにするための冗長化である。

また、スマートフォンタブレット端末等は、AtermまたはWRC-F1167ACFにより提供されるSSIDを用いてインターネット接続する。

問題点

Edge RouterとAtermによって冗長化しているとは言うものの、
現状の構成ではHG100R-02JGが死んでしまうと意味がない。
この問題は近々解決される予定である。
というのも今住んでるマンションにNuro光回線が引かれるらしいので時期が来たら契約してEdge Routerに接続する予定である。
こうすることでHG100R-02JGが死んでしまってもEdge Routerがインターネットと接続されているため、
常用マシンとサーバ共に問題なく使用できる。

今後の予定

IPv6

まとめ

自宅のネットワーク構成を冗長化を考慮して見直した。
Wi-Fi電波が2.5GHz帯と5GHz帯が2ずつの計4つ飛んでいる。特に意味はない。
家庭のネットワークで冗長化を考慮する必要があるのかというと全くない。
全ては自己満足である。

自宅ネットワーク内にハニーポット(T-Pot)をVMで構築する

「セキュリティ」という単語を見続けていたらハニーポットを構築したくなった。

T-Pot

手軽に構築できるハニーポット環境としてはT-Potが有名だろうということで、
これを用いてハニーポットを構築していく。
github.com
詳しくは他のブログ等を参照していただきたいのだが、
T-PotはISO形式で提供されているハニーポット環境で、
このOSをインストールするとCowrieやDionaeaを始めとする各種ハニーポットソフトウェアがDockerで良い感じに立ち上がるという大変便利なもの。

2年ほど前に一度構築した時はバージョン16.10だったが、現在は17.10が提供されていた。

構成

今回は諸々の事情もあって、VM上にでT-Pot環境を構築し、自宅ネットワークのDMZに配置することとする。
構成図は以下のような感じ。
f:id:itto-ki:20180702222903p:plain
VMを動かすマシンには2つのNICが挿してあるため、片方のNICDMZに接続しハニーポットを動かすVMにブリッジ接続する。

ハニーポットVMの作成

今回のホストマシンにはデスクトップ環境が入ってないため、ホストマシンに対してSSH接続した後、全てコマンドで操作していく。
前提としてハニーポットを構築し動作を確認するまではホストマシンのNICは共にLAN内に接続したまま作業をする。
今回は仮想マシンQEMU(KVM)上に作成し、macvtapでゲストOSのNICをホストOSのNICにブリッジ接続する。
まずは以下のコマンドでqcow2形式のディスクイメージを作成。

qemu-img create -f qcow2 /var/lib/libvirt/images/tpot.qcow2 128G

T-Pot 17.10 - Multi-Honeypot Platform rEvolutionのSystem Rquirementsでは64GB(128GB推奨)となっていたので、128GBとする。

続いてこのディスクイメージに対してOSをインストールしていく。
以下のコマンドを実行するとVMのインストールが始まる。

virt-install --connect qemu:///system \
--name tpot \
--virt-type kvm \
--ram 6000 \
--vcpus 2 \
--arch x86_64 \
--os-type linux \
--disk /var/lib/libvirt/images/tpot.qcow2 \
--network=type=direct,source=enp2s0f0,model=virtio \
--graphic vnc,listen=0.0.0.0 \
--cdrom=tpot.iso

使用するホストマシンのNICとしてenp2s0f0を選んだ。
上のコマンドを実行した後、VMホストマシンのポート5901にVNCクライアントより接続を行うと、ハニーポットであるゲストOSがVNC経由で操作できる。
OSインストールに関して特筆するべきことはないので適宜環境に合わせてセッティングしていく。

セッティングが終わりOSが再起動するとルータのDHCPによってIPアドレスがに割り当てられる。
今後IPアドレスが動的に変化すると面倒なので、ゲストOSの/etc/network/interfacesとルータの設定を編集して固定IPにする。
固定IPを割り当てたら、ルータの設定を変更して割り当てた固定IPをDMZに配置。

T-Potではポート64297でT-Pot内のハニーポットの様子を可視化するダッシュボードを提供している。
早速ブラウザからダッシュボードを見てみると、立ち上げてから数分も立っていないのにも関わらず攻撃がドカドカ来ている。

SSHの設定

ダッシュボードはグラフィカルで見ていて面白いのだが、攻撃の詳細は分からない。
詳細を知るためには生のログを見る必要がある。
T-Potは64295番ポートが管理用のSSHポートとして開かれている。
まずはscpコマンドを用いて公開鍵をT-Potに送る。

scp -P 64295 $HOME/.ssh/id_rsa.pub tsec@<T-PotのIPアドレス>:/home/tsec

公開鍵を送ったら一度パスワード認証でT-Potへ入り、公開鍵を.ssh/authorized_keysに追記
また/etc/ssh/sshd_configを編集してパスワード認証を禁止する。
それらが終わったら以下のコマンドでSSHデーモンの再起動

systemctl restart sshd

これで公開鍵を用いてT-Potへ入れる様になった。
ユーザ名やらポート番号が普段と違うので.ssh/configにT-Pot用の設定を書いておくと便利になる。

色々と探してみるとどうやらハニーポットのログは/data以下に置かれているらしい。
ログの詳細を見ていこうかと思ったけど疲れたのでまた後日。

まとめ

QEMU(KVM)上のVMにT-Potをインストールし、自宅ネットワークのDMZに配置した。
・けっこうな勢いで攻撃が来ている。

React+Express+Node.js+MongoDBでブログっぽい何かを作る (1)環境構築編

今までWebアプリケーションを作る時には、バックエンドであればDjango+Postgres+nginx(もしくはApache)、フロントエンドであればjQueryやその周辺を主に用いてきた。
しかし、そろそろ何か別のものを学習したくなってきたので、React + Express + Node.js + MongoDBでやっていく。
どれも触ったことがないので新鮮。

とにかくまずは環境構築をする必要がある。
今回作る環境はこんな感じ。

f:id:itto-ki:20180701054452p:plain

フロントエンド(React)を提供するためフロントエンドサーバ、APIを提供するバックエンドサーバ、データベースの3つをDockerコンテナとして用意する。

ディレクトリ構成

ディレクトリの構成はこんな感じ

blog
├── backend
│   ├── dockerfile
│   └── project
├── data
│   └── .
├── docker-compose.yml
└── frontend
    ├── dockerfile
    └── project

frontend/projectをフロントエンドコンテナに、backend/projectをバックエンドコンテナに、dataをデータベースコンテナにそれぞれマウントする。

docker-compose.ymlは以下の通り。

docker-compose.yml


gistf1da8a2e4bc697870988241df76035b1
フロントエンドコンテナのポート3000をホストの8888に、バックエンドコンテナのポート3000をホストの8080に、
データベースコンテナのポート27017をホストの27017にそれぞれおポートフォワードしている。
バックエンドとデータベースに関してはサービスを運用する上ではポートフォワードをする必要はないのだが、
このようにしておいたほうが開発時にホスト側から動作確認ができて便利である。


また、backendとfrontendのdockerfileは以下の通り。
ディレクトリの作成とグローバルに必要なモジュールのインストールのみを行っている。

dockerfile(backend)

dockerfile(frontend)

以上の3つのファイルを作成したら、docker-compose.ymlのあるディレクトリで以下のコマンドを叩くとそれぞれのイメージがビルドされる。

docker-compose build

以降でも特別な記述がない限り、docker-compose.ymlのあるディレクトリでコマンドを叩いてるものとする。

モジュールのインストール

続いて書くイメージに必要なモジュールをインストールしていく。
まずはバックエンドサーバから。
以下のコマンドでコンテナを起動する。

docker run -it -v $(pwd)/backend/express:/home/node/backend blog_backend /bin/bash

これでバックエンドコンテナに入ることができる。
続いてプロジェクトに必要な設定ファイルを作り、さらにモジュールをインストールするために以下のコマンドを順に実行。

express --view=pug --git
yarn add http-errors mongoose nodemon

これでバックエンドコンテナの環境が出来上がる。
現在のディレクトリはホストの$(pwd)/backend/expressディレクトリにマウントされているため、
上記のコマンドで生成された設定ファイル、モジュール等はホストからも操作することができる。

続いてフロントエンドコンテナにも必要な環境を作っていく。
先程とほぼ同じように、以下のコマンドでコンテナを起動する。

docker run -it -v $(pwd)/frontend/react:/home/node/frontend blog_frontend /bin/bash

これで先程と同じくフロントエンドコンテナに入ることができた。
さらに同様に環境・モジュールのセットアップを以下のコマンドで行う。

npx create-react-app .
yarn add redux react-redux react-router react-router-dom history @material-ui/core

以上でフロントエンド、バックエンド共に起動させるのに必要な設定、モジュールの準備が出来た。
モジュールはとりあえずこんなもんかなという感じなので必要に応じて適宜追加していく予定。

あとは追加でバックエンドコンテナにインストールしたnodemonモジュールを用いるための設定を行う。
/frontend/project/package.jsonのを以下の様に書き換える。

重要なのはstartコマンドの内容で、このように書き換えることでnodemonを用いてサーバを起動させることになる。
nodemonはコードに変更がある度にサーバをリスタートしてくれるモジュールで、用いることで開発が楽になる。

サービスの開始

以上が全て完了したら以下のコマンドを実行する。

docker-compose up -d

docker-compose.ymlで定義した3つのコンテナが立ち上がりサービスが開始される。
ホストのブラウザからlocalhostの8888, 8080, 27017ポートに接続してみることによって、
それぞれのサービスが稼働していることが確認できるだろう。

環境構築は以上で終了。
次回からはサービスを作り始めていく。

セグメンテーションでのメモリ管理について

IA-32 プロセッサには以下に挙げる2つの動作モードがある。

リアルモード
  • 8086用に書かれたプログラムを実行するモード
  • 16bitで動作する
プロテクトモード
  • メモリ管理やタスク管理、保護機能等の80386で拡張された機能を利用するためのモード
  • 32bitで動作する

今回はプロテクトモードについて特にセグメンテーションでのメモリ管理に注目して取り上げる。

プロテクトモードのメモリ管理

GDTとセグメントディスクリプタ

プロテクトモードではセグメントを用いてメモリ管理を行う。これをセグメンテーションと呼ぶ。
セグメンテーションのためにはメモリ上にGDT(Global Discriptor Table)と呼ばれるセグメントディスクリプタのテーブルを作成する必要がある。
GDTを作るタイミングはリアルモードからプロテクトモードに移行する時。
セグメントディスクリプタはメモリ上に存在するセグメントの位置を指定する。
この様子を以下の図に示す。
f:id:itto-ki:20180413011326p:plain

セグメントレジスタ

また、プロセッサにはセグメントレジスタと呼ばれるセグメントを管理するためのCS,DS,ES,FS,SSの5つのレジスタがある。
これらのレジスタを用いてGDTの中に複数個あるセグメントディスクリプタのうち、どれを使用するのかを指定する。
この様子を以下に示す。
f:id:itto-ki:20180413012838p:plain

この時、セグメントレジスタにあるデータ構造をセグメントセレクタと呼び、以下の様な構造になっている。
f:id:itto-ki:20180413015224p:plain

セグメントセレクタのindex値によって使用するセグメントディスクリプタを指定している。

アドレス指定

さて先程、GDT内のセグメントディスクリプタを用いてメモリ上に存在するセグメントの位置を指定すると書いたが、
これではセグメントの先頭アドレスしか分からない。
一方で、プログラムからは◯◯セグメントの△△番地のアドレスを指定される場合がある。
この様な場合にどうするのか。
ここでセグメントディスクリプタの構造を見てみると以下の様になっている。
f:id:itto-ki:20180413193804p:plain

注目するべきなのは以下の3つのフィールドである。

フィールド 説明
Base Address Low ベースアドレスの下位16bit
Base Address Mid ベースアドレスの中位8bit
Base Address Hi ベースアドレスの上位8bit

これら3つのフィールドを合わせて(32bitsで)ベースアドレスを表す。
プログラムからのメモリアクセスの時は、このベースアドレスとプログラムによって指定されたアドレス(これを論理アドレスと呼ぶ)から、
実際のメモリ上のアドレス(これを物理アドレスと呼ぶ)への変換作業がCPUにより行われる。
また、これによりメモリがどのようにセグメンテーションされていようと、
プログラムに対してはメモリを先頭から使用できるように見せかけることができる。

感想

前に一度理解していたつもりだったけど、ほとんど覚えてなかったので復習した。
セグメンテーションは複雑すぎる機能でLinuxでは使われていないため触れる機会もないので仕方ない。