私はすぐに言わなければならない:ここでやろうとしていることは、例えば、産業上の利用可能性を装うものではない。 さらに、この例の私のコードは恐ろしく、恐ろしく、不必要であると認めます。 そしてまだ-なぜ週の途中でパケットを傍受しませんか? だから、軽く。
今日はこれを想起させます:
1. TCPおよびUDP用の最も単純なパッシブパケットスニファを実装します
2. Pythonの拡張機能としてCライブラリに配置します
3.このすべてにイテレータインターフェイスを接続して、宝庫のようにバイトがばらばらになるようにします。
4. ...
5.利益!
なぜこれがすべて必要なのですか?
なぜスニファーが必要なのですか? ネットワークトラフィックを傍受する。 いいえ、冗談ではありません。英語の動詞「to sniff」は「sniff」と翻訳されます。 さて、もっと科学的にしましょう-彼らの助けを借りて、コンピュータのネットワークカードを通過するネットワークパケットを分析できます。
スニファーはパッシブおよびアクティブです。 パッシブスニファーは、必要なものだけを正確に実行します。パッシブスニファーは、インストールされているコンピューターのネットワークカードを通過する分析トラフィックをインターセプトします。 それははるかにクールに見えるでしょうか? ただし、アクティブスニッファーはネットワークカードを監視するだけでなく、ローカルネットワーク上を歩くトラフィックを取得しようとしますが、pr索好きな目を意図していません。 彼は、たとえば、 ARPスプーフィングやその他のあらゆるダーティートリックを使用してこれを実行します。 ちなみに、非リピートネットワーク(リピーターとハブに基づく)では、パッシブスニファーはそれ自体で超大電力を突然検出できます。これは、スイッチングがない場合、そのようなネットワークのすべてのパケットがすべてのホストに送信されるためです。 もちろん、受信者のみがそれらを受け入れるべきですが、... :)
しかし、それらを受け入れるには、まず最初にネットワークカードを入手して、通信をフィルタリングする個人秘書を解雇し、一度にすべてを読み始めなければなりません。 科学的には、これは「 プロミスキャスモード 」、つまり「 聞き取れないモード 」と呼ばれます。 そして待ち伏せがあります:
はい、カードを無差別モードにするにはルート権限が必要です。 したがって、スクリプトはそれらの実行を要求します。 そのようなこと。
それで何?
有名な映画キャラクターの一人が言ったように、「もっと深くする必要がある」。 つまり、リンク層でOSI層をより深く掘り下げることです。 これを行うには、ソケットを作成するときに、 PF_INETの代わりに定数PF_PACKETを指定する必要があります。
int s_sock; struct ifreq ifr; strcpy(ifr.ifr_name, IFACE); if ( (s_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) { perror("Error creating socket"); exit(-1); } ifr.ifr_flags |= IFF_PROMISC; if (ioctl(s_sock, SIOCGIFFLAGS, &ifr) < 0) { perror("Unable to set promiscious mode for device"); close(s_sock); exit(-1); }
通常、このようなソケットを開くと、インターセプトが行われる特定のプロトコルが示されます。 定数ETH_P_ALLを指定すると、すべてがインターセプトされます。 Linuxでは、 ifreq構造体が ioctl()を使用してネットワークインターフェイスを低レベルで駆動するために使用されます。この場合、 IFACEは、 「eth0」など、ネットワークを見るインターフェイスの名前を含む文字列です。
実際には、ループ内のソケットからデータを読み取り、何が起こるかを確認するだけです。
int n = 0; char buf[MTU]; n = recvfrom(s_sock, buf, sizeof(buf), 0, 0, 0);
ここでのMTUは、1500に設定するのが最も簡単です。これは、 イーサネットネットワークの標準最大パケットサイズです。 別の標準、たとえばFDDIに従って構築されたネットワークでは、値が異なる場合があります。
イーサネットで作業するので、受信パケットのヘッダーのデータは、この目的のために特別に設計されたカーネル構造に書き込むのが最も簡単です-ethhdr 。 トランスポート層までのさまざまな基本プロトコルには、信じがたいほど難しくなく、 iphdr 、 tcphdr 、さらにはudphdrのように呼ばれる類似の構造があります")。 古き良きCで期待されるように、それは次のようなことをします:
struct ethhdr eth; memcpy((char *) ð, data, sizeof(struct ethhdr));
うーん...そして、これをどのようにPythonに入れるのですか?
誰もがpythonにオブジェクトがあることを知っています。 ジェネレーター/イテレーターの場合も例外はありません-__iter __()メソッドを持ち、 next()できるオブジェクトを作成する必要があります。 オブジェクトには多数のフィールドがありますが、ほとんどのフィールドは必要ないので注意してください-ゼロの前にはたくさんのフィールドがあります。
PyTypeObject PyPacketGenerator_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "packgen", /* tp_name */ sizeof(PacketGeneratorState), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)packgen_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)packgen_next, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ packgen_new, /* tp_new */ };
この発表は、futureオブジェクトの作業メソッドがpackgen_new() 、 packgen_next()、およびpackgen_dealloc()であることを示しています。 後者はデストラクタであり、一般的に、本当に必要な場合、メモリに余分なデータがない場合はデストラクタなしで実行できます。 さらに、現在の反復でのオブジェクトの状態に関するデータを格納する構造が必要です。 格納する必要があるのはソケットだけなので、宣言します。
typedef struct { PyObject_HEAD int s_sock; } PacketGeneratorState;
前述したように、ソケットを開いてネットワークカードをスパイモードで構成する必要があります。 これを行う最も簡単な方法は、オブジェクトの初期化メソッドを直接使用することです。
static PyObject * packgen_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { int s_sock; struct ifreq ifr; strcpy(ifr.ifr_name, IFACE); if ( (s_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) { perror("Error creating socket"); exit(-1); } ifr.ifr_flags |= IFF_PROMISC; if (ioctl(s_sock, SIOCGIFFLAGS, &ifr) < 0) { perror("Unable to set promiscious mode for device"); close(s_sock); exit(-1); } PacketGeneratorState *pkstate = (PacketGeneratorState *)type->tp_alloc(type, 0); if (!pkstate) return NULL; pkstate->s_sock = s_sock; return (PyObject *)pkstate; }
原則として、モジュールのパッケージをクラスの形式で返すことは非常に現実的ですが、
PyObject *packet; packet = PyDict_New(); if (!packet) return NULL; if (ntohs(eth.h_proto) == ETH_P_IP) { ip = (struct iphdr *)(data + sizeof(struct ethhdr)); PyDict_SetItemString(packet, "ip_source", PyString_FromFormat("%s", inet_ntoa(ip->saddr))); ... if ((ip->protocol) == IPPROTO_TCP) { tcp = (struct tcphdr *)(data + sizeof(struct ethhdr) + sizeof(struct iphdr)); PyDict_SetItemString(packet, "tcp_source_port", PyString_FromFormat("%d", ntohs(tcp->source))); ... } if ((ip->protocol) == IPPROTO_UDP) { udp = (struct udphdr *)(data + sizeof(struct ethhdr) + sizeof(struct iphdr)); PyDict_SetItemString(packet, "udp_source_port", PyString_FromFormat("%d", ntohs(udp->source))); ... } } return packet;
出来上がり!
すべて次のようになります。
Python 2.7.3 (default, Apr 20 2012, 22:44:07)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pysniff
>>> for i in pysniff.packgen():
... print i
...
{'ip_destination': '192.168.1.111', 'tcp_seq': '10972', 'ip_source': '173.194.32.53', 'tcp_offset': '8', 'tcp_source_port': '443', 'tcp_dest_port': '44021'}
{'ip_destination': '173.194.32.53', 'tcp_seq': '47475', 'ip_source': '192.168.1.111', 'tcp_offset': '8', 'tcp_source_port': '44021', 'tcp_dest_port': '443'}
{'ip_destination': '192.168.1.111', 'tcp_seq': '10972', 'ip_source': '173.194.32.53', 'tcp_offset': '8', 'tcp_source_port': '443', 'tcp_dest_port': '44021'}
{'ip_destination': '173.194.32.53', 'tcp_seq': '47475', 'ip_source': '192.168.1.111', 'tcp_offset': '8', 'tcp_source_port': '44021', 'tcp_dest_port': '443'}
楽しみのために、 githubにリポジトリを作成しました。アイデアを開発したい場合はどうでしょうか すてきなスニッフィングをして、捕まらないでください!