CentOS を 6 から 7 にアップグレードしてみた。

どうもみむらです。
先日まで某学会に出席していた関係で遅くなりました。

 

学会に向かう朝に Twitter を眺めていたら CentOS 7 が出た! というツイートが流れていまして

・・まじすか! もう CentOS 7 出たんか! でも時間が無い・・!
と思いながら、学会に行って、帰ってきました。

今日は普段の行いが最高に悪かった為か、
頭痛なり腹痛なり、とりあえず若者が掛かる「痛」のある程度の症状が出て
日中はダウンしていました。

日中は布団とトイレの往復を何度やって、段々と落ち着いてきたのでやろうか、と。

・・・そんなわけで今に至る訳です。

 

閑話休題

 

それではアップデートを。

良く纏まっているウェブサイトがありますので、基本的にはこちらに従う感じで。
http://abi.io/blogs/in-place-upgrade-centos-6-5-to-7-0-using-preupg.html

 

それと systemd ベースのシステムに変わるため、
十分に時間を確保できる状況になってからアップデートすることをおすすめします。

 

1. バックアップを取る

環境が壊れたとき、対応するのはやった人本人となりますので、
普通はバックアップしてから作業をすることを強くおすすめします。

 

2. 現行のシステムにおいて必要なアップデートを全部適用する

yum update
reboot

yum でアップデートして、再起動します。

 

3. Pre-Upgrade 用のツールをインストール

Windows でいうと「システム更新準備ツール」というところでしょうか。

下記URL にファイルが転がっているのでこれをインストールしていきます。

(依存しているパッケージのインストールも含め。)

http://dev.centos.org/centos/6/upg/x86_64/Packages/

 

yum -y install openscap pcre-devel libxml2-devel libxslt-devel m2crypto python-simplejson mod_wsgi

rpm -ihv http://dev.centos.org/centos/6/upg/x86_64/Packages/preupgrade-assistant-1.0.2-33.el6.x86_64.rpm
rpm -ihv http://dev.centos.org/centos/6/upg/x86_64/Packages/preupgrade-assistant-contents-0.5.13-1.el6.noarch.rpm
rpm -ihv http://dev.centos.org/centos/6/upg/x86_64/Packages/preupgrade-assistant-ui-1.0.2-33.el6.x86_64.rpm
rpm -ihv http://dev.centos.org/centos/6/upg/x86_64/Packages/python-rhsm-1.9.7-1.el6.x86_64.rpm
rpm -ihv http://dev.centos.org/centos/6/upg/x86_64/Packages/redhat-upgrade-tool-0.7.22-1.el6.noarch.rpm

4. Pre-Upgrade 用のツールを実行

root になってから preupg を実行します。

実行直後、英語で「ちゃんとバックアップとったか?」と聞かれるので

とっている場合 or システムが動かなくなってもがんばれる人 は “y” と回答して実行させます。

#su
Password: 

#preupg
Preupg tool doesn't do the actual upgrade.
Please ensure you have backed up your system and/or data in the event of a failed upgrade
 that would require a full re-install of the system from installation media.
Do you want to continue? y/n
y
....

 

5. アップグレード

redhat-upgrade-tool を実行します。

接続先は IIJ に。

redhat-upgrade-tool --network 7.0  --instrepo http://ftp.iij.ad.jp/pub/linux/centos/7/os/x86_64/ --force

–network : バージョン指定 (今回の場合は 7.0)

–instrepo : アップグレード用起動イメージの取得先 ( –instrepo=REPOID   get upgrader boot images from REPOID )

 

ヘルプを見ていて、もしかして “enablerepo” とかでも大丈夫じゃ・・とか思ったのですが

redhat-upgrade-tool --network 7.0  --enablerepo http://ftp.iij.ad.jp/pub/linux/centos/7/os/x86_64/
Usage: redhat-upgrade-tool <SOURCE> [options]

