【C言語】ARPキャッシュポイズニングを実装する

こんにちは、まさです!

前回までで、実際にC言語のpcapライブラリを使って生のパケットを送信する方法について紹介しました。
生のパケットは、unsigned char型の配列で表されており、パケットの送信先などの情報もOSI参照モデルで決まった書式でパケットに書き込まなければいけません。


今回は実際に下の画像のような偽のARPパケットを生成する方法を紹介します。
つまり、IPアドレス192.168.0.1、MACアドレス11:22:33:44:55:66のPCに対して、自分がIPアドレス192.168.0.2であると”偽った”ARPパケットを生成します。

f:id:kasayanus:20180724213021p:plain

まず最初に言っておきますが、ARPパケットは必ず42バイトのデータにすることが決まっています。
なので、送信するパケットを表すunsigned char配列の要素数は42になります。
以下では具体的に、このこの配列の要素にはどのようなデータが入るのか説明していきます。

次の画像を見てください
f:id:kasayanus:20180802174845j:plain

パケットは必ずこのような階層構造になっており、
今回送りたいARPパケットは第三層ネットワーク層に位置していることがわかります。

つまり今回は
①第二層データリンク層のイーサヘッダ
②第三層ネットワーク層ARPヘッダ

この2つを配列のデータとして記述することになります。

①イーサヘッダ
f:id:kasayanus:20180802175703p:plain
第二層で使うイーサネットのヘッダはこのような14バイトのデータの並びになっています。

1〜6バイトまで→宛先のMACアドレス(今回の場合11:22:33:44:55:66)
7〜12バイトまで→送信元のMACアドレス(今回の場合12:34:56:78:9a:bc)
13〜14バイトまで→パケットのデータのタイプ(今回はARPのタイプを表す8,6の配列)


ARPヘッダ
f:id:kasayanus:20180802172945g:plain
データリンク層のデータが確定したので次はARPヘッダを続いて書き込んでいきます。ARPヘッダは28バイトのデータの並びになっています。

1〜2バイト→ハードウェア識別番号(今回は0,1の配列)
3〜4バイト→プロトコルのタイプ番号(今回は8,0の配列)
5バイト→ハードウェアのサイズ番号(今回は6)
6バイト→プロトコルのサイズ番号(今回は4)
7〜8バイト→オプコード(今回は0,2の配列)
9〜14バイト→ARPリプライの送信元のMACアドレス(今回は12:34:56:78:9a:bc)
15〜18バイト→ARPリプライの送信元のIPアドレス
(今回は192.168.0.2を偽る)→ココ重要!

19〜24バイト→ARPリプライの宛先MACアドレス(今回は11:22:33:44:55:66)
25〜28バイト→ARPリプライの宛先IPアドレス(今回は192.168.0.1)

以上のことをまとめると、今回送るパケットの配列の中身は

unsigned char packet[42]={
    11,22,33,44,55,66,12,34,56,78,0x9a,0xbc,8,6,
    0,1,8,0,6,4,0,2,12,34,56,78,0x9a,0xbc,192,168,0,2,
    11,22,33,44,55,66,192,168,0,1
};

この配列を前回紹介したsend_packet関数で送信すればARPキャッシュポイズニングに成功するわけです。

これで具体的な偽のパケットの作り方の紹介はおしまいですが、実際には今回生成したイーサネットヘッダ、ARPヘッダは構造体として定義したほうが後々便利でしょう。例えば次のような構造体を定義しておきます。

#define ETHER_ADDR_LEN 6
#define ETHER_HDR_LEN 14

struct ether_hdr{
	unsigned char ether_dest_addr[ETHER_ADDR_LEN];
	unsigned char ether_src_addr[ETHER_ADDR_LEN];
	unsigned short ether_type;
};

struct arp_hdr{
	unsigned short hardware_type;
	unsigned short protocol_type;
	unsigned char hardware_size;
	unsigned char protocol_size;
	unsigned short opcode;
	unsigned char sender_mac[6];
	unsigned char sender_ip[4];
	unsigned char target_mac[6];
	unsigned char target_ip[4];
};

またヘッダの各部分の意味については今回省略しましたが次のサイトに詳細が載っていますので参考にしてください。
www.atmarkit.co.jp