Python用のモジュールの形式で、クレイジーなパッシブスニファーをコーディングします





私はすぐに言わなければならない:ここでやろうとしていることは、例えば、産業上の利用可能性を装うものではない。 さらに、この例の私のコードは恐ろしく、恐ろしく、不必要であると認めます。 そしてまだ-なぜ週の途中でパケットを傍受しませんか? だから、軽く。



今日はこれを想起させます:



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 。 トランスポート層までのさまざまな基本プロトコルには、信じがたいほど難しくなく、 iphdrtcphdr 、さらにはudphdrのように呼ばれる類似の構造があります")。 古き良きCで期待されるように、それは次のようなことをします:

  struct ethhdr eth; memcpy((char *) &eth, 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; }
      
      







原則として、モジュールのパッケージをクラスの形式で返すことは非常に現実的ですが、 私はそれを簡単にして辞書を返すことを決定するのが面倒でした (そして誰かが自分のやり方でリメイクする場合、それは行われます)。 やらなければならないことは、ネットワークレベルでIPがあることを確認し、IPヘッダーに従って、上位プロトコルを決定することです(覚えていない場合、プロトコルは番号で示され、 / etc / protocolsで記述されます )。 パッケージはバーガーキングシェフの作品に似ているため、これはすべて機能します-各上位レベルは下位レベルにタイトルを追加します。 古き良き兄弟-TCPUDPを使いましょう



 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リポジトリを作成しました。アイデアを開発したい場合はどうでしょうか すてきなスニッフィングをして、捕まらないでください!



All Articles