redhat-upgrade-tool: error: --instrepo is required with --network

とのことで。

処理は結構な時間がかかりますので、ニコニコ動画で好きな動画を見てくるとか、

コーヒーを煎れるとかそういうことをして暇をつぶすといいと思います。

testing upgrade transaction
rpm transaction 100% [====================================================================]
rpm install 100% [====================================================================]
setting up system for upgrade
Finished. Reboot to start upgrade.

・・ということで再起動します。

 

6. 再起動

再起動すると、5でダウンロードしたファイルを元に

アップグレード処理が始まります。

・・アップグレード用ツールが入ったブートイメージで起動して処理が行われるため、

完了するまで操作はできなくなります。

(Windows でいうところの Service Pack インストール時の起動直後にあるような、

更新しています・・ 80%.. みたいな状態になります。)

こちらも結構な時間がかかりますので、

お茶を煎れるとかで待っているといいと思います。

 

また、初回起動は結構な時間がかかります。

それも特に文字の表示が出ませんので、いろいろと不安になりますが長く待ちましょう。

2回目以降は早く起動します。(ただしこちらも文字表示等はなし)

 

7. いろいろと設定

今まで設定されていたサービスのいくつかが立ち上がっていないことに気づくかとおもいます。

でもって  ls /etc/init.d/ とかしてもすっからかん。

でもって /etc/init.d/README を読んでみると、

”systemd based の OS になったから、昔ながらの init スクリプトは ネイティブな systemd サービスファイルになったよ!”

と書かれています。

でもって、 “systemctl” コマンドを使ってくれとも書いてあります。

要は、

今まで “service named start” とやっていたのが

“systemctl start named” という感じになる
、ということで。

 

いくつか使いそうなものを書いておくと:

 

service named start (サービス開始)

→ systemctl start named

service named stop (サービス停止)

→ systemctl stop named

service named status (サービスの状況を確認する)

→ systemctl status named

chkconfig named on (サービスを自動起動設定する)

→ systemctl enable named

chkconfig named off (サービスを自動起動から外す)

→ systemctl disable named

 

こんな感じで、ちまちま設定していくと良さそうです。

 

・・また、どんなサービスがあったか忘れたよ! という場合は、

/usr/lib/systemd/system/

あたりを見ると、思い出すかもしれません。

 

また、 net-tools による制御 (ifconfig etc..) はどうも非推奨になったようなので、

yum remove net-tools を実行して、

ip addr による制御に慣れておくのもいいかもしれません。

 

8.見落としそうなところ

1. mysql は MariaDB に変わりました

MySQL が入っていた環境だと、 systemctl start mysqld をしても立ち上がらないので

不思議に思うかもしれませんがアップグレードの最中に消されるようです。

ただ、データは残っていますので、落ち着いて yum install mysql として、

MariaDB をインストールすれば大丈夫です。(自動的に移行されます)

→ yum install mariadb-server としてもインストール可能。

 

2.xinetd が止まってます。

xinetd に依存したサービスを動かしていた場合は

systemctl enable xinetd として有効にしてやる必要があります。

 

3.dovecot でメールが受信できない

Initialization failed: namespace configuration error: inbox=yes namespace missing

こんなエラーがログにたまっていて、接続はできるけれど読み出せない状況が発生します。

この場合は、

/etc/dovecot/conf.d/15-mailboxes.conf に

inbox = yes

の記述を追記するか、

15-mailboxes.conf を削除すると動きます。

 

