
私はすぐに言わなければならない:ここでやろうとしていることは、例えば、産業上の利用可能性を装うものではない。 さらに、この例の私のコードは恐ろしく、恐ろしく、不必要であると認めます。 そしてまだ-なぜ週の途中でパケットを傍受しませんか? だから、軽く。
今日はこれを想起させます:
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", sizeof(PacketGeneratorState), 0, (destructor)packgen_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT, 0, 0, 0, 0, 0, PyObject_SelfIter, (iternextfunc)packgen_next, 0, 0, 0, 0, 0, 0, 0, 0, 0, PyType_GenericAlloc, packgen_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で記述され
ます )。 パッケージはバーガーキングシェフの作品に似ているため、これはすべて機能します-各上位レベルは下位レベルにタイトルを追加します。 古き良き兄弟
-TCPと
UDPを使いましょう
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に
リポジトリを作成しました。アイデアを開発したい場合はどうでしょうか すてきなスニッフィングをして、捕まらないでください!