4. “/home/*/public_html” にコンテンツが置かれている場合に、どうもうまく Apache が動かない

/etc/httpd/conf.d/userdir.conf

に設定が記述されていますので、このあたりを編集してみるといいかと思います。

 

5.モジュールの読み込み周りで Apache が動かない

モジュールの読み込みに関しては、

/etc/httpd/conf.modules.d

で行うように変更されたようですので、そちらに。

 

6.iptables サービスが既定で Disabled になっている

これはファイアウォールの機能が “firewalld” に移ったため。

iptables をとりあえず有効にした後に、firewalld での書き方に移っていくといいかなと思います。

 

7.CentOS 6 のパッケージをきれいに消したい

rpm –qa | grep el6 | xargs rpm –e

こんなことすると幸せになれるかも。

ただ、何も考えずにこれを実行すると不幸せになるので、ちゃんと確認してから。

 

8./var/log にログファイルがない!

http://fedoraproject.org/wiki/Changes/NoDefaultSyslog

この辺にあるのですが、 “journalctl” コマンドを使用するように標準が変更されています。

もちろん、 rsyslog を入れて、サービスを有効にすれば今まで通りログが出てきますが、

”systemd journal” に管理を任せてみるのもよいのでは。

・・一応、

journalctl | grep dovecot  とかすれば、その製品だけのログを取りだしてくる事が出来ます。

 

9.postfix でメールが送れなくなった!

saslauthd による認証を行っている環境では、

saslauthd が止まっている事によってメールが送信できない事があります。

systemctl enable saslauthd

systemctl start saslauthd

で良い感じに。

 


・・あとで何か新しいことを見つけたら書き換えます・・。

とりあえず、このあたりまで・・。

Hyper-V でネットワークブリッジを作ってもパケットが出てこない場合のメモ。

ちょっと某所でやっていてハマったのでメモ。

次に書いたような設定を書いても、反対側の口から何も出てこなかった場合にチェック。

cloned_interfaces="bridge0"
ifconfig_bridge0="addm hn0 addm hn1 up"
ifconfig_hn0="up"
ifconfig_hn1="up"

チェックするところは下図で、オレンジ色で括っているところ。

image

「MAC アドレスのスプーフィングを有効にする」を ON にしているかどうかをチェック。

ExQueueWorkItem を使って PASSIVE_LEVEL で呼び出せる命令を他の IRQL から実行させる。

どうもみむらです。

 

最近とある用があってカーネルモードドライバを書くことが出てきました。
なんだかんだ、Linux 用のドライバも Windows 用のドライバも慣れると楽しいですね。

(ブルースクリーンに行かないように考えながらコードを書くのが良い感じに脳みその体操になってとっても楽しいです。 気を抜くとすぐにブルースクリーンになりますし。)

 

さてさて。

Windows なカーネルモードドライバを書いている上でなかなかに問題になることの一つに
IRQL の話があると思います。

詳しくはこちらのウェブサイトに詳しくまとめられていますのでそちらにお任せするとして。
http://d241445.hosting-sv.jp/community/report/report11.html

要は各割り込みに優先度を付けて、すぐに行わなければならないやつをすぐに行えるようにする・・と
おおざっぱですがそのような感じです。

 

また各 IRQL によって実行可能な API が限られており、
もしそれを無視して実行すると

image

こんな感じで、 “IRQL_NOT_LESS_OR_EQUAL” な BSoD が発生します。
(ちなみにこれは KeBugCheckEx に 0xA と適当(?)な数字を設定して呼び出しました。)

 

各種コールバックでは DISPATCH_LEVEL でやってくるケースもあり、
PASSIVE_LEVEL でのみ呼び出せる関数をどうやって呼び出すか。


今回の一件は、
フィルタを挟み込んでデータをファイルに書き出すというようなドライバを書いていて、
どこかのタイミングで書き出せればいいと考えて、

ExQueueWorkItem を DelayedWorkQueue で呼び出して、
呼び出し先にファイル書き込みを書く・・という方法で対処しました。

 

コードとしてはこんな感じ

#include <Ntifs.h>
#include <ntddk.h>
#include <Ntstrsafe.h>

#define STR_LENGTH 0x1000

typedef struct _DATA
{
	LARGE_INTEGER time;
	wchar_t str[STR_LENGTH];
} DATA, *PDATA;

void _PassiveWrite(PDATA);

/* 外部から呼び出される関数。ここは IRQL <= DISPATCH_LEVEL であれば実行可能 */
void Write(PDATA d)
{
	WORK_QUEUE_ITEM workitem;
	PDATA data;

	/* 非ページプール上に領域を確保する */
	data = (PDATA)ExAllocatePoolWithTag(NonPagedPool, sizeof(DATA), 0x0616);
	if(data == NULL)
		return;

	/* データを準備する。 */
	ExInitalizeWorkItem(&workitem,_PassiveWrite,data);
	memcpy_s(data,sizeof(DATA),d,sizeof(DATA));

	/* Queue に登録する */
	ExQueueWorkItem(&workitem, DelayedWorkQueue);
}

/*
ExQueueWorkItem によって登録され、実行可能になった時に呼び出される。 
ここの IRQL は PASSIVE_LEVEL になる
*/
void _PassiveWrite(PDATA data)
{
	HANDLE handle;
	NTSTATUS status;
	UNICODE_STRING str;
	IO_STATUS_BLOCK statusblock = {0};

	/* ファイルオープン */
	{
		UNICODE_STRING path;
		OBJECT_ATTRIBUTES attr = {0};

		RtlInitUnicodeString(&path, L"\\??\\C:\\Logs\\nonohara.log");
		InitializeObjectAttributes(&attr,&path,
			OBJ_CASE_INSENSITIVE | 
			OBJ_KERNEL_HANDLE |
			OBJ_FORCE_ACCESS_CHECK,
			NULL, NULL);

		status = ZwCreateFile(
			&handle,FILE_APPEND_DATA,
			&attr,&statusblock,NULL,
			FILE_ATTRIBUTE_NORMAL,
			0,FILE_OPEN_IF,
			FILE_SYNCHRONOUS_IO_NONALERT,
			NULL,0
		);
		
	}

	if(!NT_SUCCESS(status))
	{
		ExFreePoolWithTag(data,0x0616);
		return;
	}

	/* 書き込む文字列を作る */
	str.Buffer = ExAllocatePoolWithTag(NonPagedPool,STR_LENGTH*2,0x1133);
	str.MaximumLength = STR_LENGTH*2;
	str.Length = 0;

	RtlUnicodeStringPrintf(&str,L"%I64u,%s\r\n",
		data->time,
		data->str
	);

	/* 書き込む */
	ZwWriteFile(handle, NULL, NULL, NULL, 
		&statusblock, str.Buffer, str.Length, NULL, NULL);

	/* バッファーをクリアする */
	ZwFlushBuffersFile(handle,&statusblock);
	ZwClose(handle);

	/* メモリを解放する */
	ExFreePoolWithTag(str.Buffer, 0x1133);
	ExFreePoolWithTag(data, 0x0616);
}

 

たとえばこれを応用して、

ドライバを開始したタイミングでファイルを開いてハンドルを握っておき

(その間、共有状態で CreateFile をしていないので他からのアクセスがロックされる。)

ドライバが停止するタイミングでバッファをフラッシュしてクローズする・・とか。

(その間バッファリングが効くので、たぶん良い感じになる・・はず)

 

後は何か、特定の動作があった場合に何かを呼び出すとかそういうのが書けます。

 

・・・とりあえず、個人的なメモ。

誰かドライバを書いていてこの記事で解決することがあれば・・。

Github 製エディタ ATOM for Windows.

3af1db48-d3dd-11e3-98dc-6066f8bc766f

 

7/4 追記:

http://atom.someguy123.com/#sthash.qFfvJCrT.21QtBbhw.dpbs

ここで自動的にビルドしたやつを公開しているっぽいです。(やっぱし。。)

でも安定版を追っかけてるっぽいので、
git から clone してきて・・とする場合は、やっぱり自分でビルドする必要がありそうです。


GitHub さんが出しているコードエディタ。

何となく話題になっていましたので使おうと思ったのですが、
Mac 版しかバイナリが提供されておらず、
しょうが無いのでソースを取ってきて Windows 向けにビルドしました。

 

やったことはこのページに従っただけ。
https://github.com/atom/atom/blob/master/docs/build-instructions/windows.md

ただ、手持ちの常用環境ではうまくビルド出来ず、
仮想環境を用意してやったところ成功したので、ビルド出来ていない人は多いのかも。

 

リファレンスについてはこのあたりを見ておくととても良い気がします。
http://qiita.com/spesnova/items/d3096d062d70e7385e9d

Mac 用ですが、ここの “cmd” をすべて “CTRL” に読み替えれば大丈夫です。

 

というわけで、以下のリンクよりダウンロード可能です。
(容量が大きいので Google Drive にリダイレクトされます)

( Atom-0.109.0-68f2bd5.zip – Google Drive )
http://go.mimumimu.net/1xqfwoz

ビルドしたバージョンは 0.109.0-68f2bd5 になります。

 

またこのプログラムは MIT ライセンスになります。
http://opensource.org/licenses/mit-license.php
http://sourceforge.jp/projects/opensource/wiki/licenses%2FMIT_license

 


Download Link:

http://go.mimumimu.net/1xqfwoz

Atom-0.109.0-68f2bd5.zip (Google Drive.)

セキュリティキャンプ 2014, Network クラスの Write-up

どうもみむらです。

先日、IPA が主催するセキュリティキャンプ 2014 の応募が締め切られまして、
噂では結構な倍率だったそうです。

http://www.ipa.go.jp/jinzai/camp/2014/zenkoku2014_sheet2.html

応募用紙は各クラス毎に大変難しい問題が用意されていて、
その中でも、特に今回は「ネットワーク・セキュリティ・クラス」の問題が難しいということで
少しやってみることにしました。


まずはマシンを用意。

Windows 7 Service Pack1 の環境を用意します。

01

02

 

 


問題ファイルを見てみる

ファイルをダウンロードして・・

03

テキストファイル!
ということで開いてみますと・・

04

・・・全然テキストファイルじゃないですね。
これが闇か。

 

くよくよしていられませんので早速がんばってみます。
読めそうな部分に、 “Server : Apache/2.2.16(debian)” というようなものがあります。

“Apache” という名前で調べてみると、どうやら Web サーバのようで、
もしかするとこれは HTTP の通信では無いかというところが分かります。

http://httpd.apache.org/

また、先頭が “ヤテイ” になっているところから、pcap ファイルということで間違いなさそうです。


切り出してみる

切り出してみれば何か分かるかもしれない!

05

HTTP なら “GET” があるはずということでそこ以降を切り出してみます。
・・・何か読めそうな文字が続きますが、それ以降が読めません。

帰ってくる内容だけ取り出してみることにします。
返答部分の最後が “Content-Type: text/plain” なのでそれを使います。

06

メモ帳で文字数をカウント。どうやら24文字のようです。

07

早速切り出してみます。でもやっぱりよく分からないデータはよく分からないデータ。

08

なにか余計なデータがあって、それによって化けてしまっているのかも!
・・てことで数字でデータを眺めてみます。

09

13,10,13,10..  改行ですね。必要ないので削りましょう。

10

うん。良い感じ。これなら読める・・?

11

やっぱりダメですか・・?

エンコーディングが間違っているのかもしれません。
変換する処理を書くのは面倒なので、ファイルに書き出してメモ帳に与えてみます。

12

・・・やっぱり出ません。ちょっと何か見落としているんでしょうか。

13

HTTP ヘッダのところに “Content-Encoding: gzip” とあります。

でもメモ帳ではそういうエンコーディングは対応していないようです。

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
仕様を見てみると、どうやらこれは gzip 圧縮を意味しているようです。

では残りの部分を gzip で展開させればデータが出ますね。

14

・・・いや、出ません。。

どうも調べてみると、通信時にパケットで分割されているらしく
そのまま後半の部分を与えても読めないようです。

確かに Content-Length をみるとなかなかに大きい値になっています。

TCP パケットの情報が分かれば・・というところですが、
「オプションフィールド」ということで可変長のデータが最後にくっついているため
後ろから見つけ出すのは問題がありそうです。

では pcap を頭から読むかとしても、
さすがに pcap を読むライブラリは入っていません。どうしたら良いでしょうか。


pcap を読む

困ったときは仕様を見ます。

まず pcap から
http://wiki.wireshark.org/Development/LibpcapFileFormat

最初に pcap ファイルに関する情報が入っているようです。 (pcap_hdr_s)
ですが余りここには必要な情報はなさそうですので
4+2+2+4+4+4+4 = 0x18 分読み飛ばします。

typedef struct pcap_hdr_s {
        guint32 magic_number;   /* magic number */
        guint16 version_major;  /* major version number */
        guint16 version_minor;  /* minor version number */
        gint32  thiszone;       /* GMT to local correction */
        guint32 sigfigs;        /* accuracy of timestamps */
        guint32 snaplen;        /* max length of captured packets, in octets */
        guint32 network;        /* data link type */
} pcap_hdr_t;

 

次に各パケット毎の情報が入っているようです。 (pcaprec_hdr_s)

取得時間とパケットのファイル上のサイズと実サイズが記述されています。

読み飛ばす際やパケットを処理する際に必要になるので、

8 – 12 にある incl_len を切り出しておきます。

typedef struct pcaprec_hdr_s {
        guint32 ts_sec;         /* timestamp seconds */
        guint32 ts_usec;        /* timestamp microseconds */
        guint32 incl_len;       /* number of octets of packet saved in file */
        guint32 orig_len;       /* actual length of packet */
} pcaprec_hdr_t;

Little Endian なので

[System.Bitconverter]::ToInt32($data | Select-Object -Skip (0x18 + 8) -First 4),0)

とかすると数字に変換できます。

incl_len で指定された範囲にあるデータが1つあたりのパケットになり、

incl_len 分読み飛ばした場所にはまた パケット毎のヘッダ情報とデータがあります。


パケットを読む

あとは仕様書に従って読んでいきます。

まずは イーサネットヘッダから

http://www.atmarkit.co.jp/ait/articles/0107/05/news001_3.html

最初のプリアンブル部分はどうも取得されていないようなので、宛先アドレス, 送信先アドレス, タイプ ってことで 6+6+2 = 14 バイト分読み飛ばします。

次に IP ヘッダ

http://www.atmarkit.co.jp/ait/articles/0304/04/news001_2.html

まずここの部分のサイズを取得する為にヘッダ長を取得します。

4bit ということで、8bit 単位でデータを取得した後で 0x0F を AND して取り出します。

出てきた数値は 32bit 単位ということですのでその値に ×4

コードとしては、

($ipheader[0] -band 0xF) * 4

 

とかすると、実際のサイズが出てきます。

サイズを求めたら、そのサイズ分読み飛ばします。

次に TCP ヘッダ

http://www.atmarkit.co.jp/ait/articles/0401/29/news080_2.html

まず、データ・オフセットを読みます。

これはアプリケーションが決めた送受信データ・・がどこから始まるかというのが書いてあり、

今回欲しいデータの始まる位置が分かります。

今回の場合は 上位 4bit ということで、 0xF で AND したあとで ÷16 を行い、

IP ヘッダと同じく 32bit 単位なので ×4 します。

コードとしては、

(($tcpheader[12] -band 0xf0) / 16) *4

こんな感じ。

そして、フラグも同様に切り出します。

[PSH], [ACK] を監視して PSH – ACK or [PSH,ACK] の区間を切り出してデータとして眺めるようにしてみます。

データとしては 先ほど取り出したデータオフセット(4bit)の直後から 12bit となります。

(要は 4bit + 8it)

コードとしてはこんな感じ:

($tcpheader[12] -band 0xF) * 256 + $tcpheader[13]

 

後は 先ほど取得したデータ・オフセット分だけデータを読み飛ばします。

ここまで来ればここから先は HTTP の通信データになります。(やったね!


HTTP を読む

何でしょうかこの、戻ってきた感じと達成感。

マリオRPG でもありましたよね。

クッパ城に最初に行って、なんか剣が突き刺さって・・

マップをぐるーっと回ってクッパ城に戻ってくる感じの。アレに似てますよね。

・・・・ちょっと時代が古いですかね。ごめんなさい。

 

さて。

まず HTTP 通信が行われているかどうかをさくっと判定します。

flag を見ても良いんですが 現在の位置が最初に取得したパケットのサイズを

パケットの頭の位置に足し合わせた値が一緒ならデータが無いので次のパケットを読み込みます。

ある場合にはデータを見ていきます。

・・とはいってもデータが取れているか気になるモンです。

なにか通信しているデータがある時にその中身を適当に表示させてみると。

15

・・・良い感じですね。良い感じでデータが出てきました。

あとは、Flag が PSH だけの間はそのデータを結合していき、

ACK or PSH,ACK が来たときにデータが完全に送られたと判断して、処理を行います。

データが取れたら、後は一番最初でやったように HTTP ヘッダを読み飛ばして下の部分だけ切り出し、

Gzip を展開します。

16

C# の GzipStream が使えますので、それを呼び出します。

http://msdn.microsoft.com/ja-jp/library/system.io.compression.gzipstream(v=vs.110).aspx

 

あとはそれをファイルに書き出すと・・。

17

テキストファイルが出てきました! これなら読めそうです。

・・・でも、ここからまた問題を解く必要がありそうです。

 

最後に今回作ったコードを貼り付けておきます:

$file = Get-Content "C:\Users\yahihashoo\Desktop\000038855.txt" -Encoding Byte
$text = New-Object System.String($file,0,$file.Length)
$p = 0x18 # PCAP の Header 分
$fin = 0
$stream = New-Object System.IO.MemoryStream
$output = New-Object System.IO.FileStream "C:\Users\yahihashoo\Desktop\question.txt",([IO.FileMode]::Create),([IO.FileAccess]::Write),([IO.FileShare]::ReadWrite)

do{
    $size = [System.BitConverter]::ToInt32(($file | Select-Object -Skip ($p+4+4) -First 4),0) #packet size.
    $p += 4 * 4 # PCAP の各パケット分
    
    $packet = ($file | Select-Object -Skip $p -First $size)
    $packetpos = 6 + 6 + 2 # Ethernet Frame.
    $srcip = $packet[$packetpos + 12] * 0x1000000 + $packet[$packetpos + 13] * 0x10000 + $packet[$packetpos + 14] * 0x100 + $packet[$packetpos + 15]
    $dstip = $packet[$packetpos + 16] * 0x1000000 + $packet[$packetpos + 17] * 0x10000 + $packet[$packetpos + 18] * 0x100 + $packet[$packetpos + 19]
    $packetpos += ($packet[$packetpos] -band 0xF) * 4 # IP Frame.
    $srcport = $packet[$packetpos] * 256 + $packet[$packetpos+1]
    $dstport = $packet[$packetpos+2] * 256 + $packet[$packetpos+3]
    $seq = $packet[$packetpos + 4] * 0x1000000 + $packet[$packetpos + 5] * 0x10000 + $packet[$packetpos + 6] * 0x100 + $packet[$packetpos + 7]
    $flag = (($packet[$packetpos + 12] -band 0x0f) * 256) + $packet[$packetpos + 13]
    $packetpos += (($packet[$packetpos + 12] -band 0xf0) / 16) * 4
    if ($packetpos -ne $packet.Length)
    {
        $data = $packet | Select-Object -Skip $packetpos
        $html = [System.Text.Encoding]::ASCII.GetString($data)
        $htmlpos = $html.IndexOf("`r`n`r`n")
        if($htmlpos -lt 0)
        {
            $htmlpos = 0
            $htmlbody = $data
        } else {
            Write-Host ([System.Text.Encoding]::ASCII.GetString(($data | Select-Object -First $htmlpos)))
            Write-Host "---------------------"
            $htmlpos += 4
            $htmlbody = $data | Select-Object -Skip $htmlpos
        }
        if($null -ne $htmlbody -and $htmlbody.Length -ne -1)
        {
            $stream.Write($htmlbody,0,$htmlbody.Length)
        }
        if(($flag -band 0x8) -eq 0x8) #ACK
        {
            if($stream.Length -gt 0)
            {
                $stream.Position = 0
                $gzipstream = New-Object System.IO.Compression.GzipStream $stream,([IO.Compression.CompressionMode]::Decompress)
                $buf = New-Object byte[](1024)
                do
                {
                    $read = $gzipstream.Read($buf,0,1024)
                    $output.Write($buf,0,$read)
                }while($read -gt 0)
                $output.Flush()
                $gzipstream.Close()
            }
            $stream.Close()
            $stream = New-Object System.IO.MemoryStream
        }
    }
    
    $p += $size
}while($p -lt $file.Length)
$output.Flush()
$output.Close()

説明文中で書いた読み飛ばしよりも、若干丁寧に読んでます。

実際は シーケンス番号がちゃんと続いてるかとか、IP, PORT あたりの情報も使って

切り出そうと思ったのですが今回はご愛敬ということで。

(ただし、出せるのでやろうと思えば。。でもパケットの順番を見ていないので逆になったりとかするとダメですし、再送とかが発生しているやつを食べさせても処理できません。)

 

それと注意点として。

ネットワーク上の IP アドレスの値やポート番号、シーケンス番号などは

ビッグエンディアンで取り扱われています。

そのため、一つずつ取り出して掛け合わせるというような演算で求める必要があります。

( Linq とか使って4バイト出して反転してリトルエンディアンとして処理しても求まります。)

この辺を最初忘れていて、値を取り出すのに時間がかかったのは秘密。

 


もっとずっと簡単に:

解けるらしいですね。

http://yagihashoo.com/archives/683

なんでも、wireshark というソフトウェアを使えば

すぐに内容が抽出できるということで。

いやー・・。なんというかなんというか。。

ツールを知っていることは重要ですね。

 


最後に:

もちろん、今回の記事はジョークです。

こういうことになってしまった手前、やらねば、と。

もちろん Wireshark は普段使いますし、普段使うマシンにはすべて入れてあります。

こういう縛りなので、Windows 7 のマシンを一つ新規で作成して、

Windows Update を OFF にしてやってました。

18

PowerShell は最初から入っていることを知っていましたし、

C:\Windows\Microsoft.NET 以下に csc.exe という形で C# のコンパイラが最初から

入っていることも知ってました。

・・ま、PowerShell の方が、より面白そうということで。

 

・・・なんでこんな無駄な事をやったかってのがあるかと思いますが、

「こんなことも出来るんだよ!」と、

MSP (Microsoft Student Partners ) の端くれとしての意地、とでも言いましょうか。

大道芸ですごい無駄な事を真面目にやるような、

そんな、なんか気持ちを味わってもらえたらなと思ってやりました。

・・・もし感じて頂けたら本望です。

 


そして・・。

もしこの記事を今年のセキュリティ・キャンプの応募者の方が見ていて、

全力で端折った部分の内容がきちんと分かるということであれば、

応募用紙はさくさくっと書けたのでは無いかなと思います。

是非とも、セキュリティキャンプを通して今後の人生が変わるような、

そんなステキな体験が出来るように祈っています。